我惊了😮,this就是call的第一个参数!

323 阅读3分钟

我正在参加「掘金·启航计划」

看过《你不知道的JavaScript》这本书都应该知道,书中简述四种this指向分为:(重要的事情说三次:重点不在这里!,在后文!,在后文!,在后文!

  • 默认绑定:在"use strict"下this指向undefined,否则指向默认全局对象window

    function foo() {
        console.log(this);// window对象,默认绑定:指向全局对象
    }
    foo();
    
    function foo() {
        "use strict"
        console.log(this);// window对象,默认绑定:指向全局对象
    }
    foo();
    
  • 隐式绑定:调用位置是否有上下文。

    function foo() {
        console.log(this);// 指向obj对象
    }
    
    var obj = {
        a: 1,
        foo: foo
    }
    obj.foo();
    
  • 显式绑定:也就是带有call、apply、bind的强制指定this指向的绑定。

    image.png

    function foo() {
        console.log(this);// 指向window对象
    }
    var obj = {
        a: 1,
        foo: foo
    }
    obj.foo.call(this);
    
  • new 绑定:构造函数的this指向的是自己。注意地,new创建构造函数不能改变this指向

    function foo() {
        console.log(this);// 指向foo{}函数
    }
    const bar = new foo();
    

b0dffb4b72318647a93e187cecc4c5a8.gif

1 函数调用

在js中有四种函数的调用形式:

function foo(a1,a2){};// 全局对象函数调用
obj.attr.method(a1,a2){};// 对象函数调用
new foo();// 构造函数调用
foo = ()=>{};// 箭头函数
foo.call(context,a1,a2);// 函数上下文调用

构造函数、箭头函数都是es6语法糖的,而全局函数与对象函数都是es5语法糖,而函数上下文调用才是真正的函数调用。

  • 箭头函数:箭头函数本身是不支持this,所以内部并没有this,直接把它当作箭头函数外面的this即可。

    const foo = () => {
        console.log(this);// 指向window
    }
    foo();
    
  • 构造函数:注意地,构造函数绑定的this是不能改变的。

    function foo(a, b) {
        this.a = a;
        this.b = b;
        return {
            key: this// 指向foo{ } 函数
        }
    }
    const bar = new foo();
    console.log(bar);
    

全局函数与对象函数都能转换为上下文调用函数,我们也可以从上下文调用的方式去理解这个this的指向:

  • 全局函数:严格模式,this指向就是undefined,非严格模式,this指向就是window。

    function foo() {
        console.log(this);// 指向window
    }
    foo();
    // 等价于
    foo.call();
    // 等价于
    foo.call(undefined);
    // 等价于
    foo.call(null);
    

    从上面可以看出上下文调用函数call,call的第一个参数context值有为空、undefined、null,最终的指向都是全局window对象。为什么?浏览器中规定,如果是在严格模式下使用this绑定的话,默认是undefined;如果在非严格模式下的this没有指向默认为window对象。context的值为有为空、undefined、null时,this指向都是window。也就是说,call的第一个参数context就是this

  • 对象属性函数:this指向的是调用函数前的对象,比如下面转化为上下文函数调用后this分别指向的是obj、obj.obj1。也就是说,call的第一个参数context就是this

    function foo() {
        console.log(this);// 指向obj
    }
    const obj = {
        a: 1,
        foo: foo,
    }
    obj.foo();
    // 等价于或转化为
    obj.foo.call(obj);
    
    function foo() {
        console.log(this);// 指向obj1
    }
    const obj = {
        a: 1,
        obj1: {
            a: 2,
            foo: foo,
        },
    }
    obj.obj1.foo();
    // 等价于或转化为
    obj.obj1.foo.call(obj.obj1);
    

2 数组中函数属性

  • 数组中的函数foo,arr[0].foo,我们可以假想为arr.0(),也就是说0类似于obj.foo调用函数,所以可以假想转化为arr.0.call(arr),所以context值就是arr,this指向的就是arr。
    function foo() {
        console.log(this);// 指向arr
    }
    const arr = [foo]
    arr[0]();