JavaScript第二十三篇 技巧篇之函數(shù)篇

函數(shù)篇(上)

安全的類型檢測(cè)

JavaScript 內(nèi)置的類型檢測(cè)機(jī)制并非完全可靠。事實(shí)上榨惰,發(fā)生錯(cuò)誤否定及錯(cuò)誤肯定的情況也不在少數(shù)拜英。比如說 typeof操作符吧,由于它有一些無法預(yù)知的行為琅催,經(jīng)常會(huì)導(dǎo)致檢測(cè)數(shù)據(jù)類型時(shí)得到不靠譜的結(jié)果居凶。Safari(直至第4版)在對(duì)正則表達(dá)式應(yīng)用typeof操作符時(shí)會(huì)返回"function",因此很難確定某個(gè)值到底是不是函數(shù)

再比如藤抡,instanceof 操作符在存在多個(gè)全局作用域(像一個(gè)頁面包含多個(gè) frame)的情況下侠碧,也是問題多多。

如何解決上面的這些問題呢缠黍?

大家知道弄兜,在任何值上調(diào)用 Object 原生的 toString()方法,都會(huì)返回一個(gè)[object NativeConstructorName]格式的字符串。每個(gè)類在內(nèi)部都有一個(gè)[[Class]]屬
性挨队,這個(gè)屬性中就指定了上述字符串中的構(gòu)造函數(shù)名谷暮。

示例:

alert(Object.prototype.toString.call(value)); 
//判斷是不是數(shù)組
function isArray(value){
 return Object.prototype.toString.call(value) == "[object Array]";
} 
//判斷是不是函數(shù)
function isFunction(value){
 return Object.prototype.toString.call(value) == "[object Function]";
} 
//判斷是不是正則
function isRegExp(value){
 return Object.prototype.toString.call(value) == "[object RegExp]";
} 

作用域安全的構(gòu)造函數(shù)

什么是構(gòu)造函數(shù)?
構(gòu)造函數(shù)其實(shí)就是一種用new 操作符調(diào)用的函數(shù)盛垦,并且該函數(shù)的作用域會(huì)指向新創(chuàng)建的的對(duì)象實(shí)例

示例:

//新建一個(gè)Person函數(shù)
function Person(name, age, job){
     this.name = name;
     this.age = age;
     this.job = job;
} 
//創(chuàng)建一個(gè)person構(gòu)造函數(shù)湿弦,這時(shí)Person的this就指向于person
var person = new Person("Nicholas", 29, "Software Engineer");

這是一個(gè)正常的構(gòu)造函數(shù)對(duì)吧,但是如果你忘記寫了new操作符呢腾夯?我們一起來看看

示例:

//新建一個(gè)Person函數(shù)
function Person(name, age, job){
     this.name = name;
     this.age = age;
     this.job = job;
} 
//創(chuàng)建一個(gè)person構(gòu)造函數(shù)颊埃,但是忘記了寫new操作符,這時(shí)候this指向誰呢蝶俱?
var person =  Person("Nicholas", 29, "Software Engineer");

答案是Person函數(shù)的上一層作用域班利,在此處也就是windows

那么這個(gè)問題如何讓解決呢?

解決方案就是創(chuàng)建一個(gè)作用域安全的構(gòu)造函數(shù)榨呆。

示例:

//創(chuàng)建一個(gè)Person函數(shù)
function Person(name, age, job){
    // 判斷this是不是Persoon的實(shí)例
     if (this instanceof Person){
         this.name = name;
         this.age = age;
         this.job = job;
     } else {
        // 如果不是就new Person
        return new Person(name, age, job);
     }
} 

//這個(gè)函數(shù)會(huì)在沒有寫new操作符的情況下自動(dòng)創(chuàng)建一個(gè)帶有new 操作符的構(gòu)造函數(shù)

最后的結(jié)果是罗标,調(diào)用 Person 構(gòu)造函數(shù)時(shí)無論是否使用 new 操作符,都會(huì)返回一個(gè) Person 的新實(shí)例积蜻,這就避免了在全局對(duì)象上意外設(shè)置屬性闯割。

惰性載入函數(shù)

惰性載入表示函數(shù)執(zhí)行的分支僅會(huì)發(fā)生一次。有兩種實(shí)現(xiàn)惰性載入的方式竿拆,第一種就是在函數(shù)被調(diào)用時(shí)再處理函數(shù)宙拉。在第一次調(diào)用的過程中,該函數(shù)會(huì)被覆蓋為另外一個(gè)按合適方式執(zhí)行的函數(shù)丙笋,這樣任何對(duì)原函數(shù)的調(diào)用都不用再經(jīng)過執(zhí)行的分支了谢澈。

示例:

