this 是在运行时绑定的,并不是在编写时绑定的.它的上下文取决于函数调用时的各种条件.
首先明白
- this 既不指向函数自身,也不指向函数的词法作用域
this绑定规则
- 默认绑定
独立函数调用
function foo(){
console.log(this.a);
}
var a = 2;
//函数调用时应用了this的默认绑定,因此this指向全局对象.
foo(); //2
- 隐式绑定
调用的位置是否有上下文对象,或者说被某个对象拥有或包含,不过这种说法可能造成一些误导.
function foo(){
consle.log(this.a);
}
var obj = {
a:2,
foo:foo
}
obj.foo(); //2
隐式丢失: 函数别名和参数传递 ,最经常遇见的setTimeout(fn,delay)函数,会发生隐式丢失,this指向window
//函数别名
function foo(){
console.log(this.a);
}
var obj = {
a:2,
foo:foo
}
var bar = obj.foo;
var a = "oops,global";
bar();//"oops,global"
//参数传递
function foo(){
console.log(this.a);
}
var obj = {
a:2,
foo:foo
}
var bar = obj.foo;
var a = "oops,global";
function doFoo(fn){
fn();
}
doFoo(obj.foo);//"oops,global"
-
显示绑定
-
硬绑定
使用call(...) apply(...) -
API调用的"上下文"
如[1,2,3].forEach(foo,obj) ,当执行回调函数时用作this的值(参考对象)。 -
new绑定
-
创建(或者说构造)一个全新的对象
-
这个新对象都会被执行[[Prototype]]
-
这个新对象会绑定到函数调用的this
-
如果函数没有返回其他对象,那么new表达式中的函数调用会自动返回一个新对象.
-
=>(箭头函数)
箭头函数看上去是匿名函数的一种简写,但实际上,箭头函数和匿名函数有个明显的区别:箭头函数内部的this是词法作用域,由上下文确定。即箭头函数没有自己的this,其中的this会自动从上一级继承
函数参数会使其丢失this,从而指向window, 使用箭头函数可以修改this指向,this是词法作用域由上下文确定
let a = {
x: 1,
y: function() {
setTimeout(() => {
console.log('this', this)
}, 1000)
}
}
a.y() // this a
let a = {
x: 1,
y:() => { // y:() => {}, this继承上一级, this = window
setTimeout(() => {
console.log('this', this)
}, 1000)
}
}
a.y() // this window