学习 Gutenberg:现代 JavaScript 语法

Avatar of Andy Bell
Andy Bell 发布

DigitalOcean 为您旅程的每个阶段提供云产品。立即开始使用 200 美元的免费额度!

Gutenberg 带来的 WordPress 生态系统的一个关键变化是对 JavaScript 的大量依赖。值得庆幸的是,WordPress 团队通过利用现代 JavaScript 堆栈(社区中通常称为 ES6)真正将他们的 JavaScript 框架推向了现在和未来。这也是我们在本系列中提及它的方式,以避免混淆。

让我们深入了解一下这个 ES6 世界,因为它最终将帮助我们理解如何构建和构建自定义的 Gutenberg 块。

文章系列

  1. 系列介绍
  2. 什么是 Gutenberg?
  3. 使用 create-guten-block 的入门指南
  4. 现代 JavaScript 语法 (本文)
  5. React 101
  6. 设置自定义 webpack
  7. 自定义“卡片”块

什么是 ES6?

ES6 是“EcmaScript 6”的缩写,它是 EcmaScript 的第 6 版。它的正式名称是 ES2015,您可能也听说过。EcmaScript 后来经历了许多迭代,但现代 JavaScript 通常仍然被称为 ES6。正如您可能猜到的,迭代已经继续进行,包括 ES2016、ES2017 等等。我实际上在 ShopTalk 节目中提出了一个问题,关于我们如何命名现代 JavaScript,我的结论是……ES6。

我将介绍一些在 Gutenberg 上下文中很有用的 ES6 的关键特性。

函数

函数在 ES6 中得到了很大的更新。我想重点关注的两个变化是**箭头函数**和**类方法**。

在类中,您实际上不再需要在 ES6 中编写 function 这个词了。这可能会让人感到困惑,所以请查看以下示例

class Foo { 
  // This is your 'bar' function
  bar() {
    return 'hello';
  }
}

您可以像这样调用 bar()

const fooInstance = new Foo();
const hi = fooInstance.bar();

这在现代 JavaScript 的世界中很常见,所以澄清一下是很有必要的。

有趣的事实!JavaScript 中的 ES6 类在面向对象编程的意义上并不是真正的“类”——在底层,它仍然是 JavaScript 一直以来使用的旧的原型继承。在 ES6 之前,bar() 方法的定义方式如下:Foo.prototype.bar = function() { ... }。React 充分利用了 ES6 类,但值得注意的是,ES6 类本质上是语法糖,并且受到一些人的强烈质疑。如果您想了解更多详细信息,请查看MDN 文档2ality 上的这篇文章

好的,让我们继续讨论箭头函数。🚀

箭头函数为我们提供了一种紧凑的语法,通常用作表达式的单行代码。它还用于维护 this 的值,因为箭头函数不会像 setInterval 或事件处理程序那样重新绑定 this

以下是一个作为表达式的箭头函数示例

// Define an array of fruit objects
const fruit = [
  {
    name: 'Apple',
    color: 'red'
  },
  {
    name: 'Banana',
    color: 'yellow'
  },
  {
    name: 'Pear',
    color: 'green'
  }
];

// Select only red fruit from that collection
const redFruit = fruit.filter(fruitItem => fruitItem.color === 'red');

// Output should be something like Object { name: "Apple", color: "red" }
console.log(redFruit[0]);

如您所见,由于只有一个参数并且函数用作表达式,因此我们可以删除方括号和圆括号。这使我们能够真正压缩代码并提高可读性。

让我们看看如何在之前的 Foo 类中将箭头函数用作事件处理程序

class Foo {
        
  // This is your 'bar' function
  bar() {
    let buttonInstance = document.querySelector('button');
    
    buttonInstance.addEventListener('click', evt => {
      console.log(this);
    });
  }
}

// Run the handler
const fooInstance = new Foo();
fooInstance.bar();

单击按钮时,输出应为 Foo { },因为 thisFoo 的实例。如果我们用以下内容替换该示例

class Foo {
        
  // This is your 'bar' function
  bar() {
    let buttonInstance = document.querySelector('button');
    
    buttonInstance.addEventListener('click', function(evt) {
      console.log(this);
    });
  }
}

// Run the handler
const fooInstance = new Foo();
fooInstance.bar();

单击按钮时,输出将为 <button>,因为该 function 已将 this 绑定到被单击的 <button>

您可以阅读更多关于箭头函数的信息,作者是 Wes Bos,他写了一篇关于它们的精彩文章

const、let 和 var

您可能已经注意到,我在上面的示例中使用了 constlet。这些也是 ES6 的一部分,我将快速解释每个的作用。

如果某个值绝对恒定并且不会通过重新赋值或重新声明而改变,请使用 const。这通常用于导入某些内容或声明不变的属性,例如 DOM 元素的集合。

