node、es6的module使用对比exports、require、import

node和es6中的模块使用对比

目前使用js变成离不开模块,而现在最为常见的模块也就是node采用的COMMONjs的方式和es6规范,这里对两种的使用进行对比,并没有深入源码尽情扣,

node--commonjs规范的模块化

node的模块是比较常见的,是全局变量global中的一个属性,文件和模块是一一对应的(每个文件被视为一个独立的模块)。

使用

目前比较规范的是一个文件就是一个模块,主要是exports和require进行处理,

exports

exports 变量是在模块的文件级别作用域内有效的,它在模块被执行前被赋于 module.exports 的值。它有一个快捷方式,以便 module.exports.f = ... 可以被更简洁地写成 exports.f = ...。 注意,就像任何变量,如果一个新的值被赋值给 exports,它就不再绑定到 module.exports。可以具体看看代码:

function add(x, y){
    return x+y;
}
function multiply(x, y){
    return x*y;
}
exports.add = (x, y) => x+y; //exports作为module.exports的快捷方式
exports.multiply = (x, y) => x*y;
module.exports = add; //此时exports module.exports从新被赋为新对象或者函数(函数也是对象)
exports = {add: add} //这是exports已经和module.exports没有关系了,成了独立的模块作用域内对象,并不会被导出
module.exports = {  //最后的导出部分
        add: add,
        multiply: multiply
    };

关于exports和module.exports的关系看下面代码的类似实现,好像实参和形参一样,不同的是最后如果module.exports的没有直接复制操作,会被赋值为exports。

function require(/* ... */) {
  const module = { exports: {} };
  ((module, exports) => {
    // 模块代码在这。在这个例子中,定义了一个函数。
    function someFunc() {}
    exports = someFunc;
    // 此时,exports 不再是一个 module.exports 的快捷方式,
    // 且这个模块依然导出一个空的默认对象。
    module.exports = someFunc;
    // 此时,该模块导出 someFunc,而不是默认对象。
  })(module, module.exports);
  return module.exports;
}

require

定义好了一个模块就应该使用它,

var test = require('./moduleTest.js');

console.log(test(1, 2));
console.log(mutiply(1, 2));

使用是比较简单的,使用变量获取导出的对象exports,就可以使用对象里面的方法了,我们有的时候可能会遇到这样的情况,无需使用变量接受模块的exports,既可以直接使用,这种情况一般是在模块代码导出的时候做了处理:

module.exports.add = global.add = (x, y) => x+y;

把模块的方法直接提升到全局作用域,这其实并不是好的选择。

module对象的一些解读

Node 使用两个核心模块来管理模块依赖:

  1. require 模块,是个看起来像在全局作用域有效的模块——不需要 require('require')。

  2. module 模块,看起来也像是在全局作用域内有效——不需要 require('module')。

由 require 模块导出的主要对象是一个函数(如上例所用)。 当 Node 使用本地文件路径作为函数的唯一参数调用该 require() 函数时,Node 将执行以下步骤:

  • 解析:找到文件的绝对路径。

  • 加载:确定文件内容的类型.

  • 封装:给文件其私有作用域。 这使得 require 和 module 对象两者都可以下载我们需要的每个文件。

  • 评估:这是 VM 对加载的代码最后需要做的。

  • 缓存:当我们再次需要这个文件时,不再重复所有的步骤。

模块在第一次加载后会被缓存。 这也意味着(类似其他缓存机制)如果每次调用 require('foo') 都解析到同一文件,则返回相同的对象。

多次调用 require(foo) 不会导致模块的代码被执行多次。 这是一个重要的特性。 借助它, 可以返回“部分完成”的对象,从而允许加载传递的依赖, 即使它们会导致循环。

模块是基于其解析的文件名进行缓存的。 由于调用模块的位置的不同,模块可能被解析成不同的文件名(比如从 node_modules 目录加载),这样就不能保证 require('foo') 总能返回完全相同的对象。

此外,在不区分大小写的文件系统或操作系统中,被解析成不同的文件名可以指向同一文件,但缓存仍然会将它们视为不同的模块,并多次重新加载。 例如,require('./foo') 和 require('./FOO') 返回两个不同的对象,而不会管 ./foo 和 ./FOO 是否是相同的文件。

es6的模块

在ES6之前,要使用一个模块,必须使用require函数将一个模块引入,但ES6并没有采用这种模块化方案,在ES6中使用import指令引入一个模块或模块中的部分接口,并没有将require写入标准,这也就是说require对于ES6代码而言,只是一个普通函数。

同理,在ES6标准中,导出模块的接口也只能使用export指令,而非exports对象,这也同样意味着module.exports只是node,requirejs等模块化库的自定义变量,而非ES标准接口。

当然,ES6的模块化也很复杂,不只模块接口的导入导出这点东西,只不过本文无耻的只讨论这个相对而言比较常见的问题。

export使用

先列举一些常用的使用方法:

export function fun() {};
export { name1, name2, …, nameN };
export { variable1 as name1, variable2 as name2, …, nameN };
export let name1, name2, …, nameN; // also var
export let name1 = …, name2 = …, …, nameN; // also var, const

export default expression;
export default function (…) { … } // also class, function*
export default function name1(…) { … } // also class, function*
export { name1 as default, … };

export * from …;
export { name1, name2, …, nameN } from …;
export { import1 as name1, import2 as name2, …, nameN } from …;

导出的不是变量是绝对错误的,包括导出表达式,也是绝对错误的,export允许多次export {}这种形式,看上去很奇怪,其实和react的setState一样,是一个增量的添加模式。另外,ES6更厉害之处在于,可以在export变量之后,继续修改变量。

