在 Java 裡,this 指的是所在的 class instance,多半是在 method 裡呼叫 this;但是在 Javascript 裡,function 可以是 top-level object,也可以指派給某個物件,那 function 裡的 this 指的到底是誰?
要看 context,執行時的 context,不是定義時的 context,更白話點,就是「掛在誰身上執行」。
掛在誰身上執行?
一般的 function 有兩種用法:
function a() {function c 是掛在 b 身上執行,所以 c 裡面的 this 指的就是 b,那 function a 呢?是掛在誰身上? window 物件,所以 a 裡的 this 指的就是 window。
return 'a';
}
var b = {
c: function() {
return 'c';
}
}
// 呼叫方式分別為
a();
var b1 = new b();
b1.c();
懂了嗎?接下來讓大腦冒煙一下吧!
var a = 'window.a'; // global 變數
var that = this; // 就是指 window
$(function(){
neil.log(this); // 0.[object HTMLDocument]
neil.log('-');
var a = 'document.ready.a';
var b = 'document.ready.b';
this.a = 'document.a'
this.c = 'document.c';
neil.log(a); // 1.document.ready.a
neil.log(window.a); // 2.window.a
neil.log(that.a); // 3.window.a
neil.log(this.a); // 4.document.a
neil.log('-');
neil.log(f1()); // 5.window.a
neil.log(window.f1()); // 6.window.a
neil.log(that.f1()); // 7.window.a
neil.log('-');
neil.log(f1.call(this)); // 8.document.a
neil.log(f1.apply(this)); // 9.document.a
neil.log('-');
neil.log(f2()); // 10.window.a
neil.log(window.f2()); // 11.window.a
neil.log(that.f2()); // 12.window.a
neil.log('-');
neil.log(f2.call(this)); // 13.window.aneil.log(f2.apply(this)); // 14.window.aneil.log('-');
neil.log(b); // 15.document.ready.b
neil.log(this.b); // 16.undefined
neil.log('-');
neil.log(this.c); // 17.document.c
neil.log(c); // 18.error - undefined
neil.log('-');
});
function f1() {
return this.a;
}
function f2() {
return a;
}
宣告一個 global 變數 a,以及一個 ready function 裡的 local 變數 a。
再強調一下,兩條規則:
- this 指的是掛在誰身上執行,不是在哪個環境執行!
- 如果沒有指明掛在誰身上,那就是從所在的 scope 往上找,直到找到為止。
neil.log(this); // 0.[object HTMLDocument]
先驗明正身,得知 ready function 是掛在 document 身上執行。
var a = 'document.ready.a';
var b = 'document.ready.b';
this.a = 'document.a';
this.c = 'document.c';
在 function 裡用 var 或 this 宣告變數,結果差很大。
- 用 var 表示該變數為 function 裡的 local 變數。
- 用 this 表示該變數為該 function 所屬物件的屬性,簡單說,this 宣告的變數和這個 function 是同一個物件下的屬性與 function。
neil.log(a); // 1.document.ready.a
沒說掛在誰身上,套用規則2,先看 function裡有沒有 a,若沒有再看 window 裡有沒有,但是不會看物件的屬性,也就是 document.a。
neil.log(window.a); // 2.window.a
neil.log(that.a); // 3.window.a
有頭有尾,沒問題。
neil.log(this.a); // 4.document.a
在 doucment.ready 裡呼叫 this,指的當然是 document。
neil.log(f1()); // 5.window.a
沒說掛在誰身上,套用規則2,在 window 裡找到 f1,f1 裡的 this當然是 window。。
neil.log(window.f1()); // 6.window.a
neil.log(that.f1()); // 7.window.a
指名道姓,沒問題。
neil.log(f1.call(this)); // 8.document.a
neil.log(f1.apply(this)); // 9.document.a
Javascript 特有的「張冠李戴」功能,因為 function 為獨立的物件,可以到處掛在別人身上,就有了這兩個「借腹生子」 的 function,call 與 apply 只差在餵參數的方式不一樣,都是將 function 掛在第一個參數上執行,以上面為例,就是將 f1 掛在 document 上執行。
neil.log(f2()); // 10.window.a
neil.log(window.f2()); // 11.window.a
neil.log(that.f2()); // 12.window.a
第一個因為沒有頭,所以套用規則2,得到跟後兩個一樣的頭,而 f2 裡的 a 又是沒有頭,一樣套用規則2。
neil.log(f2.call(this)); // 13.window.a
neil.log(f2.apply(this)); // 14.window.a
使用「借腹生子」掛在 document 下執行,但 f2 裡的 a 沒有頭讓我很困擾,我以為就是指 document.a,但結果卻是 window.a,唯一的解釋是「規則2不會找物件屬性,只會找 local 變數」!
neil.log(b); // 15.document.ready.b
neil.log(this.b); // 16.undefined
neil.log(this.c); // 17.document.c
neil.log(c); // 18.error - undefined
用來證明在 function裡用 var 或 this 宣告變數是不一樣的。
沒有留言:
張貼留言