ES6与CommonJS中的模块处理的区别


Posted in Javascript onJune 13, 2018

ES6和CommonJS都有自己的一套处理模块化代码的措施,即JS文件之间的相互引用。

为了方便两种方式的测试,使用nodejs的环境进行测试

CommonJS的模块处理

使用require来引入其他模块的代码,使用module.exports来引出

// exportDemo.js
count = 1;
module.exports.count = count;
module.exports.Hello = function() {
 var name;
 this.setName = function(newName) {
 name = newName;
 }
 this.sayHello = function() {
 console.log("hello Mr." + name);
 }
 this.getId = function() {
 return count++
 }
}
// requireDemo.js
var {Hello} = require("./exportDemo")
var hello = new Hello();

hello.setName("Blank");
hello.sayHello();

在终端执行 node requireDemo.js ,返回结果为'hello Mr.Blank'

导出的Hello函数是原函数的一次拷贝,修改Hello函数的属性值不会对其他require的地方造成影响

var { Hello, count } = require('./exportDemo')
var hello = new Hello();
// 让count自增
console.log(hello.getId());
console.log(hello.getId());
// 发现获取的count还是原值
console.log(count)

// 真正的count其实是已经改了的
var newHello = new Hello();
console.log(newHello.getId())

var { Hello: newHello, count: newCount } = require('./exportDemo')
console.log(newCount, 'newCount');
// 再次require,取得的newHello和之前require的Hello指向同一个拷贝
console.log(newHello === Hello)

ES6的模块处理

nodejs中运行ES6风格的代码

nodejs默认是不支持ES6的模块处理方案的。

但是在8.5.0之后,ES6代码的文件格式定为mjs后,可使用 node --experimental-modules xxx.mjs 运行。

// exportDemo.mjs
export let a = 1;
// importDemo.mjs
import {a} from './exportDemo.mjs'
console.log(a)

与CommonJS模块处理的区别

CommonJS 模块输出的是一个值的拷贝(已在上一章验证),ES6 模块输出的是值的引用。

// exportDemo.mjs
export let counter = 1;
export function incCounter() {
 counter ++;
}
// importDemo.mjs
import { counter, incCounter } from './exportDemo.mjs'

incCounter();
console.log(counter)		// 打印结果为2,而不是初始值的1

CommonJS模块是运行时加载,ES6模块是编译时输出接口

Nodejs此类的运行环境会在一个闭包中运行CommonJS模块代码

(function(exports, require, module, __filename, __dirname) {
// Module code actually lives in here
});

ES6 模块不会缓存运行结果,而是动态地去被加载的模块取值,并且变量总是绑定其所在的模块。

// exportDemo.mjs
export let a = 1;
export const b = 2;
export let obj = {};

// importDemo.mjs
import { a, b } from './exportDemo.mjs'
console.log(a, b)
a = 1 // 报错,TypeError: Assignment to constant variable,export出来的值是一个只读引用
obj.x = 1	// 可以改变属性值

在ES6模块中我们更多地要去考虑语法的问题 export default

有时候我们会在代码发现 export default obj 的用法,那么这个default是用来干嘛的?

default是ES6引入的与export配套使用的关键字,用来给匿名对象、匿名函数设置默认的名字用的

export出来的值必须要有一个命名,否则从语法层次便会报错

让我们看一下以下几个会报错的错误例子

export匿名对象

export { x: 1 }	// 报错,SyntaxError:Unexpected token,这是一个编译阶段的错误

// 正确写法
export default { x: 1 }

export匿名函数

export function() {}	// 报错,SyntaxError: Unexpected token (

// 正确写法
export default function() {}

循环引用(recycling loading)

在复杂的模块中,可能会出现模块间的 互相引用

commonJS的循环引用运行机制

// a.js
exports.loaded = false;
var b = require('./b.js')
console.log("b in a is " + JSON.stringify(b))
exports.loaded = true;
console.log("a complete")
// b.js
exports.loaded = false;
var a = require('./a.js')
console.log("a in b is " + JSON.stringify(a))
exports.loaded = true;
console.log("b complete")
// main.js
var a = require('./a.js')
var b = require('./b.js')

console.log("a in main is" + JSON.stringify(a))
console.log("b in main is" + JSON.stringify(b))

执行指令 nodejs main.js

时序图下的执行步骤分解图如下所示:

ES6与CommonJS中的模块处理的区别 

ES6的循环引用运行机制

一个会报错的例子

// a.mjs
import { bar } from './b.mjs'

console.log(bar);
export let foo = 'foo from a.mjs'
// b.mjs
import { foo } from './a.mjs'

console.log(foo)

export let bar = 'bar from b.mjs'
// main.mjs
import { foo } from './a.mjs'
import { bar } from './b.mjs'

node main.mjs

时序图下的执行步骤分解图如下所示:

ES6与CommonJS中的模块处理的区别

ES6的循环引用要特别注意变量是否已被声明,若未被声明的块级作用域变量被其他模块引用时,会报错。

