当前执行上下文(global、function 或 eval)的一个属性,在非严格模式下,总是指向一个对象,在严格模式下可以是任意值。
分类讨论
全局上下文
无论是否在严格模式下,在全局执行环境中(在任何函数体外部)this
都指向全局对象。
// 在浏览器中, window 对象同时也是全局对象:
console.log(this === window); // true
// 仅仅只有赋值操作,标识符会隐式绑定到全局对象
a = 37;
console.log(window.a); // 37
console.log(a); // 37
this.b = "MDN";
console.log(window.b) // "MDN"
console.log(b) // "MDN"
//通过声明绑定到变量对象,但在全局环境中,变量对象就是它自身
var c = 123;
console.log(c); // 只能通过这种方式
函数上下文
在函数内部,this
的值取决于函数被调用的方式。
var a = 10;
var obj = {
a: 20,
log:function(){console.log(this.a)}
}
var f = obj.log;
f(); // undefined
obj.log() // 20
对象的方法中的this
当函数作为对象里的方法被调用时,this
被设置为调用该函数的对象。
请注意,这样的行为完全不会受函数定义方式或位置的影响。
var o = {
prop: 37,
f: function() {
return this.prop;
}
};
console.log(o.f()); // 37
var o = {prop: 36};
function independent() {
return this.prop;
}
o.f = independent;
console.log(o.f()); // 36
原型链中的this
对于在对象原型链上某处定义的方法,同样的概念也适用。如果该方法存在于一个对象的原型链上,那么 this
指向的是调用这个方法的对象,就像该方法就在这个对象上一样。
var o = {
f: function() {
return this.a + this.b;
}
};
var p = Object.create(o);
p.a = 1;
p.b = 4;
console.log(p.f()); // 5
在这个例子中,对象
p
没有属于它自己的f
属性,它的f
属性继承自它的原型。虽然最终是在o
中找到f
属性的,这并没有关系;查找过程首先从p.f
的引用开始,所以函数中的this
指向p
。也就是说,因为f
是作为p
的方法调用的,所以它的this
指向了p
。
构造函数的this
当一个函数用作构造函数时(使用new关键字),它的this
被绑定到正在构造的新对象。(如果返回值不是一个对象,则返回 this
对象)。
每个构造函数在new之后都会返回一个对象,这个对象就是this。
function C(){
this.a = 37;
}
var o = new C();
console.log(o.a); // logs 37
function C2(){
this.a = 37;
return {a:38};
}
o = new C2();
console.log(o.a); // logs 38
箭头函数
this指向的是函数定义时的作用域
- 箭头函数不会创建自己的
this
,它只会从自己的作用域链的上一层继承this。 - 不能用call方法修改里面的this
箭头函数没有自己的 this 值,箭头函数中所使用的 this 都是来自函数作用域链,它的取值遵循普通普通变量一样的规则,在函数作用域链中一层一层往上找。
const obj = {
a: function() { console.log(this) }
}
obj.a() //打出的是obj对象
const obj = {
a: () => {
console.log(this)
}
}
obj.a() //打出来的是window
// 使用箭头函数
var circle = {
radius: 10,
outerDiameter() {
var innerDiameter = () => {
console.log(2 * this.radius);
};
innerDiameter();
}
};
circle.outerDiameter(); // 打印20
对于内层函数 innerDiameter,它本身并没有 this 值,其使用的 this 来自作用域链,来自更高层函数的作用域。innerDiameter 的外层函数 outerDiameter 是普通函数,它是有 this 值的,它的 this 值就是 circle 对象。因此,innerDiameter 函数中所使用的 this 来自 outerDiameter 函数,其值为 circle 对象。
参考
总结
- 对于直接调用函数来说,不管函数被放在了什么地方,
this
一定是window
- 对于
obj.fun()
来说,我们只需要记住,谁调用了函数,谁就是this
,所以在这个场景下 fun函数中的this
就是obj
对象 - 对于
new
的方式来说,this
被永远绑定在了对象上面,不会被任何方式改变this
改变 this 的指向
- call 、bind 、 apply 这三个函数的第一个参数都是 this 的指向对象,
- call 的参数是直接放进去的,第n个参数全都用逗号分隔,直接放到后面
- apply 的所有参数都必须放在一个数组里面传进去
- bind 除了返回是函数,需要手动调用,它的参数和call一样
var a ={
name : "Cherry",
fn : function (a,b) {
console.log( a + b)
}
}
var b = a.fn;
b.call(a,1,2) // 3
b.apply(a,[1,2]) // 3
b.bind(a,1,2)()