You Don't Know JS: this & Object Prototypes( 第一章 this or That?)
Foreword
this 關鍵字和prototypes
他們是用JS編程的基礎。沒有他們創建復雜的JS程序是不可能的。
我敢說大量的web developers從沒有建立過JS Object,僅僅對待這門語言作為一個事件綁定膠水,在按鈕和Ajax請求之間。
我也曾是他們的一員,但是當我了解到如何掌握prototypes並創建JS對象,一個世界的可能性對我打開了。
- Chapter 1: this Or That?
- Chapter 2: this All Makes Sense Now!
- Chapter 3: Objects
- Chapter 4: Mixing (Up) "Class" Objects
- Chapter 5: Prototypes
- Chapter 6: Behavior Delegation
- Appendix A: ES6 class
- Appendix B: Thank You‘s!
Chapter 1: this
Or That?
this作為一個識別符號關鍵字自動定義在每個函數的作用域中,但是它究竟涉及什麽,甚至困擾著有經驗的JS developer。
Why this?
既然很難理解,為什麽還使用?它的麻煩大於它的價值嗎?
看案例:
function identify() {
return this.name.toUpperCase();
}
var me = {
name: "Kyle"
};
var you = {
name: "Reader"
};
identify.call( me ); // KYLE
identify.call( you ); // READER
這段代碼讓identify函數被多次調用。
如果不用this關鍵字,也可以通過傳入一個context對象來實現:
function identify(context) {
return context.name.toUpperCase();
}
identify( you ); // READER
由此可見,this機制提供了更優雅的方式,暗示傳入了一個對象,這讓API設計更清晰,復用更容易。
Confusions
首先,消除一些錯誤觀念。常常有2個錯誤的假設:
Itself
假設this是函數自身。
function foo(num) { console.log( "foo: " + num ); // keep track of how many times `foo` is called this.count++; } foo.count = 0; var i; for (i=0; i<10; i++) { if (i > 5) { foo( i ); } } // foo: 6 // foo: 7 // foo: 8 // foo: 9 // how many times was `foo` called? console.log( foo.count ); // 0 -- WTF?
因為this指向了window對象。this指向的是調用函數的對象。
//在call方法內加上函數對象的identifier名字 for (var i=0; i<10; i++) { if (i > 5) { foo.call( foo, i ); } } // how many times was `foo` called? console.log( foo.count ); // 4
除此之外,還有規避this的方法。但都沒有直面this到底是什麽的問題。
- 使用foo.count代替this.count.
- 單獨聲明一個data對象{ count: 0},用於計數 data.count++
Its Scope
另一個常見的誤區是關於this,它涉及了函數的作用域。這裏有些詭計:
在某些情況下是對的,但在其他情況下,這麽理解是受到誤導的!
this關鍵字,在任何時候,都不涉及一個function的 Lexical scope
function foo() {
var a = 2;
this.bar();
}
function bar() {
console.log( this.a );
}
foo(); //undefined
寫 這段代碼的人,試圖通過this關鍵字,把變量a傳遞給bar函數。以為this是橋梁,能在兩個函數的lexical scope之間傳遞內部變量a。 ?。沒有這個橋梁!!
this不能得到foo函數的Lexical scope!!
this和Lexical scope是不相關的!!!
What‘s this?
this機制到底是如何工作的?
this和函數調用的方式相關!
當一個函數被invoked,一條記錄被創建。這條記錄包含信息:
- 函數從哪裏調用(the call-stack)
- 函數如何被invoked
- 什麽參數被傳入。
這條記錄的屬性之一就是 this 引用。它會在函數的執行期間被使用。
下一章,我們會學習尋找一個函數的call-site(調用點),來決定它的執行如何綁定this關鍵字
Review
this既不是函數自身的引用也不是函數的lexical作用域的引用!!
this實際是一個在函數被invoked時創建的綁定binding!!!
this引用什麽由函數被調用的地點call-site決定!!!
You Don't Know JS: this & Object Prototypes( 第一章 this or That?)