当心,babel 处理 Symbol 的麻烦

在使用 babel 转换 ES next 代码的时候,并不会将 Symbol 直接转换成 ES5 中对应的内容,需要引入额外的 polyfill 才能正常工作。

有的团队为了避免引入这个额外的 polyfill ,会选择不使用 Symbol ,包括通过 babel 生成 Symbol 的特性(比如 for of 等)。

这时候就会有个比较隐蔽的地方需要注意,就是尽量不要让 babel 生成这样的代码:

var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };

这个里面包含了一个 Symbol ,为了让 Symbol 不至于报错,又要想办法在全局先声明一下 Symbol 变量,比较丑陋。

目前在实践中,发现这样的 ES next 代码会生成上述代码:

function fn1() {
    if (1) {
        let a = 1;
        filter(function fn() {
            console.log(a);
        });
        return;
    }
}

生成的代码为:

"use strict";

var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };

function fn1() {
    if (1) {
        var _ret = function () {
            var a = 1;
            filter(function fn() {
                console.log(a);
            });
            return {
                v: void 0
            };
        }();

        if ((typeof _ret === "undefined" ? "undefined" : _typeof(_ret)) === "object") return _ret.v;
    }
}

这段代码有什么特征呢?就是在 if 块中定义了函数,函数中访问了 if 块中的“块级变量”,并且 if 块使用了 return 语句。

可以看出,babel 为了保证 if 块内变量的作用域,会套一个匿名函数,同时由于 if 块中存在 return 返回,所以就用 _ret 来接收匿名函数的返回值。然后后面为啥会生成那串长长的对 _ret 的类型判断代码,目前还不太清楚,可能要结合 babel 的内部处理逻辑去看了,单从生成的代码看,这个完全是多余的。

推而广之, for 块等局部非函数作用域都会有类似的问题。

实际上,从代码编写规范角度来看,是不应该在这种局部作用域块里面定义函数的。函数应该是一段通用的代码,不应该缩在那一小块里面。

你可能感兴趣的:(当心,babel 处理 Symbol 的麻烦)