易错点详解解 Babel 编译构造函数的问题

阅读时长 7 分钟读完

前言

对于前端开发者来说,Babel 是一个相对高阶的工具,旨在让我们在编写高级 JavaScript 时,使代码能够在翻译为低版本的 JavaScript 时得到支持。它提供了许多优化、转换和语法支持。但是,在使用 Babel 编译构造函数时,我们容易遇到一些问题。这篇文章将详细讲解这个问题及其解决方案,以帮助我们编写更好的代码,更好地使用 Babel。

问题描述

让我们从一个例子开始。考虑以下代码:

-- -------------------- ---- -------
----- ------- -
  ------------- -
    ----------- - ----------
  -
-
  ---------- -
    -------------------------
  -
-

这是一个简单的 ES6 类,具有一个构造函数和一个方法。Babel 可以将这个代码翻译成 ES5 代码,如下所示:

-- -------------------- ---- -------
---- --------
-------- ------------------------- ------------ - -- ----------- ---------- ------------- - ----- --- ----------------- ---- - ----- -- - ----------- - -

--- ------- - -------- --------- -
  --------------------- ---------

  ----------- - ----------
--

-------------------------- - -------- -- -
  -------------------------
--

这段代码定义了一个可以在 ES5 环境中工作的对象,其中包含一个用于实例化类的构造函数和一个对象方法。然而,如果您实际运行这些代码,您会发现使用它们时会遇到一些问题。

让我们使用 ES5 代码创建一个实例并调用类的方法:

这意味着调用对象方法时,myProp 的值为 undefined。 本应该输出 “myValue”,而输出却是 “undefined”。为什么会这样呢?

原因分析

这个问题与 Babel 编译构造函数时的一个内在问题有关。你会看到,Babel 翻译构造函数时会在构造函数中添加一个 _createClass 函数。如下所示:

-- -------------------- ---- -------
---- --------
-------- ------------------------- ------------ - -- ----------- ---------- ------------- - ----- --- ----------------- ---- - ----- -- - ----------- - -

-------- ------------------------- ----------- ------------ -
  -- ------------ ---------------------------------------- ------------
  -- ------------- ------------------------------ -------------
  ------ ------------
-

--- ------- - --------------------- --------- -
  --------------------- ---------

  ----------- - ----------
-- -
  --------- -
    ------ -------- ---------- -
      -------------------------
    --
    ----------- ------
    ------------- -----
    --------- ----
  -
-- ------

我们可以看到,当翻译构造函数时,Babel 调用 _createClass 函数,该函数创建了一个构造函数和一个对象方法。该函数还将对象方法添加到构造函数的原型上。以上所有内容看起来都很不错,因此我们应该不会遇到任何问题。 但是,这里涉及到的 _createClass 函数中的一些东西可能使我们感到困惑。让我们先看看 _createClass 的第一行:

该函数需要三个参数。尽管我们不需要传递第二个和第三个参数,但我们需要了解它们的含义:

  • protoProps:用于设置构造函数原型的对象属性。
  • staticProps:用于设置构造函数的静态(类)属性的对象属性。

所以,这是关键部分——在我的例子中,Babel 返回的构造函数的原型根本没有传入 protoProps

因此,构造函数不会继承来自超类的方法,例如 toString 甚至是由于默认值带来的 constructor

因此,实际执行的代码行为可能与预期的不同。这就是为什么我们在调用“myMethod()”时获得“undefined”的原因。

解决方案

解决这个问题的方法很简单。我们需要将 _createClass 的条件语句中的 protoProps 替换为 protoProps && protoProps.hasOwnProperty("constructor")。这将检查protoProps中是否存在 constructor 属性。如果不存在,则跳过处理原型。这使得原型正确地继承并修复了上述示例代码中出现的问题。

因此,我们可以手动更改由 Babel 产生的输出代码,或者使用 Babel 插件(例如 @babel/plugin-transform-classes)来自动完成此操作。让我们看看如何自动处理这个问题。

为此,我们将使用以下 .babelrc 配置文件:

-- -------------------- ---- -------
-
  ---------- -
    ----------------------------------
    ------------------------------------------
    ----------------------------------
    ----------------------------------- -
        -------- ----
    --
  -
-

@babel/plugin-transform-runtime@babel/plugin-proposal-class-properties 是常见插件,但是我们需要注意的是 @babel/plugin-transform-classes。我们在进行 Babel 转换时,需要使用“loose”属性。这将确保 _createClass 内部的检查语句如预期一样工作,修改后的 _createClass 代码如下:

现在,我们可以再次使用与上述代码中类似的代码,但这次我们将能够正确地执行它:

总结

在本文中,我们讲述了一个常见的 Babel 编译构造函数的问题。我们详细解释了为什么会发生这种情况,以及如何解决问题。我们还考虑了如何使用 Babel 插件来避免这种问题。在阅读完本文后,我们希望您能够更好地了解 Babel 的工作方式,并能够构建不会出现任何问题的代码。

来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/6457039e968c7c53b09e1dee

纠错
反馈