全局执行环境
无论是否在严格模式下,在全局执行环境中(在任何函数体外部)this 都指向全局对象。
// 在浏览器中,window 对象同时也是全局对象:
console.log(this === window); // true
a = 37;
console.log(window.a); // 37
this.b = "test";
console.log(window.b) // "test"
console.log(b) // "test"
在函数中
非严格模式下,且 this 的值不是由该调用设置的,所以 this 的值默认指向全局对象,浏览器中就是 window。
function f1(){
return this;
}
//在浏览器中:
f1() === window; //在浏览器中,全局对象是 window
//在 Node 中:
f1() === globalThis;
严格模式下,如果进入执行环境时没有设置 this 的值,this 会保持为 undefined,如下:
function f2(){
"use strict"; // 这里是严格模式
return this;
}
f2() === undefined; // true
在类中
this 在 类 中的表现与在函数中类似,因为类本质上也是函数(寄生式组合继承语法糖),但也有一些区别和注意事项,详情参考MDN。
在原型链中,在对象中同理跟在函数中一样
bind方法
ECMAScript 5 引入了 Function.prototype.bind()。调用f.bind(someObject)会创建一个与f具有相同函数体和作用域的函数,但是在这个新函数中,this将永久地被绑定到了bind的第一个参数,无论这个函数是如何被调用的。
function f(){
return this.a;
}
var g = f.bind({a:"azerty"});
console.log(g()); // azerty
var h = g.bind({a:'yoo'}); // bind 只生效一次!
console.log(h()); // azerty
var o = {a:37, f:f, g:g, h:h};
console.log(o.a, o.f(), o.g(), o.h()); // 37, 37, azerty, azerty
调用bind()通常是让非箭头函数变得像箭头函数,所以箭头函数里没法调用
箭头函数
ES2015 引入了箭头函数,箭头函数不提供自身的 this 绑定,在箭头函数中,this会继承父作用域的this,而且不是在执行的时候确定的,是在定义的时候确定的。
var globalObject = this;
var foo = (() => this);
console.log(foo() === globalObject); // true
总结
普通函数,作用域是静态的,而this指向是动态的(指向调用者的作用域),这样的不一致导致写代码时心智负担加重,于是就容易写出bug,指向全局作用域大概率就是bug,于是在严格模式下this没有显式设置this的值,就默认为undefined,之后在ES5中加入了bind方法,来使this静态化(声明时即绑定)
再之后的ES2015,更进一步推出了箭头函数来解决这个问题,箭头函数this默认是静态的(指向父作用域,定义时即确定),因此不需要,也不允许apply、call、bind再次改变this指向,以免再次产生可能的问题