你不知道的 JavaScript 系列中( 31 ) - 让人误解的语句
语句的结果值
var a = 3 * 6; var b = a; b;
以赋值表达式 b = a 为例,其结果值是赋给 b 的值(18),但规范定义 var 的结果值是 undefined。如果在控制台中输入var a = 42会得到结果值 undefined,而非 42
如果你用开发控制台调试过代码,应该会看到很多语句的返回值显示为 undefined,只是你可能从未探究过其中的原因。 其实控制台中显示的就是语句的结果值
var b; if (true) { b = 4 + 38; }
在控制台中输入以上代码应该会显示 42,即最后一个语句 / 表达式 b= 4 + 38 的结果值。 换句话说,代码块的结果值就如同一个隐式的返回,即返回最后一个语句的结果值。
下面这样的代码无法运行:
var a, b; a = if (true) { b = 4 + 38; };
因为语法不允许我们获得语句的结果值并将其赋值给另一个变量(至少目前不行)
表达式的副作用
var a = 2; var b = a + 3;
表达式 a + 3 本身没有副作用(比如改变a的值)。它的结果值为5,通过 b = a + 3 赋值 给变量 b。
var a = 42; var b = a++;
a++ 首先返回变量 a 的当前值 42(再将该值赋给 b),然后将 a 的值加 1:
var a = 42;
var b = a++; a; // 43 b; // 42
很多开发人员误以为变量 b 和 a 的值都是 43,这是因为没有完全理解 ++ 运算符的副作用 何时产生。
var a = 42; a++; // 42 a; // 43 ++a; // 44 a; // 44
++ 在前面时,如 ++a,它的副作用(将 a 递增)产生在表达式返回结果值之前,而 a++ 的 副作用则产生在之后
但也不是没有办法,可以使用,语句系列逗号运算符(statement-series comma operator)将
多个独立的表达式语句串联成一个语句:
var a = 42, b; b = ( a++, a ); a; // 43 b; // 43
a++, a中第二个表达式a在a++之后执行,结果为43,并被赋值给b。
上下文规则
{}
// 假定函数bar()已经定义 var a = { foo: bar() };
{ .. }被赋值给a,因而它是一个对象常量。
{
foo: bar()
}
{ .. } 在这里只是一个普通的代码块。JavaScript 中这种情况并不多见(在其他语言中则常见得多),但语法上是完全合法的,特别是和 let(块作用域声明)在一起时非常有用
还有一个坑常被提到(涉及强制类型转换,参见第 4 章):
[] + {}; // "[object Object]" {} + []; // 0
第一行代码中,{} 出现在 + 运算符表达式中,因此它被当作一个值(空对象)来处理。[]会被强制类型转换为"",而{}会被强制类型转换为"[object Object]"。
但在第二行代码中,{} 被当作一个独立的空代码块(不执行任何操作)。代码块结尾不需 要分号,所以这里不存在语法上的问题。最后+ []将[]显式强制类型转换(参见第4章) 为0。
else if 和可选代码块
很多人误以为JavaScript中有else if,因为我们可以这样来写代码:
if (a) { // .. }else if (b) { // .. }else { // .. }
事实上 JavaScript 没有 else if,但 if 和 else 只包含单条语句的时候可以省略代码块的 { }。下面的代码你一定不会陌生:
if (a) doSomething( a );
很多JavaScript代码检查工具建议对单条语句也应该加上{ },如:
if (a) { doSomething( a ); }
else也是如此,所以我们经常用到的else if实际上是这样的:
if (a) { // .. }else { if (b) { // .. }else { // .. } }
if (b) { .. } else { .. }实际上是跟在else后面的一个单独的语句,所以带不带{ }都可以。换句话说,else if不符合前面介绍的编码规范,else中是一个单独的if语句。 else if 极为常见,能省掉一层代码缩进,所以很受青睐。但这只是我们自己发明的用法,切勿想当然地认为这些都属于 JavaScript 语法的范畴。