JS學習 之 this

現象

先上代碼

var obj = {
  foo: function () { console.log(this.bar) },
  bar: 1
};

var foo = obj.foo;
var bar = 2;

obj.foo() // 1
foo() // 2
複製代碼

解釋

this指向的是 函數運行時所在的環境 。對於obj.foo()來講,foo運行在obj環境,因此this指向obj;對於foo()來講,foo運行在全局環境,因此this指向全局環境。因此,二者的運行結果確定不同。javascript

疑問

函數的運行環境究竟是怎麼決定的?爲何obj.foo()就是在obj環境執行,而一旦var foo = obj.foo,foo()就變成在全局環境執行?html

試着說說原理

內存的數據結構

(首先要了解堆與棧,可參考以前寫的 JS 學習 之 棧與堆 )java

JavaScript 語言之因此有this的設計,跟內存裏面的數據結構有關係。bash

var obj = { foo:  1 };
複製代碼

上面的代碼將一個對象賦值給變量obj。由於是引用數據類型,JavaScript 引擎會先在堆內存裏面生成一個對象 { foo: 5 },而後把這個對象的地址指針賦值給變量obj,儲存在棧內存中。也就是說,變量obj只是棧內存中保存一個地址指針。要讀取obj.foo,引擎先從棧內存中拿到obj保存的地址指針,而後再從該地址指針讀出原始的對象,返回它的foo屬性。數據結構

函數

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

若是對象屬性的值是一個函數,這時,引擎會將函數單獨保存在內存中,而後再將函數的地址賦值給foo屬性的value屬性。函數

var f = function () {};
var obj = { f: f };

// 單獨執行
f()

// obj 環境執行
obj.f()
複製代碼

因爲函數是一個單獨的值,因此它能夠在不一樣的環境(上下文)執行。post

環境變量

var f = function () {
  console.log(x);
};
複製代碼

JavaScript 容許在函數體內部,引用當前環境的其餘變量。學習

var f = function () {
  console.log(this.x);
}
複製代碼

因爲函數能夠在不一樣的運行環境執行,因此須要有一種機制,可以在函數體內部得到當前的運行環境(context)。因此,this就出現了,它的設計目的就是在函數體內部,指代函數當前的運行環境。this

回到本文開頭提出的問題,obj.foo()是經過obj找到foo,因此就是在obj環境執行。一旦var foo = obj.foo,變量foo就直接指向函數自己,因此foo()就變成在全局環境執行。spa

參考

  1. JavaScript 的 this 原理
相關文章
相關標籤/搜索