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
lab: function a () {}
console.log(lab) //ReferenceError: lab is not defined
在JavaScript中有两个重要但是容易混淆的语法类别:语句(statements)和表达式(expression)。
弄清楚它们之前的区别是很重要的。表达式可以当做语句来使用,我们称之为表达式语句;但是反过来,语句却不能被当做表达式。
表达式 -
Expression
表达式产生一个值
在JavaScript中,表达式是一个结果为一个值的代码片段。表达式可以是任意长度的,但是它们最终只能是一个单个值。
上面出现的每一行都是一个表达式,可以出现在JS代码中任意需要一个值的地方。
表达式不一定会改变状态
例如:
上面的后两行都是表达式,但是
aa
的值始终都是一开始的1。之所以用‘不一定’,是因为函数调用也是表达式,但是函数里可能包含语句从而改变状态:
如果要用更加优雅的方式来改变状态,应该这样改写:
这样的代码更加易读和可组合,并且能显式的区分表达式和语句,这也是函数式和声明式JS的基础。
语句 -
Statements
语句是函数式编程中令人头疼的东西。大概来说,语句就像一个动作,执行一个操作。
在JS中语句不能被用在需要值的地方。类似的地方有:函数的参数、赋值符号的右边、运算符的操作数、被
return
返回的值,等等。以下是JS中全部的语句:
如果你在浏览器的控制台中输入
if (true) {9+9}
,你可以看到控制台中会返回18
。但是你仍然不能把这段代码写在JS里需要一个值的地方。这很奇怪,你不期望语句返回任何内容,因为你不能使用它的返回值,即使返回了也是白搭。这就是JS给我们带来的,要学会接受 😩函数声明 vs 函数表达式 vs 命名函数表达式
函数声明是一个语句:
函数表达式是一个表达式(听起来像是废话 😆 ),也就是匿名函数:
命名函数表达式也是一个表达式,类似匿名函数,除了它有一个名字:
函数声明和命名函数表达式看起来非常类似(根本就是完全一样 😭 ),有一个比较好的方法区分它们:
无论何时,当你在JS中需要一个值的地方声明了一个函数,这个函数将被看做一个值,如果它不能被当做值处理就会抛出错误;
当你在一个顶层作用域声明了一个函数,它将被看做是函数声明。
立即执行函数
上面第一种写法会导致报错,而第二种是合法的。如果把一个匿名函数放到括号内,它会立即将这个匿名函数返回,所以可以在后面加上括号来立即调用这个匿名函数:
因为
funciton () {}
既可以被解析成表达式也可以被认为是声明语句,如果要用作立即调用函数,我们需要确保它是在表达式的上下文中被解析的,括号内的内容可以确保是处于表达式的上下文中,所以这种写法也可以通过:我们还可以用一些一元运算符来确保表达式的上下文环境:
使用
+
或者!
会改变原本的返回值,大部分情况下这没什么问题,如果你介意的话,可以使用关键字void
。如果是使用括号的话,当连接多个IIFE的时候需要注意了:
因为括号会被当做表达式,所以JS不会自动插入分号在行末,而是试图把他们连起来解析,就会抛出语法错误。手动插入分号可以避免这个问题:
表达式语句 -
Expression Statements
你只需要在表达式的最后添加一个分号,或者让JS的自动插入分号生效,就可以转化为语句。
2+2
或者foo()
本身是一个表达式,你可以将它们用在任何需要值的地方,但是上面整个一行(加上分号)算是一个语句,只能出现在上述表达式应该出现的地方。逗号 vs 分号
分号可以使多个表达式显示在一行。
逗号可以是多个表达式出现在一行,每一个表达式都会被计算,最后一个表达式会被当做结果返回。
像上面的
console.log
可以接受多个参数的场景,你可以使用括号将多个表达式包裹起来,告诉编译器这是一个整体。字面量对象 vs 块表达式
以上的代码都是在脚本顶层作用域下的合法的表达式。特别是第一个,
r
被称作标签,一个代码块的标签,可以被break
打断,但是并不意味着你在顶层作用域下有一个参数r
,它是无法被访问的:花括号允许你将任意的表达式和语句包裹在一起,JS会计算每一个语句或者表达式,并且返回最后一个表达式的值:
这种形式叫做块语句,和字面量对象有些相似,但是是不同的东西:
字面量对象是表达式,可以当做一个值使用,而块语句是一个语句,虽然它有返回值,但是我们却不能使用。
有些场景下,这两者的形式可能会让人迷惑:
上面这两个,可以是字面量表达式,也可以是块语句,至于到底是什么,取决于它们出现的位置:
第一种情况,
{}
被当做表达式使用,[] + {}
使对象转化为字符串;第二种情况{}
是一个块语句,那最后返回值其实就是+[]
的值,确实是0。还有一些更加过分的例子,但是只要记住:块语句虽然有返回值,却不可以被当做表达式使用:
参考链接