原文地址:http://www.2ality.com/2012/09/expressions-vs-statements.html

Update 2012-09-21: New in Sect. 4: using void for IIFEs, concatenating IIFEs.

This blog post looks at a syntactic distinction that is unfortunately quite important in JavaScript: the difference between expressions and statements.

Statements and expressions

JavaScript distinguishes expressions and statements. An expression produces a value and can be written wherever a value is expected, for example as an argument in a function call. Each of the following lines contains an expression:

    myvar
3 + x
myfunc("a", "b")

Roughly, a statement performs an action. Loops and if statements are examples of statements. A program is basically a sequence of statements (we’re ignoring declarations here). Wherever JavaScript expects a statement, you can also write an expression. Such a statement is called an expression statement. The reverse does not hold: you cannot write a statement where JavaScript expects an expression. For example, an if statement cannot become the argument of a function.

Similar kinds of statements and expressions

The difference between statements and expressions becomes clearer if we look at members of the two syntactic categories that are similar.

If statement versus conditional operator

The following is an example of an if statement:

    var x;
if (y >= 0) {
x = y;
} else {
x = -y;
}

Expressions have an analog, the conditional operator. The above statements are equivalent to the following statement.

    var x = (y >= 0 ? y : -y);

The code between the equals sign and the semicolon is an expression. The parentheses are not necessary, but I find the conditional operator easier to read if I put it in parens.

Semicolon versus comma operator

In JavaScript, one uses the semicolon to chain statements:

    foo(); bar()

For expressions, there is the lesser-known comma operator:

    foo(), bar()

That operator evaluates both expressions and returns the result of the second one. Examples:

    > "a", "b"
'b' > var x = ("a", "b");
> x
'b' > console.log(("a", "b"));
b

Expressions that look like statements

Some expressions look like statements. We’ll examine why that is a problem at the end of this section.

Object literal versus block

The following is an object literal, an expression that produces an object.

    {
foo: bar(3, 5)
}

However, it is also a perfectly legal statement, with these components:

  • A block: a sequence of statements in curly braces.
  • A label: you can prefix any statement with a label. Here the label is foo.
  • A statement: the expression statement bar(3, 5).

{} being either a block or an object literal is responsible for the following WAT:

    > [] + {}
"[object Object]" > {} + []
0

Given that the plus operator is commutative, shouldn’t these two (expression) statements return the same result? No, because the second statement is equivalent to a code block followed by +[]:

    > +[]
0

For details on this and other WAT phenomena, consult [1].

JavaScript has stand-alone blocks? It might surprise you that JavaScript has blocks that can exist on their own (as opposed to being part of a loop or an if statement). The following code illustrates one use case for such blocks: You can give them a label and break from them.

    function test(printTwo) {
printing: {
console.log("One");
if (!printTwo) break printing;
console.log("Two");
}
console.log("Three");
}

Interaction:

    > test(false)
One
Three > test(true)
One
Two
Three

Function expression versus function declaration

The code below is a function expression:

    function () { }

You can also give a function expression a name and turn it into a named function expression:

    function foo() { }

The function name (foo, above) only exists inside the function and can, for example, be used for self-recursion:

    > var fac = function me(x) { return x <= 1 ? 1 : x * me(x-1) }
> fac(10)
3628800
> console.log(me)
ReferenceError: me is not defined

A named function expression is indistinguishable from a function declaration (which is, roughly, a statement). But their effects are different: A function expression produces a value (the function). A function declaration leads to an action – the creation of a variable whose value is the function. Furthermore, only a function expression can be immediately invoked, but not a function declaration.

Using object literals and function expressions as statements

We have seen that some expressions are indistinguishable from statements. That means that the same code works differently depending on whether it appears in an expression context or a statement context. Normally the two contexts are clearly separated. However, with expression statements, there is an overlap: There, you have expressions that appear in a statement context. In order to prevent ambiguity, the JavaScript grammar forbids expression statements to start with a curly brace or with the keywordfunction:

    ExpressionStatement :
[lookahead ∉ {"{", "function"}] Expression ;

So what do you do if you want to write an expression statement that starts with either of those two tokens? You can put it in parentheses, which does not change its result, but ensures that it appears in an expression-only context. Let’s look at two examples: evaland immediately invoked function expressions.

eval

eval parses its argument in statement context. If you want eval to return an object, you have to put parentheses around an object literal.

    > eval("{ foo: 123 }")
123
> eval("({ foo: 123 })")
{ foo: 123 }

Immediately invoked function expressions (IIFEs)

The following code is an immediately invoked function expression.

    > (function () { return "abc" }())
'abc'

If you omit the parentheses, you get a syntax error (function declarations can’t be anonymous):

    > function () { return "abc" }()
SyntaxError: function statement requires a name

If you add a name, you also get a syntax error (function declarations can’t be immediately invoked):

    > function foo() { return "abc" }()
SyntaxError: syntax error

Another way of guaranteeing that an expression is parsed in expression context is a unary operator such as + or !. But, in contrast to parentheses, these operators change the result of the expression. Which is OK, if you don’t need it:

    > +function () { console.log("hello") }()
hello
NaN

NaN is the result of applying + to undefined, the result of calling the function. Brandon Benvie mentions another unary operator that you can use: void [2]:

    > void function () { console.log("hello") }()
hello
undefined

Concatenating IIFEs

When you concatenate IIFEs, you must be careful not to forget semicolons:

    (function () {}())
(function () {}())
// TypeError: undefined is not a function

This code produces an error, because JavaScript thinks that the second line is an attempt to call the result of the first line as a function. The fix is to add a semicolon:

    (function () {}());
(function () {}())
// OK

With operators that are only unary (plus is both unary and binary), you can omit the semicolon, because automatic semicolon insertion kicks in.

    void function () {}()
void function () {}()
// OK

JavaScript inserts a semicolon after the first line, because void is not a valid way of continuing this statement [3].

Related posts

  1. What is {} + {} in JavaScript?
  2. The void operator in JavaScript
  3. Automatic semicolon insertion in JavaScript

最新文章

  1. Linux或Unix环境利用符号链接升级Maven
  2. 操作系统开发系列—13.e.三进程
  3. 透过统计力学,模拟软物质——EPJE专访2016年玻尔兹曼奖得主Daan Frenkel
  4. MySQL5.6 on Windows 安装失败: String was not recognized as a valid DateTime
  5. sql-where
  6. String使用equals方法和==分别比较的是什么?
  7. nodejs连接MySQL数据库
  8. mysql忘记root密码 + 授权登录
  9. 实现类似QQ的折叠效果
  10. 1018 Big Number
  11. Kubernetes存储之Persistent Volumes简介
  12. eregi
  13. 排序总结(java)
  14. SSIS使用事务回滚
  15. 收藏Dotnetbar的官方学习链接
  16. Ubuntu16.04下安装QQ的完整操作记录(经验证可用)
  17. pycharm中查找替换妙用
  18. 1001 A+B
  19. Hadoop本地库介绍及相关问题解决方法汇总
  20. [Python]南邮OJ代码备份爬虫

热门文章

  1. android软件开发之获取本地音乐属性
  2. 竞赛题解 - NOIP2018 保卫王国
  3. js 校验身份证号
  4. linux进程篇 (二) 进程的基本控制
  5. c语言杨氏矩阵算法
  6. linux 下的torrent下载器qBitTorrent
  7. SpaceVim 语言模块 elixir
  8. JavaScript基础part2
  9. 通过c#操作word文档的其他方式
  10. 成都Uber优步司机奖励政策(2月1日)