只是想知道使用import的最佳方式是哪一种:
import * as Foo from './foo';
VS:
import { bar, bar2, bar3 } from './foo';
就效率而言,比如说,我正在使用webpack来打包所有的JavaScript文件。即使我在主代码中没有使用它们,第一个文件是否会导入所有内容?
一些我能找到的参考资料是:
在Airbnb风格指南中,他们建议不要使用通配符,这样就会始终有默认的导入对象,以及this。
只是想知道使用import的最佳方式是哪一种:
import * as Foo from './foo';
VS:
import { bar, bar2, bar3 } from './foo';
如果您使用webpack与新的uglify提供的死代码消除,或者使用tree-shaking的rollupjs,则未使用的导入将被剥离。
我部分同意airbnb风格指南不使用通配符导入,尽管JavaScript的通配符导入不像例如Python或Java的通配符导入那样患有相同的问题,即它不会在范围内污染由其他模块定义的变量名称(当使用import * as moduleB from ...
时,您只能通过moduleB.foo
而不是foo
来访问它们)。
关于测试文章:我有点理解这些问题,但我认为没有什么是不能解决的。您可以使用一些自定义模块加载器(自定义amd模块加载器只需15行代码)来模拟导入本身,因此您无需干扰已测试模块的本地作用域。
import * as Foo from './foo'
,并且只使用 Foo.bar
,那么 Foo.bar2
和 Foo.bar3
会被消除为死代码吗? - brietsparksFoo.bar2
和 Foo.bar3
完全没有被使用。 - Tamas Hegedus关于问题的这个部分:
即使我在主要代码中没有使用它们,第一个是否会实际导入所有内容?
以下是使用 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设置下,两者将生成相同的编译/转译JS代码,因此命名导入的真正价值在于它更加表达。通过为导入命名,您告诉打开文件的任何人您将使用哪个模块中的函数。这种方法有助于编写测试时,如果需要模拟,您就可以获得一个明确的导入列表以进行模拟。
我同意 @Tamas 的观点。
如果你需要在目标文件中完全访问所有导出,那么可以使用 import * as Foo from './foo';
或者 import foo from './foo':
但是,如果你需要使用特定的函数或常量,则最好避免使用 "import *" 并明确说明你需要做什么。