深入了解js这门语言后,才发现它有着诸多众所周知的难点(例如:闭包、原型链、内存空间等)。有的是因为js的设计缺陷导致的,而有的则是js的优点。不管如何,总需要去学会它们,在学习过程中我觉得只看别人的文章并不能做到深刻理解,所以我决定写这一系列的文章来记录我所学习到的知识点,也方便自己以后回顾,如有写错的地方欢迎指正。
废话不多说,马上进入正题!
一、默认绑定
在看过很多种的this解读思路后,我觉得《你不知道的JavaScript(上卷)》中对this的讲解比较有操作性,即有个很明确的标准让你去判断。
默认绑定指的是在没有new绑定和显示绑定(后面会提到)的前提下解析器会运行的绑定逻辑,它的思路是:this是由调用者提供的,每个函数的this取决于函数的调用位置(也就是调用方法)。
具体的判断标准是:如果函数被一个对象所拥有,那么该函数在调用时内部的this指向该对象。如果函数是独立调用(直接不带任何修饰的函数引用进行调用),那么函数内部的this指向undefined(严格模式下)。
// 独立调用
function foo() {
console.log(this.a)
}
var a = 2
foo() // undefined
独立调用中有些情况属于比较隐蔽且容易让人混淆的:
// 隐式丢失(也是属于独立调用的情况)
function foo() {
console.log(this.a)
}
var obj = {
a: 2,
foo: foo
}
var bar = obj.foo // bar引用的是foo函数本身,即相当于bar=foo
var a = "global"
bar() // undefined
// 这里和上面的foo()独立调用同理
// 回调中的独立调用
var a = 20;
function foo () {
console.log(this.a)
}
var obj = {
a: 2,
foo: foo
}
function doFoo (fn) {
fn() // 相当于在此处直接调用foo()
}
doFoo(obj.foo)
// 被某个对象拥有
function foo() {
console.log(this.a)
}
var obj = {
a: 2,
foo: foo
}
obj.foo(); // 2
// 如果被多个对象调用,this绑定到离函数调用最近的对象
function foo() {
console.log(this.a)
}
var obj2 = {
a: 42,
foo: foo
}
var obj1 = {
a: 2,
obj2: obj2
}
obj1.obj2.foo() // 42
// 离foo()最近的是obj2,所以this绑定到obj2
二、显式绑定
显式绑定是指使用函数的call()、apply()和bind()方法强制地让函数的this绑定到我们想要的对象。显式绑定的优先级比默认绑定优先级高,即如果有显式绑定出现,默认绑定的规则失效。
// call()和apply()方法的第一个参数是一样的,都是this的绑定对象。
function foo() {
console.log(this.a)
}
var obj = {
a: 42
}
foo.call(obj) // 42
foo.apply(obj) // 42
// bind()方法会返回一个新函数,新函数内部的this绑定到bind()方法的第一个参数
var obj = {
a: 2,
foo: function() { return this.a }
}
var bar = obj.foo
bar() // undefined
var new_bar = bar.bind(obj)
new_bar() // 2
三、new绑定
new绑定是优先级最高的。使用new来调用函数时,会创建一个全新的对象,并把函数的this绑定到新对象上。
function foo(a) {
this.a = a
}
var bar = new foo(2)
console.log(bar.a) // 2
四、ES6箭头函数
ES6的最好用的新特性之一就是箭头函数了。箭头函数中的this和我们上述说的规则都没有关系,它是根据箭头函数的外层作用域来决定this(JS中只有函数作用域和全局作用域)
function foo() {
setTimeout(() => {
// 这里的this继承自外层作用域的this,即foo的this
console.log(this.a)
}, 100)
}
var obj = {
a: 2
}
foo.call(obj) // 2
五、总结
以上三种绑定规则的优先级是:new绑定 > 显式绑定 > 默认绑定。所以我们在判断this时,只要按照优先级来一步一步判断就没有问题了。
写在最后
我个人开了一个公众号“前端搬运小工”,我会定期推送优秀的前端精选文章,拒绝无脑基础入门的文章,带给你不一样的前端视角。