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 相关文章推荐
用prototype实现的简单小巧的多级联动菜单
Mar 24 Javascript
Javascript查询DBpedia小应用实例学习
Mar 07 Javascript
Jquery同辈元素选中/未选中效果的实例代码
Aug 01 Javascript
JS限制Textarea文本域字符个数的具体实现
Aug 02 Javascript
jQuery页面加载初始化常用的三种方法
Jun 04 Javascript
Angularjs实现分页和分页算法的示例代码
Dec 23 Javascript
微信小程序后台解密用户数据实例详解
Jun 28 Javascript
vue devtools的安装与使用教程
Aug 08 Javascript
js实现每日签到功能
Nov 29 Javascript
9102年webpack4搭建vue项目的方法步骤
Feb 20 Javascript
QML实现圆环颜色选择器
Sep 25 Javascript
浅谈vue 组件中的setInterval方法和window的不同
Jul 30 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
dedecms模版制作使用方法
2007/04/03 PHP
php数组去重实例及分析
2013/11/26 PHP
PHP通过API获取手机号码归属地
2015/05/28 PHP
深入解析WordPress中加载模板的get_template_part函数
2016/01/11 PHP
PHP中STDCLASS用法实例分析
2016/11/11 PHP
PHP面向对象程序设计方法实例详解
2016/12/24 PHP
基于jQuery的消息提示插件之旅 DivAlert(三)
2010/04/01 Javascript
Dojo Javascript 编程规范 规范自己的JavaScript书写
2014/10/26 Javascript
完美实现仿QQ空间评论回复特效
2015/05/06 Javascript
jquery读取xml文件实现省市县三级联动的方法
2015/05/29 Javascript
Extjs实现下拉菜单效果
2016/04/01 Javascript
jQuery实现模拟flash头像裁切上传功能示例
2016/12/11 Javascript
利用js的闭包原理做对象封装及调用方法
2017/04/07 Javascript
JS将unicode码转中文方法
2017/05/08 Javascript
微信小程序实现下拉刷新和轮播图效果
2017/11/21 Javascript
使用layer弹窗和layui表单实现新增功能
2018/08/09 Javascript
微信小程序-可移动菜单的实现过程详解
2019/06/24 Javascript
微信小程序 下拉刷新及上拉加载原理解析
2019/11/06 Javascript
vue中解决chrome浏览器自动播放音频和MP3语音打包到线上的实现方法
2020/10/09 Javascript
[02:17]TI4西雅图DOTA2前线报道 啸天mik夫妻档解说
2014/07/08 DOTA
[04:12]第二届DOTA2亚洲邀请赛选手传记-Newbee.Sccc
2017/04/03 DOTA
Ubuntu 16.04 LTS中源码安装Python 3.6.0的方法教程
2016/12/27 Python
Python实现霍夫圆和椭圆变换代码详解
2018/01/12 Python
python对Excel的读取的示例代码
2020/02/14 Python
Pycharm2020.1安装无法启动问题即设置中文插件的方法
2020/08/07 Python
英国骑行、跑步、游泳、铁人三项运动装备专卖店:Wiggle
2016/08/23 全球购物
美国排名第一的泳池用品直接来源:In The Swim
2019/09/23 全球购物
Emma Bridgewater官网:英国餐具制造商
2019/11/24 全球购物
电气工程及自动化专业自荐书范文
2013/12/18 职场文书
护士试用期自我鉴定
2014/02/08 职场文书
元旦获奖感言
2014/03/08 职场文书
法人代表授权委托书
2014/04/08 职场文书
2014年幼儿园教学工作总结
2014/12/04 职场文书
出纳试用期自我评价
2015/03/10 职场文书
2016幼儿园教师年度考核评语
2015/12/01 职场文书
Python学习之时间包使用教程详解
2022/03/21 Python