深刻理解JavaScript中的this


對於剛剛開始接觸前端開發的程序猿來講,不管是平常工做仍是面試新工做,對this的理解與掌握都相當重要,不要着急,學完這節課,你就真正的能理解this其實沒那麼難。javascript

起源

var obj = {
   name: "hansheng",
   getName:function (){
        console.log(this.name)
   }
}
var name = "shengxiansheng";
var getName = obj.getName;
getName(); //shengxiansheng
obj.getName();//hansheng
複製代碼

這段代碼,相信小夥伴們都能看得懂,網上搜索的時候,大部分都是這種例子,全部的人都告訴你,this指向運行時調用它的對象。obj.getName()運行時,getName運行在obj環境(上下文),因此,this指向obj,而getName()運行在全局環境下,因此獲取到的是全局環境下的name值。 規則是這麼定義的,可是,不多有人告訴你,函數的運行環境究竟是怎麼決定的。html

內存數據結構

JavaScript中,內存分爲棧內存和堆內存。前端

基礎數據類型:

  • Number
  • String
  • Boolean
  • null
  • undefined
  • symbol

這些基礎數據類型存儲在棧內存中。java

引用數據類型

  • Array
  • Function
  • Object
  • ...

能夠認爲除了上文提到的基本數據類型之外,全部類型都是引用數據類型。 引用數據類型存在於堆內存中。 舉個例子:面試

var obj  = {name: hansheng};
複製代碼

上面的代碼中,將一個對象賦值給變量obj。JavaScript引擎會先在堆內存中,生成一個對象{name: hansheng},而後把這個對象的內存地址賦值給變量obj。 數據結構

也就是說,變量obj是一個內存地址,後面要讀obj.name,引擎先從obj中拿到內存地址,而後再從該地址讀出原始對象,返回它的name屬性。 原始對象以字典結構保存,每個屬性名都對應一個屬性描述對象。

值爲函數

上面的例子中,值爲基礎數據類型時,顯示的很是明顯,可是,有可能,對象屬性值爲函數。函數

var obj = {
    name:function(){}
}
複製代碼

這時候,引擎會將函數單獨保存在內存中,而後再將函數的地址賦值給foo屬性的value屬性。 ui

這就能夠解釋,爲何函數能夠在不一樣的環境中運行了。

var f = function(){}
var obj  = {
    f: f
}
f(); //單獨環境運行
obj.f()//obj環境運行
複製代碼

那麼問題來了,一個函數能夠在不一樣的環境中運行,這時候,就須要一種機制,可以在函數體內部得到當前的運行環境。因此,this的出現,就是爲了在函數體內部,指代函數當前的運行環境。this

var f = function () {
  console.log(this.x);
}

var x = 1;
var obj = {
  f: f,
  x: 2,
};

// 單獨執行
f() // 1
// obj 環境執行
obj.f() // 2
複製代碼

上面代碼中,函數f在全局環境中執行,this.x指向全局環境x。 spa

在obj環境中運行,this.x指向obj.x
回到開頭,obj.getName()是經過obj找到的getNamee,因此就在obj環境執行,一旦 var getName = obj.getName,變量getName就直接指向函數自己,因此getName是運行在全局環境中的。

感謝阮一峯大神的分享。 下面的文章我會給你們分享,如何改變this的指向,相信你會學到不同的內容. 切圖不易,感謝你們閱讀,若是以爲不錯,記得關注哦。 文章會每週更新兩篇,別忘了點贊呦~

相關文章
相關標籤/搜索