this - 2020-11-03

1. 默认绑定与隐式绑定

function fun() {
  console.log(this.a); 
}
var a = 'a';
var o2 = {a: "a2", fun: fun}; 
var o3 = {a: "a3", fun: fun}; 
fun();            // "a" – 默认绑定
o2.fun();          // "a2" – 隐式绑定
o3.fun();          // "a3" – 隐式绑定

fun()这种调用方法,就是默认绑定。如果在非严格模式下,this就是全局对象,浏览器当中就是window。而如果在严格模式(use strict)下,this就会是undefined。

之所以这是默认绑定,因为fun的调用不属于任何人,前面没有任何限定条件。这是最简单的绑定。

o2.fun()和o3.fun()这两种调用方法,都是隐式绑定。fun是作为o2和o3的方法而调用的,那么谁调用fun,this就指向谁。在上面的例子中,o2.fun()中的this指向o2,因此this.a就是o2当中的a: “a2”;同理,o3.fun()打印出来的就是o3中的”a3”。

2. 显式绑定

function fun() { 
  console.log(this.a); 
} 
var a = "a"; 
var obj = {a: "a2"}; 

fun();          // "a"   默认绑定
fun.call(obj);     // "a2"  显式绑定,使用obj作为"this" 

如果fun是通过call、apply或者bind调用的,那么这种调用就是显式绑定。这种绑定中,this的指向就是这三个函数中传递的第一个参数。

3. 关键字new绑定

function fun() { 
    this.b = "b"; 
    console.log(this.a + " " + b); 
} 
var a = "a"; 
var b = new fun(); 

如果把new这个关键字放在一个函数调用的前面,JS编译器会做这四件事情:

  1. 创建一个新的空的对象
  2. 把这个对象链接到原型对象上(prototype)
  3. 这个对象被绑定为this
  4. 如果这个函数不返回任何东西,那么就会默认return this

我们从这四步可以看出,如果在函数调用前面加上new,那么这个函数中的this就是这个新的对象。

上面的例子,最终会输出undefined undefined。这是因为b这个变量并没有a这个属性,而b此时只被定义,没有被赋值,因此b也是undefined。

4. 箭头函数

箭头函数会无视以上所有的规则,this的值就是函数创建时候所在的lexical scope中的this,而和调用方式无关。

可以对比下面两个例子:

function Person(){
  this.age = 0;
  setTimeout(function () {
    console.log(this.age);     // 输出undefined
  }, 1000);
}
var p = new Person();
function Person(){
  this.age = 10;
  setTimeout(()=> {
    console.log(this.age);     // 输出10
  }, 1000);
}
var p = new Person();

在上面没有使用箭头函数的例子当中,setTimeout内部的函数是被global调用的,而global没有age这个属性,因此输出undefined。

第二个例子使用了箭头函数,this就会使用lexical scope中的this,就是Person,因此输出10。

绑定优先级

如果多重绑定规格都适用,那么绑定规则的优先级顺序是这样的:

  1. 箭头函数
  2. 关键字new调
  3. 显式绑定
  4. 隐式绑定
  5. 默认绑定

箭头函数优先级最高,会无视2-5绑定规则。而默认绑定优先级最低,只有其他绑定都不使用的时候,才会使用默认绑定。

你可能感兴趣的:(this - 2020-11-03)