JavaScript中的this指向谁

五种this的情况

  1. 在全局环境中简单调用普通函数,严格模式下,函数内的this会被绑定到undefined上,在非严格模式下则会被绑定到全局对象(在浏览器中为window对象,在Node环境中为global对象)。

    function f1() {
        console.log(this);
    }
    function f2() {
        'use strict'
        console.log(this);
    }
    f1();    // window/global
    f2();    // undefined
    复制代码

    函数实际就是一个对象实体,只有在调用时、执行前才能确定它的this是什么,比如下面的情况,函数虽然声明在对象内,但调用是在全局,所以this是全局变量。

    let person = {
        name: "fan",
        say() {
            console.log(this);
        }
    };
    
    person.say();                 // this指向person
    let sayAlias = person.say;    // this指向全局对象
    sayAlias();
    复制代码
  2. 上下文对象(即一个普通对象)调用函数,函数中的this指向该上下文对象。

    const student = {
        name: 'fan',
        fn: function () {
            return this;
        }
    }
    console.log(student.fn() === student);    // 由于fn是student调用的,所以fn中的this指向student
    复制代码
  3. 通过apply、call、bind改变this的指向。其中apply、call是直接调用,bind只是绑定this为某个对象。

    function fn() {
        console.log(this);
    }
    let target = {};
    fn.apply(target, ['arg1', 'arg2']);    // 输出target
    fn.call(target, 'arg1', 'arg2');       // 输出target
    fn.bind(target, 'arg1', 'arg2')();     // 输出target
    复制代码
  4. 构造函数中的this指向。由于new操作符是创建新对象,并绑定至构造函数中的this,然后开始执行构造函数,所以,构造函数中的this指向new操作符创建的新对象。

    function Person(name) {
        this.name = name;
        console.log(this);
    }
    let person = new Person();    // 输出person对象
    复制代码
  5. 箭头函数中的this指向和外层(函数或全局)的this保持一致,并且箭头函数中的this一旦确定,就不能再修改(不能被apply、call、bind和new修改)。

    let person1 = {
        name: "fan"
    };
    function f() {
        let person2 = {
            name: "gen"
        }
        let sayHello = () => {
            console.log(this);
        }
        sayHello.call(person2);     // this仍然为person1
    }
    f1.apply(person1);    // 箭头函数的this和外层this保持一致
    复制代码

优先级

  • 显式绑定:用apply、call、bind、new进行绑定的情况;
  • 隐式绑定:根据调用关系决定的绑定。

其中,显式绑定优先级 > 隐式绑定,如下:

let person = {
    name: "fan",
    say() {
        console.log(this);
    }
};
let student = {
    name: 'gen',
}
person.say.call(student);    // this为student,而不是person
复制代码

bind绑定this后,可以被new修改,如下:

function Person(name) {
    this.name = name;
}
let target = {
    age: 18
};
Person.bind(target);          // Person构造函数中的this指向target
let person = new Person();    // new运算符会修改this为person
console.log(target);          // target并没有被增加name属性
console.log(person);          // person被增加了name属性
复制代码

只要一个函数不是被上下文对象调用、被apply、call、bind、new调用这几种情况,那么无论在哪里调用,该函数的this都指向全局对象。其中要注意若箭头函数是定义在一个对象里,则this指向全局,因为在声明这个外层对象时,对象的this就是全局,箭头函数的this一开始就被绑定并且无法再更改。而如果箭头函数定义在函数内,那么this和该函数的this一样。

let person = {
    name: 'fan',
    fn: () => {
        console.log(this);
    }
};
person.fn();    // 输出全局对象

function f1() {
    let f2 = () => {
        console.log(this);
    };
    f2();
    return f2;
}
let person = {
    name: 'fan'
};
f1.call(person)();    // 两次输出person对象

复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享