通配符或星号 (*) 与命名或选择性导入 es6 javascript
Wildcard or asterisk (*) vs named or selective import es6 javascript
只是想知道哪个是使用导入的最佳方式:
import * as Foo from './foo';
对比:
import { bar, bar2, bar3 } from './foo';
在效率方面,例如,我使用 webpack 来捆绑所有 JavaScript 文件。即使我没有在主代码中使用它们,第一个实际上会导入所有内容吗?
我能找到的一些参考文献是:
在Airbnb style guide, they are recommending no wildcard so there will always be default import object, and this.
如果您使用带有新 uglify 提供的死代码消除的 webpack,或带有 tree-shaking 的 rollupjs,那么未使用的导入将被删除。
我部分同意 airbnb 风格指南不使用通配符导入,尽管 javascripts 通配符导入不会遭受与例如 pythons 或 javas 通配符导入相同的疾病,即它不会污染定义变量名的范围在其他模块中(您只能通过 moduleB.foo
访问它们,而在使用 import * as moduleB from ...
时不能通过 foo
访问它们)。
关于测试的文章:我有点理解这些担忧,但我没有看到那里无法解决的问题。您可以使用一些自定义模块加载器模拟导入本身(自定义 amd 模块加载器实际上是 15 行代码),因此您不必弄乱测试模块的本地范围。
我同意@Tamas。
如果您需要对目标文件中所有导出的完全访问权限,那么您可以使用 import * as Foo from './foo';
要么
import foo from './foo':
但是如果您需要使用特定的函数或常量,那么最好避免使用 "import *" 并明确说明您需要做什么。
关于这部分问题:
Will the first one actually importing everything even though I'm not using them in the main code?
下面是它是如何用 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 的大小略有增加。
因为,使用现代 WebPack 设置,两者将生成相同的 compiled/transpiled JS,命名导入的真正价值在于它的表现力。通过命名您的导入,您是在告诉任何打开文件的人,您将使用模块中的哪些功能。这可能有用的一个例子是在编写测试时,如果需要模拟,你有一个明确的导入列表来模拟。
只是想知道哪个是使用导入的最佳方式:
import * as Foo from './foo';
对比:
import { bar, bar2, bar3 } from './foo';
在效率方面,例如,我使用 webpack 来捆绑所有 JavaScript 文件。即使我没有在主代码中使用它们,第一个实际上会导入所有内容吗?
我能找到的一些参考文献是:
在Airbnb style guide, they are recommending no wildcard so there will always be default import object, and this.
如果您使用带有新 uglify 提供的死代码消除的 webpack,或带有 tree-shaking 的 rollupjs,那么未使用的导入将被删除。
我部分同意 airbnb 风格指南不使用通配符导入,尽管 javascripts 通配符导入不会遭受与例如 pythons 或 javas 通配符导入相同的疾病,即它不会污染定义变量名的范围在其他模块中(您只能通过 moduleB.foo
访问它们,而在使用 import * as moduleB from ...
时不能通过 foo
访问它们)。
关于测试的文章:我有点理解这些担忧,但我没有看到那里无法解决的问题。您可以使用一些自定义模块加载器模拟导入本身(自定义 amd 模块加载器实际上是 15 行代码),因此您不必弄乱测试模块的本地范围。
我同意@Tamas。
如果您需要对目标文件中所有导出的完全访问权限,那么您可以使用 import * as Foo from './foo';
要么
import foo from './foo':
但是如果您需要使用特定的函数或常量,那么最好避免使用 "import *" 并明确说明您需要做什么。
关于这部分问题:
Will the first one actually importing everything even though I'm not using them in the main code?
下面是它是如何用 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 的大小略有增加。
因为,使用现代 WebPack 设置,两者将生成相同的 compiled/transpiled JS,命名导入的真正价值在于它的表现力。通过命名您的导入,您是在告诉任何打开文件的人,您将使用模块中的哪些功能。这可能有用的一个例子是在编写测试时,如果需要模拟,你有一个明确的导入列表来模拟。