ES6模块与CommonJS模块的差异
ES6模块与CommonJS模块的差异
讨论 Node 加载 ES6模块之前,必须了解 ES6模块与 CommonJS模块完全不同。
它们有两个重大差异。
CommonJS模块输出的是一个值的拷贝,ES6模块输出的是值的引用。
CommonJS模块是运行时加载,ES6模块是编译时输出接口。
第二个差异是因为 CommonJS 加载的是一个对象(即module.exports属性),该对象只有在脚本运行完才会生成。而 ES6模块不是对象,它的对外接口只是一种静态定义,在代码静态解析阶段就会生成。
下面重点解释第一个差异。
CommonJS 模块输出的是值的拷贝,也就是说,一旦输出一个值,模块内部的变化就影响不到这个值。请看下面这个模块文件lib.js的例子。
// lib.js
var counter = 3;
function incCounter() {
counter++;
}
module.exports = {
counter: counter,
incCounter: incCounter,
};
上面代码输出内部变量counter和改写这个变量的内部方法incCounter。然后,在main.js里面加载这个模块。
// main.js
var mod = require('./lib');
console.log(mod.counter); // 3
mod.incCounter();
console.log(mod.counter); // 3
上面代码说明,lib.js模块加载以后,它的内部变化就影响不到输出的mod.counter了。这是因为mod.counter是一个原始类型的值,会被缓存。除非写成一个函数,才能得到内部变动后的值。
// lib.js
var counter = 3;
function incCounter() {
counter++;
}
module.exports = {
get counter() {
return counter
},
incCounter: incCounter,
};
上面代码中,输出的counter属性实际上是一个取值器函数。现在再执行main.js,就可以正确读取内部变量counter的变动了。
$ node main.js
3
4
ES6模块的运行机制与 CommonJS 不一样。JS 引擎对脚本静态分析的时候,遇到模块加载命令import,就会生成一个只读引用。等到脚本真正执行时,再根据这个只读引用,到被加载的那个模块里面去取值。换句话说,ES6 的import有点像 Unix 系统的“符号连接”,原始值变了,import加载的值也会跟着变。因此,ES6模块是动态引用,并且不会缓存值,模块里面的变量绑定其所在的模块。
还是举上面的例子。
// lib.js
export let counter = 3;
export function incCounter() {
counter++;
}
// main.js
import { counter, incCounter } from './lib';
console.log(counter); // 3
incCounter();
console.log(counter); // 4
上面代码说明,ES6模块输入的变量counter是活的,完全反应其所在模块lib.js内部的变化。
再举一个出现在export一节中的例子。
// m1.js
export var foo = 'bar';
setTimeout(() => foo = 'baz', 500);
// m2.js
import {foo} from './m1.js';
console.log(foo);
setTimeout(() => console.log(foo), 500);
上面代码中,m1.js的变量foo,在刚加载时等于bar,过了 500 毫秒,又变为等于baz。
让我们看看,m2.js能否正确读取这个变化。
$ babel-node m2.js
bar
baz
上面代码表明,ES6模块不会缓存运行结果,而是动态地去被加载的模块取值,并且变量总是绑定其所在的模块。
由于 ES6 输入的模块变量,只是一个“符号连接”,所以这个变量是只读的,对它进行重新赋值会报错。
// lib.js
export let obj = {};
// main.js
import { obj } from './lib';
obj.prop = 123; // OK
obj = {}; // TypeError
上面代码中,main.js从lib.js输入变量obj,可以对obj添加属性,但是重新赋值就会报错。因为变量obj指向的地址是只读的,不能重新赋值,这就好比main.js创造了一个名为obj的const变量。
最后,export通过接口,输出的是同一个值。不同的脚本加载这个接口,得到的都是同样的实例。
// mod.js
function C() {
this.sum = 0;
this.add = function () {
this.sum += 1;
};
this.show = function () {
console.log(this.sum);
};
}
export let c = new C();
上面的脚本mod.js,输出的是一个C的实例。不同的脚本加载这个模块,得到的都是同一个实例。
// x.js
import {c} from './mod';
c.add();
// y.js
import {c} from './mod';
c.show();
// main.js
import './x';
import './y';
现在执行main.js,输出的是1。
$ babel-node main.js
1
这就证明了x.js和y.js加载的都是C的同一个实例。
ES6模块与CommonJS模块的差异的更多相关文章
- ES6 模块与 CommonJS 模块的差异
ES6 模块与 CommonJS 模块完全不同.它们有两个重大差异 CommonJS 输出是值的拷贝,即原来模块中的值改变不会影响已经加载的该值,ES6静态分析,动态引用,输出的是值的引用,值改变,引 ...
- ES6模块与CommonJS模块有什么区别?
ES6 Module和CommonJS模块的区别: CommonJS是对模块的浅拷贝,ES6 Module是对模块的引用,即ES6 Module只存只读,不能改变其值,具体点就是指针指向不能变,类似c ...
- commonJS模块规范 和 es6模块规范 区别
ES6 模块与 CommonJS 模块的差异 CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用. CommonJS 模块是运行时加载,ES6 模块是编译时输出接口. Commo ...
- commonjs模块和es6模块的区别?
commonjs模块和es6模块最主要的区别:commonjs模块是拷贝,es6模块是引用,但理解这些,先得理解对象复制的问题,在回过头来理解这两模块的区别. 一.基本数据类型的模块 ./a1.js ...
- es6 模块和commonjs规范模块的区别
相关代码地址:https://github.com/blank-x/blog-code/tree/main/1-module 引入变量 es6 导入变量只是一个符号链接,是个常量,类似于const 声 ...
- es6 模块与commonJS的区别
在刚接触模块化开发的阶段,我总是容易将export.import.require等语法给弄混,今天索性记个笔记,将ES6 模块知识点理清楚 未接触ES6 模块时,模块开发方案常见的有CommonJS. ...
- commonjs模块和es6模块的区别
commonjs模块与es6模块的区别 到目前为止,已经实习了3个月的时间了.最近在面试,在面试题里面有题目涉及到模块循环加载的知识.趁着这个机会,将commonjs模块与es6模块之间一些重要的的区 ...
- CommonJS 模块规范 1.1.1
本规范致力于描述一类可以同时适用于客户端和服务器端的模块系统.该系统中的模块拥有自己的作用域,可以从其他模块导入单例对象,或者对外提供 API. Require require 是一个函数对象. re ...
- "浏览器端" 使用 commonjs 模块规范开发网页应用,像开发 node 那样开发网页应用
Containjs 1.0 Containjs 是什么? Containjs 是一个基于 Commonjs 模块管理规范的 浏览器端 的 JavaScript 模块加载器(目前为非标准的,代码会持续迭 ...
随机推荐
- [LeetCode] 39. 组合总和
题目链接 : https://leetcode-cn.com/problems/combination-sum/ 题目描述: 给定一个无重复元素的数组 candidates 和一个目标数 target ...
- 2019牛客暑期多校训练营(第八场) - B - Beauty Values - 水题
https://ac.nowcoder.com/acm/contest/888/B 实际上的确是个水题,写个小数据找个规律看看,所谓不同度,其实就是依次插入每个元素后,各种元素出现的最后位置的坐标求和 ...
- django学习笔记(四)
1.请求周期 url> 路由 > 函数或类 > 返回字符串或者模板语言? Form表单提交: 提交 -> url > 函数或类中的方法 - .... HttpRespon ...
- json.dumps、json.dump、json.loads、json.load的区别
json 模块提供了一种很简单的方式来编码和解码JSON数据. 其中两个主要的函数是 json.dumps() 和 json.loads() 下面是如何将Python数据结构转换为json impor ...
- vue中使用better-scroll滚动条插件
应用场景: overflow: hidden会让超出的部分隐藏,并且无法拖拽,所以可使用插件让长列表限定的区域滚动拖拽. 参考:https://zhuanlan.zhihu.com/p/2740702 ...
- git上传代码到code.csdn.net出错
用git push代码到csdn code的时候出现错误 error:failed to push some refs to - Dealing with "non-fast-forward ...
- Linux系统性能测试工具(八)——网络性能测试工具之netperf
本文介绍关于Linux系统(适用于centos/ubuntu等)的网络性能测试工具-iperf.磁盘io性能测试工具包括: iperf: netperf 参考链接:https://www.jiansh ...
- [转]tKC(The Keyboard Caper)的自传
每个玩儿计算机的朋友都知道破解,或多或少地使用着各种各样的破解,也就逐渐地知道了一些著名的破解团体和破解人,比如:PC(Phrozen Crew).CiA(Crackers in Action)COR ...
- DevOps书单:调研了101名专家,推荐这39本必读书籍
任何一个领域都遵循从新人到熟手,从熟手到专家的路径.在成长过程中,DevOps人经常会陷入没人带,没人管,找不到职业方向的迷茫. DevOps是在商业演进与企业协作的进化过程中诞生的一个全新职业,被很 ...
- Django【第5篇】:Django之ORM数据库操作
django之ORM数据库操作 一.ORM介绍 映射关系: 表名 -------------------->类名 字段-------------------->属性 表记录-------- ...