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 相关文章推荐
网页的标准,IMG不支持onload标签怎么办
Jun 29 Javascript
简单JS代码压缩器
Oct 12 Javascript
firefox和IE系列的相关区别整理 以备后用
Dec 28 Javascript
从面试题学习Javascript 面向对象(创建对象)
Mar 30 Javascript
javascript游戏开发之《三国志曹操传》零部件开发(一)让静态人物动起来
Jan 23 Javascript
JQuery设置文本框和密码框得到焦点时的样式
Aug 30 Javascript
js中通过split函数分割字符串成数组小例子
Sep 21 Javascript
在javascript中使用com组件的简单实现方法
Aug 17 Javascript
javascript鼠标跟随运动3种效果(眼球效果,苹果菜单,方向跟随)
Oct 27 Javascript
javascript html5轻松实现拖动功能
Mar 01 Javascript
JS排序算法之希尔排序与快速排序实现方法
Dec 12 Javascript
JavaScript This指向问题详解
Nov 25 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
盘点被央视点名过的日本动画电影 一部比一部强
2020/03/08 日漫
一个没有MYSQL数据库支持的简易留言本的编写
2006/10/09 PHP
解决Codeigniter不能上传rar和zip压缩包问题
2014/03/07 PHP
php使用websocket示例详解
2014/03/12 PHP
PHP-Java-Bridge使用笔记
2014/09/22 PHP
php集成环境xampp中apache无法启动问题解决方案
2014/11/18 PHP
PHP 使用 Imagick 裁切/生成缩略图/添加水印自动检测和处理 GIF
2016/02/19 PHP
JavaScript 学习笔记二 字符串拼接
2010/03/28 Javascript
JQuery AJAX提交中文乱码的解决方案
2010/07/02 Javascript
javascript写的日历类(基于pj)
2010/12/28 Javascript
JSON序列化与解析原生JS方法且IE6和chrome测试通过
2013/09/05 Javascript
jquery无刷新验证邮箱地址实现实例
2014/02/19 Javascript
Javascript图片上传前的本地预览实例
2014/06/16 Javascript
JavaScript实现俄罗斯方块游戏过程分析及源码分享
2015/03/23 Javascript
EasyUI Pagination 分页的两种做法小结
2016/07/09 Javascript
AngularJS模块详解及示例代码
2016/08/17 Javascript
jQuery 全选 全不选 事件绑定的实现代码
2017/01/23 Javascript
Node.js使用Express.Router的方法
2017/11/14 Javascript
JavaScript递归函数解“汉诺塔”算法代码解析
2018/07/05 Javascript
通过图带你深入了解vue的响应式原理
2019/06/21 Javascript
微信小程序实现收货地址左滑删除
2020/11/18 Javascript
使用Python对Access读写操作
2017/03/30 Python
基于pip install django失败时的解决方法
2018/06/12 Python
使用 tf.nn.dynamic_rnn 展开时间维度方式
2020/01/21 Python
Python正则表达式如何匹配中文
2020/05/27 Python
Python如何使用27行代码绘制星星图
2020/07/20 Python
pandas apply多线程实现代码
2020/08/17 Python
python如何调用php文件中的函数详解
2020/12/29 Python
浅谈Html5多线程开发之WebWorkers
2018/05/02 HTML / CSS
美国最大的农村生活方式零售店:Tractor Supply Company(TSC)
2017/05/15 全球购物
最好的商品表达自己:Cafepress
2019/09/04 全球购物
机关门卫岗位职责
2013/12/30 职场文书
聘任书模板
2014/03/29 职场文书
人大代表选举标语
2014/10/07 职场文书
文案策划岗位职责
2015/02/11 职场文书
职场中的你,辞职信写对了吗?
2019/06/26 职场文书