
undefined值很特殊,每當js無法提供具體的值時,就會産生undefined。 undefined值場景 未指派的變量的初始值即為undefined。var x; x;//undefined 通路對象不存在的屬性也會産生undefined。var obj={}; obj.x;//undefined 一個函數體結尾使用未帶參數的return語句,或未使用return語句都會傳回值undefin
undefined值很特殊,每當js無法提供具體的值時,就會産生undefined。
undefined值場景
未指派的變量的初始值即為undefined。
var x;
x;//undefined
通路對象不存在的屬性也會産生undefined。
var obj={};
obj.x;//undefined
一個函數體結尾使用未帶參數的return語句,或未使用return語句都會傳回值undefined。
function f(){
return;
}
function g(){}
f();//undefined
g();//undefined
未給函數參數提供實參則該參數的值為undefined。
function f(x){
return x;
}
f();//undefined
這幾種情況下undefined值表明操作結果并不是一個特定的值。或說叫做“沒有值”,但undefined是一個值,很自相沖突。因為js裡的每個操作都要産生點什麼,是以就用undefined來填補這些空白了。
undefined公約
将undefined看做缺少某個特定值是js裡的公約。将它用于其他的目的,可能會産生嚴重的問題。例如,一個使用者界面元素庫可能支援一個highlight方法用于改變一個元素的背景顔色。
element.highlight();//使用預設的顔色
element.highlight('yellow');//使用黃色
如果想提供一種方法來設定一個随機顔色,可能會使用undefined作為特殊的值來實作。
element.highlight(undefined);//使用随機顔色
但上面的代碼會産生一個歧義,因為undefined在不傳入實參的時候,形參的值也是undefined。是以程式無法在預設顔色,還是随機顔色之間做決定。程式産生了二義性無法正确運作。
再比如,程式可能用一個可選的顔色偏好的配置對象。
var config=JSON.parse(preferences);
//...
element.highlight(config.highlightColor);
如果config.highlightColor并沒有設定,那麼它的值也會是undefined。這個時候程式員可能希望得到一個預設的顔色。但由于上面的undefined被做為一個特殊的值,這樣像上面說的産生了二義性,産生了一個随機的顔色值。更好的方式是對可能會使用一種特殊的顔色名來實作随機顔色。
element.highlight('random');
有時一個API不能夠從通常函數可接受的字元串集合中區分出一個特殊的字元串值。在這種情況下,可以使用除undefined以外的其他特殊值,如null或true。這往往會導緻可讀性下降。
element.highlight(null);
如果閱讀代碼的人沒有記住這個函數的具體使用方法,那麼這樣的代碼很難了解。可能會給人以取消元素高亮的誤解。一個更具明确、更具描述性的可選做法是将随機情況表示為一個具有random屬性的對象
element.highlight({random:true});
可選參數的實作
undefined有可能出問題的地方是可選參數的實作。理論上arguments對象可檢測是否傳遞了一個參數,但實際上,測試是否為undefined會使API更健壯。例如,一個Web伺服器可以接收一個可選的主機名稱。
var s1=new Server(80,'example.com');
var s2=new Server(80);//預設為localhost
參數長度
可以通過判斷arguments.length來實作Server構造函數。
function Server(port,hostname){
if(arguments.length<2){
hostname='localhost';
}
hostname=''+hostname;
}
上面的這個實作也是會産生問題,當我第二個參數顯式傳遞從其他源請求的一個值。那麼可能變成傳遞的是一個undefined值,但這個時候arguments.length的值是2,代碼被破壞。
var s3=new Server(80,config.hostname);
上面代碼如果config.hostname沒有值,hostname的正常行為應該是設定為'localhost'。上面的代碼會産生一個undefined的主機名。
檢測參數是否為undefined
最好是測試undefined,不傳遞參數和傳遞一個表達式結果是undefined的情況都可以覆寫。
function Server(port,hostname){
if(hostname === undefined){
hostname='localhost';
}
hostname=''+hostname;
//...
}
測試參數是否為真
另一種替代方案是測試hostname是否為真。使用邏輯運算符很好實作
function Server(port,hostname){
hostname=''+(hostname||'localhost');
//...
}
|| 邏輯運算符或。當第一個參數為真值則會傳回第一個參數,否則傳回第二個參數。是以hostname值為undefined或空字元串,該表達式(hostname||'localhost')的結果是'localhost'。這裡把hostname的值測試了很多種情況,包括其他能轉化為false的值。這裡對于Server函數是可以的。真值測試是實作參數預設值的一種簡明的方式。
真值測試
真值測試并不是總是安全的。如果一個函數應該接收空字元串為合法值,真值測試将覆寫空字元串并傳回預設值。還有其它的可以轉化為false的值,則不應該使用真值測試。例如,一個用于建立使用者界面元素的函數可能允許一個元素的寬度或高度為0,但提供預設值卻不一樣。
var c1=new Element(0,0);//width:0 height:0
var c2=new Element();//width:320 height:240
使用真值測試的實作會出現問題
function Element(w,h){
this.width=w||320;
this.height=h||240;
}
var c1=new Element(0,0);
c1.width;//320
c1.height;//240
這裡就不能使用真值而應該使用undefined檢測
function Element(w,h){
this.width=w===undefined?320:w;
this.height=h===undefined?240:h;
}
var c1=new Element(0,0);
c1.width;//320
c1.height;//240
var c2=new Element();
c2.width;//320
c2.height;//240
提示
- 避免使用undefined表示任何非特定值
- 使用描述性的字元串值或命名布爾屬性的對象,而不要使用undefined或null來代表特定應用标志
- 提供參數預設值應當采用測試undefined的方式,而不是檢查arguments.length
- 在允許0、NaN或空字元串為有效參數的地方,絕不要通過真值測試來實作參數預設值
相關閱讀
- 第3條:當心隐式的強制轉換
版權聲明
翻譯的文章,版權歸原作者所有,隻用于交流與學習的目的。
原創文章,版權歸作者所有,非商業轉載請注明出處,并保留原文的完整連結。