你不知道的js 读书笔记--this解析

245 阅读3分钟

this指向规则

函数在执行过程中的调用位置决定this的指向

一、默认绑定(独立函数调用)

函数直接使用不带任何修饰的函数引用进行调用
    function foo() {
        console.log(this.a);
    }
    var a = 2;
    foo(); // 2

但是如果使用严格模式,则this指向的是undefined,而不是全局对象

    function foo() {
        "use strict";
        console.log(this); // undefined
        console.log(this.a);
    }
    var a = 2;
    foo(); // TypeError: this is undefined

foo只有在严格模式下运行this才会指向undefined,如果只是在严格模式下调用foo则不影响

    function foo() {
        console.log(this.a);
    }
    var a = 2;
    (function() {
        "use strict";
        foo(); // 2
    })();

二、隐式绑定

当函数引用有上下文对象时,隐式绑定规则会使函数调用中的this指向这个上下文对象
    function foo() {
        console.log(this.a);
    }
    var obj = {
        a: 2,
        foo: foo
    };
    obj.foo(); // 2

对象属性引用链中只有最后一层在调用位置中起作用

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

隐式丢失

  • 函数别名调用
    function foo() {
        console.log(this.a);
    }
    var obj = {
        a: 2,
        foo: foo
    }
    var bar = obj.foo; // 只是函数的一个别名而已
    var a = "global";
    bar(); // global(此时bar其实是一个不带任何修饰的调用调用)
  • 函数作为入参调用
    function doFoo(fn) {
        fn();
    }
    var obj = {
        a: 2,
        foo: foo
    };
    var a = "global";
    doFoo(obj.foo); // "global"

三、显示绑定

直接指定this的指向

额外知识点:装箱 传入一个原始值作为this的指向,这个原始值会被转换为它的对象形式

    function foo() {
        console.log(this);
    }
    foo.call(2); // Number {2}
    foo.call("a"); // String {"a"}

apply, call, bind, 使用这种方式改变this的指向时,无论之后如何调用函数,this的指向都会是这三种方式改变的那个对象

四、new绑定

使用new来调用函数时,会构造一个新对象,并把this指向该对象
  1. 创建一个新对象
  2. 链接到原型(使该对象的__proto__等于构造函数的prototype), 可以访问到构造函数原型中的属性
  3. this指向该对象
  4. 如果函数没有返回其他对象,那么new表达式中的函数会自动返回这个新对象

判断this

  1. 函数是否通过new 调用,如果是的话this指向新对象var bar = new foo()
  2. 函数是否通过call,apply或硬绑定调用,如果是的话this指向绑定的对象var bar = foo.call(obj2)
  3. 函数是否通过对象调用,是的话指向这个对象var bar = obj1.foo()
  4. 如果都不是的话,就是默认绑定,在严格模式下,this就指向undefined,否则指向全局对象var bar = foo()

特殊情况

  • 如果把null和undefined作为call、apply或者bind的第一个参数,这些值在调用时会被忽略,实际是默认绑定
    function foo() {
        console.log(this.a);
    }
    var a = 2;
    foo.call(null); // 2

应用:把数组展开为参数

    foo.apply(null, [2, 3]);
  • 间接引用
    function foo() {
        console.log(this.a);
    }
    var a = 2;
    var o = { a: 3, foo: foo };
    var p = { a: 4 };
    o.foo(); // 3
    (p.foo = o.foo)(); // 2  (这里调用的直接是foo())
  • 箭头函数 根据外层(函数或全局)作用域来决定,会继承外层函数内的this指向