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 一個函式時,傳入的第一個引數,
(完)
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/109915.html
標籤:JavaScript
