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

node和es6中的模块使用对比

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

node--commonjs规范的模块化

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

使用

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

exports

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

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。express

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,既能够直接使用,这种状况通常是在模块代码导出的时候作了处理:api

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....

相关文章
相关标签/搜索