以前的理解:this 永遠指向最後調用它的那個對象
var name = "windowsName";
var a = {
name: "Cherry",
fn : function () {
console.log(this.name);
}
}
a.fn();// Cherry
var name = "windowsName";
var a = {
name: "Cherry",
fn : function () {
console.log(this.name);
}
}
var f = a.fn;
f(); //最後調用的是window所以打印出來是windowsName
函數調用模式的不同理解
你可能遇到過這樣的 JS 面試題:
var obj = {
foo: function(){
console.log(this)
}
}
var bar = obj.foo
obj.foo() // 打印出的 this 是 obj
bar() // 打印出的 this 是 window
請解釋最後兩行函數的值爲什麼不一樣。
函數調用
JS(ES5)裏面有三種函數調用形式:
- func(p1, p2)
- obj.child.method(p1, p2)
- func.call(context, p1, p2) // 先不講 apply
一般,都知道前兩種形式,而且認爲前兩種形式「優於」第三種形式。
但第三種調用形式,纔是正常調用形式:
func.call(context, p1, p2)
其他兩種都是語法糖,可以等價地變爲 call 形式:
func(p1, p2)等價於 func.call(undefined, p1, p2);
obj.child.method(p1, p2) 等價於 obj.child.method.call(obj.child, p1, p2);
至此我們的函數調用只有一種形式:
func.call(context, p1, p2)
這樣,this 就好解釋了 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 對象了
回到題目:
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 對象
[ ] 語法
function fn (){ console.log(this) }
var arr = [fn, fn2]
arr[0]() // 這裏面的 this 又是什麼呢?
我們可以把 arr[0]( ) 想象爲arr.0( ),雖然後者的語法錯了,但是形式與轉換代碼裏的 obj.child.method(p1, p2) 對應上了,於是就可以愉快的轉換了:
arr[0]() 假想爲 arr.0()
然後轉換爲 arr.0.call(arr)
那麼裏面的 this 就是 arr 了