深入探究js中無所不在的this


 黃金守則:

       this對象是在運行時基於函數的執行環境綁定的:在全局函數中,this等於window而當函數被作為某個對象的方法調用時, this等於那個對象。

 

下面是一些相關實踐:

------------------------------------------------->閉包相關的this<--------------------------------------------------------

 

我們知道,匿名函數的執行環境具有全局性,因此this對象通常指向window,但是由於閉包的編寫方式不同,這一點可能不那么明顯:

 

 

 

 

這是為什么呢?其實每個函數在被調用時,其活動對象都會自動獲取兩個特殊的變量:this和arguments。內部函數在搜索這兩個變量時,只會搜索到其活動對象為止,因此永遠不可能直接訪問到外部函數中的這兩個變量了。

 

不過下面這樣改寫,就可以做到了。

 

 

 

 ----------------------------------------------->函數相關的this<-----------------------------------------------------

 

先看一個最最簡單的例子:

 

 

this當然會undefined,因為this的指向實際是指向它的調用的。實際上,前面這樣說是不對的,謝小胡子的提醒呢。實際上這個undefined是整個函數的運行結果,函數並沒有返回任何值,所以它才是undefined的~~~

下面還有兩個特殊的情況,閉包中this的表現:

 

 

因為閉包立即執行,這相當於在全局的作用於下調用了函數,於是乎,可以看到,他就是指向了window了。

可是.......strict模式下的:

 

 

這就是閉包中使用嚴格模式的后遺症,它不讓this指向全局作用域了呢。

這有個總結javascript中‘use strict’的資料,總結的挺好聽明白的:http://www.web-tinker.com/article/20125.html

 

那么說了this是指向他的調用了,到底是怎么指向的呢,我們試試幾個小例子,看看它的行為:

1.最普通的:

 

 

看吧,剛才還undefined呢,調用一下this就指向調用它的作用域了喔。

 

 

這個更印證了this指向調用他的作用域。

 

2.那我現在把函數嵌套一下試試看呢:

 

 

還是window喔,這里this是屬於window喔,好像說也說不清楚,自己寫寫試試想想,體會體會喔。

 

3.上面基本上都是函數調用時候的情況,那下面我試一下函數引用,來看看會是什么樣子呢,稍稍復雜些:

 

 

 

上面事實證明,引用函數是可以改變函數的執行作用域的,但是像之前的,調用函數是不會改變函數的執行作用域的呢:

 

 

事實證明條用函數是不會改變函數的執行作用域的(注意上面兩段代碼中me:后面的使用方式)。

這有道題目:

 

------------------------------------------------>構造函數中的this<----------------------------------------------------

 

1.下面我們先看看js中簡單封裝過程中用到的this:

 

 

上面實現的並不是嚴格的封裝,但是從中我們可以看到this的作用。

 

2.別急,肯定還是有點有意思的事情的:

 

 

這里通過new創建了一個新的對象呢,並將這個對象通過this傳入到了構造器中,這也就是為什么b的作用域跑到了a{}里面。

這是為什么呢?? 我們來來看new構造函數這種用法是怎么回事吧:

簡單來看:

 

 

其實new的作用就是使this指向一個新建的對象,然后return this。

實際它的運行情況是這樣的:

復制代碼
1 function Person (){
2     // var obj = new Object();
3     // this = obj;
4     alert(this);     // new 出來的 Person 對象
5     // return this;
6 }
7 var person = new Person(); 
復制代碼

實際上js的實現是這樣的:

復制代碼
1 function newOperator(Constr, args) {
2     var thisValue = Object.create(Constr.prototype); // (1)
3     var result = Constr.apply(thisValue, args);
4     if (typeof result === 'object' && result !== null) {
5         return result; // (2)
6     }
7     return thisValue;
8 }
復制代碼

在網上看資料的時候看到的,鏈接在這里:http://speakingjs.com/es5/ch17.html#_the_new_operator_implemented_in_javascript

 

--------------------------------------------->call和apply對this的影響 <------------------------------------------------------------

 

看例子:

 

 

這里this就指向String了。

 

 

上面這個例子就通過call(),把x,y,傳到了函數中。

 

------------------------------------------------------->定時器(setTimeout,setInterval)中的this<--------------------------------------------------------------

先看最簡單的:

 

 

這里面this就是指向window。

實際上因為setTimeout()和setInterval()發放根本就是window的,所以當然指向window了。

 

 

更加印證了上面所說的。

但其實是,setTimeout()就是會產生一個不符合常理的this。它會在一個獨立的執行上下文中運行。結果就是,他就會使this關鍵字指向window。 mdn上有詳細的解釋:https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers.setTimeout

 1 myArray = ["zero", "one", "two"];
 2 myArray.myMethod = function (sProperty) {
 3     alert(arguments.length > 0 ? this[sProperty] : this);
 4 };
 5 
 6 myArray.myMethod(); // prints "zero,one,two"  7 myArray.myMethod(1); // prints "one"  8 setTimeout(myArray.myMethod, 1000); // prints "[object Window]" after 1 second  9 setTimeout(myArray.myMethod, 1500, "1"); // prints "undefined" after 1.5 seconds 10 // let's try to pass the 'this' object
11 setTimeout.call(myArray, myArray.myMethod, 2000); // error: "NS_ERROR_XPC_BAD_OP_ON_WN_PROTO: Illegal operation on WrappedNative prototype object" 12 setTimeout.call(myArray, myArray.myMethod, 2500, 2); // same error

 

但是mdn上面 也提供了解決方法:

1 myArray = ["zero", "one", "two"];
2 myArray.myMethod = function (sProperty) {
3     alert(arguments.length > 0 ? this[sProperty] : this);
4 };
5 
6 setTimeout(alert, 1500, "Hello world!"); // the standard use of setTimeout and setInterval is preserved, but... 7 setTimeout.call(myArray, myArray.myMethod, 2000); // prints "zero,one,two" after 2 seconds 8 setTimeout.call(myArray, myArray.myMethod, 2500, 2); // prints "two" after 2.5 seconds

 

 

--------------------------------------------------------------->eval()中的this<---------------------------------------------------------------------------

 

直接調用eval():

 

 

直接調用eval()的話,this指向當前作用域的。('use strict'不用也是一樣的)

下面展示了不直接調用的情況:

 

 

 

------------------------------------------------------->復雜情況中的this<--------------------------------------------------------

在查找資料的過程中,發現了一個總結的挺好的,復雜情況下this的優先級,貼過來收藏:

 

優先級 情景 this 的值 備注
1 new new出來的空 object  
  apply / call 傳入的參數 並列第一,apply / call不能和 new 同時出現
new arr1.show.apply(“1”); // 報錯
2 定時器 window  
3 事件 發生事件的元素  
4 方法 所有者  
5 其他(嵌套等) window || undefined 看是否為嚴格模式

注:不管如何修改this,this只會影響一層

例:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM