this 去哪?
this 去哪?
本文写于 2020 年 4 月 26 日
let obj = { foo() { console.log(this) }, } let bar = obj.foo obj.foo() // 打印出的 this 是 obj bar() // 打印出的 this 是 window
最后两行函数的值为什么不一样???
之前关于函数的文章里写过了,let bar = obj.foo
可以让bar()
和obj.foo()
等价,那为什么 this 指向不一样?
在学 react 的时候,很多人会发现有个很烦人的操作,就是在constructor
里面,需要bind(this)
。
首先需要从函数的调用开始讲起。
es5 里面有三种函数调用形式:
foo(p1, p2) console.log('================') obj.foo(p1, p2) console.log('================') foo.call(obj, p1, p2) /* * 或者apply或者bind,这三个都是用来绑定this的 */
乍看之下,前两种简单,后面一种复杂。很多人就选择完全不使用后面的call()
。
但实际上,后面的才是我们真正的写法,前面的都可以等价的变成该种写法:
func.call(context, p1, p2)
foo(p1, p2)
等价于 foo.call(undefined, p1, p2)
obj.foo(p1, p2)
等价于 obj.foo.call(obj, p1, p2)
很多人特别喜欢死记硬背这个 this 的指向,“谁调用 this 就指向谁”blablabla……
但实际上,this 是要为我们所用的,我想让你指向谁,你就要指向谁。我们不应该被它牵着走。
先看foo(p1, p2)
中的 this 如何确定。
当你写下面代码时:
function foo() { console.log(this) } foo()
等价于
function foo() { console.log(this) } foo.call(undefined) // 可以简写为 foo.call()
按理说打印出来的 this 应该就是 undefined 了吧,但是浏览器里有一条规则:
如果你传的第一个参数是null
或者undefined
, window 对象就是默认的。因此上面的打印结果是 window。
如果希望这里的 this 不是 window 该怎么做呢?
很简单:
func.call(obj) // 那么里面的 this 就是 obj 对象了
再看obj.foo(p1, p2)
里的 this 如何确定:
let obj = { foo() { console.log(this) }, } obj.foo()
他本身的指向就是 obj 自己,所以写成call()
也就是:obj.foo.call(obj)
回到最上面的代码。
let obj = { foo() { console.log(this) }, } let bar = obj.foo obj.foo() // 转换为 obj.foo.call(obj),this 就是 obj bar() // 转换为 bar.call() // 由于没有传 context // 所以 this 就是 undefined // 最后浏览器给你一个默认的 this —— window 对象
提一个有趣的用法:如果把函数放到数组里,然后数组[]调用函数,this 指向哪里呢?
function fn() { console.log(this) } let arr = [fn, fn2] arr[0]()
这里面的 this 是什么呢?
我们可以把arr[0]()
理解为arr.0()
,虽然后者的语法错了,但是形式与转换代码里的obj.foo(p1, p2)
对应上了!
arr[0]()
=> arr.0()
=> arr.0.call(arr)
那么里面的 this 就是 arr
了。
总之,this 就是你 call 一个函数时,传入的第一个参数。
(完)
上一篇: 为何说宣德年间是明朝最鼎盛的时期?