今天对this的指向做一下了解吧,好好学习一下这个问题,在平时中,这个问题很常见的。
1.全局变量默认挂载在window对象下
var a = 2;
console.log(window.a)//=>2
(function(){
b = 3
}
())
console.log(window.b)//=>3
在全局下直接定义一个变量,还有在立即执行函数中没有定义变量也是挂载在全局下的,但是他们有些不同,之前也说过了,没有定义的变量可以删除掉,定义过的变量删除不了。
2.正常的函数中,this指向它的直接调用者。
function(){
console.log(this);
}
test();//=>相当于window.test(),所以指向window
var obj = {
say: function(){
console.log(this)
}
}
obj.say()//=>obj
上面两个例子可以说明这个问题,一般单独调用的时候,这个时候window会省略掉。
3.call/apply来改变this指向
function person () {
this.name = 'si';
console.log(this);
}
person(); // window
var obj = {};
person.call(obj); // Object {name: "si"}
我们可以看到,当使用了call方法之后,person函数内部的this就指向了我们传递的这个对象。现在这个函数就可以为obj来赋属性值了。
如果这个函数还有参数的话,我们只要把实参的值写在call后面并且用逗号间隔开就可以了。
function person(name, age) {
this.name = name;
this.age = age;
}
var obj = {};
person.call(obj, 'si', 18);
console.log(obj.name); // si
apply和call基本没有区别,唯一的区别是call后面的参数是一个一个传的,而apply后面的参数是放进一个数组里面然后传进去的。
还是上面那个例子,如果用apply来传递实参的话,将是下面这种形式。
person.apply(obj, ['si', 18]);
由于匿名函数、定时器中的函数没有默认的宿主对象,所以指向window。
var obj = {
say: function(){
setTimeout(function(){
console.log(this)
})
}
}
obj.say()//=>window
如果想要在setTimeout/setInterval中使用这个对象的this引用,那该怎么办呢?
1. 用一个变量吧this保存起来,that = this保存我们需要的this指向,当使用的时候再去调用它。
2. function.bind(this) 给回调函数直接绑定宿主对象,bind绑定宿主对象后依然返回这个函数;
var obj = {
say: function(){
setTimeout(function(){
console.log(this)
}.bind(this))
}
}
obj.say()//=>obj
接下来的例子来感受一下this指向:
var a = 1;
var obj = {
a : 2,
say : function(){
this.a *= 2;
a *= 2;
console.log(a)
console.log(this.a)
}
}
obj.say();
var run = obj.say;
run();
结果是:
2
4
8
8
那么就分析一下,到底是为什么?
obj.say();这个this指向是obj, this.a = 2; obj里面的a就会变成4,并保存下来。 a = 2;这个相当于window.a *= 2,所以window下的a就会变成2。
接下来,run = obj.say、 run(),这时候this指向是window,所以 this.a *= 2,这时候window下的啊变成4,a *= 2
;同样也是window下,这样window下的a就变成了8。
这就是对这题的分析。
接下来再享受一个例题:
var name = '222';
var a = {
name:‘111’,
say:function () {
console.log(this.name);
}
}
var fun = a.say;
fun(); // 222
a.say(); // 111
var b = {
name: '333',
say: function (fun) {
fun();
}
}
b.say(a.say); // 222
this-->b;
fun();
b.say = a.say;
b.say(); // 333
这就留着自己去分析吧,如果这两题整明白的话,那么你的this指向就没有问题了。