• 语句和表达式有什么不同


    前言

    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

  • 相关阅读:
    c语言字符函数和字符串函数
    leetcode995. K 连续位的最小翻转次数
    【Linux】C语言翻译过程
    TIS-prescan
    跨语言深入探讨如何实现方法增强:Java & Go的多策略实现
    含碘稀土铕(Ⅲ)配合物荧光微球/稀土铕配合物掺杂功能化二氧化硅微球的制备方法
    nvm安装与永久配置
    【证明】线性变换在两个基下的矩阵相似
    MySql 笔记
    应用层协议的实现
  • 原文地址:https://www.cnblogs.com/chuckQu/p/16479740.html