首頁 >web前端 >js教程 >詳細解讀在JS中this引發的bug

詳細解讀在JS中this引發的bug

亚连
亚连原創
2018-06-21 14:20:271298瀏覽

這篇文章主要介紹了分析JavaScript中this引發的bug以及相關的處理方法分析,一起學習下吧。

在js 中,this 這個上下文總是變化莫測,很多時候出現bug 總是一頭霧水,其實,只要分清楚不同的情況下如何執行就可以了,以下就是我們給大家整理的相關內容:

在JavaScript中有一個很特別、很常用又常常讓初學者很困擾的東西─ “this”,在這堂課中會來談談這個”this”。

this通常會指向一個對象,同時this會在不同的情境下指向不同的對象。讓我們來看幾個不同的情境,幫助我們更了解」this」。

window object (global object)

這裡我們在三種不同情境去列印」this”,分別是在函數的最外層(outer environment)直接去執行;使用fuction statement去執行;使用function expression去執行(如果還不清楚function statement和function expression的差別,可以參考註1)。

結果會發現,這三個」this」都會指向同樣的對象,也就是global environment的window object (global object):

這也就是說,我們可以直接利用這個function和this在window object建立新的屬性:

在這裡我們利用this.NewVariable = "... "來在window object建立新的屬性,函數的最後,我們則可以直接console.log(NewVariable),這裡之所以可以不用打this.NewVariable或window.NewVariable是因為任何在global object (window)的屬性,我們都可以直接去使用它,而不用使用」。」。

跑出來的結果會像這樣子:

它會印出我們的」Create a new property ”,同時,在window這個大的object中,我們也會找到NewVariable這個屬性:

method in object

我們知道,在物件裡的值如果是原生值(primitive type;例如,字符串、數值、邏輯值),我們會把這個新建立的東西稱為「屬性(property)」;如果物件裡面的值是函數(function)的話,我們則會把這個新建立的東西稱為「方法(method)」。

在這裡,我們就要來建立method:

首先,我們利用object literal的方式來建立一個物件c,裡麵包含屬性name和方法log。 log是匿名函數(anonymous function),函數內容很簡單,就是印出this而已(關於匿名函數可參考註1)。最後則是使用c.log的方式來執行該方法。

讓我們來看看,這時候的」this」會是什麼呢?

答案是物件c!

當這個函數是物件裡面的method時,這時候的this就會指向到包含這個method的物件

JavaScript中關於this的一個bug

讓我們更進一步延伸來看這個範例:

假設我們在method log裡面多這一行this.name = "Updated Object C name"

#因為我們知道」this」現在指的是物件c,所以可以想像的,當我執行這個method的時候,它會去變更c.name的值。

這個部分是沒有什麼大問題的,不過讓我們繼續看下去…。

假設我在method log裡面在做一些變更,我在這個method裡面,另外建立一個函數叫做setname,一樣是用this.name = newname的方式來修改這個object c中name屬性的值。

接著執行setname這個函數,希望把object c中name的屬性值改成”New name for object c”,最後再去印出”this”來看一下。

結果我們會發現,物件c中name屬性的值並沒有變成”New name for object c”,竟然還是一樣! ?怎麼會這樣呢?

仔細一看,我們回來看一下我們的window object,我們會發現,在window object中發現了一個新的屬性”name”,而且值是” New name for object c」。

這是什麼意思呢?意思是原來我們剛剛在函數setname裡面的this,指向到的是global object (window object),而不再是剛剛的object C!

我們在setname這個function中,用console.log(this)來看一下:

在log這個method中,我們一共執行了三次的console.log(this)結果如下:

第一個和第三個」this」指向到的是物件c,而第二個在setname中的this,指向的則是window object (global object),而這也就是為什麼setname這個function沒辦法幫我們修改物件c中name屬性的名稱,因為」this」根本沒指向到物件c。

而許多人都認為,這是JavaScript的一個bug。

那麼我們可以怎麼做

那麼碰到上述的這個例子時,我們可以怎麼做來避免指向到不同的物件呢?

許多人的解法是這樣的,因為我們知道物件都是用的引用的方式,所以我們可以這樣做

STEP 1

我們在整個函數的最上面加上一行var self = this(有些人會用var that = this)。由於引用的特性,self和this會指向同一個對象,而this指向對象c,所以self一樣會指向對象c。

STEP 2

接著,把方法log內原本使用的”this”都改成”self”,這樣做可以確保self指向到的是c對象而不用擔心會像上面的例子一樣指向到錯誤的物件。

結果也如同我們預期的,在第二次console.log(self)的時候,就再次取代了物件c中name屬性的值。

總結

讓我們來總結一下:

如果我們是在全域環境建立函數並列印this,這時候this會指向到全域對象,也就是window對象。

如果我們是在物件裡面建立函數,也就是方法(method)的情況時,這時候的this一般就會指向到包含這個方法的物件(之所以說」一般」是因為除了上述bug的情況之外)。

碰到method中可能會有不知道this指向到什麼的情況時,為了避免不必要的錯誤,我們可以在method中的最上面建立一個變量,去把它指定成this(var self = this)。

4.如果真的還是不知道那個情況下的this會指向到什麼,就console.log出來看看吧!

範例程式碼

// function statement
function a(){
 console.log(this);
 this.NewVariable = "Create a new property";
}
a();
console.log(NewVariable);
var c = {
 name:"The C object",
 log: function(){
 var self = this;
 self.name = "Updated object C name";
 console.log(self);
 
 var setname = function(newname){
  self.name = newname;
  console.log(self);
 }
 setname("New name for object c");
 console.log(self)
 }
}
c.log();

上面是我整理給大家的,希望今後會對大家有幫助。

相關文章:

如何使用vue-cli實作多頁應用程式

在VUE中如何實作陣列更新功能

在vuejs中使用模組化的方式開發

Vue專案最佳化需要注意哪些?

在vue-cli中如何實作元件通訊

以上是詳細解讀在JS中this引發的bug的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn