四种绑定规则
1、默认绑定规则:this 指向 window。
2、隐式绑定规则:谁调用就指向谁。
3、显式绑定规则:this 指向 call、apply、bind 函数的第一个传参。
4、new 绑定规则:this 指向构造函数产生的对象。
1、默认绑定规则
// 全局中的 this 指向 window
console.log(this === window) // true
// 函数独立调用,函数内部的 this 指向 window
function func() {
console.log(this === window) // true
}
func() // 等同于 window.func,即,函数 func 的调用者是 window
2、隐式绑定规则
var obj = {
a: 'aaa',
b: function() {
console.log(this) // 指向 obj
function c() {
console.log(this) // 指向 window
}
c() // 这里可以理解为函数的独立调用,也可以理解为函数调用时产生了 AO 对象,AO 对象中默认的 this 指向 window。
;(function(){
console.log(this) // 指向 window,原理同上
})()
return function(){
console.log(this) // 指向 window,原理同上,obj.b() 需要变成 obj.b()(),可以把return function 拆分成两步,var d = function...,return d,这样就很明显的能看出,“闭包”的调用实际上就是 d(),也就是函数的独立调用。
}
}
}
obj.b() // 这里可以理解为谁调用就指向谁,也可以理解为函数调用产生了 AO 对象呢,AO 对象中默认的 this 指向 window,但是函数是被 obj 对象调用的,因此触发了隐式绑定规则,this 指向改变,指向了 obj。
// 隐式绑定规则失效的情况
var obj = {
a: 'aaa',
b: function(){
console.log(this)
}
}
// 一、变量赋值导致隐式绑定规则失效
var bar = obj.b
bar() // 这里 this 指向 window。虽然看起来任然是 obj.b() 这样执行,但是当 obj.b 赋值给 bar 变量后,指向就变了,bar() 等同于 window.bar(),所以调用者为 window
// 二、函数传参导致隐式绑定规则失效
function foo(fn){
fn() // 类似于独立调用
}
foo(obj.b) // 这里 this 指向 window。实参传递给形参的过程,是值的浅拷贝,fn 和 obj.b 是两个不同的引用对象,因此 fn() 可以理解为单独调用。在函数 foo 内部添加如下代码可以证明这一点:
// obj.b = function() {
// console.log('我变了')
// }
// console.log(fn) // 我没变
// 父函数有能力决定子函数的 this 指向
function foo(fn){
new fn() // 这时 this 指向了 obj.b 这个构造函数 new 出来的对象
fn.bind(obj)() // 这时 this 指向了 obj
}
foo(obj.b)
// forEach 函数的第二个参数传递 this 指向对象
var arr = [1, 2, 3]
arr.forEach(function(){
console.log(this) // this 指向了 obj
}, obj)
3、显式绑定规则
func.call(obj, args1, args2, args3 ...) // this 指向 obj
func.apply(obj, [args1, args2, args3 ...]) // this 指向 obj
func.bind(obj, args1, args2, args3 ...)() // this 指向 obj
// 注意,当绑定对象为 undefined 或 null 时,由于这个参数必须是 Object 类型,而 undefined 和 null 没有包装类可以转换,就会触发静默失败,就会采取默认绑定方式,默认绑定方式即绑定 window 对象。
func.call(undefined) // this 指向 window
func.call(null) // this 指向 window
func.call(1) // this 指向 Number {1} 对象
4、new 绑定规则
function Person(){
console.log(this) // this 指向 person 实例
}
var person = new Person()
// 构造函数默认返回 this,如果改变 return 的值,那么,返回引用类型将改变返回值,其他情况返回 this
function Person(){
return 1 // 返回的还是 this
return [] // 返回的是 []
return {} // 返回的是 {}
return undefined // 返回的还是 this
return null // 返回的还是 this
}
var person = new Person()
console.log(person)
四种绑定规则的优先级
4 > 3 > 2 > 1
箭头函数的 this 指向问题
箭头函数体内部没有 this 指向问题,因此,箭头函数中使用的 this 其实是箭头函数外层代码的 this。
四种绑定规则对箭头函数无效。
箭头函数不能用 new 关键词,会报错。