var obj = {
name:"Wythe",
getName:function(){
console.log(this.name);
}
};
obj.getName(); //Wythe
window.fun(){}
一样var name = "lucy"
var norMal = function () {
var name = "Wythe"
console.log(this.name)
}
norMal(); //lucy
//或者这样
var obj = {
name:"Wythe",
getName:function(){
console.log(this.name);
}
};
var getName = obj.getName
getName(); //lucy 因为执行时的this已经不是由obj调用了!
//
//
//
//
//
//
//
window.id = "haha";
document.getElementById("divEle").onclick = function () {
console.log(this.id);//divEle
//var that = this
var callback = function () {
console.log(this.id);//haha 看似在获取的元素对象里面,但是执行时依然是被当做函数执行,不是被对象调用;
//that.id
}
callback()
}
//
//
如果我们提前用一个变量接收this,并传递进去就可以解决该问题!就和闭包一样,用一个变量将作用域串起来!
所以我们用构造器这样创建对象实例:
var theClass = function () {
this.name = 'lucy'
}
var obj = new theClass();
console.log(obj.name); //lucy
var theClass = function () {
this.name = 'lucy'
return {
name: 'Bob'
}
}
var obj = new theClass();
console.log(obj.name); //Bob
如果return 'Bob'
就不会出现这种情况!
var obj1 = function () {
this.name = 'lucy'
this.getName = function () {
return this.name
}
}
var obj2 = function () {
this.name = 'Bob'
}
var obj3 = {
name: 'Tom'
}
var obj4 = {
name: 'Assa',
getName: function () {
return this.name
}
}
var obj1 = new obj1();
var obj2 = new obj2();
console.log(obj1.getName()); //lucy
console.log(obj4.getName.call(obj3)); //Tom
console.log(obj1.getName.call(obj2)); //Bob
console.log(obj1.getName.call(obj3)); //Tom
console.log(obj4.getName.call(obj2)); //Bob
不管是构造器还是对象数据,call都能顺利的改变this的指向,call和apply当然不止这么简单,后面部分再进行详解。
var obj = {
name: 'Assa',
getName: function () {
return this.name
}
}
var myObjGetName = obj.getName;
console.log(obj.getName()); //Assa
console.log(myObjGetName()); //undefined
obj的getName函数体赋给myObjGetName后,因为myObjGetName本身是个全局变量,挂载全局window下,所以,执行的时候this的指向不会再指向原来的obj对象。
document.getElementById
,它就是一个别叫特殊的方法,我们先看一下会出什么错://
//
//
//
//
//
//
var getId = document.getElementById;
console.log(getId("divEle")); //Uncaught TypeError
//
//
究其原因呢是getElementById这个方法内部使用了this,本来这个this是指向document的,能够正常接入文档流,但是被赋值给变量后成为了普通函数,this指向发生了改变!
//
//
//
//
//
//
//
document.getElementById = (function (func) {
return function () {
return func.apply(document,arguments)
}
})(document.getElementById);
var getId = document.getElementById;
console.log(getId("divEle")); //成功了嘛
//
//
函数自执行将document.getElementById
作为参数传递进去,apply将函数体里的this强行指向了参数的document。如上例子,在getId执行时,id通过参数传递进去,由func接收,同时自执行函数接收document.getElementById
并拿到对象,apply将document
当成了一个this传给了getId,使得getId的this发生了改变,得以修正!
Function.prototype.bind = function (params) {
var self = this;
return function () {
return self.apply(params,arguments);
}
};
var obj = {
name:"Lucy"
};
var func = function () {
console.log(this.name);
}.bind(obj);
func()//Lucy
这个例子其实有三个过程,第一个过程,func调用bind,并传递对象obj。bind被调用时,bind的this指向func,但是因为func本身是个普通函数,所以指向func后,被func的this指向了window;第二个过程,bind函数里,用self保存了这个指向func然后指向window的this,接收到了对象obj,return将后续内容传递回调用者func函数;第三个过程,本来被返回的是个函数体,但是内部有一个执行了的apply函数,于是,apply将预先保存好this的变量self指向了第一个参数params,并将params的属性遍历后生成的类数组arguments一并返回给了func函数,而这个params也就是obj。最终也就形成了func的this指向了obj对象的结果。
总的来说,call和apply都是用于改版this的指向,使调用者的this指向第一个参数传递进去的对象,而后面的参数都是作为数据传递给调用者!区别在call的数据是分开传递,后面可以由多个参数,而apply的第二个参数是以数组或类数组的方式传递!
obj.getName.call(obj2,1,2,3,4);
obj.getName.apply(obj2,[1,2,3,4]);
var A = function (name) {
this.name = name;
}
var B = function () {
A.apply(this,arguments)
}
B.prototype.getName = function () {
return this.name;
}
var b = new B('Lucy');
console.log(b.getName())
实例一个B的对象,由变量b接收,传递参数‘lucy’,虽然B函数体没有设置形参接收参数,但是arguments仍然能接到数据并创建类数组;然后,A.apply将this指向apply的第一个参数this,这个this代表的是构造器的this,并将arguments的数据传递给A;紧接着,A的this(指向构造器的this,实例化后指向对象b)的name属性接收参数name的数据(由arguments传递过来),使b形成了一个属性name,值为’Lucy’;最后,b调用getName方法,返回出本身的属性name的值。
(function () {
Array.prototype.push.call(arguments,3);
console.log(arguments);
})(1,2)
/*
Arguments(3)
0: 1
1: 2
2: 3
callee: ƒ ()
length: 3
Symbol(Symbol.iterator): ƒ values()
__proto__: Object
*/
var a = {};
Array.prototype.push.call(a,'first');
console.log(a.length,a[0])//1 'first'
var a = 1;
Array.prototype.push.call(a,'first');
console.log(a.length,a[0])//undefined undefined
如果遇到某些不支持的浏览器,我们需要给对象等显示的赋值length属性obj.length
.
[1]参考文献——JavaScript设计模式与开发实践,曾探–腾讯AlloyTeam;