this指向的问题归总一下,可分为6种类型:
- 全局环境、普通函数(非严格模式)this都指向window
- 普通函数(严格模式)指向undefined
- 函数作为对象方法及原型链指向的都是上一级对象
- 构造函数指向构造的实例
- DOM事件中指向触发事件的元素
- 箭头函数指向它父级的环境
1.全局环境
全局环境下,this始终指向window,无论是否严格模式。
2.函数环境
2.1普通函数
2.1.1 严格模式下,this指向undefined。
2.1.2 非严格模式下,没有被上一级的对象调用,this默认指向全局对象window
2.2函数作为对象的方法被调用
2.2.1 函数由上一级对象所调用,那么this指向的就是上一级的对象
var obj = {
a:22,
fn:function(){
return this.a;
}
}
obj.fn() // => 22
2.2.2 多层嵌套的对象,内部方法的this指向距离被调用函数最近的对象(window也是对象,其内部函数调用方法的this指向内部对象,而非window)
var obj = {
a:22,
b:{
a:10,
fn:function(){
console.log(this.a)
console.log(this)
}
}
}
obj.b.fn() // => 10
var f = o.b.fn;
f() // => undefined
this始终指向的是最后调用它的对象,也可就是说谁调用它,它就指向谁。当使用obj.b.fn()调用执行函数时,离它最近的对象是b,所以this指向b。第二种方式调用时,虽然函数fn被b所引用,但是却将fn赋值给了变量f,并没有执行,所以this指向了window,而window中没有a属性,故得到undefined。
2.3 setTimeOut或setInterval
2.3.1 对于延迟函数内部的回调函数的this指向全局对象window
2.3.2 可以通过bind方法改变内部函数this指向,详见3.4。
3.原型链调用
3.1 如果该方法存在于一个对象的原型链上,当通过该对象调用这个方法时,this指向的是调用这个方法的对象。
3.2 call和apply:当函数通过Function对象的原型中继承的方法call()和apply()方法调用时,其中函数内部的this值可绑定到call()或apply()方法指定的第一个对象上,如果第一个参数不是对象,js会尝试将它转成对象然后指向它。
3.4 bind():有ES5引入,存在于Function的原型链上,Function.propotype.bind()。通过bind绑定后,函数永远绑定到其第一个参数对象上,无论什么时候调用。
function f(){
console.log(this.a)
}
var g = f.bind({a:'ghh'})
g(); // => ghh
var o = {
a:'指向o',
f:f,
g:g
}
o.f() // => 指向o
o.g() // => ghh
4.构造函数
当一个函数用做构造函数时(通过new创建),它的this指向正在构造的新对象上。构造器默认返回的是this指向的对象,也可以手动返回其他的对象。
function c(){
this.a = 1111;
return {c:"2222"}
}
var o = new c();
console.log(o.a) // => undefined
// 注意:这里的构造器中 如果没有return返回值或者返回的为非对象(包括null和undefined)时,通过new构造出来的实例对象,this指向构造函数;如果有return返回对象时,通过new构造出来的实例对象,this指向返回的对象。
5.在DOM事件中
5.1 作为一个DOM事件处理函数
当函数被用作事件处理函数时,它的this指向触发事件的元素。
5.2 作为一个内联事件处理函数
5.2.1 当代码被内联处理函数直接调用时,他的this指向覆盖监听器所在的DOM元素
5.2.2 当代码被函数包裹内联调用时,等同于普通函数调用,非严格模式下指向window,严格模式下指向undefined,详见2.1。
6.箭头函数
6.1 全局环境下
在全局代码中,箭头函数被设置为全局对象
6.2 this捕捉上下文
箭头函数没有自己的this,而是使用箭头函数所在作用域的this。当在setTimeOut或setInterval中使用箭头函数时,this指向构造函数新生成的对象,情况如同2.3.2。
6.3 箭头函数作为对象方法
箭头函数作为对象方法时,this指向全局对象,而普通函数指向该对象。
6.4 箭头函数中,call()、apply()和bind()方法无效
6.5 this指向固定化
箭头函数的this指向不会根据调用它的方式决定,箭头函数的this永远指向它父级的上下文环境,这种特性有利于封装回调函数。
6.6 箭头函数不适合场景
6.6.1 箭头函数不适合定义对象的方法,因此指向window
6.6.2 需要动态this的时候