我之前问过this问题,在仔细考虑了这个话题之后,我开始想知道“陈述”和“表达”这两个术语的含义之间看似模糊的界限在哪里。所有陈述都是表达式吗? REPL控制台中的返回值来自哪里?它们似乎并不总是具有直观意义。当然,如果你输入1+1
,你会得到2
,但有时候它的逻辑并不明显。
鉴于在REPL中输入的任何内容都会产生一些价值,这是否意味着它可以在JS源代码中用作表达式和独立语句?
在下面的代码片段中可以用于_X_
的代码串也可用于_Y_
,反之亦然? if(_X_) _Y_
所有陈述都是表达式吗?
“无论JavaScript何时需要声明,您都可以编写表达式。这样的语句称为表达式语句。反过来说不成立:你不能写一个JavaScript期望表达式的语句。例如,if语句不能成为函数的参数。“
这是来自Axel Rauschmayer最近关于这个主题的文章:Expressions versus statements in JavaScript
希望能帮助到你。
据MDN说:
表达式是解析为值的任何有效代码单元。
因此,任何可以用作右值的东西都是表达式。
标准不是是否存在副作用。表达肯定会有副作用。例如。 a=2
是一个表达式,因为它有一个值(2)并且还为变量赋值。这就是为什么你可以这样做的原因:
let a;
let b = 1 + (a = 2); // a is now 2 and b is 3
根据上下文,相同(文本)代码块可以被视为表达式和语句。例如。文本片段function f(){}
是第1行的表达式,以及下面代码中第2行的语句:
let g = function f() {};
function f() {};
因此,无论某事物是表达还是陈述都不能(在一般情况下)通过查看脱离上下文的文本代码来确定;相反,它是语法树中节点的属性,只能在(精神上或实际上)解析代码之后才能确定。
此外,也许更重要的是,函数f
中的函数语句(a.k.a函数声明)构成了在调用函数f
时创建的执行上下文的一部分。但是,函数表达式不构成该执行上下文的一部分。
一个经常被引用的效果是函数声明被“提升”而函数表达却没有。
考虑到函数语句占用执行上下文中的空间而函数表达式不占用,在深度递归中也可以通过实验观察到更微妙的效果。例如。下面的代码使用函数f
的无限递归。函数f
在第一种情况下包含一个函数表达式,在第二种情况下它包含等效的函数声明:
// Function Expression
{
let i = 0;
try {
function f () {
i++;
(function g() {})(); // this is an expression
f();
}
f();
} catch (err) {
console.log(`Function Expressions case: depth of ${i} reached. Error: ${err.name}`);
}
}
// Function Declaration
{
let i = 0;
try {
function f () {
i++;
function g() {}; // this is a statement
g();
f();
}
f();
} catch (err) {
console.log(`Functions Declarations case: depth of ${i} reached. Error: ${err.name}`);
}
}
在我的机器上,我一直得到以下内容(在node.js中):
Function Expressions case: depth of 17687 reached. Error: RangeError
Functions Declarations case: depth of 15476 reached. Error: RangeError
...这与函数声明增加了保存执行上下文所需的空间量并因此更快地占用堆栈空间并因此略微减小最大递归深度的事实一致。
表达式生成或评估某些值。
表达式示例:new Date()
生成新的Date对象,没有任何副作用。 [1,2,3]
生成一个没有任何副作用的新阵列。 5+6
产生一个新的价值11.它只产生新的价值,没有任何副作用。
Statement会产生一些行为或做某事,它也有一些副作用。根据副作用,可以对报表进行分类。
x=5;
是一个声明,这里的副作用是x的赋值或变化。
setTimeout()
- 计时器的开始是副作用。
语句通常用分号分隔。
表达式语句是具有一些副作用或简单地“具有副作用的表达”的表达。
表达式语句的示例:
x+=6;
是复杂表达式(主表达式组)正在进行的赋值是副作用,因此称为表达式语句。
delete a[2];
在最简单的术语中,表达式被评估以产生值。另一方面,执行语句以使某些事情发生。
表达式:解析为值的代码单元,例如,文字和运算符。表达式的示例:
> 3
> 1 + 2
> "expression"
> fn()
> []
> {}
语句:表示一条或多条指令的代码单元,通常以语言保留关键字开头,并以语句终止符显式或隐式结束。陈述的例子:
> 3;
> let x = 3;
> if () {}
> for () {}
> while () {}
JavaScript中的所有程序都是由语句组成的,它们以分号结尾,除了用于对零个或多个语句进行分组的块语句。语句只是执行一些操作但不产生任何值或输出,而表达式返回一些值。当解释器看到表达式时,它会检索其值并用新值替换表达式。语句用于操纵这些表达式。你可以在这里查看它是表达式还是声明:JavaScript Parser
我强烈推荐阅读Axel Rauschmayer博士的综合博客文章 Expressions versus statements in JavaScript 正如@ ZER0在上面接受的答案中提到的那样。
但我最喜欢的内存快捷方式是:
表达:
e
可以设置E
qual到Expression
..orExpressed
通过打印它。 声明: ..还要别的吗。
以下内容经过修改 Anders Kaseorg's Quora answer。
语句是执行某些操作的完整代码行。
E
very E
xpression可以用作声明
(其作用是评估表达式,并忽略结果值)。
但是E
xpression是代码的任何部分,e
val对一个value
。
表达式可以使用运算符“水平”组合成更大的表达式。
E
有一个水平平顶
大多数语句不能用作表达式。
语句只能通过一个接一个地写入或使用块结构“垂直”组合。 相比之下,
S
垂直运行。
这是一般的经验法则:如果您可以打印它,或将其分配给变量,那么它就是一个表达式。如果你不能,那就是一个声明。
以下是一些表达式示例:
2 + 2
3 * 7
1 + 2 + 3 * (8 ** 9) - sqrt(4.0)
min(2, 22)
max(3, 94)
round(81.5)
"foo"
"bar"
"foo" + "bar"
None
True
False
2
3
4.0
以上所有内容都可以打印或分配给变量。
以下是一些陈述的例子:
if CONDITION:
elif CONDITION:
else:
for VARIABLE in SEQUENCE:
while CONDITION:
try:
except EXCEPTION as e:
class MYCLASS:
def MYFUNCTION():
return SOMETHING
raise SOMETHING
with SOMETHING:
上述构造都不能分配给变量。它们是有目的的语法元素,但它们本身并没有任何内在的“价值”。换句话说,这些结构不会“评估”任何东西。例如,尝试执行以下任何操作都是荒谬的,并且根本不起作用:
x = if CONDITION:
y = while CONDITION:
z = return 42
foo = for i in range(10):