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