JavaScript中的this
引子
本文是看完《你不知道的js》这本书中关于this的介绍后写的,相当于是读书笔记,把书中的重点总结了出来。如果你看完本文还有什么不懂的话,可以直接看《你不知道的js》这本书,写的灰常好。
概要
- 函数被
new
调用,this
是新构建的对象; - 函数被硬绑定
(call、apply、bind)
后调用,this
是指定绑定的对象; - 函数被持有自己的环境对象调用,
this
是该环境对象; - 函数直接被调用,
this
是全局对象window
,strict mode
下是undefined
;
如果上面说的四种情况你都懂的话,本文就不太适合你了;
this是什么
this是函数执行时建立的一个绑定,指向什么是由函数执行时确定的;
所以判断this指向什么,要先看函数在哪执行,然后再判断this的指向。
判断this指向的四种规则
-
默认绑定
函数被直接执行,this默认绑定的是window对象,严格模式下是undefined。例如:
function foo() {
console.log(this) // window
}
foo() // 函数在直接执行,this 指向 window
-
隐式绑定
隐式绑定需要考虑函数执行时是否有拥有者对象,this一般指向该对象。例如:
let obj = {
foo: function () {
console.log(this) // obj
}
}
obj.foo() // 函数执行时有个拥有者对象 obj,所以 this 指向 obj
需要注意的是,隐式绑定会丢失它的绑定。一般会退回到默认绑定。例如:
let obj = {
foo: function () {
console.log(this)
}
};
let baz = obj.foo
baz() // window,函数执行时才绑定 this,相当于直接执行,this 绑定到 window 上
obj.foo() // obj,隐式绑定,this 指向 obj
当我们传递回调函数时,隐式绑定也会丢失它的绑定。比如:
let obj = {
foo: function () {
console.log(this)
}
};
function doFoo(fn) {
fn()
}
doFoo(obj.foo) // window
// 参数传递相当于一种赋值,
// 这里是 obj.foo 赋值给 fn,fn 函数执行时,this 绑定到 window
obj.foo() // obj , 隐式绑定,this 指向 obj
-
明确绑定
有隐式绑定就有明确绑定,它是使用call、apply、bind
这些方法强行改变this
的指向。比如:
function foo() {
console.log( this.a )
}
let obj = {
a: 2
};
foo.call( obj ); // 2, 通过 call 方法强行让 this 指向 obj
-
new 绑定
通过new
生成的对象,this
指向的是新生成的对象。例如:
function foo(a) {
this.a = a
}
let bar = new foo( 2 )
console.log( bar.a ) // 2,
// new 构建的对象,this 指向新构建出来的对象,
// 至于为什么会这样,跟 new 干了啥有关;
一些特例
-
间接引用
看个栗子:
function foo() {
console.log( this )
}
let o = { foo: foo }
let p = { }
o.foo() // o
(p.foo = o.foo)() // window
赋值表达式p.foo = o.foo
的结果是指向函数的引用,在执行时相当于foo()
,this
指向window
。
-
箭头函数
从上面我们可以看出,this
是函数执行时,才绑定的。但是箭头函数不同,箭头函数的this
是编写时,被绑定到调用者的外层;比如:
function foo() {
let fn = () => {
console.log( this )
}
return fn()
}
foo() // window