JavaScript筆記

你可能不知道的一些JavaScript 奇淫巧技

? ? ? ?這里記錄一下以前學(xué)習(xí)各種書籍和文章里邊出現(xiàn)的JS的小技巧,分享給大家没咙,也供自己查閱猩谊,同時(shí)感謝那些發(fā)現(xiàn)創(chuàng)造和分享這些技巧的前輩和大牛們。

1祭刚、遍歷一個(gè)obj的屬性到數(shù)組

var a=[];

for(a[a.length] in obj);

return a;

乍一看可能比較蒙牌捷,不過仔細(xì)分析還是不難理解的。常見用法是for(var key in obj)涡驮,這里key初始也是undefined的暗甥,a[a.length]整體也是undefined,所以二者其實(shí)是等價(jià)的捉捅。在for循環(huán)中撤防,obj的屬性會依次賦值給key,同樣棒口,也依次賦值給a[a.length]寄月,這里length一直在變辜膝,就巧妙地挨個(gè)賦值給數(shù)組的每一個(gè)元素了。

2漾肮、重復(fù)字符串(如abc=>abcabc)

function repeat(target,n){

return(new Array(n+1).join(target));

}

改良版本:

function repeat(target,n){

return Array.prototype.join.call(

{length:n+1},target);//之所以要創(chuàng)建帶length屬性的對象厂抖,是因?yàn)檎{(diào)用數(shù)組原型方法時(shí),必須是一個(gè)類數(shù)組對象忱辅,而類數(shù)組對象的條件就是length為非負(fù)整數(shù)

}

不新建數(shù)組,而是用擁有l(wèi)ength屬性的對象替代谭溉,然后調(diào)用數(shù)組的join方法,性能提升很大

再改進(jìn):

var repeat=(function(){

? ? var join=Array.prototype.join,obj={};

? ? return function(target,n){

? ? ? ? obj.length=n+1;

? ? ? ? return join.call(obj,target);

? ? }

})();

利用閉包將對象和join方法緩存起來,不用每次都新建對象和尋找方法

3扮念、for循環(huán)中,當(dāng)?shù)诙?xiàng)為false時(shí)會終止循環(huán)扔亥,這里并不一定存在比較谈为,可以直接賦值旅挤,如果賦值為undefined之類的值時(shí)粘茄,轉(zhuǎn)成bool值也為假,因此也會終止秕脓,比如遍歷數(shù)組可以寫成:

for(var i=arr.length,element;element=arr[—-i];){…}

這里,第二項(xiàng)一定是arr[—-i]而非arr[i--],如果是后者的話吠架,上來就是undefined芙贫,就不會執(zhí)行循環(huán)體,或者for(vari=0,element;element=arr[i++];){…}

4傍药、NaN是JS中唯一不等于自己的值磺平,因此可以用來判斷一個(gè)變量是否真的為NaN:a!==a

5拣挪、“<”俱诸,”+”等運(yùn)算符會強(qiáng)制符號兩邊的表達(dá)式執(zhí)行valueOf然后比較,所以如果兩邊是函數(shù)或者對象赶诊,而又重寫了該對象的valueOf方法,就會自動執(zhí)行兩邊的方法出吹。如:

var a={valueOf:function(){console.log(“aaa”);}},b={valueOf:function(){console.log(“bbb”);}};

a<b;//會輸出:aaa;bbb;false;

6辙喂、JS具備自動插入分號的能力巍耗,但是自動插入分號并不是萬能的,其有三條規(guī)則:

1)只在”}”標(biāo)記之前灸蟆、一個(gè)或多個(gè)換行之后以及程序輸入的結(jié)尾被插入炒考;

2)分號只在隨后的輸入標(biāo)記不能被解析時(shí)插入霎迫;

這一點(diǎn)很重要,比如:

a=b

(f());

是不會在a=b之后自動插入分號的瓤帚,因?yàn)閍=b(f())是可以被解析的涩赢,因此像”(“,”[“,”+”,”-“,”/“開頭的時(shí)候,需要特別注意上一行可能不會自動插入怯邪。

還有一些情況花墩,盡管不會出現(xiàn)解析錯誤,JS仍然會強(qiáng)制插入分號搂捧,這就是所謂的JS語法限制產(chǎn)生式允跑。它不允許在兩個(gè)字符間出現(xiàn)換行,最危險(xiǎn)的就是return語句索烹,如

return

{};

會被強(qiáng)制插入而成為

return;

{};

類似的還有:throw語句百姓、帶有顯示標(biāo)簽的break活著continue語句况木、后置自增或自減運(yùn)算符

3)分號不會作為分隔符在for循環(huán)空語句的頭部被自動插入

因此火惊,最好的辦法是在自己的js文件的最開始防御性地插入”;”,這樣在合并js文件的時(shí)候就不會出問題了尸疆。

7寿弱、閉包按灶。理解閉包需學(xué)會三個(gè)基本事實(shí):

(1)JS允許你引用在當(dāng)前函數(shù)意外定義的變量

(2)即使外部函數(shù)已經(jīng)返回,當(dāng)前函數(shù)仍然可以引用在外部函數(shù)所定義的變量地沮。這是因?yàn)镴S的函數(shù)值包含里比調(diào)用它們時(shí)執(zhí)行所需要的代碼更多的信息

