原载于前端开发指南,喜欢请关注。javascript
你可能遇到过这样的 JS 面试题:前端
var obj = {
foo: function(){
console.log(this)
}
}
var bar = obj.foo
obj.foo() // 打印出的 this 是 obj
bar() // 打印出的 this 是 window复制代码
请解释最后两行函数的值为何不同。java
初学者关于 this 的理解一直很模糊。今天这篇文章就要一次讲清楚了。面试
并且这个解释,你在别的地方看不到。看懂这篇文章,全部关于 this 的面试题,都是小菜。浏览器
首先须要从函数的调用开始讲起。app
JS(ES5)里面有三种函数调用形式:函数
func(p1, p2)
obj.child.method(p1, p2)
func.call(context, p1, p2) // 先不讲 apply复制代码
通常,初学者都知道前两种形式,并且认为前两种形式「优于」第三种形式。
从看到这篇文章起,你必定要记住,第三种调用形式,才是正常调用形式:post
func.call(context, p1, p2)复制代码
其余两种都是语法糖,能够等价地变为 call 形式:ui
func(p1, p2) 等价于
func.call(undefined, p1, p2)
obj.child.method(p1, p2) 等价于
obj.child.method.call(obj.child, p1, p2)复制代码
请记下来。(咱们称此代码为「转换代码」,方便下文引用)this
至此咱们的函数调用只有一种形式:
func.call(context, p1, p2)复制代码
this,就是上面代码中的 context。就这么简单。
this 是你 call 一个函数时传的 context,因为你历来不用 call 形式的函数调用,因此你一直不知道。
先看 func(p1, p2) 中的 this 如何肯定:
当你写下面代码时
function func(){
console.log(this)
}
func()复制代码
等价于
function func(){
console.log(this)
}
func.call(undefined) // 能够简写为 func.call()复制代码
按理说打印出来的 this 应该就是 undefined 了吧,可是浏览器里有一条规则:
若是你传的 context 就 null 或者 undefined,那么 window 对象就是默认的 context(严格模式下默认 context 是 undefined)
所以上面的打印结果是 window。
若是你但愿这里的 this 不是 window,很简单:
func.call(obj) // 那么里面的 this 就是 obj 对象了复制代码
再看 obj.child.method(p1, p2) 的 this 如何肯定
var obj = {
foo: function(){
console.log(this)
}
}
obj.foo()复制代码
按照「转换代码」,咱们将 obj.foo() 转换为
obj.foo.call(obj)复制代码
好了,this 就是 obj。搞定。
回到题目:
var obj = {
foo: function(){
console.log(this)
}
}
var bar = obj.foo
obj.foo() // 转换为 obj.foo.call(obj),this 就是 obj
bar()
// 转换为 bar.call()
// 因为没有传 context
// 因此 this 就是 undefined
// 最后浏览器给你一个默认的 this —— window 对象复制代码
之后你遇到全部跟 this 有关的笔试题,都不会有疑问了。
完。
更多精彩教程,请加入前端 7 群:369325292
P.S.
使用 new 时,状况又不同,能够看个人另外一篇文章《JS 的 new 究竟是干什么的?》。