for/in循环
这是C/C++语言没有的便捷语法,Java支持for/in,不过JavaScript语法稍有不同。
for(variable in object) {
statement
}
for/in循环常用来遍历对象属性成员:
for(var p in o) //将属性名字赋值给变量p
console.log(o[p]); //输出每一个属性的值
在执行for/in语句的过程中,JavaScript解释器首先计算object表达式。如果表达式为null或者undefined,JavaScirpt解释器将会跳过循环并执行后续的代码。如果表达式等于一个原始值,这个原始值将会转换为与之对应的包装对象(wrapper object)JavaScript会依次枚举对象的属性来执行循环,每次循环之前,JavaScript都会先计算variable表达式的值,并将属性名(一个字符串)赋值给它。
只要for/in循环中variable的值可以当做赋值表达式的左值,它可以是任意表达式。每次循环都会计算这个表达式,也就是说每次循环它计算的值有可能不同。例如,可以使用下面这段代码将所有对象属性复制至一个数组中:
var o = {x:1, y:2, z:3};
var a = [], i = 0;
for (a[i++] in o) /*empty*/ ;
JavaScript数组不过是一种特殊的对象,因此,for/in循环可以像枚举对象属性一样枚举数组索引。例如,在上面的代码之后加上这段代码就可以枚举数组的索引0、1、2:for(i in a)console.log(i);
for/in循环并不会遍历对象的所有属性,只有“可枚举”(enumerable)的属性才会遍历到。由JavaScript语言核心所定义的内置方法就不是“可枚举的”,比如,所有的对象都有方法toString(),但for/in循环并不枚举toString这个属性。除了内置方法之外,还有很多内置对象的属性也是“不可枚举的”(nonenumerable)。而代码中定义的所有属性和方法都是可枚举的,当然也可以使用Object.defineProperty()定义为不可枚举的属性。
标签语句
语句是可以添加标签的,标签是由语句前的标识符和冒号组成:
identifer: statement
break和continue是JavaScript中唯一可以使用语句标签的语句。
mainloop: while (token != null) {
//忽略这里的代码...
if (condition1) continue mainloop; //跳转到下一次循环
//忽略这里的代码...
if (condition2) break mainloop; //结束这个循环代码段
//忽略这里的代码...
}
标签语句尽量少用,与C/C++中的标签语句类似,除非在减少出口让逻辑变得更简单的情况下使用,否则,这总归是代码不优雅的表现!
with语句
这还是很多年前使用Delphi用到的语法了,不过在JavaScript中严格模式下是禁用with语句的,非严格模式里实际上也不推荐使用,了解含义即可。with语句用于临时拓展作用域,比如下面访问HTML表单中的元素:
document.forms[0].name.value
document.forms[0].address.value
document.forms[0].email.value
如果这种表达式在代码中多次出现,则可以使用with语句将form对象添加至作用域链的顶层:
with (document.forms[0]) {
name.value = "";
address.value = "";
email.value = "";
}
debugger语句
debugger语句通常什么也不做,但当调试程序可用并运行的时候,JavaScript解释器将会以调式模式运行。这条语句用来产生一个断点(breakpoint),JavaScript代码的执行会停止在断点的位置,这时可以使用调试器输出变量的值、检查调用栈等。例如,假设由于调用函数f()的时候使用了未定义的参数,因此f()抛出一个异常,但无法定位到底是哪里抛出了异常。为了有助于调试这个问题,需要修改函数f():
function f(o) {
if (o === undefined) debugger; //这一行代码只是用于临时调试
... //函数的其他部分
}
"use strict"
使用"use strict"指令的目的是说明(脚本或函数中)后续的代码将会解析为严格代码(strict code)。如果顶层(不在任何函数内的)代码使用了"use strict"指令,那么它们就是严格代码。如果函数体定义所处的代码是严格代码或者函数体使用了"use strict"指令,那么函数体的代码也是严格代码。如果eval()调用时所处的代码是严格代码或者eval()要执行的字符串中使用了"scrict code"指令,则eval()内的代码是严格代码。
严格模式和非严格模式之间的区别如下(前三条尤为重要):
- 在严格模式中禁止使用with语句。
- 在严格模式中,所有的变量都要先声明,如果给一个未声明的变量、函数、函数参数、catch从句参数或全局对象的属性赋值,将会抛出一个引用错误异常(在非严格模式中,这种隐式声明的全局变量的方法是给全局对象新添加一个新属性)。
- 在严格模式中,调用的函数中的this值是undefined,(在非严格模式中,调用的函数中的this值总是全局对象),可以利用这种特性来判断JavaScript实现是否支持严格模式:
var hasStrictMode=(function(){"use strict";return this===undefined}());
。 - 同样,在严格模式中,当通过call()或apply()来调用函数时,其中的this值就是通过call()或apply()传入的第一个参数(在非严格模式中,null和undefined值被全局对象和转换为对象的非对象值所代替)。
- 在严格模式中,给只读属性赋值和给不可扩展的对象创建新成员都将抛出一个类型错误异常(在非严格模式中,这些操作只是简单地操作失败,不会报错)。
- 在严格模式中,传入eval()的代码不能在调用程序所在的上下文中声明变量或定义函数,而在非严格模式中是可以这样做的。相反,变量和函数的定义是在eval()创建的新作用域中,这个作用域在eval()返回时就弃用了。
- 在严格模式中,函数里的arguments对象拥有传入函数值的静态副本。在非严格模式中,arguments对象具有“魔术般”的行为,arguments里的数组元素和函数参数都是指向同一个值的引用。
- 在严格模式中,当delete运算符后跟随非法的标识符(比如变量、函数、函数参数)时,将会抛出一个语法错误异常(在非严格模式中,这种delete表达式什么也没做,并返回false)。
- 在严格模式中,试图删除一个不可配置的属性将抛出一个类型错误异常(在非严格模式中,delete表达式操作失败,并返回false)。
- 在严格模式中,在一个对象直接量中定义两个或多个同名属性将产生一个语法错误(在非严格模式中不会报错)。
- 在严格模式中,函数声明中存在两个或多个同名的参数将产生一个语法错误(在非严格模式中不会报错)。
- 在严格模式中是不允许使用八进制整数直接量(以0为前缀,而不是0x为前缀)的(在非严格模式中某些实现是允许八进制整数直接量的)。
- 在严格模式中,标识符eval和arguments当做关键字,它们的值是不能更改的。不能给这些标识符赋值,也不能把它们声明为变量、用做函数名、用做函数参数或用做catch块的标识符。
- 在严格模式中限制了对调用栈的检测能力,在严格模式的函数中,arguments.caller和arguments.callee都会抛出一个类型错误异常。严格模式的函数同样具有caller和arguments属性,当访问这两个属性时将抛出类型错误异常(有一些JavaScript的实现在非严格模式里定义了这些非标准的属性)。