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 相关文章推荐
Javascript实例教程(19) 使用HoTMetal(6)
Dec 23 Javascript
让angularjs支持浏览器自动填表
Nov 10 Javascript
微信小程序 数据交互与渲染实例详解
Jan 21 Javascript
Router解决跨模块下的页面跳转示例
Jan 11 Javascript
vue 的keep-alive缓存功能的实现
Mar 22 Javascript
在Vue中获取组件声明时的name属性方法
Sep 12 Javascript
微信小程序实现的3d轮播图效果示例【基于swiper组件】
Dec 11 Javascript
如何封装了一个vue移动端下拉加载下一页数据的组件
Jan 06 Javascript
详解Vue-cli3 项目在安卓低版本系统和IE上白屏问题解决
Apr 14 Javascript
javascript面向对象程序设计实践常用知识点总结
Jul 29 Javascript
Vue内部渲染视图的方法
Sep 02 Javascript
Electron 调用命令行(cmd)
Sep 23 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
php实现mysql数据库备份类
2008/03/20 PHP
在CentOS系统上从零开始搭建WordPress博客的全流程记录
2016/04/21 PHP
表单的一些基本用法与技巧
2006/07/15 Javascript
javascript call和apply方法
2008/11/24 Javascript
JavaScript 克隆数组最简单的方法
2009/02/12 Javascript
纯JavaScript实现的完美渐变弹出层效果代码
2010/04/02 Javascript
JavaScript 面向对象之命名空间
2010/05/04 Javascript
解决IE6的PNG透明JS插件使用介绍
2013/04/17 Javascript
javascript 构造函数方式定义对象
2015/01/02 Javascript
AngularJS基础 ng-click 指令示例代码
2016/08/01 Javascript
详细分析Javascript中创建对象的四种方式
2016/08/17 Javascript
bootstrap制作jsp页面(根据值让table显示选中)
2017/01/05 Javascript
vue中使用localstorage来存储页面信息
2017/11/04 Javascript
webpack之引入图片的实现及问题
2018/10/08 Javascript
JavaScript中常用的简洁高级技巧总结
2019/03/10 Javascript
webpack proxy 使用(代理的使用)
2020/01/10 Javascript
VUE子组件向父组件传值详解(含传多值及添加额外参数场景)
2020/09/01 Javascript
[13:55]Newbee vs Team Spirit
2018/06/07 DOTA
python错误处理详解
2014/09/28 Python
Djang中静态文件配置方法
2015/07/30 Python
在MAC上搭建python数据分析开发环境
2016/01/26 Python
python执行使用shell命令方法分享
2017/11/08 Python
django DRF图片路径问题的解决方法
2018/09/10 Python
Python大数据之使用lxml库解析html网页文件示例
2019/11/16 Python
python 读取更新中的log 或其它文本方式
2019/12/24 Python
python 多线程死锁问题的解决方案
2020/08/25 Python
手摸手教你用canvas实现给图片添加平铺水印的实现
2019/08/20 HTML / CSS
耐克中国官方商城:Nike中国
2018/10/18 全球购物
C#里面可以避免一个类被其他类继承么?如何?
2013/09/26 面试题
人力资源管理专业毕业生推荐信
2013/11/07 职场文书
简历自荐信
2013/12/02 职场文书
酒店出纳岗位职责
2013/12/29 职场文书
四风个人对照检查材料思想汇报(办公室通用版)
2014/10/07 职场文书
党的群众路线教育实践活动总结
2014/10/30 职场文书
Mysql MVCC机制原理详解
2021/04/20 MySQL
Win11安全功能升级:内置防网络钓鱼功能
2022/04/08 数码科技