(3)閉包可以更新外部變量的值。這是因?yàn)殚]包存儲的是外部變量的引用而非值副本危融。如:

function box(){

? ? var ? val=undefined;

? ? return{

? ? ? ? set:function(x){val=x;},

? ? ? ? get:function(){return val;}

? ? };

}

var b=box();

b.get();//“undefined”

b.set(5);

b.get();//5

這一點(diǎn)很重要吉殃,比如在函數(shù)的for循環(huán)體內(nèi)返回閉包或者有閉包取for循環(huán)的計(jì)數(shù)器值,那么這個(gè)閉包取到的永遠(yuǎn)是for循環(huán)結(jié)束時(shí)i的最終值瓦灶,因?yàn)殚]包存儲的是它的引用而非當(dāng)時(shí)的值副本。

8碉怔、JS沒有塊級作用域桨踪,因此通常情況下函數(shù)內(nèi)部的所有變量都是綁定到函數(shù)作用域的,也就是說相當(dāng)于都在函數(shù)一開始就聲明了的纳账,一個(gè)例外就是try/catch中的變量是塊級的,只屬于try/catch塊啤呼。

9、眾所周知惕蹄,在函數(shù)內(nèi)部聲明函數(shù)是可以的卖陵,但是在在函數(shù)內(nèi)的局部塊里聲明,可能會出現(xiàn)問題:

function f(){return“global”;}

function test(x){

? ? function f(){return“l(fā)ocal”}

? ? var ? ?result=[];

? ? if(x){

? ? ? ? result.push(f());

? ? }

? ? result.push(f());

? ? return result;

}

test(true);//[“l(fā)ocal”,”local”]

test(false);//[“l(fā)ocal”]

將函數(shù)聲明到if塊中:

function f(){return“global”;}

? ? function test(x){

? ? var ?result=[];

? ? if(x){

? ? ? ? functionf (){return“l(fā)ocal”}

? ? ? ? result.push(f());

? ? }

? ? result.push(f());

? ? return result;

}

test(true);//?

test(false);//?

結(jié)果會如何呢?理論上講餐曹,JS沒有塊級作用域俱两,因此f()的作用域是整個(gè)test函數(shù)锋华,因此合理猜測應(yīng)該是與上一次輸出相同,全部為”local”磺樱,可是并不是所有的JS執(zhí)行環(huán)境都如此行事,有的會根據(jù)是否執(zhí)行包含f的代碼塊來有條件地綁定函數(shù)f(綁定即意味著將該變量綁定到其最近的作用域块差,而賦值是發(fā)生在代碼實(shí)際執(zhí)行到賦值那一步的時(shí)候進(jìn)行的)状蜗。

因此最好的辦法是如果要聲明嵌套函數(shù),都在其富函數(shù)的最外層聲明缸血,要么就不要聲明函數(shù),而是使用var聲明和函數(shù)表達(dá)式來實(shí)現(xiàn):

function f(){return “global”;}

function test(x){

? ? varresult=[];

? ? if(x){

? ? ? ? var g=function(){return “l(fā)ocal”}

? ? ? ? result.push(g());

? ? }

? ? result.push(f());

? ? return result;

}

10族扰、用js創(chuàng)建字典的時(shí)候怒竿,如果是利用對象的方式(因?yàn)镴S對象的核心是一個(gè)字符串屬性名稱和屬性值的映射表)爷辱,會遇到一個(gè)問題就是原型污染双饥,因?yàn)楂@取字典屬性值的時(shí)候用hasOwnProperty還好,如果用for in遍歷的話阀趴,不僅會遍歷對象本身棚菊,包括它的原型,因此如果在其他地方污染了Object的原型码邻,那么for in就會產(chǎn)生非預(yù)期的結(jié)果,這時(shí)可能會用hasOwnProperty來先檢測該對象本身是否含有屬性來避免原型污染浪谴,然而更極端的情況是連hasOwnProperty這個(gè)原型方法都有可能被污染。避免原型污染的方法是在創(chuàng)建字典對象的時(shí)候用Object.create(null)來創(chuàng)建一個(gè)完全空對象胁艰,這個(gè)對象沒有原型腾么,這個(gè)方法是ES5的,在沒有這個(gè)方法可用的時(shí)候,最好是創(chuàng)建字典類殴泰,然后在字典類里用數(shù)組來存儲有序集合捞魁,自己維護(hù)這個(gè)集合。

11健霹、JS中的類數(shù)組對象可以享用數(shù)組的大部分原型方法