改进方案:循环引用中尽量去export可以提前确定的值(例如函数),其实我们总是希望去 引用模块执行完全后最终确定的变量

// a.mjs
import { bar } from './b.mjs'

console.log(bar());
export function foo() {
 return 'foo from a.mjs'
}
// b.mjs
import { foo } from './a.mjs'
console.log(foo());
export function bar() {
 return 'bar from b.mjs'
}
// main.mjs
import { foo } from './a.mjs'
import { bar } from './b.mjs'

node main.mjs

返回结果:

foo from a.mjs
bar from b.mjs

时序图下的执行步骤分解图如下所示:

ES6与CommonJS中的模块处理的区别 

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
jQuery Flash/MP3/Video多媒体插件
Jan 18 Javascript
Jquery实现视频播放页面的关灯开灯效果
May 27 Javascript
javascript实现window.print()去除页眉页脚
Dec 30 Javascript
javascript浏览器窗口之间传递数据的方法
Jan 20 Javascript
JavaScript中几种排序算法的简单实现
Jul 29 Javascript
javascript中checkbox使用方法简单实例演示
Nov 17 Javascript
JS代码实现根据时间变换页面背景效果
Jun 16 Javascript
vue给组件传递不同的值方法
Sep 29 Javascript
利用原生JavaScript实现造日历轮子实例代码
May 08 Javascript
JS获取动态添加元素的方法详解
Jul 31 Javascript
vuex中store存储store.commit和store.dispatch的用法
Jul 24 Javascript
js实现直播点击飘心效果
Aug 19 Javascript
浅谈webpack 构建性能优化策略小结
Jun 13 #Javascript
详解webpack运行Babel教程
Jun 13 #Javascript
Babel 入门教程学习笔记
Jun 13 #Javascript
Vue中在新窗口打开页面及Vue-router的使用
Jun 13 #Javascript
微信小程序支付功能 php后台对接完整代码分享
Jun 12 #Javascript
js replace 全局替换的操作方法
Jun 12 #Javascript
微信小程序自定义prompt组件步骤详解
Jun 12 #Javascript
You might like
如何提高MYSQL数据库的查询统计速度 select 索引应用
2007/04/11 PHP
PHP中删除变量时unset()和null的区别分析
2011/01/27 PHP
使用php发送有附件的电子邮件-(PHPMailer使用的实例分析)
2013/04/26 PHP
Linux下PHP连接Oracle数据库
2014/08/20 PHP
thinkphp3.x中session方法的用法分析
2016/05/20 PHP
php 运算符与表达式详细介绍
2016/11/30 PHP
capacityFixed 基于jquery的类似于新浪微博新消息提示的定位框
2011/05/24 Javascript
JS获取文本框,下拉框,单选框的值的简单实例
2014/02/26 Javascript
jQuery后代选择器用法实例
2014/12/23 Javascript
js获取时间精确到秒(年月日)
2016/03/16 Javascript
深入理解js generator数据类型
2016/08/16 Javascript
Vue.js实现无限加载与分页功能开发
2016/11/03 Javascript
如何使用headjs来管理和异步加载js
2016/11/29 Javascript
一道面试题引发的对javascript类型转换的思考
2017/03/06 Javascript
JavaScript实现获取远程的html到当前页面中
2017/03/26 Javascript
使用JavaScript开发跨平台的桌面应用详解
2017/07/27 Javascript
jQuery+koa2实现简单的Ajax请求的示例
2018/03/06 jQuery
layDate日期控件使用方法详解
2018/11/15 Javascript
整理 node-sass 安装失败的原因及解决办法(小结)
2020/02/19 Javascript
openlayers4.6.5实现距离量测和面积量测
2020/09/25 Javascript
[01:51]历届DOTA2国际邀请赛举办地回顾 TI9落地上海
2018/08/26 DOTA
[02:23]1个至宝=115个英雄特效 最“绿”至宝拉比克“魔导师密钥”登场
2018/12/29 DOTA
python采用getopt解析命令行输入参数实例
2014/09/30 Python
在Python中使用SQLite的简单教程
2015/04/29 Python
Python的Tornado框架实现图片上传及图片大小修改功能
2016/06/30 Python
numpy给array增加维度np.newaxis的实例
2018/11/01 Python
Python 3 实现定义跨模块的全局变量和使用教程
2019/07/07 Python
Django的性能优化实现解析
2019/07/30 Python
Python实现栈的方法详解【基于数组和单链表两种方法】
2020/02/22 Python
优秀安全员事迹材料
2014/05/11 职场文书
工厂仓管员岗位职责范本
2014/07/17 职场文书
工会趣味活动方案
2014/08/18 职场文书
医院党的群众路线教育实践活动领导班子对照检查材料
2014/09/25 职场文书
县长“四风”对照检查材料思想汇报
2014/10/05 职场文书
小学课改工作总结
2015/08/13 职场文书
如何获取numpy array前N个最大值
2021/05/14 Python