小括號
JavaScript中小括號有五種語義
語義1,函數聲明時參數表
function func(arg1,arg2){
// ...
}
語義2,和一些語句聯合使用以達到某些限定作用
// 和for in一起使用
for(var a in obj){
// ...
}
// 和if一起使用
if(boo){
//...
}
// 和while一起使用
while(boo){
// ...
}
// 和do while一起使用 do{
// ...
}
while(boo)
注意:在與if、while及do while一起使用時小括號會將其中的表達式結果隱式的轉換成布爾值。見無處不在的隱式類型轉換 。
語義3,和new一起使用用來傳值(實參)
// 假設已經定義了類Person,它有兩個字段姓名(name),年齡(age)
var p1 = new Person('Jack',26);
語義4,作為函數或對象方法的調用運算符(如果定義了參數也可與語義3一樣傳實參)
// 假設已經定義了函數func
func();
// 假設已經定義了對象obj,且擁有func方法
obj.func();
這里提下typeof運算符,有人喜歡這么使用
請注意typeof后的小括號並非語義4(即不是函數調用),而是后面提到的語義5。我使用typeof一般不加后面的小括號。見 具名函數的多種調用方式
語義5,強制表達式運算
function strToJson(str){ // eval 中字符串兩旁加了強制運算符()
var json = eval('(' + str + ')');
return json;
}
關於語義5,大家最熟悉的莫過於使用eval解析JSON
又如使用較多的是匿名函數自執行
(function(){
// ...
})();
注意,以上代碼第1對小括號是語義5,第3對則是語義4。
大括號
JavaScript中大括號有四種語義作用
語義1,組織復合語句,這是最常見的
if( condition ) {
//...
}else {
//...
} for() {
//...
}
語義2,對象直接量聲明
var obj = { name : 'jack', age : 23 };
整個是個賦值語句,其中的{name:'jack',age:23}是個表達式。
語義3,聲明函數或函數直接量
function f1(){
//...
}
var f2 = function(){
//...
}
f1與非f2的區別是前者在語法解釋期,后者在運行期。區別在於:如果調用該函數的代碼在函數定義之后,則沒有區別;如果調用該函數的代碼在函數定義之前,則f1仍然可以調用,f2則會報錯,提示f2未定義。
語義4,結構化異常處理的語法符號
try {
//...
}catch( ex ){
//...
}finally{
//...
}
這里的大括號與符合語句(語義1 )是有區別的,大括號中如果只有一條語句,在if/else/for等中大括號是可以省略的,但try/catch/finally則不能省略。
以下代碼糾結了偶N久
function(){}() //匿名函數立即執行, 語法分析期報
{}.constructor //獲取對象直接量的構造器,語法分析期報錯
令人不解的是為何[].constructor這么寫卻不報錯呢,一個是想獲取對象直接量的構造器,一個是獲取數組直接量的構造器而已。
當然添加個變量接收也不會報錯
同樣的情況如
var fn = function(){}(),也不會報錯。
實際上是js的“語句優先”在作怪,即{}被理解成復合語句塊(語義1 )而不是對象直接量(語義2 )或聲明函數(語義3 )的語義。
function(){}(),大括號被理解成復合語句,自然前面的function()聲明函數的語法不完整導致語法分析期出錯。
{}.constructor,大括號被理解成復合語句,大括號后面是點運算符,點運算符前沒有合理的對象自然也報錯。
修復方式眾所周知:加個強制運算符()
(function(){})(),(function(){});//強制其理解為函數(語義3 ),“函數()”表示執行該函數,即聲明后立即執行了。
({}).constructor //({})強制把大括號理解成對象直接量(語義2 ),“對象.xx”表示獲取對象的成員,自然后面的點運算符可以正常執行了。
中括號
JavaScript中括號有四種語義
語義1,聲明數組
var ary = []; // 聲明一個空數組
var ary = [1,3]; // 聲明一個數組,同時賦初值
語義2,取數組成員
var ary = [1,2,3]; var item = ary[0];
語義3,定義對象成員 (可以不遵循標識符規則 )
var obj = {};
// 為obj添加一個屬性name,name是合法的標識符,即也可以通過obj.name方式來定義
obj['name'] = 'jack';
// 為obj添加一個屬性2a,2a不是合法的標識符(不能以數字開頭),不能通過obj.2a來定義
obj['2a'] = 'test';
語義4,取對象成員
var obj = {name:'jack'}; obj['2a'] = 'test';
obj['name']; // --> jack
obj['2a']; // --> test (不能通過obj.2a獲取)