moztw.org

JavaScript 如何定義 Function

Mozilla Firefox 的程式大部份是用 C++ 寫成,但也有不少的元件是以 JavaScript 完成,在開發 B2G 的時候免不了就要寫一些 JavaScript。

在跌跌撞撞的參考 Mozilla 的 Coding Style Guide 完成 patch 並接受 review 之後,發現有個問題經常被 reviewer 提出來的就是在寫 member function 的時候記得給 function 一個名字,這樣在 debugger 裡面才比較容易看得出來是執行到什麼地方,如:

Foo.prototype.bar = function bar() { // do something }

1

Foo.prototype.bar = function bar() { // do something }

就會比寫成這樣:

Foo.prototype.bar = function () { // do something }

1

Foo.prototype.bar = function () { // do something }

還要好。但是好奇心比較強的人可能會想,這樣定義的名字怎麼和全域環境裡面已經存在的同名 function 怎麼互動呢?例如:

function foo() { return "foo"; } var bar = function foo() { return "bar"; } foo(); // => ?

1

function foo() { return "foo"; } var bar = function foo() { return "bar"; } foo(); // => ?

如果呼叫 foo(); 究竟會回傳什麼?或是

var bar = function bar() {}

1

var bar = function bar() {}

的 bar 究竟是哪個 bar? 誰先被定義呢?

在 ECMA-262 的 “Function Definition” 有定義,其實看起來一樣的

function <em>Identifier</em> ( <em>FormalParameterList</em> ) { <em>FunctionBody</em> }

1

function <em>Identifier</em> ( <em>FormalParameterList</em> ) { <em>FunctionBody</em> }

這樣的語法有兩種不同的意義,第一個是 FunctionDeclaration,第二個是 FunctionExpression,根據出現的位置不同,則有不同的解讀。

若是出現在 var bar = function bar() {} 這樣的地方,則會被解讀成 FunctionExpression,如果有定義 Identifier 的話,則會產生一個新的 scope,這個新的 Identifier 就會存在這個新的 scope 內,所以從 function body 就可以用這個名字遞迴呼叫自己,但是又不影響到外部的環境,也就是說這個 function bar 和 variable bar 有不同的 scope!