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