如果您有一个变量,希望它只能在其定义的块中访问,则使用 let。这可能难以理解,所以请查看以下小示例

function foo() {
  if (1 < 2) {
    let bar = 'always true';
    
    // Outputs: 'always true'
    console.log(bar);
  }
  
  // Outputs 'ReferenceError: bar is not defined'
  console.log(bar);
}

// Run the function so we can see our logs
foo();

这是一种很好地控制变量并使其在某种意义上可丢弃的方法。

最后,var 是我们熟悉和喜爱的旧朋友。不幸的是,在 constlet 之间,随着时间的推移,我们的朋友变得越来越冗余。使用 var 绝对是可以接受的,所以不要灰心——您在本文档的其余部分中不会经常看到它!

解构赋值

解构允许您在将对象键赋值给本地变量时提取它们。所以,假设您有以下对象

const foo = {
  people: [
    {
      name: 'Bar',
      age: 30
    },
    {
      name: 'Baz',
      age: 28
    }
  ],
  anotherKey: 'some stuff',
  heyAFunction() {
    return 'Watermelons are really refreshing in the summer' 
  }
};

传统上,您将使用 foo.people 提取 people。使用解构,您可以这样做

let { people } = foo;

这会从 foo 对象中提取 people 数组,因此我们可以删除 foo. 前缀并按原样使用它:people。这也意味着 anotherKeyheyAFunction 被忽略了,因为我们现在不需要它们。当您处理大型复杂对象时,能够选择性地提取内容非常有用。

您还可以利用解构将对象分解为局部变量以提高代码可读性。让我们更新上面的代码段

let { people } = foo;
let { heyAFunction } = foo;

现在我们从同一个对象中获得了这两个单独的元素,同时仍然忽略 anotherKey。如果您运行 console.log(people),它将显示自身是一个数组;如果您运行 console.log(heyAFunction),您猜对了,它将显示自身是一个函数。

JSX

最常出现在 React JS 上下文中:JSX 是 JavaScript 的一种类似 XML 的扩展,旨在由预处理器编译成普通的 JavaScript 代码。从本质上讲,它使我们能够在 JavaScript 中编写 HTML(ish)代码,只要我们对其进行预处理。它通常与 React JS 等框架相关联,但也用于 Gutenberg 块开发。

让我们从一个示例开始

const hello = <h1 className="heading">Hello, Pal</h1>;

很酷,对吧?不需要模板系统、转义或连接。只要您返回单个元素(可以有多个子元素),就可以了。因此,让我们展示一些更复杂的内容,以及一个 React 渲染函数

class MyComponent extends React.Component {
  /* Other parts redacted for brevity */
  
  render() {
    return (
      <article>
        <h2 className="heading">{ this.props.heading }</h2>
        <p className="lead">{ this.props.summary }</p>
      </article>
    );
  }
};

您可以在上面看到,我们可以在任何我们想要的地方插入表达式。元素属性也是如此,因此我们可以有类似这样的内容

<h2 className={ this.props.headingClass }> 
  { this.props.heading }
</h2> 

您可能在想,“这些随机的花括号在做什么?”

答案是这是一个表达式,您将在 JSX 中看到很多这样的内容。从本质上讲,它是在 JavaScript 中进行的小型内联执行,其行为与 PHP echo 非常相似。

您可能还会注意到它使用的是 className 而不是 class。虽然它看起来像 HTML/XML,但它仍然是 JavaScript,因此自然会避免保留字。属性也使用驼峰命名法,所以要注意这一点。这是一个关于为什么是这样的有用的答案。

正如您在本系列的后续内容中将看到的,JSX 非常强大。它是我们堆栈中的一个很棒的工具,并且通常理解它非常有用。

我喜欢将 JSX 视为由虚构标签名组成的,这些标签名实际上只是函数调用。挑选出您在 Gutenberg 中看到的任何虚构标签,例如 <InspectorControls />,然后对 class InspectorControls 执行“在文件夹中查找”,您将看到类似 Andy 在此处的示例的内容!如果您找不到它,则 JSX 必须注册为函数组件,并且应该通过搜索 function InspectorControls 来查找。

总结

我们快速浏览了 ES6 的一些有用特性。还有很多东西需要学习,但我希望将你的注意力集中在我们将在本教程系列中使用的内容上。我强烈建议你通过 Wes Bos 的课程进一步学习,JavaScript 30ES6.io

接下来,我们将构建一个迷你 React 组件!


文章系列

  1. 系列介绍
  2. 什么是 Gutenberg?
  3. 使用 create-guten-block 的入门指南
  4. 现代 JavaScript 语法 (本文)
  5. React 101
  6. 设置自定义 webpack
  7. 自定义“卡片”块