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 相关文章推荐
js兼容的placeholder属性详解
Aug 18 Javascript
javascript读取Xml文件做一个二级联动菜单示例
Mar 17 Javascript
浅谈EasyUI中编辑treegrid的方法
Mar 01 Javascript
JS实现从连接中获取youtube的key实例
Jul 02 Javascript
three.js绘制地球、飞机与轨迹的效果示例
Feb 28 Javascript
如何编写jquery插件
Mar 29 jQuery
Vue.js 2.0 移动端拍照压缩图片预览及上传实例
Apr 27 Javascript
详解webpack介绍&安装&常用命令
Jun 29 Javascript
详解Vue2.0配置mint-ui踩过的那些坑
Apr 23 Javascript
关于Vue项目跨平台运行问题的解决方法
Sep 18 Javascript
从零开始用electron手撸一个截屏工具的示例代码
Oct 10 Javascript
Vue+element 解决浏览器自动填充记住的账号密码问题
Jun 11 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
JS 网站性能优化笔记
2011/05/24 PHP
一个PHP的QRcode类与大家分享
2011/11/13 PHP
CodeIgniter启用缓存和清除缓存的方法
2014/06/12 PHP
destoon实现公司新闻详细页添加评论功能的方法
2014/07/15 PHP
php根据年月获取当月天数及日期数组的方法
2016/11/30 PHP
PHP memcache在微信公众平台的应用方法示例
2017/09/13 PHP
Vagrant(WSL)+PHPStorm+Xdebu 断点调试环境搭建
2019/12/13 PHP
Javascript客户端脚本的设计和应用
2006/08/21 Javascript
jQuery autocomplate 自扩展插件、自动完成示例代码
2011/03/28 Javascript
javascript 拖动表格行实现代码
2011/05/05 Javascript
javascript:;与javascript:void(0)使用介绍
2013/06/05 Javascript
Js判断参数(String,Array,Object)是否为undefined或者值为空
2013/11/04 Javascript
Jquery实现自定义tooltip示例代码
2014/02/12 Javascript
js delete 用法(删除对象属性及变量)
2014/08/24 Javascript
JavaScript实现的一个日期格式化函数分享
2014/12/06 Javascript
javascript中数组方法汇总
2015/07/07 Javascript
jQuery实现批量判断表单中文本框非空的方法(2种方法)
2015/12/09 Javascript
Vue.js实现按钮的动态绑定效果及实现代码
2017/08/21 Javascript
基于JavaScript 实现拖放功能
2019/09/12 Javascript
JavaScript实现鼠标经过表格某行时此行变色
2020/11/20 Javascript
[04:53]DOTA2英雄基础教程 祈求者
2014/01/03 DOTA
[49:43]VG vs FNATIC 2019国际邀请赛小组赛 BO2 第一场 8.15
2019/08/17 DOTA
跟老齐学Python之Python安装
2014/09/12 Python
Python标准库defaultdict模块使用示例
2015/04/28 Python
用Python实现web端用户登录和注册功能的教程
2015/04/30 Python
Python for Informatics 第11章之正则表达式(四)
2016/04/21 Python
Python编写简单的HTML页面合并脚本
2016/07/11 Python
tensorflow实现逻辑回归模型
2018/09/08 Python
Python用requests库爬取返回为空的解决办法
2021/02/21 Python
CSS3实现鼠标悬停显示扩展内容
2016/08/24 HTML / CSS
存储过程的优缺点是什么
2015/01/10 面试题
家长给孩子的表扬信
2014/01/17 职场文书
班级课外活动总结
2014/07/09 职场文书
大学生团支书竞选稿
2015/11/21 职场文书
Filebeat 采集 Nginx 日志的方法
2021/03/31 Servers
Python 数据结构之十大经典排序算法一文通关
2021/10/16 Python