1. this 绑定的几种方式
- 默认绑定
- 隐式绑定
- 显式绑定
- bind绑定
2. 例题剖析
2.1 案例一
var name = 'window'
var person1 = {
// {} 对象或者是函数,对象中是没有 this 的,只有作为函数时才有 this
name: 'person1',
foo1: function () {
console.log(this.name)
},
foo2: () => console.log(this.name),
foo3: function () {
return function () {
console.log(this.name)
}
},
foo4: function () {
// console.log(this) // 第一个表达式this -> person1
// console.log(this) // 第一个表达式this -> person2
// console.log(this) // 第一个表达式this -> person1
return () => {
console.log(this.name)
}
}
}
var person2 = { name: 'person2' }
person1.foo1(); // 隐式绑定 person1
// 可以这样写的前提是非箭头函数
// 由于 call 方式显式绑定高于隐式绑定,所以可以写成 person2.foo1()
person1.foo1.call(person2); // 显式绑定 person2
// 箭头函数不绑定 this,所以 this 会从上层作用域查找
person1.foo2(); // 上层作用域 window
person1.foo2.call(person2); // 上层作用域 window
// person1.foo3() 执行结果是一个函数, 虽然有绑定 person1,但是是独立函数调用
person1.foo3()(); // window
person1.foo3.call(person2)(); // window
// 不妨记内层函数为 bar,所以 person1.foo() = bar,即为bar.call(person2),普通函数绑定this
person1.foo3().call(person2); // person2
// person1.foo() 执行会隐式绑定 person1
// 箭头函数内部不绑定 this,会从上层作用域中查找
person1.foo4()(); // person1
// 可以看成是 person2.foo()()
person1.foo4.call(person2)(); // person2
person1.foo4().call(person2); // person1
2.2 案例二
var name = 'window'
function Person (name) {
this.name = name
this.foo1 = function () {
console.log(this.name)
},
this.foo2 = () => console.log(this.name),
this.foo3 = function () {
return function () {
console.log(this.name)
}
},
this.foo4 = function () {
return () => {
console.log(this.name)
}
}
}
/**
* 1. 创建一个空的对象
* 2. 将这个空的对象赋值给 this
* 3. 执行函数体中代码
* 4. 将这个新的对象默认返回
*/
var person1 = new Person('person1')
var person2 = new Person('person2')
person1.foo1() // 隐式绑定:person1
person1.foo1.call(person2) // 显式绑定:person2
// person1.foo.call(undefined) 箭头函数不绑定 this,上层作用域是 person1
person1.foo2() // person1
person1.foo2.call(person2) // person1
person1.foo3()() // 独立函数调用 window
person1.foo3.call(person2)() // window
person1.foo3().call(person2) // person2
person1.foo4()() // person1
person1.foo4.call(person2)() // person2
person1.foo4().call(person2) // person1
2.3 案例三
var name = 'window'
function Person(name) {
this.name = name
this.obj = {
name: 'obj',
foo1: function () {
return function () {
console.log(this.name)
}
},
foo2: function () {
// console.log(this) -> 第一个表达式 obj
// console.log(this) -> 第二个表达式 person2
return () => {
console.log(this.name)
}
}
}
}
var person1 = new Person('person1')
var person2 = new Person('person2')
person1.obj.foo1()() // 独立函数调用:window
person1.obj.foo1.call(person2)() // 独立函数调用:window
// foo1 是一个普通函数,所以后面的显式绑定是有效的
person1.obj.foo1().call(person2) // 显式绑定:person2
person1.obj.foo2()() // 上层作用域:obj
person1.obj.foo2.call(person2)() // 显式绑定:person2
// 箭头函数不绑定 person2,会去上层作用域查找
person1.obj.foo2().call(person2) // 上层作用域:obj
PS: 案例二的内存图