乐趣区

你不知道的this

MDN 中的 this 定义

当前执行代码的环境对象。

多么简约凝练的概括,寥寥 11 个字,将伴随程序员的前世今生。话不多说,让我们一起探讨你不知道的 this

牛刀小试

  function foo() {console.log( this.a);
  }
  var a = 10;
  foo();

答案:
10
this —> window

  function foo() {console.log( this.a);
  }
  var obj2 = { 
      a: 42,
      foo: foo 
  };
  var obj1 = { 
      a: 2,
      obj2: obj2 
  };
  obj1.obj2.foo(); 

42
this -> obj2

初露锋芒

  function foo() {setTimeout(() => this.a = 1, 0)
      console.log(this.a);
  }
  function foo2() {setTimeout(() => this.a = 1, 500)
      console.log(this.a);
  }
  function doFoo(fn) {
      this.a = 4
      fn();}
  var obj = {
      a: 2,
      foo: foo,
      foo2: foo2
  };
  var a =3
  doFoo(obj.foo);
  setTimeout(obj.foo, 0)
  setTimeout(obj.foo2, 100)

答案:
4
1
1
foo 函数,第 2 行是一个定时器,哪怕定时器的延迟时间为 0,仍然先执行第 3 行。故为 4
当使用定时器调用函数时,先执行函数内代码,在进行函数调用。故为 1
同理:故为 1

展露头脚

a = 3
function foo() {console.log( this.a);
}
var obj = {a: 2};
foo.call(obj); 
foo.call(null);
foo.call(undefined); 
foo.call( ); 
var obj2 = {
    a: 5,
    foo
}
obj2.foo.call() // 3,不是 5!
//bind 返回一个新的函数
function foo(something) {console.log( this.a, something);
    return this.a + something;
}
var obj = {a: 2}
var bar = foo.bind(obj);
var b = bar(3); 
console.log(b);

答案:
2 undefined
3 undefined
3 undefined
3 undefined
3 undefined
2 3
5
第 8 行:this -> obj = 2, msg 没有传值,故为 undefined
第 9~12 行:当 call 的第一个参数为 null, undefined 或者不传值时,只想 window,this -> window = 3, msg 没有传值,故为 undefined
第 25 行:bind 改变指向 -> obj,第 26 行:msg 为 3,故为 2 3
第 27 行:执行函数,为 2 +3 = 5

锐不可当

隐式丢失

一个最常见的 this 绑定问题就是被 隐式绑定 的函数会丢失绑定对象,也就是说它会应用 默认绑定,从而把 this 绑定到全局对象或者 undefined 上,取决于是否是严格模式

function foo() {console.log( this.a);
}
function doFoo(fn) {fn()
}
var obj = {
    a: 2,
    foo: foo 
};
var a = "oops, global";
doFoo(obj.foo); 

答案:oops, global
第 5 行 fn()引用第位置其实 foo, 因此 doFoo()相当于是一个不带修饰符的函数调用,因此应用了默认绑定—> window = oops, global

舍我其谁

function foo(something) {this.a = something;}
var obj1 = {foo: foo};
var obj2 = {};
obj1.foo(2);
console.log(obj1.a);
obj1.foo.call(obj2, 3);
console.log(obj2.a);
var bar = new obj1.foo(4); 
console.log(obj1.a);

答案:
2
3
2
4
new 绑定比隐式绑定优先级高, 也闭隐式绑定绑定优先级高

总结

  1. 函数是否在 new 中调用(new 绑定)? 如果是的话 this 绑定的是新创建的对象。
    var bar = new foo()
  2. 函数是否通过 call、apply(显式绑定)或者硬绑定调用? 如果是的话,this 绑定的是 指定的对象。
    var bar = foo.call(obj2)
  3. 函数是否在某个上下文对象中调用(隐式绑定)? 如果是的话,this 绑定的是那个上 下文对象。
    var bar = obj1.foo()
  4. 如果都不是的话,使用默认绑定。如果在严格模式下,就绑定到 undefined,否则绑定到 全局对象。
    var bar = foo()
退出移动版