揭开 React 警告和错误的第一步-了解语句和表达式

109 阅读5分钟

原文链接:www.joshwcomeau.com/javascript/…

作者:Joshua Comeau

声明 VS 表达式

去年面试时,一个面试官问我:

JavaScript 中的语句表达式有什么区别?

我讲不清他两准确的区别😅,只能举了几个例子说明这是表达式,这是语句,这是表达式。

面试结束后我决定,好好的搞清楚他们。

对于 React 开发人员

如果您使用过 React,您可能知道花括号( { 和 } )允许我们在 JSX 中嵌入一些 JavaScript,如下所示:

function Demo() {
  return (
    <div>
      {1+1} 
    </div>
  );
}

如果我们尝试在此处嵌入一个语句,例如 if/else 语句,我们将得到一个错误:

function Demo() {
  return (
    // 🚫 抛出一个错误
    <div>
      {if (1 > 0) {
        `正确的`
      } else {
        "错误的"
      }}
    </div>
  );
}

很多开发者认为这是一个奇怪的 JSX/React 限制,

但它实际上是一个 JavaScript 限制。

因为在JSX中是不能插入语句,只能插入表达式。很多开发者遇到这个问题,都仅是记住他,并没有深入的去研究他。

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

Expressions 表达式

表达式的核心是能生成一些值的 JavaScript 代码

例如,这些都是表达式

  • 1 → 生成 1
  • "hello" → 生成 "hello"
  • 5 * 10 → 生成50
  • num > 100 → 生成 true 或 false
  • isHappy ? "🙂" : "🙁" → 生成表情符号
  • [1, 2, 3].pop() → 生成数字 3

Statements 语句

JavaScript 程序就是一系列语句。每条语句都是让计算机做某事的指令。

例如,这些都是语句

let hi = 5;
if (hi > 10) {
  // More statements here
}
throw new Error('Something exploded!');

我喜欢将他们想象成:语句是将我们的程序的结构,而表达式填充细节

语句通常有表达式的。我们可以将任何表达式放入这些插槽中。

例如,声明一个有表达式槽的变量:

let hi = /* some expression */;

我们可以在槽中插入的任何表达式:

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”没有改变,循环会一直运行
}

如何判断呢?

使用console.log()就能知道一段 JS 代码是表达式还是语句

console.log(/* 这有一些JS的代码 */);

如果它运行,代码就是一个表达式。如果你得到一个错误,它是一个语句(或者,可能是无效的 JS)。

我们甚至可以看到表达式解析的内容,因为它将打印在浏览器控制台中!

为何可行呢?

因为所有函数参数都必须是表达式。表达式产生一个值,该值将传递给函数。语句不产生值,因此不能用作函数参数。

没想到用 console.log 解决了这个问题吧!

Expressions as statements 表达式作为语句

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

如果我们创建一个只包含这个表达式的 JS 文件会发生什么?假设我们将以下内容保存为 test.js :

1 + 2 + 3

这个文件有多少条语句?零还是一个?

要知道:表达式不能单独存在。它们始终是声明的一部分。所以在这种情况下,我们有一个看起来像这样的声明:

/* 表达式槽 */

除了它的表达式槽外,该语句是空的。我们的表达式 1 + 2 + 3 填充了这个槽,我们的语句就完成了。

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

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

通常,很多教程会错误告诉大家表达式就是语句,但这并不完全正确。

表达式和语句是不同的东西。只能说语句在没有额外字符的情况下包裹着表达式,他两才一致。

可以把它想象成用透明收缩包装纸包裹三明治。

语句通常以分号结尾,分号表示语句结束。某些语句不需要分号,例如 if 语句、 while 循环和函数声明。

还记得上面那个Reactif else代码吗

如果我们想在我们的 JSX 中嵌入 if/else 逻辑,我们需要使用三元运算符表达式:

function Demo() {
  return (
    // ✅ 没问题
    <div>
      {1 > 0
        ? `正确的`
        : "错误的"
      }
    </div>
  );
}

这可能看起来像是一个奇怪的 JSX/React 限制,但它实际上是一个 JavaScript 限制。

我认为我们经常责怪 React 看似武断的规则,比如组件必须只能返回一个标签。

但通常情况下,React 只是警告我们 JavaScript 的限制

总结

  • JavaScript 由一系列语句组成。每个语句都是执行某项操作的指令,例如创建变量、运行 if/else 条件或启动循环。

  • 表达式产生一个值,这些值被放入语句中。

  • 表达式始终是语句的一部分,即使该语句在其他方面为空。

例如,下面的代码在不使用 for 语句的情况下运行一个循环,它仍然包含一个空包裹器的语句:

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

最后希望你理解了这两者的区别!

全文完。

谢谢!

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 6 天

点击查看活动详情