匿名函數的this指向為什麼是window?

關於匿名函數的this指向window我看到2種觀點。

  1. 這是javascript的設計缺陷

  2. 因為匿名函數的執行環境具有全局性

我更相信第二點,而我想問的是為什麼匿名函數的執行環境具有全局性?也可以說是匿名函數的執行環境具有全局性的依據在哪兒?

望指點,感謝。

var nimo={}
nimo.fn=function(){
console.log(this);//Object {fn: function}
+function(){
console.log(this)//window
}()

}
nimo.fn()


這個問題的官方答案就是,ES3時代設計上就是故意如此. 但是準確的表述並不和 匿名函數直接關聯. 只是匿名函數符合函數調用時的某個規則而已.

因為一些生產環境代碼經常無意中進入某種陷阱或帶來一些代碼的邏輯性斷層. 導致ES5時代,在嚴格模式中.把原有this的行為做了修正.

現在我來說說那個所謂某個規則是什麼..

準確來說,我們拋開 call,和apply . 那麼影響this 的就是 Property accessor 語法.

即 obj.foo() ; 屬性訪問語法,即函數調用運算符"()" 左邊部分. 會獲取一個 base 為obj 的 referenceType . 然後進行函數調用運算. 則referenceType.base 會為該函數執行環境的this 提供引用.

你想消除referenceType 很簡單 (1,obj.foo)() 這樣就行了. 因為 分組運算符的加入.導致提前對 referenceType進行getValue 操作. 直接拿到函數對象進行函數調用運算.導致提供給該函數執行環境關聯的this值是null. ES3明確表述,當此類情形發生時.則把global作為 this. ES5 的嚴格模式則修正了這一規則.

忘了補充下,你所謂的匿名函數在函數調用時是什麼. 舉個例子.

(function(){this === global}());

就拿常用的例子來說. 外層分組運算符的作用是讓 匿名函數表達式合法. 因 javascript 語法限制. 禁止函數表達式中, function 關鍵字出現在表達式的第一個token位置. so. 必須藉助其他輔助語法來完成所謂匿名函數的立即調用..比如 賦值表達式,逗號運算等等.

顯然匿名函數解釋執行的結果不是一個referenceType .但是規則中有表述,當不是referenceType時. 仍然把null (undefined-SE5) 作為this 提供給該函數執行環境.

那麼你看到上面所謂匿名函數調用(函數立即調用表達式). 和平時的 函數直接調用有啥區別么?

var fn = function(){this === null};

fn();

答案是有. fn(); 這玩意其實解釋執行fn時還是有referenceType .但是其base 是ES3世道的變數對象. 此時仍然把null 作為this. 然後又符合那種規則了.


每個函數在調用時,都會去獲取2個值: arguments和this。

匿名函數在獲取這2個值時,只會搜索自己執行環境中的,永遠不會直接訪問外部函數或執行環境中的這2個變數。

而this指向的是自己的調用者,匿名函數的調用者=window,所以this指向window。

所以,匿名函數具有全局性!


只覺得是深受JS高級程序設計這本書中文版的毒害。

英文版完全沒有提到匿名函數執行環境的全局性這個字眼。翻譯有毒。以下是英文原文:

Anonymous functions are not bound to an object in this context, meaning the this object points to window unless executing in strict mode (where this is undefined).

翻譯:在這個上下文(執行環境)中匿名函數並沒有綁定到任何一個對象中,意味著this指向window(除非這個上下文(執行環境)是在嚴格模式下執行的,而嚴格模式下該this指向undefined)

var name = 「The Window」;

var object = {

name : 「My Object」,

getNameFunc : function(){

return function(){

return this.name;

}; } };

alert(object.getNameFunc()()); //」The Window」 (in non-strict mode)


正好在自學js,說一下我的看法吧。

這個問題實際上就是在問匿名函數的調用著到底是誰。回答是匿名函數的調用者是window。

至於為什麼是window。我個人認為是故意這樣設計的。目的是為了保證函數的一致性。也就是確保定義函數的兩種方式:函數聲明 和 函數表達式 具有一致性。因為函數聲明定義函數的方法有函數聲明提升的特性,所以this 指向window。為確保一致性,讓匿名函數的 this也為 window。

先不看上面拗口的表達(我語言組織能力。。。),一步一步來。先解釋用函數聲明方式定義的函數的調用者是誰。

先看個例子:

function func(){

alert(this);

function func2(){alert(this);}

func2();

}

func();

上面這這種情況下 兩個this 都是指向 window(而不是第一個是window,第二個是指向func函數)。很好理解吧。func內部調用func2函數實際上就是把控制權交給func2函數。而func2函數的 this 是window。這個應該沒有爭議,這是函數聲明的提升特性決定的。上面的例子可以看成是下面這個(其實還是有不同):

function func2(){alert(this);}

function func(){

alert(this);

func2();

}

func();

接下來我把函數定義放到對象里:

var o={};

o.func=function(){

function func2(){ alert(this);}

func2();

}

this 也是 window 對吧。 說白就是調用函數,而調用者是window,不理解把 聲明放到最上面去看看,一樣的。

然後,我們看用 函數表達式的方法。記住,要保證 函數聲明 和 函數表達式 兩種方法定義函數的一致性:

var o={};

o.func=function(){

func2=function (){ alert(this);};

func2();

}

這裡函數的調用者是window。而不是o對象。雖然沒有聲明,沒有聲明的提升特性。這可以說是函數調用規則了。原因我認為是為了一致性。所以,this 自然也也該是 window.

再往下一步,就是把變數去掉:

var o={};

o.func=function(){

(function (){ alert(this);}());

}

this 自然也是 window。

綜上:

也就是匿名函數的執行環境具有全局性,匿名函數的調用者是window。

ps:我初學者,保不齊有錯誤。這回答也是加強我自己的理解。


從作用域和調用鏈方面看就很好理解了, 匿名函數是一個沒有指針的全局變數,那麼它的this指向的就是全局 就是window對象。這並不是設計缺陷,這種調用很安全,通過window並不能找到這個匿名函數,因為匿名函數沒有指針。


推薦閱讀:

HTML中的html head body標籤有且只能有一個,為什麼不可以直接省略?
bootstrap 用來構建大型互聯網網站前端布局可行性如何?
如何招到一個優秀的前端工程師?
Web 前端的未來會怎樣?
國內有哪些公司在使用 React.js ?

TAG:前端開發 | JavaScript | 前端工程師 |