JavaScript 中表达式和语句的区别?
本文要讲的是 JavaScript 中非常重要的两个知识点:表达式(expressions)和语句(statements)之间的区别.
1.语句和表达式
JavaScript 中的表达式和语句是有区别的,一个表达式会产生一个值,它可以放在任何需要一个值的地方,比如作为一个函数调用的参数,下面的每行代码都是一个表达式:
myvar
3 + x
myfunc("a", "b")
语句可以理解成一个行为,循环语句和if语句就是典型的语句,一个程序是由一系列语句组成的,JavaScript 中某些需要语句的地方,你可以使用一个表达式来代替,这样的语句称之为表达式语句,但反过来不可以,你不能在一个需要表达式的地方放一个语句,比如一个 if 语句不能作为一个函数的参数。
2.其他语法
看看下面这两对类似的语法,搞懂这些后,能够帮助我们更好的理解语句和表达式之间的关系。
2.1 If 语句和条件运算符
下面是一个 if 语句的例子:
var x;
if (y >= 0) {
x = y;
} else {
x = -y;
}
类似 if 语句功能的表达式叫做条件运算符,上面的语句等价于下面的。
var x = (y >= 0 ? y : -y);
在等于号 = 和分号 ; 之间的代码就是条件表达式,两边的小括号不是必需的,但我觉得小括号能让条件表达式更易读。
2.2 分号和逗号运算符
在 JavaScript 中,使用分号可以连接两个语句:
foo(); bar()
要想连接两个表达式,使用的是不常见的逗号运算符:
foo(), bar()
逗号运算符会计算前后两个表达式,然后返回右边表达式的计算结果,例如:
> "a", "b"
'b'
> var x = ("a", "b");
> x
'b'
> console.log(("a", "b"));
b
3. 看似语句的表达式
一些表达式看起来像是语句,这可能会带来一些麻烦。
3.1 对象字面量和语句块
下面是一个对象字面量,也就是一个可以生成一个对象值的表达式。
{
foo: bar(3, 5)
}
不过同时,它也是一个完全合法的语句,这个语句的组成部分有:
- 一个代码块:一个由大括号包围的语句序列.
- 一个标签:你可以在任何语句前面放置一个标签,这里的
foo 就是一个标签
。 - 一条语句:表达式语句
bar(3, 5)
.
你也许会感到震惊,那就是 JavaScript 居然可以有独立的代码块(常见的代码块是依托于循环或者 if 语句的),下面的代码演示了这种代码块的作用,你可以给它设置一个标签然后跳出这个代码块。
function test(printTwo) {
printing: {
console.log( "One");
if (!printTwo) break printing;
console.log( "Two");
}
console.log( "Three");
}
> test(false )
One
Three
> test(true )
One
Two
Three
3.2 函数表达式和函数声明
下面的代码是一个函数表达式:
function () { }
你还可以给这个函数表达式起一个名字,将它转变为一个命名(非匿名)的函数表达式:
function foo() { }
这个函数的函数名(foo)
只存在于函数内部,比如可以用它来做递归运算:
> var fac = function me(x) { return x <= 1 ? 1 : x * me(x-1) }
> fac(10)
3628800
> console.log(me)
ReferenceError: me is not defined
一个命名的函数表达式从表面上看起来,和一个函数声明并没有什么区别。但他们的效果是不同的,一个函数表达式产生一个值(一个函数),一个函数声明执行一个动作,将一个函数赋值给一个变量。此外只有函数表达式可以被立即调用,函数声明不可以。
3.3 解决冲突
从 3.1 和 3.2 可以看出,有些表达式和语句在表面上看不出有什么区别。也就意味着,相同的代码,出现在表达式上下文和出现在语句上下文会表现出不同的作用。通常情况下,这两种上下文是没有交集的,但是如果是表达式语句的话,会有一个重叠,也就是说,会有一些表达式出现在语句上下文上,为了解决这种歧义,JavaScript 语法禁止表达式语句以大括号或关键字 function 开头:
ExpressionStatement :
[lookahead { "{", "function"}] Expression ;
那么,如果你想写一个以那些标志开头的表达式语句,该怎办呢? 你可以把它放在一个括号内部,这样并不会改变运行结果,只会确保该表达式被解析在表达式上下文中,让我们看两个例子,第一个例子,eval 会按照语句上下文解析它的参数
,如果你想让 eval 返回一个对象
,你必须在对象字面量两边加上一个括号。
> eval("{ foo: 123 }")
123
> eval("({ foo: 123 })")
{ foo: 123 }
第二个例子,下面的例子是一个立即执行的函数表达式。
> (function () { return "abc" }())
'abc'
如果你省略了小括号,你会得到一个语法错误(函数声明不可以是匿名的):
> function () { return "abc" }()
SyntaxError: function statement requires a name
如果你添加上函数名,还会得到一个语法错误(函数声明不能被理解执行):
> function foo() { return "abc" }()
SyntaxError: syntax error
另外一个能让表达式在表达式上下文上被解析的办法是使用一元运算符,比如 +
或者 !,但是和使用括号不同的是,这些操作符会改变表达式的运行结果,如果你不关心结果的话,完全可以使用:
> +function () { console.log("hello") }()
hello
NaN
NaN
是 + 作用在函数执行后的返回值
undefined 上的结果
。
原文:http://www.2ality.com/2012/09/expressions-vs-statements.html
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论