通配符或星号 (*) 与命名或选择性导入 es6 javascript

问题描述 投票:0回答:4

只是想知道哪个是使用导入的最佳方式:

import * as Foo from './foo';

对:

import { bar, bar2, bar3 } from './foo';

在效率方面,例如,我使用 webpack 来打包所有的 JavaScript 文件。即使我没有在主代码中使用它们,第一个实际上会导入所有内容吗?

我能找到的一些参考资料是:

Airbnb 风格指南 中,他们建议不要使用通配符,因此将始终有默认导入对象,并且 this.

javascript import ecmascript-6 wildcard es6-modules
4个回答
46
投票

如果你使用带有新 uglify 提供的死代码消除的 webpack,或带有 tree-shaking 的 rollupjs,那么未使用的导入将被删除。

我部分同意 airbnb styleguide 不使用通配符导入,尽管 javascripts 通配符导入不会遭受与 pythons 或 javas 通配符导入相同的疾病,即它不会污染其他模块中定义的变量名的范围(你只能通过

moduleB.foo
访问它们,而不是
foo
使用
import * as moduleB from ...
)。

关于测试的文章:我有点理解这些担忧,但我没有看到那里无法解决的问题。您可以使用一些自定义模块加载器模拟导入本身(自定义 amd 模块加载器实际上是 15 行代码),因此您不必弄乱被测试模块的本地范围。


36
投票

关于这部分问题:

即使我没有在主代码中使用它们,第一个实际上会导入所有内容吗?

下面是它是如何用 Babel 6.26 编译的:

有名

import { bar, bar2, bar3 } from './foo';

...变成...

'use strict';

var _foo = require('./foo');

通配符

import * as Foo from './foo';

...变成...

'use strict';

var _foo = require('./foo');

var Foo = _interopRequireWildcard(_foo);

function _interopRequireWildcard(obj) { 
    if (obj && obj.__esModule) { 
        return obj;
    } else {
        var newObj = {}; 
        if (obj != null) { 
            for (var key in obj) { 
                if (Object.prototype.hasOwnProperty.call(obj, key))
                    newObj[key] = obj[key];
            }
        }
        newObj.default = obj; 
        return newObj;
    }
}

在这两种情况下,整个文件都是通过

require
导入的。

使用通配符导入,定义了一个

_interopRequireWildcard
函数并用于将所有导出分配给命名空间变量。

值得注意的是,编译后的代码将只包含一个

_interopRequireWildcard
定义,以及一次调用
require
_interopRequireWildcard
每次导入。

最终,使用通配符导入将在运行时涉及更多处理,并导致编译后的 js 的大小略有增加。


10
投票

因为,使用现代 WebPack 设置,两者将生成相同的编译/转译 JS,命名导入的真正价值在于它的表现力。通过命名您的导入,您是在告诉任何打开文件的人,您将使用模块中的哪些功能。这可能有用的一个例子是在编写测试时,如果需要模拟,你有一个明确的导入列表来模拟。


8
投票

我同意@Tamas。
如果您需要对目标文件中所有导出的完全访问权限,那么您可以使用

import * as Foo from './foo';
或者
import foo from './foo':

但是如果您需要使用特定的函数或 const,那么最好避免“导入 *”并明确说明您需要做什么。

© www.soinside.com 2019 - 2024. All rights reserved.