龙空技术网

ES6 模块与 CommonJS 模块的差异

技术瘾君子 1181

前言:

如今我们对“调用不同的js”大概比较注重,朋友们都需要了解一些“调用不同的js”的相关资讯。那么小编同时在网摘上收集了一些有关“调用不同的js””的相关知识,希望兄弟们能喜欢,朋友们快快来学习一下吧!

讨论 Node.js 加载 ES6 模块之前,必须了解 ES6 模块与 CommonJS 模块完全不同。

它们有三个重大差异。

CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用。CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。CommonJS 模块的require()是同步加载模块,ES6 模块的import命令是异步加载,有一个独立的模块依赖的解析阶段。

第二个差异是因为 CommonJS 加载的是一个对象(即module.exports属性),该对象只有在脚本运行完才会生成。而 ES6 模块不是对象,它的对外接口只是一种静态定义,在代码静态解析阶段就会生成。

下面重点解释第一个差异。

CommonJS 模块输出的是值的拷贝,也就是说,一旦输出一个值,模块内部的变化就影响不到这个值。请看下面这个模块文件lib.js的例子。

// lib.jsvar counter = 3;function incCounter() {  counter++;}module.exports = {  counter: counter,  incCounter: incCounter,};

上面代码输出内部变量counter和改写这个变量的内部方法incCounter。然后,在main.js里面加载这个模块。

// main.jsvar mod = require('./lib');console.log(mod.counter);  // 3mod.incCounter();console.log(mod.counter); // 3

上面代码说明,lib.js模块加载以后,它的内部变化就影响不到输出的mod.counter了。这是因为mod.counter是一个原始类型的值,会被缓存。除非写成一个函数,才能得到内部变动后的值。

// lib.jsvar counter = 3;function incCounter() {  counter++;}module.exports = {  get counter() {    return counter  },  incCounter: incCounter,};

上面代码中,输出的counter属性实际上是一个取值器函数。现在再执行main.js,就可以正确读取内部变量counter的变动了。

$ node main.js34

上面代码说明,ES6 模块输入的变量counter是活的,完全反应其所在模块lib.js内部的变化。

再举一个出现在export一节中的例子。

// m1.jsexport var foo = 'bar';setTimeout(() => foo = 'baz', 500);// m2.jsimport {foo} from './m1.js';console.log(foo);setTimeout(() => console.log(foo), 500);

上面代码中,m1.js的变量foo,在刚加载时等于bar,过了 500 毫秒,又变为等于baz。

让我们看看,m2.js能否正确读取这个变化。

$ babel-node m2.jsbarbaz

上面代码表明,ES6 模块不会缓存运行结果,而是动态地去被加载的模块取值,并且变量总是绑定其所在的模块。

由于 ES6 输入的模块变量,只是一个“符号连接”,所以这个变量是只读的,对它进行重新赋值会报错。

// lib.jsexport let obj = {};// main.jsimport { obj } from './lib';obj.prop = 123; // OKobj = {}; // TypeError

上面代码中,main.js从lib.js输入变量obj,可以对obj添加属性,但是重新赋值就会报错。因为变量obj指向的地址是只读的,不能重新赋值,这就好比main.js创造了一个名为obj的const变量。

最后,export通过接口,输出的是同一个值。不同的脚本加载这个接口,得到的都是同样的实例。

// mod.jsfunction 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.jsimport {c} from './mod';c.add();// y.jsimport {c} from './mod';c.show();// main.jsimport './x';import './y';

现在执行main.js,输出的是1。

$ babel-node main.js1

这就证明了x.js和y.js加载的都是C的同一个实例。

标签: #调用不同的js