1. 程式人生 > >JS 中的 this 總結

JS 中的 this 總結

post hellip body ret object show color log apply

JavaScript 中的 this:
this指向是在運行函數時確定的,而不是定義函數時候確定的
匿名函數的執行環境具有全局性,因此其this 對象通常指向window(在通過call()或apply()改變函數執行環境的情況下,this 就會指向其他對象)

全局上下文:無論是否在嚴格模式下,在全局執行上下文中(在任何函數體外)this都指代全局對象

如:
1、console.log(this === window); // true
2、var girl={name:"amy",testThis:this}; console.log(girl.testThis); // window

(可理解為:var girl=new Object(); girl.name="amy"; girl.testThis=this;(指向window)


函數上下文:在函數內部,this的取值取決於函數被調用的方式

1、簡單調用:
function f1(){
return this;
}
f1() === window; //在瀏覽器中,全局對象是window
非嚴格模式下,且this的值不是由該調用設置時(具體說就是不由該調用通過 call、apply、bind 這些方法來設置),this的值默認指向全局對象 嚴格模式下,this將保持它進入執行上下文時的值 所以默認為undefined

2、如果要想把 this 的值從一個上下文傳到另一個,就要用 call 或者apply 方法

3、bind方法:
ECMAScript 5 引入了 Function.prototype.bind。調用f.bind(someObject)會創建一個與f具有相同函數體和作用域的函數,但是在這個新函數中,this將永久地被綁定到了bind的第一個參數,無論這個函數是如何被調用的

4、箭頭函數:this與封閉詞法上下文的this保持一致(即this被設置為它創建時的上下文)。如果將this的值傳給call、bind、apply,它將被忽略,不過仍然可以為為調用添加參數,不過第一個參數應設置為null

5、作為對象的方法:當作為對象的方法被調用時,它們的this是調用該函數的對象,並且此時this的綁定只受最靠近的成員引用的影響

6、原型鏈中的this:this指向的是調用該方法的對象,就像該方法在對象上一樣

7、getter(與setter)中的this:用作getter(或setter)的函數會把this綁定到獲取(或設置)屬性的對象上

8、作為構造函數:this被綁定到正在構造的新對象(雖然構造器返回的默認值是this所指的那個對象,但它仍可以手動返回其他的對象)

9、作為一個DOM事件處理函數:this指向觸發事件的元素

10、作為一個內聯事件處理函數:this指向監聽器所在的DOM元素
如:
1、<button onclick="alert(this.tagName.toLowerCase());"> Show this </button> this指向button(註意只有外層代碼中的this是這樣設置的)

2、<button onclick="alert((function(){return this})());"> Show inner this </button> 這種情況下,沒有設置內部函數的this,相當於函數簡單調用的情況,所以它指向global/window對象

部分代碼示例:

  1 <!DOCTYPE html>
  2 <html lang="en">
  3 <head>
  4     <meta charset="UTF-8">
  5     <title>This</title>
  6 </head>
  7 <body>
  8 
  9 <script>
 10     //全局上下文:無論是否在嚴格模式下,在全局執行上下文中(在任何函數體外)this都指代全局對象 
 11     var girl={
 12         name:"amy",
 13         testThis:this
 14     };
 15     /*
 16         可理解為:
 17         var girl=new Ojbect();
 18         girl.name="amy";
 19         girl.testThis=this;
 20     */
 21     console.log(girl.testThis);//window
 22 </script>
 23 
 24 <script>
 25     console.log("JS 是基於詞法作用域的語言,函數在定義它的作用域中執行,而不是在調用它的作用域中執行");
 26     console.log("類的方法默認是不會綁定 this 的,作為對象的方法:當作為對象的方法被調用時,它們的this是調用該函數的對象,並且this的綁定只受最靠近的成員引用的影響");
 27     console.log("-----------About Amy --------------");
 28     var Amy={
 29             name:"Amy",
 30             sex:"girl",
 31             amyOutter:function(){
 32                 console.log("amyOutter:",this);
 33                 return function(){
 34                     console.log("amyAnonymous:",this);
 35                 };
 36             }
 37         };
 38     console.log("----Amy.func amyOutter -----");
 39     var amy_anony=Amy.amyOutter();
 40     //輸出: amyOutter: {name: "Amy", sex: "girl", amyOutter: ƒ}
 41     // 解析:作為對象的方法調用
 42 
 43     console.log("----Amy.func amyOutter quote-----");
 44     var quote=Amy.amyOutter;//獲取Amy.amyOutter函數的引用
 45     quote();
 46     //輸出:amyOutter: Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
 47     // 解析:這裏相當於簡單調用
 48     
 49     console.log("----Amy.func amyAnonymous-----");
 50     amy_anony();
 51     //輸出: amyAnonymous: Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
 52     // 解析:直接調用返回的匿名函數
 53 
 54     amy_anony.call(Amy);
 55     //輸出: amyAnonymous: {name: "Amy", sex: "girl", amyOutter: ƒ}
 56     // 解析:Amy用call調用返回的匿名函數
 57     
 58 </script>
 59 
 60 <script>
 61     console.log("-----------About Mike -----------");
 62     var Mike={
 63         name:"Mike",
 64         sex:"boy",
 65         mikeOutter:function(){
 66             console.log("mikeOutter:",this);
 67             (function(){
 68                 console.log("mikeAnonymous:",this);
 69             })();
 70         }
 71     };
 72 
 73     console.log("----Mike.func mikeOutter---");
 74     Mike.mikeOutter();
 75     //輸出: mikeOutter: {name: "Mike", sex: "boy", mikeOutter: ƒ}
 76     // 解析:作為對象的方法調用  
 77     //輸出: mikeAnonymous: Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
 78     // 輸出:window 解析:匿名函數被調用
 79 
 80     console.log("----Mike.func mikeOutter quote-----");
 81     var quote=Mike.mikeOutter;//獲取Mike.mikeOutter函數的引用
 82     quote();
 83     //輸出:mikeOutter: Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
 84     // 解析:這裏相當於簡單調用
 85     //輸出: mikeAnonymous: Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
 86     // 解析:匿名函數被調用
 87 
 88     console.log("---Mike func call---");
 89     Mike.mikeOutter.call(Amy);
 90     //輸出: mikeOutter: {name: "Amy", sex: "girl", amyOutter: ƒ}
 91     // 解析:Amy 用call調用返回的匿名函數 
 92     //輸出:mikeAnonymous: Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
 93     // 解析:匿名函數被調用
 94 
 95 </script>
 96 
 97 <script>
 98     console.log("-----------About Guang -----------");
 99     var Guang={
100         name:"Guang",
101         sex:"boy",
102         GuangOutterOne:function(){
103             console.log("GuangOutterOne:",this);
104             var that=this;
105             // 正確 that 中保留了對 this 的引用
106             this.GuangOutterTwo(function(){
107                 that.GuangOutterThree();                
108             });
109             
110             // 正確 匿名函數直接綁定 this
111             // this.GuangOutterTwo(function(){
112             //     this.GuangOutterThree();                
113             // }.bind(this));
114 
115             // 出錯 匿名函數作參數 this 為 window ,window 無 GuangOutterThree 方法
116             // this.GuangOutterTwo(function(){
117             //     this.GuangOutterThree();                
118             // });
119         },
120         GuangOutterTwo:function(cb){
121             console.log("GuangOutterTwo:",this);
122             cb();
123         },
124         GuangOutterThree:function(){
125             console.log("GuangOutterThree:",this);
126         }
127     };
128 
129     console.log("----Guang.func GuangOutterOne---");
130     Guang.GuangOutterOne();
131     //輸出:GuangOutterOne: {name: "Guang", sex: "boy", GuangOutterOne: ƒ, GuangOutterTwo: ƒ, GuangOutterThree: ƒ} 
132     //解析:作為對象的方法調用  
133 
134     //輸出: GuangOutterTwo: {name: "Guang", sex: "boy", GuangOutterOne: ƒ, GuangOutterTwo: ƒ, GuangOutterThree: ƒ}
135     //解析: GuangOutterOne 中的 this 指向 Guang 調用 Guang 中的 GuangOutterTwo 方法
136 
137     //輸出: GuangOutterThree: {name: "Guang", sex: "boy", GuangOutterOne: ƒ, GuangOutterTwo: ƒ, GuangOutterThree: ƒ}
138     //解析: that 保留對 this 的引用 調用 Guang 中的 GuangOutterTwo 方法
139    
140 
141 </script>
142 
143 <script>
144     console.log("JS 是基於詞法作用域的語言,函數在定義它的作用域中執行,而不是在調用它的作用域中執行");
145     console.log("箭頭函數:this與封閉詞法上下文的this保持一致(即this 被設置為他被創建時的上下文)");
146     var foo=(()=>this);
147     /*
148         可以把箭頭函數看成是
149         var foo=function(){
150             //other code
151             return this;
152             //此處this所在的函數被創建時是在全局環境中 因為 this被設置為他被創建時的上下文 所以 this就被設置為window
153         };
154     */
155     // 由下可見 無論如何,foo 中的 this 都被設置為他被創建時的上下文(在上面的例子中,就是全局對象)
156     // 註意:對於箭頭函數 如果將this傳遞給call、bind、或者apply,它將被忽略 不過你仍然可以為調用添加參數,不過第一個參數(thisArg)應該設置為null
157     var obj = {foo: foo};
158     console.log("直接調用:",foo()===window,", call調用:",obj.foo() === window,", apply調用:",foo.call(obj) === window,", bind綁定:",foo.bind(obj)() === window); // true true true true
159     
160    //這同樣適用於在其他函數內創建的箭頭函數:這些箭頭函數的this被設置為封閉的詞法上下文的
161     console.log("-----------About John ------------------");
162     var John={
163         name:"John",
164         johnOutter:function(){
165             //console.log("johnOutter",this);//johnOutter中的this具體情況可參考上面的Amy和Mike實例
166             var x=(()=>this);
167             //此處this所在的函數被創建時是在johnOutter中  因為 this被設置為他被創建時的上下文 所以 this就被設置為 johnOutter 函數中的this
168             return x;
169         }
170     }
171 
172     var fn=John.johnOutter();//獲取返回的函數 若去掉johnOutter中console.log語句的註釋 輸出:John 解析:解析:作為對象的方法調用 
173     console.log("John.johnOutter():",fn());
174     //輸出:John.johnOutter(): Object { name: "John", johnOutter: johnOutter() }
175     //解析:此時johnOutter函數由John調用 所以johnOutter函數中的this為John,而箭頭函數的this被設置為johnOutter的this
176 
177     var quote=John.johnOutter;//獲取John.johnOutter函數的引用
178     console.log("quote:",quote()());
179     //輸出:window 
180     //解析:此時quote獲取johnOutter的引用,quote()相當於簡單調用,所以johnOutter函數中的this為window,而箭頭函數的this被設置為johnOutter的this
181     
182     /**
183      * 對於箭頭函數:
184      * 1、確定箭頭函數是在哪個執行環境中被創建的
185      * 2、根據執行環境確定this被設置為哪個執行環境
186      * 3、最後對函數的調用參考對象中的方法調用即可
187      * 總結可以簡單理解為:
188      * 箭頭函數的this在全局執行上下文創建時 它的this就是全局上下文中的this 
189      * 箭頭函數的this在全局執行上下文創建時 它的this就是全局上下文中的this 
190      */
191 
192 </script>
193 
194 </body>
195 </html>

JS 中的 this 總結