看完了javaScript資料類型和運算式與運算子相關知識後以為可以對JavaScript筆試題牛刀小試一把了,沒想到有一次次的死在逗號,冒號和括弧上,不得已再看看這幾個符號吧。
逗號逗號我們常見的用法就是在連續聲明一些變數的時候,可以少些很多var var a=1, b=2, c=3;方法參數我們使用逗號隔開,對象屬性也是逗號隔開 ``` function fbn(name,title){} var person={ name:"Byron", age:"24" }; ``` 然而我們也會遇到這樣的問題,在賦值運算式中出現的逗號 1var a=(1,2,3);在運算式與運算子中提到過逗號運算子就是對應這種情況,這時運算式計算結果是最後一個子運算式結果,也就是3。千萬不要誤會前面的子運算式不會執行,每個子運算式都會執行,只不過“傳回值”是最後一個運算式結果。 var a,b;a=(b=1,2);console.log(a);//2console.log(b);//1冒號?:運算子 var p=gender ? 'male':female;對象字面量 var obj={ name:"Byron", age:24};switch語句 switch(t){ case 1: console.log('xxx'); break; case 2: console.log('ooo'); break;}相信這是大家所熟知的用法了,那麼我們可以個題目 1x:y:z:1,2,3;上面運算會不會報錯?不報錯運算結果是什嗎?很多同學初次看到這個會很驚訝,覺得肯定會出錯,但結果卻是3,來看看為什麼 其實冒號還有個作用:聲明label,JavaScript中語句可以有個標籤首碼,我們稱之為標記語句,break或continue可以和標記的語句結合使用,控制流程程。如果標籤有重複,就會出錯。我們上面的語句可以翻譯成這樣 x: y: z:1,2,3這樣我們結合剛才說的逗號的知識就能明白為什麼結果是3了,很多最佳化建議都是不提倡使用標籤的,有沒有想起C語言的goto,使用了標籤控制流程程,使程式相當難讀懂。 var x=1;foo:{ x=2; break foo; x=3;}console.log(x);大括弧對象直接量聲明 var obj={ name:"Byron", age:24};整條語句使指派陳述式,右值部分十個運算式,通過直接量構造出一個對象 函式宣告或者函數直接量 function fn1(){ //....}<br>var fn2=function(){ //...};相信這種用法不閉多說什麼了 組織複合陳述式 with(obj){ //...}for(){ //...}if(){ //...}else{ //...}大括弧沒有帶來塊級範圍熟悉JavaScript的同學肯定對這點兒已經熟知了,大括弧雖然能夠組織複雜的語句等,是指算是同一“塊”,with甚至提供了相近的功能,但遺憾的使JavaScript只有函數範圍,沒有塊範圍,再JavaScript中下面做法會聲明全域變數,這個小小的知識點往往引英雄競折腰 在function外使用聲明變數(無論是否使用var)在function內不是用var 聲明變數直接賦值於window屬性 var a=2;function fn(){ b=3; window.c=4;}除了這三種剩下的就是function範圍內的局部變數了,在很多JavaScript規範中都有提到,盡量提早聲明變數正是由於其沒有塊範圍 function fn(n){ if(n>1){ var a=n; }else{ var b=n; } console.log(a);}這樣的代碼在很多語言中有語法錯誤,因為if和else的大括弧有塊範圍,變數a、b在自己對應塊範圍中,出了塊就訪問不到了。但在JavaScript中,沒有塊範圍,所以我們在if、else內聲明的變數console.log依然能夠訪問,這確實是糟糕的設計,為了減少錯誤可能,盡量把變數聲明提前。 很多筆試題目正是針對這方面知識出題的 {a:1};var x={a:1};{a:1,b:2};var y={a:1,b:2};親自試試是不是發現很驚訝,我們分析一下 {a:1} JavaScript有傳說中的“語句優先”,也就是當大括弧既可以被理解為複合陳述式塊也可以被理解為對象直接量的時候,JavaScript會將其理解為複合陳述式快。{a:1}其實就是 a: 1,想想冒號的作用是不是知道為什麼傳回值是1了。 var x={a:1} 當{a:1} 作為右值出現的時候,明顯就不是語句,而是直接量運算式了,所以把大括弧當作對象直接量文法處理,結果是個對象。 {a:1,b:2}; 看了上面這個就簡單了,可以翻譯為:a:1,b:2 結合逗號和冒號作用,結果似乎顯而易見了,就是2嘛。然而其實報錯了,這是為什嗎?在逗號運算子後面必須是運算式,而標籤語句十個label statement,是條語句,所以就報錯了。 瞭解了這些知識我們再來試幾個題目(看答案在控制台上,不要試圖alert) {foo:[1,2,3]}[0];{a:1}+2;2+{a:1};不知道小夥伴兒們做對了沒有,這幾個題目核心一樣,大括弧雖然看起來沒什麼作用,但起到了語句分隔字元作用,{foo:[1,2,3]}[0]可以理解為 {foo:[1,2,3]};[0];所以傳回值是[0],同樣{a:1}+2變為 {a:1};+2但是!為什麼2+{a:1}就不一樣了呢?這時加法運算子導致的,加號是左結合的,{}被解析為運算式(得是運算式相加嘛),根據資料類型中知識對象{a:1}轉換為NaN 小括弧在JavaScript中小括弧有幾種用法 函式宣告或調用運算式參數表 這個好理解,函數定義的時候需要用小括弧將其參數包裹,用逗號隔開,調用的時候也一樣 function fn(name,age){ //...}fn('Byron',24);var f=new fn('Byron',24)與一些關鍵字組成條件陳述式 我們常見的if、switch、while中的小括弧就是幹這個用的 if(a>0){ //...}while(i<len){ //...}for(var i=0;i<len;i++){ //...}分組運算子 分組運算子內部只能包含運算式,可以改變運算子優先順序,捨棄一些可能的文法樹,最常見的 var x=()1+2)*3;相信不用多解釋,很多同學會認為小括弧有強製表達式運算的功能,其實這時片面的理解,這隻是改變了運算子優先順序,產生新的文法樹後的結果。對於簡單的json字串轉為對象的時候,因為瀏覽器安全色性原因,不能使用JSON對象,又懶得引入json2,所以就會用eval()處理,大概寫法這樣 var jsonStr=...;var jsonObj=eval('(' + jsonStr + ')');很多同學會問,為什麼還要加上個小括弧呢?像我們上面解釋的大括弧的作用,json字串 "{a:1,b:2}" 這樣的格式會被理解為語句,也就是傳說中的label statement,文法樹是這樣的 {a:1,b:2} 上面提到過逗號運算子不能在label statement後面,所以會報錯,而加上括弧後由於分組運算子只能包含運算式,所以{}變成直接量文法,這樣就是我們希望的內容了。 立即調用的函數運算式再來回頭看看我們所謂的立即執行函數,一般有兩種寫法 (function(){})();(function(){}());!function(){}();搜了很多資料,終於看到了靠譜解釋,總結一下,首先我們需要搞清楚函數運算式和函式宣告區別,ECMAScript規範中定義的相當模糊:函式宣告必須帶有標示符(Identifier)(就是大家常說的函數名稱),而函數運算式則可以省略這個標示符: 函式宣告: function 函數名稱 (參數:可選){ 函數體 } 函數運算式: function 函數名稱(可選)(參數:可選){ 函數體 } 其實我們常用的區分方式是根據上下文,如果function fn(){}作為右值出現(賦值運算式右邊)那麼就是運算式,否則就是函式宣告。有幾種看起來不常規的方式需要我們注意 new function fn(){}; //運算式,因為在new 運算式中(function(){}());//運算式,在分組運算子中這樣我們就能理解第二種寫法了,就是利用分組運算子改變了文法樹。同樣第三種寫法其實是利用了一元運算子後面跟運算式的原理,我們也可以寫成 +function(){}()-function(){}()~function(){}()知乎上長天之雲甚至寫出了這麼多 ( function() {}() );( function() {} )();[ function() {}() ];////////////////////////////////~ function() {}();! function() {}();+ function() {}();- function() {}();////////////////////////////////delete function() {}();typeof function() {}();void function() {}();new function() {}();new function() {};/////////////////////////////////var f = function() {}();/////////////////////////////////1, function() {}();1 ^ function() {}();1 > function() {}();所以我們應該稱立即執行函數為立即調用的函數運算式! 中括弧相對而言中括弧是個最簡單的符號了,一般有幾種語義 *數組相關 我們知道數組可以通過中括弧來直接量執行個體化 var a=[1,2,3];*擷取對象屬性值 這也是很常見的用法 var a=[1,2,3];var b={name:'Byron'};a[2];b['name'];看幾個有意思的小題目 [1,2,3,4,5][0..toString.length];//0.等同於0.0'foo'.split('') + [];