'this' is a question

193 阅读2分钟

this 在JavaScript中不同的使用场景其指向各有不同,总结起来有下面六种情形。每种场景的优先级逐步递增,也就说当同时满足下面的场景时,会以后面的场景为主。

1、全局对象

在一般函数方法中使用this代替全局对象,浏览器的全局对象是window,node环境的全局对象是global,需要特别注意的是use strict模式下的全局对象是undefined

function showGlobalThis() {
    console.log(this); //window
}

function showStrictThis() {
    'use strict';
    console.log(this); // undefined
}

2、对象方法

在JavaScript对象中,this经常会作为对象方法调用,此时this指向当前对象

let currObj = {
    name: 'currObj',
    showCurrThis() {
        console.log(this);
    }
}

currObj.showCurrThis(); // currObj

3、call和apply指定

Object.prototype.toString.call和Object.prototype.toString.apply可以给对象绑定一个上下文this,此时,this指向入参对象

let name = 'window';

function showThisName() {
    return this.name;
}

let obj = {name: 'global'};

showThisName.call(obj); // ‘global'

4、bind绑定this

Object.prototype.toString.bind,它不但会通过一个新函数来提供永久的绑定,还会覆盖call和apply的命令,所以bind返回的函数不能再通过call或apply修改this对象。bind会创建一个新的函数,称为绑定函数。bind和call,apply最大的区别是bind不会理解调用,其他两个会立即执行

let name = 'window';

function showThisName() {
    return this.name;
}

let obj1 = {name: 'global1'};

let bindFun = showThisName.bind(obj1);

bindFun();  // 'global1'

let obj2 = {name: 'global2'};

bindFun.call(obj2); // ‘global1’, bind返回的函数不能再通过call,apply指定this对象

5、new操作

一个比较容易忽视的会绑定this的就是new操作。当new一个对象的时候,this指向new出来的对象,同时它会覆盖bind的绑定,使得bind失去作用。

function showThis() {
    console.log(this); //window
}

showThis(); //window

new showThis(); // showThis

let obj = {name: 'global'};

showThis.call(obj); // global

new showThis().call(obj); // Uncaught TypeError: showThis.call is not a constructor

let bindFun = showThis.bind(obj);

bindFun(); // global

new bindFun(); // showThis对象, bind会被覆盖,不再起到绑定this的作用

6、箭头函数

ES6的箭头函数中的this指向不再多变,它被永远封印在词法作用域中,待代码运行前确定后,便不能被覆盖

let id = 22;

function foo() {
    setTimeout(function(){
        console.log(this.id);
    }, 100);
}

foo(); // undefined

function foo() {
    setTimeout(() => {
        console.log(this.id);
    }, 100);
}

foo.call({id: 43}); // 43