JavaScript复习—this绑定

183 阅读3分钟

先了解一下this的四种绑定

首先需要明确的一点是,this并不是在函数被定义时绑定,而是在函数被调用时

this的绑定规则有以下五种:

  • 默认绑定(严格/非严格模式)
  • 显示绑定(call、apply方法)
  • 隐式绑定
  • new绑定

1. 默认绑定

独立函数调用:直接调用函数,使用默认绑定;

  • 严格模式:this绑定到undifined

  • 非严格模式:函数在非严格模式时将默认绑定到全局对象上。

      function foo() {
          console.log(this.a);
      }
      let a = 1;
      foo() // 1
    

2.隐式绑定

函数在被调用时,如果存在上下文对象,那么this会绑定到这个上下文对象上。

function foo() {
    console.log(this.a)
}
let obj = {
    a: 1,
    foo: foo
};
let a = 2;
obj.foo();         // 1

显然这个函数foo()被调用时落脚点是obj对象。obj对象里的foo引用了foo函数,所以当调用obj.foo()时,隐式绑定了

let foo = function () {
  console.log(this.a)
}
let obj2 = {
  a: 2
  foo: foo
}
let obj1 = {
  a: 1
  obj2: obj2
};
obj1.obj2.foo();       // 2

(这个我没想好要怎么讲...先留着...)

但是应用隐式绑定this存在一个问题,那就是隐式丢失

看下面这个栗子:

function foo() {
    console.log(this.a)
}
let obj = {
    a: 1,
    foo: foo
};
let a = 2;
let bar = obj.foo;
bar();    //  2

bar是指向obj.foo的一个引用,可是实际上,它引用的是foo函数本身,所以在调用bar()时,已经是作为独立函数调用了,这个时候执行的是默认绑定。

3. 显示绑定

通过call()、apply()的方法绑定。接受一个参数,为绑定的对象,在函数调用时,将this绑定到这个对象上。

    function foo() {
        console.log(this.a);
    }
    let obj = {
        a: 1,
    };
    let a = 2;
    foo.call(obj)         // 1

在看刚才那个隐式丢失的栗子:

function foo() {
    console.log(this.a)
}
let obj = {
    a: 1,
    foo: foo
};
let a = 2;
let bar = obj.foo;
bar.call(obj);    //  1

所以用call()、apply()可以解决隐式丢失的问题。

4. new绑定

构造函数其实是使用new操作调用的一个普通函数,包括内置函数在内的所有函数都可以用new操作符来调用,称为构造函数调用

实际上并不存在所谓的构造函数,确切的说是函数的构造调用

new一个函数会执行下面操作:

  • 创建一个新的对象;

  • 将这个新对象的__proto__指向构造函数的原型(prototype);

  • 使用这个新对象调用函数,将函数的this绑定到这个新对象上;

  • 如果函数里没有返回对象,那么返回这个创建的新对象。但是如果return 了一个对象,那么这个新对象作废。

      function Foo(a) {
          this.a = a;
      }
      let bar = new Foo(2);
      console.log(bar.a);   // 2
    

箭头函数和普通函数的this区别

  • 普通函数: this指向调用这个方法的对象(谁调用我,我的this就绑定谁);
  • 箭头函数: 其实箭头函数没有自己作用域下的this,箭头函数里的this对象,就是定义时所在的对象,而不是调用时所在的对象。

我之前的理解:其实箭头函数没有自己作用域下的this,它的this其实是定义时所在作用域的this值。换个说法,箭头函数的this其实是包裹这个箭头函数的普通函数的this值