寫出更好的JavaScript程序之undefined篇(中)
寫在前面的依然是消歧義聲明:本文中JavaScript是指一般意義上的JavaScript,并不只限定“自稱是JavaScript”的運(yùn)行環(huán)境;“全局變量”和“全局對象的屬性”是指同樣的東西,只是因?yàn)橐浜仙舷挛牟庞昧瞬煌恼f法,正文中我就不再另外解釋了;“聲明”指通過“var”語句聲明變量和/或?qū)瘮?shù)及其簽名的定義;“變量”指通過“var”語句聲明過或者在函數(shù)體中試圖訪問的命名參數(shù);“undefined”指名為“undefined”的值(全局或本地變量),而“未定義”指type(...) == “undefined”的概念值;“output”是向我們顯示傳入?yún)?shù)的函數(shù),其實(shí)就是“alert”的同類。
首先介紹的是和void(0)具有異曲同工之妙的一種辦法,我們知道在JavaScript中嘗試訪問任何一個“沒有返回值”的函數(shù)的執(zhí)行結(jié)果,都會得到“未定義”這個概念值,所以我們可以這樣做:
myVar = function(){}();
這個方法的原理是創(chuàng)建一個空函數(shù),并且獲取其(根本不存在的)返回值。很明顯,我們會得到“未定義”這個概念值,這個原理是和void(0)一樣的。
需要特別注意的是,只有當(dāng)function關(guān)鍵字不在語句之首的時候,才可以使用這種調(diào)用方式;如果需要直接調(diào)用一個匿名函數(shù),應(yīng)該這樣做:
(function(){
// code here
})();
假如我們不想污染全局作用域,我們就可以用這種方式來創(chuàng)造一個閉包——很多現(xiàn)有的JavaScript庫就是這樣做的。
這種辦法是在不了解void(0)的執(zhí)行效果的情況下誕生的,既然我們知道void(0),也就不需要這種辦法了。
第二種不常見的辦法是訪問window.undefined,就像下邊這樣:
output(myVar === window.undefined);
myVar = window.undefined;
這種辦法的原理是:
如果JavaScript的運(yùn)行環(huán)境預(yù)定義了undefined這一值,window.undefined就可以直接訪問到;
如果沒有預(yù)先定義undefined這一值,window.undefined就會返回“未定義”這一概念值——還是我們想要的東西。
訪問形式從“全局變量”變成“屬性”以后,腳本引擎就不會認(rèn)為這是一個意外操作了,因此代碼可以正確執(zhí)行。
然而這種辦法還是存在不足:
undefined在所有的JavaScript引擎中都不是保留字,也就是說它是可以被污染的,這會影響我們的程序的運(yùn)行效果;
直接訪問全局對象的屬性效率是很差的,應(yīng)該避免這么做。
因此,接下來就要介紹我所見過的最為有趣的辦法——在本地聲明undefined變量!
它的做法是這樣的:
function myFunc(){
var undefined;
// some code here
output(myVar === undefined);
myVar = undefined;
}
說到這里我要提一下,有的人對“早期的瀏覽器上沒有undefined”這一說法有不同的理解,認(rèn)為上面這樣的做法是行不通的。
而我認(rèn)為這種觀點(diǎn)是不對的,在我的印象中(大約是2003年),IE5雖然沒有預(yù)定義undefined,但并不影響我們的不指派聲明。
不過畢竟是很多年前的事情,記憶模糊,為了避免想當(dāng)然造成的錯誤,我特地裝了Windows 98來實(shí)驗(yàn)一下:

上面兩幅是用了QQ屏幕截取 ,不知道為什么變成了JPG,下邊這幅是用OneNote截取的。

由此可以得出,為這樣不指派聲明undefined變量擔(dān)憂是多余的。
前一篇解釋過,在JavaScript中,如果嘗試讀取一個沒有預(yù)定義也未聲明過的變量,會引發(fā)一個“不存在(未定義)”異常,因此在早期的瀏覽器上如果直接訪問undefined的操作可能會失敗。
這種(引發(fā)異常的)現(xiàn)象可能是為了方便排除故障而有意設(shè)計(jì)的;而對于聲明過的變量,即使是未經(jīng)賦值,也不會在讀取的時候引發(fā)異常——經(jīng)過聲明就表示開發(fā)人員確定有“這個東西”。
上面這種在函數(shù)作用域內(nèi)聲明本地變量undefined的做法,既解決了引用未聲明變量會引發(fā)異常的問題,又避免了受全局變量污染的影響,還取代了void(0)這種乍看之下意味不明的小把戲,不僅沒有造成難以覺察的拼寫錯誤的隱患,還能提高運(yùn)算效率——真是一舉N得的妙招!
所以了解了這么多之后就發(fā)現(xiàn),最后介紹的這種辦法實(shí)在是居家旅行首選
如果有人問:“undefined應(yīng)該怎么用?”我們現(xiàn)在就可以回答:就這么用!
終于到了結(jié)尾,有的人可能忍不住要問了:為什么在這個系列中我的代碼示例都用三個等號的“嚴(yán)格相等”來比較?兩個等號的普通的“相等”有什么問題嗎?
這就是這個系列的下篇要講解的內(nèi)容:undefined及其各種等價形態(tài)的適用場合。
相關(guān)文章
詳解JavaScript私有類字段和TypeScript私有修飾符
這篇文章主要介紹了JavaScript私有類字段和TypeScript私有修飾符,對私有類感興趣的同學(xué),可以參考下2021-04-04
js 實(shí)現(xiàn) input type="file" 文件上傳示例代碼
在開發(fā)中,文件上傳必不可少但是它長得又丑、瀏覽的字樣不能換,一般會讓其隱藏點(diǎn)其他的標(biāo)簽(圖片等)來時實(shí)現(xiàn)選擇文件上傳功能2013-08-08
window.event.keyCode兼容IE和Firefox實(shí)現(xiàn)js代碼
window.event.keyCode兼容IE和Firefox具體實(shí)現(xiàn)代碼如下,感興趣的朋友可以參考下哈2013-05-05
nuxt+axios實(shí)現(xiàn)打包后動態(tài)修改請求地址的方法
這篇文章主要介紹了nuxt+axios實(shí)現(xiàn)打包后動態(tài)修改請求地址的方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-04-04
JavaScript中Array對象用法實(shí)例總結(jié)
這篇文章主要介紹了JavaScript中Array對象用法,結(jié)合實(shí)例形式總結(jié)分析了Array數(shù)組對象的常用屬性與方法的功能與相關(guān)使用技巧,需要的朋友可以參考下2016-11-11
TypeScript工具類 Partial 和 Required 的場景分析
這篇文章主要介紹了TypeScript工具類 Partial 和 Required 的詳細(xì)講解,本文通過場景描述給大家詳細(xì)講解工具類的使用,結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2022-09-09
在使用JSON格式處理數(shù)據(jù)時應(yīng)該注意的問題小結(jié)
這篇文章主要介紹了在使用JSON格式處理數(shù)據(jù)時應(yīng)該注意的問題,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2017-05-05
js實(shí)現(xiàn)點(diǎn)擊切換TAB標(biāo)簽實(shí)例
這篇文章主要介紹了js實(shí)現(xiàn)點(diǎn)擊切換TAB標(biāo)簽的方法,涉及javascript鼠標(biāo)點(diǎn)擊事件及頁面元素的遍歷技巧,需要的朋友可以參考下2015-08-08
js將日期格式轉(zhuǎn)換為YYYY-MM-DD HH:MM:SS
這篇文章主要介紹了js將日期格式轉(zhuǎn)換為YYYY-MM-DD HH:MM:SS,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09

