5

语句和表达式有什么不同 - chuckQu

 3 years ago
source link: https://www.cnblogs.com/chuckQu/p/16479740.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

语句和表达式有什么不同

JavaScript中的语句和表达式有什么不同之处?

对于这个问题,我似乎知道答案,但当我尝试向别人解释时,我却语塞了。对于这个问题我有一种感觉,但无法清晰的表达出来。

我后来才意识到,这个问题极其重要。它可以说是房屋的承重墙,将有助于支撑大量的JavaScript知识。

对React开发者来说,更为如此。你不得不记住的那些JSX规则,以及总是忘记遵守的那些规则,大部分都是 语句/表达式 双重性的结果。

在这篇文章中,我将分享我对这两者区别的一些感悟,以及我们如何在日常工作中使用这些信息。

从本质上来说,表达式是产生值的一段JavaScript代码。

下面所有的例子全部都是表达式:

  • 1 → 产生值为1
  • "hello" → 产生值为"hello"
  • 5 * 10 → 产生值为50
  • num > 100 → 产生值为true或者false
  • isHappy ? "?" : "?" → 产生值为一个emoji
  • [1, 2, 3].pop() → 产生值为3

表达式可以包含其他表达式。举例来说,你觉得下面的JS代码中有多少个表达式?

(5 + 1) * 2

答案是一共有5个表达式。

具体来说,分别是以下5个:

  1. (5 + 1) * 2 ,这段代码本身就是表达式,产生的值为12
  2. (5 + 1) ,由于有括号,这个子表达式首先求值,并解析为6
  3. 5,单个数字本身就是表达式,因为它们产生一个值。这个表达式解析为5
  4. 1,同样的道理,这个表达式解析为1
  5. 2,这个数字形成最后的表达式,它解析为2

一个JavaScript程序是一连串的语句。每条语句都是计算机做某件事的指令。

这里是有关JavaScript中语句的示例:

let hi = 5;
if (hi > 10) {
  // 更多语句
}
throw new Error('报错了');

关于语句和表达式,我是这么认为的:语句是支撑我们程序的刚性结构,而表达式则填充了细节。

语句中通常有表达式的 "插槽"。我们可以把任何我们喜欢的表达式放到这些插槽里。

举例来说,声明一个具有表达式插槽的变量可以这么做:

let hi = /* 表达式 */;

在这个插槽中,我们可以使用任何先前看到过的表达式:

let hi = 1;
let hi = "hello";
let hi = 5 * 10;
let hi = num > 100;
let hi = isHappy ? "?" : "?";
let hi = [1, 2, 3].pop();

就有效语法而言,表达式是可以互换的。如果一个语句有一个表达式插槽,我们可以把任何表达式放在那里,代码就会运行。并且我们不会得到语法报错。

也就是说,我们可能会遇到其他的问题。比如说,下面的代码在语法层面来说是有效的,但如果我们尝试运行就会让浏览器崩溃,因为它会导致死循环:

while ("hello") {
    // 因为"hello"永不改变,因此循环会一遍又一遍的重复,直到脚本崩溃。
    // 语法上是有效的,但仍是有问题的。
}

想知道一段JS代码到底是语句还是表达式吗?试着将它打印出来吧!

console.log(/* 这里是JS代码 */);

如果能够运行,该代码就是表达式。如果报错,那就是语句(当然,也有可能是非法JS)。

此外,我们甚至可以看到表达式的结果,因为会将结果打印到浏览器的控制台中。

这样可以凑效是因为任意函数的参数都必须是表达式。表达式会产生一个值,并将该值传递到函数中。语法并不会产生一个值,因此语句不能被用作函数的参数。

即使作为一个有经验的开发者,我也非常依赖console.log。它真的是一个好东西。

表达式作为语句

这是一个表达式:1 + 2 + 3

如果我们创建一个只包括这个表达式的JS文件,会发生什么?让我们试想把下面的内容保存为test.js

1 + 2 + 3

该文件中有多少个语句?0个还是1个?

事情是这样的:表达方式不能单独存在。它们总是语句的一部分。所以在这种情况下,我们有一个看起来像这样的语句:

/* 表达式插槽 */

除了表达式插槽之外,该语句基本上是空的。表达式1 + 2 + 3填充了该插槽,那么语句也就生成了。

换句话说,以下所有行都是有效的语句:

// 语句 1:
let hi = /* 表达式插槽 */;
// 语句 2:
return /* 表达式插槽 */;
// 语句 3:
if (/* 表达式插槽 */) { }
// 语句 4:
/* 表达式插槽 */

通常情况下,某些教程会错误地指出,表达式就是语句,但这并不完全正确。表达式和语句是不同的东西。但是语句有可能在不提供任何额外字符的情况下包裹住表达式。这就好像用透明的保鲜膜包裹住一个三明治。

语句通常以分号结尾,它标志着语句的结束。对某些语句来说分号不是必须的,如if语句、while循环和函数声明。

React中的实践

如果你曾使用过React,你可能知道大括号{}允许我们在JSX中嵌入一些JavaScript,就像这样:

function CountdownClock({ secondsRemaining }) {
  return (
    <div>
      Time left:
      {Math.round(secondsRemaining / 60)} minutes!
    </div>
  );
}

这就是React的神奇之处,它可以让我们拥有JavaScript的全部能力。

但有一个问题 — 我们不能在大括号里面放置任意JavaScript代码。具体来说,我们只能包括表达式,而不能包括语句。大括号本质上是在我们的JSX中创建一个表达式插槽。

如果我们尝试在大括号内嵌入一个语句,比如说if/else语句,我们会得到错误:

function CountdownClock({ secondsRemaining }) {
  return (
    // ? 语法报错
    <div>
      {if (secondsRemaining > 0) {
        `${secondsRemaining} seconds left`
      } else {
        "Time expired!"
      }}
    </div>
  );
}

这是因为语句不会产生值,只有表达式才会产生值。如果我们想在JSX中嵌入if/else逻辑,我们需要使用一个三元操作符表达式:

function CountdownClock({ secondsRemaining }) {
  return (
    // ✅ 没问题
    <div>
      {secondsRemaining > 0
        ? `${secondsRemaining} seconds left`
        : "Time expired!"
      }
    </div>
  );
}

这似乎是一个诡异的JSX/React限制,但它实际上是一个JavaScript限制。

我想我们经常责怪React的一些看似武断的规则,比如组件必须返回一个顶层元素。但更多的时候,React只是在警告我们一个关于JavaScript的限制。

理解语句和表达式的区别是非常重要的。我们还需要了解JSX是如何编译成JavaScript的,以及React的调度与渲染周期是如何工作的......但是,这些话题已经超出了本篇文章的范围。

一个JavaScript程序由一连串的语句组成。每个语句都是做某件事的指令,比如说,创建一个变量,运行一个if/else条件语句,或者开始一个循环。

表达式产生一个值,这些值被放入语句的插槽内。表达式始终是语句的一部分,即使该语句是空的。例如,下面的代码在运行一个循环时没有使用for语句,但它仍然包含一个”透明保鲜膜”语句:

data.forEach(item => console.log(item));

这种区别可能需要一段时间才能变得显而易见,希望这篇文章可以帮助到你。

以上就是本文的所有内容,欢迎点赞收藏转发~

原文链接:https://www.joshwcomeau.com/javascript/statements-vs-expressions/

作者:Joshua Comeau


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK