当前执行上下文(global、function 或 eval)的一个属性,在非严格模式下,总是指向一个对象,在严格模式下可以是任意值。

分类讨论

全局上下文

无论是否在严格模式下,在全局执行环境中(在任何函数体外部)this 都指向全局对象。

  1. // 在浏览器中, window 对象同时也是全局对象:
  2. console.log(this === window); // true
  3. // 仅仅只有赋值操作,标识符会隐式绑定到全局对象
  4. a = 37;
  5. console.log(window.a); // 37
  6. console.log(a); // 37
  7. this.b = "MDN";
  8. console.log(window.b) // "MDN"
  9. console.log(b) // "MDN"
  10. //通过声明绑定到变量对象,但在全局环境中,变量对象就是它自身
  11. var c = 123;
  12. console.log(c); // 只能通过这种方式

函数上下文

在函数内部,this的值取决于函数被调用的方式。

  1. var a = 10;
  2. var obj = {
  3. a: 20,
  4. log:function(){console.log(this.a)}
  5. }
  6. var f = obj.log;
  7. f(); // undefined
  8. obj.log() // 20

对象的方法中的this

当函数作为对象里的方法被调用时,this 被设置为调用该函数的对象。
请注意,这样的行为完全不会受函数定义方式或位置的影响。

  1. var o = {
  2. prop: 37,
  3. f: function() {
  4. return this.prop;
  5. }
  6. };
  7. console.log(o.f()); // 37
  8. var o = {prop: 36};
  9. function independent() {
  10. return this.prop;
  11. }
  12. o.f = independent;
  13. console.log(o.f()); // 36

原型链中的this

对于在对象原型链上某处定义的方法,同样的概念也适用。如果该方法存在于一个对象的原型链上,那么 this 指向的是调用这个方法的对象,就像该方法就在这个对象上一样。

  1. var o = {
  2. f: function() {
  3. return this.a + this.b;
  4. }
  5. };
  6. var p = Object.create(o);
  7. p.a = 1;
  8. p.b = 4;
  9. console.log(p.f()); // 5

在这个例子中,对象 p 没有属于它自己的 f 属性,它的 f 属性继承自它的原型。虽然最终是在 o 中找到 f 属性的,这并没有关系;查找过程首先从 p.f 的引用开始,所以函数中的 this 指向p。也就是说,因为f是作为p的方法调用的,所以它的this指向了p

构造函数的this

当一个函数用作构造函数时(使用new关键字),它的this被绑定到正在构造的新对象。(如果返回值不是一个对象,则返回 this 对象)。
每个构造函数在new之后都会返回一个对象,这个对象就是this。

  1. function C(){
  2. this.a = 37;
  3. }
  4. var o = new C();
  5. console.log(o.a); // logs 37
  6. function C2(){
  7. this.a = 37;
  8. return {a:38};
  9. }
  10. o = new C2();
  11. console.log(o.a); // logs 38

箭头函数

this指向的是函数定义时的作用域

  • 箭头函数不会创建自己的this,它只会从自己的作用域链的上一层继承this。
  • 不能用call方法修改里面的this

箭头函数没有自己的 this 值,箭头函数中所使用的 this 都是来自函数作用域链,它的取值遵循普通普通变量一样的规则,在函数作用域链中一层一层往上找。

  1. const obj = {
  2. a: function() { console.log(this) }
  3. }
  4. obj.a() //打出的是obj对象
  5. const obj = {
  6. a: () => {
  7. console.log(this)
  8. }
  9. }
  10. obj.a() //打出来的是window
  1. // 使用箭头函数
  2. var circle = {
  3. radius: 10,
  4. outerDiameter() {
  5. var innerDiameter = () => {
  6. console.log(2 * this.radius);
  7. };
  8. innerDiameter();
  9. }
  10. };
  11. 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

image.png

改变 this 的指向

  • call 、bind 、 apply 这三个函数的第一个参数都是 this 的指向对象,
  • call 的参数是直接放进去的,第n个参数全都用逗号分隔,直接放到后面
  • apply 的所有参数都必须放在一个数组里面传进去
  • bind 除了返回是函数,需要手动调用,它的参数和call一样
  1. var a ={
  2. name : "Cherry",
  3. fn : function (a,b) {
  4. console.log( a + b)
  5. }
  6. }
  7. var b = a.fn;
  8. b.call(a,1,2) // 3
  9. b.apply(a,[1,2]) // 3
  10. b.bind(a,1,2)()