import使用

import的使用其实比require更加的舒服

import {a,obj} from './module-file';

和node之前的require不一样,require只能把模块放到一个变量中,而在ES6中,拥有对象解构赋值的能力,所以直接就把引入的模块的接口赋值给变量了。内在机理也有不同,require需要去执行整个模块,将整个模块放到内存中(也就是我们说的运行时),如果只是使用到其中一个方法,性能上就差很多,而import...from则是只加载需要的接口方法,其他方法在程序启动之后根本触及不到,所以这种又被称为“编译时”,性能上好很多。

AS DEFAULT * 关键字

编程的同学对as都容易理解,简单的说就是取一个别名。上面export中可以用,import中其实也可以用:

// a.js
var a = function() {};
export {a as fun};

// b.js
import {fun as a} from './a';
a();

而default则是一种语法糖,实践类似:

// d.js
export default function() {}

// 等效于:
function a() {};
export {a as default};

//在import的时候,可以这样用:
import a from './d';

// 等效于,或者说就是下面这种写法的简写,是同一个意思
import {default as a} from './d';

则是代表把所有的export赋值给 as newExport,这个后面跟这个的别名对象,从而获取模块所有方法。

参考:http://www.tangshuang.net/288...
https://juejin.im/entry/58d4e...
http://nodejs.cn/api/modules....

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: ES6模块和CommonJS的区别在于它们的语法和实现方式不同。ES6模块是ES6规范中定义的一种模块化方式,它使用importexport关键字来导入和导出模块。而CommonJS是Node.js中使用的一种模块化方式,它使用requiremodule.exports来导入和导出模块。 ES6模块支持静态分析,可以在编译时确定模块的依赖关系,从而实现更好的性能和可靠性。而CommonJS模块是动态加载的,需要在运行时才能确定模块的依赖关系,因此在性能和可靠性方面不如ES6模块。 此外,ES6模块还支持命名导入和导出,可以更灵活地控制模块的导入和导出。而CommonJS模块只支持默认导入和导出,无法实现命名导入和导出。 ### 回答2: ES6 module和CommonJS是两种不同的模块化解决方案,虽然两者主要目的都是为了让JavaScript代码更容易组织和重用,但是它们在具体实现上存在很大的区别,本文将从以下四个方面来介绍它们的区别: 1.语法区别 ES6 module使用了新的关键字来声明模块中的变量、方法和类等例如exportimport等,而CommonJS则用require()和module.exports。ES6 module的语法更加简洁易读且与JavaScript同步加载,CommonJS的语法比较复杂,且需要异步加载模块。 2.模块加载方式不同 ES6模块在编译的时候会根据import引用的模块信息,去异步加载依赖的模块,这种方式叫做静态加载。而CommonJS的模块则是在运行时同步加载,也就是说CommonJS会将所有依赖的模块全部加载完成,然后再运行代码,这种方式比较适合服务器端的开发。 3.ES6模块有作用域 ES6模块和CommonJS中的模块是有作用域的,但是ES6模块中的作用域是静态的,而CommonJS中的模块作用域是动态的,也就是说在CommonJS中,模块中变量的值在代码运行期间是可变的,而在ES6模块中则不是。 4.ES6模块支持循环依赖 ES6模块中是支持循环依赖的,它会先给所有需要依赖的模块都分配一个空间,然后再去填充它们,这样就避免了循环依赖的问题。而CommonJS中的模块是不支持循环依赖的,因为在CommonJS中,模块的加载是同步的,所以不能把某个模块的加载工作放在另外一个模块加载完毕之后再执行。 总之,ES6 module是一种新的、更加先进和可靠的模块化方案,并且支持静态加载和循环依赖等功能,虽然目前不被所有浏览器支持,但是它的优点是显而易见的。相比之下,CommonJS更适用于服务器端的开发,但是因为它还需要异步加载和模块作用域的问题等,所以在实际的开发过程中并不是很方便和实用。 ### 回答3: ES6模块和CommonJS模块是JavaScript中两种主要的模块化规范,它们有一些明显的区别。 1. 语法不同 ES6模块的导入和导出是基于语法的,也就是使用importexport关键字来操作。而CommonJS模块则是使用require()函数来导入模块,使用module.exports(或exports的简写)来导出模块。 2. 执行方式不同 ES6模块是在代码编译时进行解析的,也就是在代码执行前进行模块解析和编译。而CommonJS模块是在代码运行时才会进行解析。 3. 是否支持静态分析 ES6模块支持静态分析,也就是可以在编译时对模块进行分析和优化,这在性能上有很大的优势。而CommonJS模块不支持静态分析,这在性能上有些影响。 4. 值拷贝与动态绑定不同 在ES6模块中,导入的变量是值拷贝,也就是说,导入的变量与导出的变量不是同一个引用,它们是两个相互独立的对象。而在CommonJS模块中,导入的变量是动态绑定,也就是说,导入的变量与导出的变量是同一个引用。这可能会导致意外的副作用。 5. 是否支持异步加载 ES6模块原生支持异步加载,也就是可以在代码中使用import()函数来异步加载模块。而CommonJS模块不支持异步加载,必须在同步代码中使用require()来加载模块。 总体来说,ES6模块在语法、执行方式、静态分析、值拷贝与动态绑定、支持异步加载等方面都有优势,这也是为什么越来越多的JavaScript开发者选择使用ES6模块。不过,在Node.js环境下,CommonJS模块仍然是主要的模块化规范。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值