当import/export、require/module.exports 混用时, 你能分清吗?

ES6的模块化: import export default

common.js的模块化: require module.exports node.js使用该规范

为什么有模块概念

理想情况下,开发者只需要实现核心的业务逻辑,其他都可以加载别人已经写好的模块。

但是,Javascript不是一种模块化编程语言,在es6以前,它是不支持”类”(class),所以也就没有”模块”(module)了。同时以前也没有webpack这样的工具,可以使用node去操作文件,读取文件内容, 然后达到引入文件内容的目的.(也就是模块化)--在不同的文件中放着不同的功能模块

Common.js

首先需要明白的在node中每个文件都是一个自执行函数(只不过我们肉眼凡胎看不出来,哈啊哈)

(function (exports, require, module, __filename, __dirname) {
    module.exports = exports = this
    return module.exports
})()
复制代码

为了说明module.exports = exports = this请看下面例子

a.js

this.a = 123  // 第一种
exports.a = 123   //第二种
module.exports.a = 123  // 第三种
复制代码

b.js

let a = require('./a')
console.log(a)
复制代码

效果:

ES6中的模块化

import/export

export defaultexport 的区别
  1. 在一个文件或模块中 export 可以有多个,但 export default 仅有一个
  2. 通过 export 方式导出,在导入时要加 { },而 export default 则不需要
1.export
//a.js
export const str = "小生方勤";
//b.js
import { str } from 'a';   // 导入的时候需要花括号

2.export default
//a.js
const str = "小生方勤";
export default str;
//b.js
import str from 'a';      // 导入的时候无需花括号
复制代码

export default const a = 1; 这样写是会报错的哟。

es6 的导出模块写法有

export default 123;

export const a = 123;

const b = 3;
const c = 4;
export { b, c };
复制代码

虽然我们一般在像Vue一些框架中都可以使用Es6的语法进行导入导出,但是babel 会将这些统统转换成 commonjs 的 exports。

exports.default = 123;
exports.a = 123;
exports.b = 3;
exports.c = 4;
exports.__esModule = true;
复制代码

babel 转换 es6 的模块输出逻辑非常简单,即将所有输出都赋值给 exports,并带上一个标志 __esModule 表明这是个由 es6 转换来的 commonjs 输出。

babel将模块的导出转换为commonjs规范后,也会将引入 import 也转换为 commonjs 规范。即采用 require 去引用模块,再加以一定的处理,符合es6的使用意图。

也就是所有最后通过webpack打包后都将转化为common.js的规范

引入 default

对于最常见的

import a from './a.js';
复制代码

在es6中 import a from './a.js' 的本意是想去引入一个 es6 模块中的 default 输出。

通过babel转换后得到 var a = require(./a.js) 得到的对象却是整个对象,肯定不是 es6 语句的本意,所以需要对 a 做些改变。

我们在导出提到,default 输出会赋值给导出对象的default属性。

exports.default = 123;
复制代码

所以这里最后的 a 变量就是 require 的值的 default 属性。如果原先就是commonjs规范的模块,那么就是那个模块的导出对象。

引入 * 通配符

我们使用 import * as a from './a.js' es6语法的本意是想将 es6 模块的所有命名输出以及defalut输出打包成一个对象赋值给a变量。

已知以 commonjs 规范导出:

exports.default = 123;
exports.a = 123;
exports.b = 3;
exports.__esModule = true;
复制代码

那么对于 es6 转换来的输出通过 var a = require('./a.js') 导入这个对象就已经符合意图。

import { a } from './a.js'

import { a } from './a.js' 直接转换成 require('./a.js').a 即可。

总结

经过上面的转换分析,我们得知即使我们使用了 es6 的模块系统,如果借助 babel 的转换,es6 的模块系统最终还是会转换成 commonjs 的规范。所以我们如果是使用 babel 转换 es6 模块,混合使用 es6 的模块和 commonjs 的规范是没有问题的,因为最终都会转换成 commonjs。

问题

为何有的地方使用 require 去引用一个模块时需要加上 default?

require('xx').default

我们在上文 babel 对导出模块的转换提到,es6 的 export default 都会被转换成 exports.default,即使这个模块只有这一个输出。

我们经常会使用 es6 的 export default 来输出模块,而且这个输出是这个模块的唯一输出,我们会误以为这种写法输出的是模块的默认输出。

// a.js

export default 123;
复制代码
// b.js 错误

var foo = require('./a.js')
复制代码

在使用 require 进行引用时,我们也会误以为引入的是a文件的默认输出。

结果这里需要改成 var foo = require('./a.js').default

这个场景在写 webpack 代码分割逻辑时经常会遇到。

require.ensure([], (require) => {
   callback(null, [
     require('./src/pages/profitList').default,
   ]);
 });
复制代码
模块依赖的优化

模块依赖的优化

我们在使用各大 UI 组件库时都会被介绍到为了避免引入全部文件,请使用 babel-plugin-component 等babel 插件。

import { Button, Select } from 'element-ui'
复制代码

由前文可知 import 会先转换为 commonjs, 即

var a = require('element-ui');
var Button = a.Button;
var Select = a.Select;
复制代码

var a = require('element-ui'); 这个过程就会将所有组件都引入进来了。

所以 babel-plugin-component就做了一件事,将 import { Button, Select } from 'element-ui' 转换成了

import Button from 'element-ui/lib/button'
import Select from 'element-ui/lib/select'
复制代码

即使转换成了 commonjs 规范,也只是引入自己这个组件的js,将引入量减少到最低。

所以我们会看到几乎所有的UI组件库的目录形式都是

|-lib
||--component1
||--component2
||--component3
|-index.common.js
复制代码

index.common.jsimport element from 'element-ui' 这种形式调用全部组件

给个element的链接去看看吧 :element.eleme.cn/#/zh-CN/com…

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值