function createXHR(){
     if (typeof XMLHttpRequest != "undefined"){
         createXHR = function(){ 
            return new XMLHttpRequest();
        };
     } else if (typeof ActiveXObject != "undefined"){
         createXHR = function(){
             if (typeof arguments.callee.activeXString != "string"){
                 var versions = ["MSXML2.XMLHttp.6.0", "MSXML2.XMLHttp.3.0",
                 "MSXML2.XMLHttp"],
                 i, len;
                 for (i=0,len=versions.length; i < len; i++){
                     try {
                         new ActiveXObject(versions[i]);
                         arguments.callee.activeXString = versions[i];
                         break;
                     } catch (ex){
                     //skip
                     }
                 }
             }
             return new ActiveXObject(arguments.callee.activeXString);
         };
     } else {
         createXHR = function(){
            throw new Error("No XHR object available.");
         };
     }
     return createXHR();
} 

第二種實(shí)現(xiàn)惰性載入的方式是在聲明函數(shù)時(shí)就指定適當(dāng)?shù)暮瘮?shù)。這樣御板,第一次調(diào)用函數(shù)時(shí)就不會(huì)損失性能了锥忿,而在代碼首次加載時(shí)會(huì)損失一點(diǎn)性能。

示例:

var createXHR = (function(){
     if (typeof XMLHttpRequest != "undefined"){
         return function(){
            return new XMLHttpRequest();
         };
     } else if (typeof ActiveXObject != "undefined"){
         return function(){
             if (typeof arguments.callee.activeXString != "string"){
                 var versions = ["MSXML2.XMLHttp.6.0", "MSXML2.XMLHttp.3.0",
                 "MSXML2.XMLHttp"],
                 i, len;
                 for (i=0,len=versions.length; i < len; i++){
                     try {
                         new ActiveXObject(versions[i]);
                         arguments.callee.activeXString = versions[i];
                        break;
                     } catch (ex){
                         //skip
                     }
                 }
                     
             }
             return new ActiveXObject(arguments.callee.activeXString);
         };
     } else {
         return function(){
             throw new Error("No XHR object available.");
         };
     }
})(); 

這個(gè)例子中使用的技巧是創(chuàng)建一個(gè)匿名稳吮、自執(zhí)行的函數(shù)缎谷,用以確定應(yīng)該使用哪一個(gè)函數(shù)實(shí)現(xiàn)。實(shí)際的邏輯都一樣灶似。不一樣的地方就是第一行代碼(使用 var 定義函數(shù))、新增了自執(zhí)行的匿名函數(shù)瑞你,另外每個(gè)分支都返回正確的函數(shù)定義酪惭,以便立即將其賦值給 createXHR()。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末者甲,一起剝皮案震驚了整個(gè)濱河市春感,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖鲫懒,帶你破解...
    沈念sama閱讀 217,406評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件嫩实,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡窥岩,警方通過查閱死者的電腦和手機(jī)甲献,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來颂翼,“玉大人晃洒,你說我怎么就攤上這事‰Γ” “怎么了球及?”我有些...
    開封第一講書人閱讀 163,711評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長呻疹。 經(jīng)常有香客問我吃引,道長,這世上最難降的妖魔是什么刽锤? 我笑而不...
    開封第一講書人閱讀 58,380評(píng)論 1 293
  • 正文 為了忘掉前任际歼,我火速辦了婚禮,結(jié)果婚禮上姑蓝,老公的妹妹穿的比我還像新娘鹅心。我一直安慰自己,他們只是感情好纺荧,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,432評(píng)論 6 392
  • 文/花漫 我一把揭開白布旭愧。 她就那樣靜靜地躺著,像睡著了一般宙暇。 火紅的嫁衣襯著肌膚如雪输枯。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,301評(píng)論 1 301
  • 那天占贫,我揣著相機(jī)與錄音桃熄,去河邊找鬼。 笑死型奥,一個(gè)胖子當(dāng)著我的面吹牛瞳收,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播厢汹,決...
    沈念sama閱讀 40,145評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼螟深,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了烫葬?” 一聲冷哼從身側(cè)響起界弧,我...
    開封第一講書人閱讀 39,008評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤凡蜻,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后垢箕,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體划栓,經(jīng)...
    沈念sama閱讀 45,443評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,649評(píng)論 3 334
  • 正文 我和宋清朗相戀三年条获,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了忠荞。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,795評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡月匣,死狀恐怖钻洒,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情锄开,我是刑警寧澤素标,帶...
    沈念sama閱讀 35,501評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站萍悴,受9級(jí)特大地震影響头遭,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜癣诱,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,119評(píng)論 3 328
  • 文/蒙蒙 一计维、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧撕予,春花似錦鲫惶、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至吆寨,卻和暖如春赏淌,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背啄清。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評(píng)論 1 269
  • 我被黑心中介騙來泰國打工六水, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人辣卒。 一個(gè)月前我還...
    沈念sama閱讀 47,899評(píng)論 2 370
  • 正文 我出身青樓掷贾,卻偏偏與公主長得像,于是被迫代替她去往敵國和親添寺。 傳聞我的和親對(duì)象是個(gè)殘疾皇子胯盯,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,724評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容