js函數會根據上下文改變其含義。
function double(x){return x*2;}
這是一個函數聲明,也可以是一個命名函數表達式(named function expression),取決於它出現的地方。
聲明一個函數,並綁定一個當前作用域的變量。
同一段函數代碼也可以作為一個表達式。
var f=function double(x){return x*2;}
根據ECMAScript規范,該函數綁定到變量f,而不是變量double。這裡給函數表達式命名並不是必要的的,可以直接使用匿名的函數表達式。
var f=function(x){return x*2;}
匿名和命名函數表達式的官方區別在於後者會綁定到與其函數名相同的變量上,該變量將作為函數內的一個局部變量。
可以用來寫遞歸函數表達式
var f=function find(tree,key){
if(!tree){
return null;
}
if(tree.key === key){
return tree.value;
}
return find(tree.left,key)||find(tree.right,value);
}
注意:變量find的作用域只在其自身函數中。不像函數聲明,命名函數表達式不能通過其內部的函數名在外部被引用。
find(myTree,”foo”);//error:find is not defined
使用命名函數表達式來進行遞歸似乎沒有必要,因為使用外部作用域的函數名也可以達到同樣的效果
var f=function(tree,key){
if(!tree){
return null;
}
if(tree.key === key){
return tree.value;
}
return f(tree.left,key)||f(tree.right,value);
}
或
function find(tree,key){
if(!tree){
return null;
}
if(tree.key === key){
return tree.value;
}
return find(tree.left,key)||find(tree.right,value);
}
var f=find;
大多數現代的JS環境都提供對Error對旬的棧跟蹤功能。在棧跟蹤中,函數表達式的名稱通常作為其入口作用。用於檢查棧的設備調試器對命名函數表達式有類似的使用。
命名函數表達式是作用域和兼容性問題的來源。ES規范的錯誤,在ES3中就已經存在,JS引擎被要求將命名函數表達式的作用域表示為一個對象,像有問題的with結構。該作用域對象只含有單個屬性,該屬性將函數名和函數自身綁定起來。該作用域對象也繼承了Object.prototype的屬性。這意味著僅僅是給函數表達式命名也會將Object.prototype中的所有屬性引用到作用域中。結果出問題如:
var constructor=function(){return null;};
var f=function f(){
return constructor();
};
f();//{}(in ES3 environments)
ES5修正了這個問題。運行如下:
但有些JS環境仍然使用過時的對象作用域,有些環境更不符合標准,對匿名函數表達式使用對象作為作用域。
在系統中避免對象污染函數表達式作用域的最好方式是避免任何時候在Object.prototype中添加屬性,以及避免使用任何與標准Object.prototype屬性同名的局部變量。
在流行的JS引擎中的另一個缺陷是對命名函數表達式的聲明進行提升。
var f=function g(){return 17;}
g();//17(在不標准的環境中)
注意這是不符合標准的行為。
有一些JS環境甚至把f和g這兩個函數作為不同的對象,從而導致不必要的內存分配。這種行為的一個合理的解決辦法是創建一個與函數表達式同名的局部變量並賦值為null。
var f=function g(){return 17;}
var g=null;
即使在沒有錯誤地提升函數表達式聲明的環境中,使用var重聲明變量能確保仍然會綁定變量g。設置變量g為null能確保重復的函數被垃圾回收。
js函數會根據上下文改變其含義。
function double(x){return x*2;}
這是一個函數聲明,也可以是一個命名函數表達式(named function expression),取決於它出現的地方。
聲明一個函數,並綁定一個當前作用域的變量。
同一段函數代碼也可以作為一個表達式。
var f=function double(x){return x*2;}
根據ECMAScript規范,該函數綁定到變量f,而不是變量double。這裡給函數表達式命名並不是必要的的,可以直接使用匿名的函數表達式。
var f=function(x){return x*2;}
匿名和命名函數表達式的官方區別在於後者會綁定到與其函數名相同的變量上,該變量將作為函數內的一個局部變量。
可以用來寫遞歸函數表達式
var f=function find(tree,key){
if(!tree){
return null;
}
if(tree.key === key){
return tree.value;
}
return find(tree.left,key)||find(tree.right,value);
}
注意:變量find的作用域只在其自身函數中。不像函數聲明,命名函數表達式不能通過其內部的函數名在外部被引用。
find(myTree,”foo”);//error:find is not defined
使用命名函數表達式來進行遞歸似乎沒有必要,因為使用外部作用域的函數名也可以達到同樣的效果
var f=function(tree,key){
if(!tree){
return null;
}
if(tree.key === key){
return tree.value;
}
return f(tree.left,key)||f(tree.right,value);
}
或
function find(tree,key){
if(!tree){
return null;
}
if(tree.key === key){
return tree.value;
}
return find(tree.left,key)||find(tree.right,value);
}
var f=find;
大多數現代的JS環境都提供對Error對旬的棧跟蹤功能。在棧跟蹤中,函數表達式的名稱通常作為其入口作用。用於檢查棧的設備調試器對命名函數表達式有類似的使用。
命名函數表達式是作用域和兼容性問題的來源。ES規范的錯誤,在ES3中就已經存在,JS引擎被要求將命名函數表達式的作用域表示為一個對象,像有問題的with結構。該作用域對象只含有單個屬性,該屬性將函數名和函數自身綁定起來。該作用域對象也繼承了Object.prototype的屬性。這意味著僅僅是給函數表達式命名也會將Object.prototype中的所有屬性引用到作用域中。結果出問題如:
var constructor=function(){return null;};
var f=function f(){
return constructor();
};
f();//{}(in ES3 environments)
ES5修正了這個問題。運行如下:
但有些JS環境仍然使用過時的對象作用域,有些環境更不符合標准,對匿名函數表達式使用對象作為作用域。
在系統中避免對象污染函數表達式作用域的最好方式是避免任何時候在Object.prototype中添加屬性,以及避免使用任何與標准Object.prototype屬性同名的局部變量。
在流行的JS引擎中的另一個缺陷是對命名函數表達式的聲明進行提升。
var f=function g(){return 17;}
g();//17(在不標准的環境中)
注意這是不符合標准的行為。
有一些JS環境甚至把f和g這兩個函數作為不同的對象,從而導致不必要的內存分配。這種行為的一個合理的解決辦法是創建一個與函數表達式同名的局部變量並賦值為null。
var f=function g(){return 17;}
var g=null;
即使在沒有錯誤地提升函數表達式聲明的環境中,使用var重聲明變量能確保仍然會綁定變量g。設置變量g為null能確保重復的函數被垃圾回收。