for/in循環(huán)
這是C/C++語言沒有的便捷語法,Java支持for/in视卢,不過JavaScript語法稍有不同演训。
for(variable in object) {
statement
}
for/in循環(huán)常用來遍歷對象屬性成員:
for(var p in o) //將屬性名字賦值給變量p
console.log(o[p]); //輸出每一個屬性的值
在執(zhí)行for/in語句的過程中锁右,JavaScript解釋器首先計算object表達式。如果表達式為null或者undefined哎壳,JavaScirpt解釋器將會跳過循環(huán)并執(zhí)行后續(xù)的代碼。如果表達式等于一個原始值尚卫,這個原始值將會轉換為與之對應的包裝對象(wrapper object)JavaScript會依次枚舉對象的屬性來執(zhí)行循環(huán)归榕,每次循環(huán)之前,JavaScript都會先計算variable表達式的值吱涉,并將屬性名(一個字符串)賦值給它刹泄。
只要for/in循環(huán)中variable的值可以當做賦值表達式的左值,它可以是任意表達式怎爵。每次循環(huán)都會計算這個表達式特石,也就是說每次循環(huán)它計算的值有可能不同。例如鳖链,可以使用下面這段代碼將所有對象屬性復制至一個數(shù)組中:
var o = {x:1, y:2, z:3};
var a = [], i = 0;
for (a[i++] in o) /*empty*/ ;
JavaScript數(shù)組不過是一種特殊的對象姆蘸,因此,for/in循環(huán)可以像枚舉對象屬性一樣枚舉數(shù)組索引。例如逞敷,在上面的代碼之后加上這段代碼就可以枚舉數(shù)組的索引0狂秦、1、2:for(i in a)console.log(i);
for/in循環(huán)并不會遍歷對象的所有屬性推捐,只有“可枚舉”(enumerable)的屬性才會遍歷到裂问。由JavaScript語言核心所定義的內置方法就不是“可枚舉的”,比如玖姑,所有的對象都有方法toString()愕秫,但for/in循環(huán)并不枚舉toString這個屬性。除了內置方法之外焰络,還有很多內置對象的屬性也是“不可枚舉的”(nonenumerable)戴甩。而代碼中定義的所有屬性和方法都是可枚舉的,當然也可以使用Object.defineProperty()定義為不可枚舉的屬性闪彼。
標簽語句
語句是可以添加標簽的甜孤,標簽是由語句前的標識符和冒號組成:
identifer: statement
break和continue是JavaScript中唯一可以使用語句標簽的語句。
mainloop: while (token != null) {
//忽略這里的代碼...
if (condition1) continue mainloop; //跳轉到下一次循環(huán)
//忽略這里的代碼...
if (condition2) break mainloop; //結束這個循環(huán)代碼段
//忽略這里的代碼...
}
標簽語句盡量少用畏腕,與C/C++中的標簽語句類似缴川,除非在減少出口讓邏輯變得更簡單的情況下使用,否則描馅,這總歸是代碼不優(yōu)雅的表現(xiàn)把夸!
with語句
這還是很多年前使用Delphi用到的語法了,不過在JavaScript中嚴格模式下是禁用with語句的铭污,非嚴格模式里實際上也不推薦使用恋日,了解含義即可。with語句用于臨時拓展作用域嘹狞,比如下面訪問HTML表單中的元素:
document.forms[0].name.value
document.forms[0].address.value
document.forms[0].email.value
如果這種表達式在代碼中多次出現(xiàn)岂膳,則可以使用with語句將form對象添加至作用域鏈的頂層:
with (document.forms[0]) {
name.value = "";
address.value = "";
email.value = "";
}
debugger語句
debugger語句通常什么也不做,但當調試程序可用并運行的時候磅网,JavaScript解釋器將會以調式模式運行谈截。這條語句用來產生一個斷點(breakpoint),JavaScript代碼的執(zhí)行會停止在斷點的位置涧偷,這時可以使用調試器輸出變量的值簸喂、檢查調用棧等。例如嫂丙,假設由于調用函數(shù)f()的時候使用了未定義的參數(shù)娘赴,因此f()拋出一個異常,但無法定位到底是哪里拋出了異常跟啤。為了有助于調試這個問題诽表,需要修改函數(shù)f():
function f(o) {
if (o === undefined) debugger; //這一行代碼只是用于臨時調試
... //函數(shù)的其他部分
}
"use strict"
使用"use strict"指令的目的是說明(腳本或函數(shù)中)后續(xù)的代碼將會解析為嚴格代碼(strict code)唉锌。如果頂層(不在任何函數(shù)內的)代碼使用了"use strict"指令,那么它們就是嚴格代碼竿奏。如果函數(shù)體定義所處的代碼是嚴格代碼或者函數(shù)體使用了"use strict"指令袄简,那么函數(shù)體的代碼也是嚴格代碼。如果eval()調用時所處的代碼是嚴格代碼或者eval()要執(zhí)行的字符串中使用了"scrict code"指令泛啸,則eval()內的代碼是嚴格代碼绿语。
嚴格模式和非嚴格模式之間的區(qū)別如下(前三條尤為重要):
- 在嚴格模式中禁止使用with語句。
- 在嚴格模式中候址,所有的變量都要先聲明吕粹,如果給一個未聲明的變量、函數(shù)岗仑、函數(shù)參數(shù)匹耕、catch從句參數(shù)或全局對象的屬性賦值,將會拋出一個引用錯誤異常(在非嚴格模式中荠雕,這種隱式聲明的全局變量的方法是給全局對象新添加一個新屬性)稳其。
- 在嚴格模式中,調用的函數(shù)中的this值是undefined炸卑,(在非嚴格模式中既鞠,調用的函數(shù)中的this值總是全局對象),可以利用這種特性來判斷JavaScript實現(xiàn)是否支持嚴格模式:
var hasStrictMode=(function(){"use strict";return this===undefined}());
盖文。 - 同樣嘱蛋,在嚴格模式中,當通過call()或apply()來調用函數(shù)時五续,其中的this值就是通過call()或apply()傳入的第一個參數(shù)(在非嚴格模式中浑槽,null和undefined值被全局對象和轉換為對象的非對象值所代替)。
- 在嚴格模式中返帕,給只讀屬性賦值和給不可擴展的對象創(chuàng)建新成員都將拋出一個類型錯誤異常(在非嚴格模式中,這些操作只是簡單地操作失敗篙挽,不會報錯)荆萤。
- 在嚴格模式中,傳入eval()的代碼不能在調用程序所在的上下文中聲明變量或定義函數(shù)铣卡,而在非嚴格模式中是可以這樣做的链韭。相反,變量和函數(shù)的定義是在eval()創(chuàng)建的新作用域中煮落,這個作用域在eval()返回時就棄用了敞峭。
- 在嚴格模式中,函數(shù)里的arguments對象擁有傳入函數(shù)值的靜態(tài)副本蝉仇。在非嚴格模式中旋讹,arguments對象具有“魔術般”的行為殖蚕,arguments里的數(shù)組元素和函數(shù)參數(shù)都是指向同一個值的引用。
- 在嚴格模式中沉迹,當delete運算符后跟隨非法的標識符(比如變量睦疫、函數(shù)、函數(shù)參數(shù))時鞭呕,將會拋出一個語法錯誤異常(在非嚴格模式中蛤育,這種delete表達式什么也沒做,并返回false)葫松。
- 在嚴格模式中瓦糕,試圖刪除一個不可配置的屬性將拋出一個類型錯誤異常(在非嚴格模式中,delete表達式操作失敗腋么,并返回false)咕娄。
- 在嚴格模式中,在一個對象直接量中定義兩個或多個同名屬性將產生一個語法錯誤(在非嚴格模式中不會報錯)党晋。
- 在嚴格模式中谭胚,函數(shù)聲明中存在兩個或多個同名的參數(shù)將產生一個語法錯誤(在非嚴格模式中不會報錯)。
- 在嚴格模式中是不允許使用八進制整數(shù)直接量(以0為前綴未玻,而不是0x為前綴)的(在非嚴格模式中某些實現(xiàn)是允許八進制整數(shù)直接量的)灾而。
- 在嚴格模式中,標識符eval和arguments當做關鍵字扳剿,它們的值是不能更改的旁趟。不能給這些標識符賦值,也不能把它們聲明為變量庇绽、用做函數(shù)名锡搜、用做函數(shù)參數(shù)或用做catch塊的標識符。
- 在嚴格模式中限制了對調用棧的檢測能力瞧掺,在嚴格模式的函數(shù)中耕餐,arguments.caller和arguments.callee都會拋出一個類型錯誤異常。嚴格模式的函數(shù)同樣具有caller和arguments屬性辟狈,當訪問這兩個屬性時將拋出類型錯誤異常(有一些JavaScript的實現(xiàn)在非嚴格模式里定義了這些非標準的屬性)肠缔。