1. 程式人生 > >JavaScript中的this(你不知道的JavaScript)

JavaScript中的this(你不知道的JavaScript)

JavaScript中的this,剛接觸JavaScript時大家都在大肆渲染說其多麼多麼的靈巧重要,然而自己並不關心;隨著自己對JavaScript一步步深入瞭解,突然恍然大悟,原來它真的很重要!所以,自己花費了大約2周的時間去查貼、翻閱之前讀的書籍,將this的全貌展示如下。

一、this是什麼--基於呼叫位置的上下文;呼叫位置不同,this值不同。

大家都JavaScript中this存在兩個誤解:
(1)this指向函式自身
(2)this指向函式的作用域

作用域無法通過JavaScript程式碼訪問,它存在於JavaScript引擎內部。每當把this和詞法作用域的查詢混合使用時,一定要提醒自己,這是無法實現的!

this是在執行時進行繫結的,並不是在編寫時繫結,它的上下文取決於函式呼叫時的各種條件。this的繫結和函式宣告的位置沒有任何關係,只取決於函式的呼叫位置(也就是函式的呼叫方式)!

示例:
[javascript] view plain copy
  1. var foo = "golbal foo";  
  2. var myObj = {foo : 'myObj foo'};  
  3. var say = function(){  
  4.     console.log(this.foo);  
  5. }  
  6. myObj.say = say;  
  7. myObj.say();    //結果:myObj foo
  8. say();      //結果:golbal foo

二、為什麼使用this

[javascript] view plain copy
  1. var me = {  
  2.     name: "fenfei"
  3. };  
  4. //不使用this,呼叫
  5. function speak(name){  
  6.     console.log("Hello, I'm "+ name);  
  7. }  
  8. speak(me.name);     //Hello, I'm fenfei
  9. //使用this,呼叫
  10. function speak(){  
  11.     console.log("Hello, I'm "
    this.name);  
  12. }  
  13. speak.call(me);     //Hello, I'm fenfei

this提供了一種更優雅的方式來隱式“傳遞”物件引用,因此可以將API設計得更加簡潔並易於複用。

三. this的四大繫結規則

1. 預設繫結--函式呼叫型別:獨立函式呼叫,this指向全域性物件。

[javascript] view plain copy
  1. var a = "foo";  
  2. function foo(){  
  3.     console.log(this.a);  
  4. }  
  5. foo();  // "foo"

在嚴格模式下,全域性物件將無法使用預設繫結,因此this會繫結到undefined。

[javascript] view plain copy
  1. var a = "foo";  
  2. function foo(){  
  3.     "use strict";  
  4.     console.log(this.a);  
  5. }  
  6. foo();  // TypeError:this is undefined

2. 隱式繫結--呼叫位置是否有上下文物件,或者說被某個物件擁有或者包含

[javascript] view plain copy
  1. function foo(){  
  2.     console.log(this.a);  
  3. }  
  4. var obj1 = {  
  5.     a : 2,  
  6.     foo : foo  
  7. }  
  8. var obj2 = {  
  9.     a : 1,  
  10.     obj1 : obj1  
  11. }  
  12. obj2.obj1.foo();    //結果:2

當foo()被呼叫時,它的落腳點指向obj1物件,隱式繫結規則會把函式呼叫中的this繫結到這個上下文物件。
物件屬性引用鏈中只有最頂層或者說最後一次層會影響呼叫位置。

注意:隱式丟失

常見的this繫結問題就是“隱式繫結”的函式會丟失繫結物件,也就是“預設繫結”,從而把this繫結到全域性物件(嚴格模式下為undefined)。

[javascript] view plain copy
  1. var a = "foo";  
  2. function foo(){  
  3.     console.log(this.a);  
  4. }  
  5. var obj = {  
  6.     a : 2,  
  7.     foo : foo  
  8. }  
  9. var bar = obj.foo;  
  10. bar();  //"foo"

雖然bar是obj.foo的一個引用,但是實際上,它引用的是foo函式本身,因此此時的bar()其實是不帶任何修飾的函式呼叫,因此應用了預設繫結。

[javascript] view plain copy
  1. var a = "foo";  
  2. function foo(){  
  3.     console.log(this.a);  
  4. }  
  5. function doFoo(fn){     //var fn = obj.foo
  6.     fn();  
  7. }  
  8. var obj = {  
  9.     a : 2,  
  10.     foo : foo  
  11. }  
  12. doFoo(obj.foo); //"foo"
  13. setTimeout(obj.foo, 100);   //"foo"

引數傳遞其實就是一種隱式賦值,因此傳入函式式會被隱式賦值(LHS)

3. 顯示繫結

(1)call、apply
(2)硬繫結
[javascript] view plain copy
  1. function foo(){  
  2.     console.log(this.a);  
  3. }  
  4. var obj = { a:2 };  
  5. var bar = function(){