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 尚未实现错误解决办法
Nov 27 Javascript
面向对象的Javascript之二(接口实现介绍)
Jan 27 Javascript
基于JavaScript实现继承机制之构造函数+原型链混合方式的使用详解
May 07 Javascript
动态创建script标签实现跨域资源访问的方法介绍
Feb 28 Javascript
JS实现网页游戏中滑块响应鼠标点击移动效果
Oct 19 Javascript
jQuery Validate初步体验(二)
Dec 12 Javascript
jQuery.form插件的使用及跨域异步上传文件
Apr 27 Javascript
BootStrap Validator对于隐藏域验证和程序赋值即时验证的问题浅析
Dec 01 Javascript
React快速入门教程
Jan 17 Javascript
微信小程序实战之仿android fragment可滑动底部导航栏(4)
Apr 16 Javascript
node前端模板引擎Jade之标签的基本写法
May 11 Javascript
jQuery实现查看图片功能
Dec 01 jQuery
浅谈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压缩html网页代码(清除空格,换行符,制表符,注释标记)
2012/04/02 PHP
PHP CLI模式下的多进程应用分析
2013/06/03 PHP
PHP用户验证和标签推荐的简单使用
2016/10/31 PHP
支持ie与FireFox的剪切板操作代码
2009/09/28 Javascript
extjs DataReader、JsonReader、XmlReader的构造方法
2009/11/07 Javascript
jquery操作下拉列表、文本框、复选框、单选框集合(收藏)
2014/01/08 Javascript
超级好用的jQuery圆角插件 Corner速成
2014/08/31 Javascript
AngularJS中$http服务常用的应用及参数
2016/08/22 Javascript
更靠谱的H5横竖屏检测方法(js代码)
2016/09/13 Javascript
Angular2  NgModule 模块详解
2016/10/19 Javascript
关于页面刷新vuex数据消失问题解决方案
2017/07/03 Javascript
利用ES6实现单例模式及其应用详解
2017/12/09 Javascript
Vue完整项目构建(进阶篇)
2018/02/10 Javascript
详解Vue开发微信H5微信分享签名失败问题解决方案
2018/08/09 Javascript
Vue用v-for给循环标签自身属性添加属性值的方法
2018/10/18 Javascript
vue项目里面引用svg文件并给svg里面的元素赋值
2020/08/17 Javascript
[00:35]DOTA2上海特级锦标赛 EG战队宣传片
2016/03/04 DOTA
介绍Python的@property装饰器的用法
2015/04/28 Python
Python使用sqlalchemy模块连接数据库操作示例
2019/03/13 Python
利用Python实现Shp格式向GeoJSON的转换方法
2019/07/09 Python
Numpy与Pytorch 矩阵操作方式
2019/12/27 Python
Python3.7.0 Shell添加清屏快捷键的实现示例
2020/03/23 Python
牛津在线药房:Oxford Online Pharmacy
2020/11/16 全球购物
运动鞋、街头服装、手表和手袋的实时市场:StockX
2020/11/25 全球购物
Java 中访问数据库的步骤?Statement 和PreparedStatement 之间的区别?
2012/06/05 面试题
介绍下java.util.Arrays类
2012/10/16 面试题
大学生军训感想
2014/02/16 职场文书
《美丽的彩虹》教学反思
2014/02/25 职场文书
公务员试用期满考核材料
2014/05/22 职场文书
学习党的群众路线剖析材料
2014/10/09 职场文书
四川省传达学习贯彻党的群众路线教育实践活动总结大会精神新闻稿
2014/10/26 职场文书
高中生打架检讨书1000字
2015/02/17 职场文书
2016元旦晚会主持词
2015/07/01 职场文书
班级管理经验交流材料
2015/11/02 职场文书
MySQL8.0.18配置多主一从
2021/06/21 MySQL
Redis主从配置和底层实现原理解析(实战记录)
2021/06/30 Redis