文章目录
1、预备知识
要想对require、import 、export、export default、 exports、module.exports
了解的更为清楚, 我们不得不先来谈谈Node.js
以及AMD、CMD、UMD
等规范。
Node.js
百度百科
Node.js发布于2009年5月,由Ryan Dahl开发,是一个基于Chrome V8引擎的JavaScript运行环境,使用了一个事件驱动、非阻塞式I/O模型,让JavaScript 运行在服务端的开发平台,它让JavaScript成为与PHP、Python、Perl、Ruby等服务端语言平起平坐的脚本语言。
Node.js对一些特殊用例进行优化,提供替代的API,使得V8在非浏览器环境下运行得更好,V8引擎执行Javascript的速度非常快,性能非常好,基于Chrome JavaScript运行时建立的平台, 用于方便地搭建响应速度快、易于扩展的网络应用。 [3]
通俗的说法
Node.js就是前端开发人员转后端开发的首选语言,经常搭配Express框架进行快速开发。
模块化系统以及CommonJs
值得一提的是,在Node环境中,采用的是模块化系统(即每个js文件就是一个模块)。
CommonJs 是一种 JavaScript 语言的模块化规范,它通常会在服务端的 Nodejs 上使用。项目是由多个模块组成的,模块和模块之间的调用,需要各个模块有相同规范的 API,这样一来在使用的过程中不会有那么多的学习成本,并且对于单个模块来说是类聚的。
在 CommonJs 的模块化规范中,每一个文件就是一个模块,拥有自己独立的作用域、变量、以及方法等,对其他的模块都不可见。CommonJS规范规定,每个模块内部,module 变量代表当前模块。这个变量是一个对象,它的 exports 属性(module.exports)是对外的接口。加载某个模块,其实是加载该模块的 module.exports 属性。require 方法用于加载模块。
//moudle-a.js moudle.exports = { a: 1 }; //moudle-b.js var ma = require('./moudle-a'); var b = ma.a + 2; module.exports ={ b: b };
模块化规范给项目带来的好处
在业务复杂,模块众多的大型项目中,开发者都遵循相同的规则来开发各自的模块,他们通过规范来约束模块的定义,大家不需要太多的沟通或者大量的文档来说明自己的模块使用规则,成千上万的模块就这样生产,并能够容易的使用。它的意义不仅是让模块看起来很规范,在合作开发、社区中传播中也起到了重大的作用。
AMD
AMD 叫做异步模块定义规范
(Asynchronous Module Definition)
,它是 CommonJs 模块化规范的超集,但是运行于浏览器之上的。AMD 的特点就和它的名字一样,模块的加载过程是异步的,它大大的利用了浏览器的并发请求能力,让模块的依赖过程的阻塞变得更少了。requireJs 就是 AMD 模块化规范的实现。
AMD 作为一个规范,只需定义其语法 API,而不关心其实现。AMD 规范简单到只有一个 API,即 define 函数:
define(id?, dependencies?, factory); • 1
具体用法如下:
// moudle-a.js define('moudleA', function() { return { a: 1 } }); // moudle-b.js define(['moudleA'], function(ma) { var b = ma.a + 2; return { b: b } });
它看起来似乎和 CMD 差不多,不过在实现上还是有一定的差异,它们各有优缺点,我们未来会专门对这些模块化规范做对比。
CMD
CMD 叫做通用模块定义规范
(Common Module Definiton)
,它是类似于 CommonJs模块化规范,但是运行于浏览器之上的,关于模块化的好处我们在 上文了解过。它是随着前端业务和架构的复杂度越来越高运用而生的,来自淘宝玉伯的 SeaJS 就是它的实现。
CMD 规范尽量保持简单,并与 CommonJS 的 Modules 规范保持了很大的兼容性。通过 CMD 规范书写的模块,可以很容易在 Node.js 中运行。在 CMD 规范中,一个模块就是一个文件。格式如下:
define(factory);
具体用法如下:
// moudle-a.js define(function(require, exports, module) { module.exports = { a: 1 }; }); // moudle-b.js define(function(require, exports, module) { var ma = require('./moudle-a'); var b = ma.a + 2; module.exports = { b: b }; });
CMD 规范拥有简单、异步加载脚本、友好的调试并且兼容 Nodejs,它的确在开发过程中给我们提供了较好的模块管理方式。
UMD
UMD 叫做通用模块定义规范
(Universal Module Definition)
。也是随着大前端的趋势所诞生,它可以通过运行时或者编译时让同一个代码模块在使用 CommonJs、CMD 甚至是 AMD 的项目中运行。未来同一个 JavaScript 包运行在浏览器端、服务区端甚至是 APP 端都只需要遵守同一个写法就行了。
它没有自己专有的规范,是集结了 CommonJs、CMD、AMD 的规范于一身,我们看看它的具体实现:
((root, factory) => { if (typeof define === 'function' && define.amd) { //AMD define(['jquery'], factory); } else if (typeof exports === 'object') { //CommonJS var $ = requie('jquery'); module.exports = factory($); } else { root.testModule = factory(root.jQuery); } })(this, ($) => { //todo });
不难发现,它在定义模块的时候回检测当前使用环境和模块的定义方式,将各种模块化定义方式转化为同样一种写法。它的出现也是前端技术发展的产物,前端在实现跨平台的道路上不断的前进,UMD 规范将浏览器端、服务器端甚至是 APP 端都大统一了,当然它或许不是未来最好的模块化方式,未来在 ES6+、TypeScript、Dart 这些拥有高级语法的语言会代替这些方案。
2、正文
1、require
- 在Node环境中用于加载模块
- 例如Node加载fs模块
const fs = require('fs')
2、import
- ES6的一个语法,可通过
Babel
转化成ES5的require
// 导入默认模块 import defaultExport from "module-name"; // 导入模块的所有对象,并命名为name import * as name from "module-name"; // 导入模块中的export对象, 使用了ES6的解构赋值 import { export } from "module-name"; // 导入模块中的export对象并命名为alias, 使用了ES6的解构赋值 import { export as alias } from "module-name";
3、export与export default
export与export default ,是ES6规范,被使用于React或Vue中。
在创建JavaScript模块时,
**export**
语句用于从模块中导出实时绑定的函数、对象或原始值,以便其他程序可以通过import
语句使用它们。被导出的绑定值依然可以在本地进行修改。在使用import进行导入时,这些绑定值只能被导入模块所读取,但在export导出模块中对这些绑定值进行修改,所修改的值也会实时地更新。
4、exports与module.exports
module.exports
与exports
,是CommonJS的规范,被使用于Node.js中。
其中通过查看exports的源码可以发现:
- 在Node中,每一个模块内都有一个自己的
module
对象 - module中有个
exports
空对象
var module = { exports:{ }, } return module.exports
- Node为了简化
module.exports = xxx
, 在底层定义了var exports = module.exports
- globals.ts部分代码 即 node部分源码
declare var require: NodeRequire; declare var module: NodeModule; // Same as module.exports declare var exports: any;
- 导出多个成员(导出对象)
exports.a = 123 exports.b = 'hello' exports.c = function(){ console.log('hello') } exports.d = { name:'Tom' }
module.exports = 'hello'
- 以下情况会覆盖
module.exports = 'hello' // 覆盖前面的module.exports module.exports = 'asd'
- 也可以通过导出一个对象来导出多个成员
module.exports = { a:'hello', b:function(){ console.log('bbbb') } }
等价于
exports.a = 'hello' exports.b = function(){console.log('bbbb')}