js中的undefined探尋
背景
如果你瞭解Java,便知道類中未賦值的屬性將在編譯時間由編譯器賦予初始值。與Java、C#等一些靜態語言不同的是,Javascript是一種解釋型的動態語言,因為沒有編譯環節,因而它的變數類型可在程式運行時動態改變。這種弱類型的性質,也就決定了Javascript的設計中應該採用一種開放的、無意義的值作為變數的初始值——它便是undefined。
探尋
undefined作為Javascripts的五種基礎資料型別 (Elementary Data Type)之一,在編程中也是很常見的了。比如所有未賦值的變數都會預設為undefined;未指明return語句的函數也會返回undefined;不存在的對象屬性、不存在的數組項以及一些操作符等也會返回undefined,下面我們就來一同探尋undefined的蹤跡。
變數
最常見的,未賦值的全域變數或局部變數將會返回undefined。
var buzz;buzz; // undefined,全域變數(fucntion(arg) { var fizz; console.log(arg); // undefined,參數變數 console.log(fizz); // undefined,局部變數})();
函數
每個函數都有傳回值,如果未指定return後的傳回值,預設將返回undefined。
var fn1 = function() {}; fn2 = function() {return;}var res1 = fn1(); res2 = fn2();console.log(res1); // undefined,省略returnconsole.log(res2); // undefined,未指定傳回值
數組
訪問數組中未定義資料項目返回undefined。
var arr = [1,2];arr.length = 5;console.log(arr[3]); // undefinedconsole.log(arr[10]); // undefined
對象
訪問對象上的未定義屬性返回undefined。
var person = { name:Lee,};person.age; // undefined
操作符
void操作符對後方運算式求值,不論求值結果如何,總是返回undefined。
var res = void(1+1);res; // undefined
陷阱
儘管undefined的本意表示”缺少值”,本應有值,卻還未定義。同時,JavaScript中的另一個基本類型變數之一null,也有”Null 參考、未定義”對象之意,初學者常常將兩者混為一談,有時稍不留意便會跌入陷阱。
undefined使用
對於undefined的判斷,擷取,轉型需要牢記用法,若憑藉其他語言的經驗則容易發生意外結果。
判斷undefined
可以使用==、===或typeof操作符判斷undefined。
var buzz;buzz == undefined; // truebuzz === undefined; // truebuzz == 'undefined'; // falsetypeof buzz == undefined; // falsetypeof buzz == 'undefined'; // true
當使用==或===時與undefined基本類型值比較,使用typeof時與字串比較。這麼這幾種判斷方法真的都安全可靠嗎,我們繼續來看下面的例子:
(function() { var undefined = 'hello'; var buzz; console.log(buzz == undefined); // false console.log(buzz === undefined); // false console.log(typeof buzz == 'undefined'); // true})();
這是一個自調用函數,由於undefined在Javascript中不是保留字,因而我們可以在函數內重定義undefined的值,而對於原本的值,只能外部的全域範圍擷取:
window.undefined; // 瀏覽器環境GLOBAL.undefined; // Node環境(function() { var undefined = 'hello'; var buzz; console.log(undefined); // 'hello' console.log(buzz == window.undefined); // true console.log(buzz === window.undefined); // true console.log(typeof buzz == 'undefined'); // true})();
總結以上結果,我們可以看到,使用typeof來判斷undefined值,無論在什麼情況下總會返回正確結果。為保障代碼的健碩性,因而我們應始終使用typeof操作符來判斷undefined。
擷取 undefined通過原始字面量擷取
var buzz = 'hello';buzz = undefined;buzz; // undefined
通過void操作符擷取
void操作符對後方運算式求值,不論求值結果如何,總是返回undefined。
var buzz = 'hello';buzz = void 0;typeof buzz === 'undefined'; // true
最佳實務
雖然通過原始字面量方式擷取undefined簡單方便,但在【判斷undefined】這一小節中,我們曾提到undefined不是Javascript中的保留字,其值可以在函數範圍內被改寫。但要注意的是,即便是window,GLOBAL對象,在函數內也仍可被重寫。故從window/GLOBAL上取undefined並不是100%可靠的做法。如:
(function() { var undefined = 'hello', foo = {}, window = { 'undefined': 'world' }; console.log(undefined); // 'hello' console.log(window.undefined); // 'world' console.log(foo.a === undefined); // false console.log(foo.a === void 0); // true })();
於是,採用void方式擷取undefined便成了通用準則。如underscore.js裡的isUndefined便是這麼寫的:
_.isUndefined = function(obj) { return obj === void 0;}
還有一種方式是通過函數參數預設值。如AngularJS的源碼裡就用這樣的方式:
(function(window, document, undefined) { //.....})(window, document);
“undefined“參數通過省略傳參,確保了其值是一個預設的undefined。
undefined轉型
undefined轉Number類型返回NaN,轉String返回字串形式,轉Boolean返回false。
// 顯示轉換Number(undefined); // NaNString(undefined); // 'undefined'Boolean(undefined); // false// 隱式轉換1 + undefined; // NaN,隱式轉number'str' + undefined; // 'strundefined',隱式轉stringif(undefined) { console.log(true); // 不會被輸出} else { console.log(false); // false,隱式轉boolean}
null
在Java,C#等一些物件導向語言中null代表Null 參考。當類中聲明一個引用型變數未賦初值時,編譯器會自動初始化引用值為null。JavaScript借鑒了這一設計,也將null定義為“空”,當一個變數值為null時代表它未引用任何對象實體。
null和undefined在表現上有著一定的相似性,兩者在if()語句中,都會被自動轉為false,使用”==“運算子兩者判定相等。
var buzz = undefined; fizz = null;if (buzz) { console.log(buzz + ' is true');} else { console.log(buzz + ' is false');}// undefined is falseif (fizz) { console.log(fizz + ' is true');} else { console.log(fizz + ' is false');}// null is falseundefined == null; // true
雖然undefined和null在JavaScript中都可代表“空,未定義”的意思,但他們之間還是有一些細微的區別:
null值需要顯式指定,變數賦值為
null時,代表一個對象,其引用實體為空白。 將
null轉換為數值時返回0,
undefined返回
NaN。
var foo = null;typeof foo; // 'object'+ null; // 0+ undefined; // NaN
總結使用
typeof判斷
undefined; 使用
void 0擷取
undefined;
undefined與
null轉型為布爾值均返回
false。拓展閱讀
undefined與null的區別
談談Javascript中的void操作符