如map等宣吱,類數(shù)組對象是指滿足兩個(gè)條件的對象:一是具備合理范圍值內(nèi)的length屬性,二是length屬性大于該對象的最大索引疤坝,索引是一個(gè)合理范圍的證書跑揉,它的字符串表示的是對象的一個(gè)key;但是數(shù)組的一個(gè)原型方法contact是不能被類數(shù)組對象調(diào)用的望侈,因此需要先用[].slice.call把類數(shù)組對象轉(zhuǎn)換為真正的數(shù)組比如[].slice.call(arguments)。

12捐韩、并不是所有時(shí)候都需要繼承,繼承也不是完美的寨蹋,有時(shí)候會創(chuàng)造比他能解決的更多的問題,特別是當(dāng)層次關(guān)系沒那么明顯的時(shí)候

這時(shí)候應(yīng)該多用結(jié)構(gòu)類型(又叫鴨子類型召娜,如果它看起來像鴨子秸讹、游泳像鴨子并且叫聲像鴨子璃诀,那么它就是鴨子),用結(jié)構(gòu)類型設(shè)計(jì)靈活的對象接口的時(shí)候凿将,不需要創(chuàng)建類工廠來返回類的實(shí)例,而是直接返回對象犀变,對象具備預(yù)期的方法和屬性,比如:

SomeObj.someWidget=function(opts){

? ? return{

? ? ? ? a:blabla,

? ? ? ? b:function(){...},

? ? ? ? c:blabla

? ? }

}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末映琳,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌持寄,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,376評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異油宜,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)蚁堤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,126評論 2 385
  • 文/潘曉璐 我一進(jìn)店門熟空,熙熙樓的掌柜王于貴愁眉苦臉地迎上來掂咒,“玉大人绍刮,你說我怎么就攤上這事〉迷耍” “怎么了饱搏?”我有些...
    開封第一講書人閱讀 156,966評論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長肺素。 經(jīng)常有香客問我,道長飞苇,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,432評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮崔挖,結(jié)果婚禮上薛匪,老公的妹妹穿的比我還像新娘。我一直安慰自己瘸右,他們只是感情好苞俘,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,519評論 6 385
  • 文/花漫 我一把揭開白布基协。 她就那樣靜靜地躺著澜驮,像睡著了一般悍缠。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上廊蜒,一...
    開封第一講書人閱讀 49,792評論 1 290
  • 那天著榴,我揣著相機(jī)與錄音,去河邊找鬼。 笑死钞翔,一個(gè)胖子當(dāng)著我的面吹牛妄田,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播东且,決...
    沈念sama閱讀 38,933評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼薯演!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,701評論 0 266
  • 序言:老撾萬榮一對情侶失蹤璃氢,失蹤者是張志新(化名)和其女友劉穎一也,沒想到半個(gè)月后讼渊,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體菱皆,經(jīng)...
    沈念sama閱讀 44,143評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,488評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了方淤。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片携茂。...
    茶點(diǎn)故事閱讀 38,626評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出式廷,到底是詐尸還是另有隱情览绿,我是刑警寧澤饿敲,帶...
    沈念sama閱讀 34,292評論 4 329
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響硕蛹,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜埃仪,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,896評論 3 313
  • 文/蒙蒙 一么库、第九天 我趴在偏房一處隱蔽的房頂上張望桑滩。 院中可真熱鬧运准,春花似錦、人聲如沸韭畸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,742評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽机蔗。三九已至,卻和暖如春萝嘁,著一層夾襖步出監(jiān)牢的瞬間扬卷,已是汗流浹背怪得。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留庞钢,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,324評論 2 360
  • 正文 我出身青樓财岔,卻偏偏與公主長得像河爹,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子夷恍,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,494評論 2 348

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

  • JS基礎(chǔ)講解 JavaScript組成ECMAScript:解釋器酿雪、翻譯DOM:Document Object M...
    FConfidence閱讀 571評論 0 1
  • 單例模式 適用場景:可能會在場景中使用到對象州丹,但只有一個(gè)實(shí)例亲怠,加載時(shí)并不主動創(chuàng)建,需要時(shí)才創(chuàng)建 最常見的單例模式,...
    Obeing閱讀 2,058評論 1 10
  • 工廠模式類似于現(xiàn)實(shí)生活中的工廠可以產(chǎn)生大量相似的商品,去做同樣的事情吴旋,實(shí)現(xiàn)同樣的效果;這時(shí)候需要使用工廠模式。簡單...
    舟漁行舟閱讀 7,724評論 2 17
  • JavaScript 將字符串轉(zhuǎn)換為數(shù)字 parseInt() ◆只保留數(shù)字的整數(shù)部分,不會進(jìn)行四舍五入運(yùn)算嚷掠。 ...
    AkaTBS閱讀 980評論 0 9
  • 《快思慢想》共讀內(nèi)容 《快思慢想》170715共讀015 交流內(nèi)容 by chundan 新概念 【周哈里窗模型】...
    三片阿司匹林閱讀 207評論 0 0