在之前对于js的模块总是一知半解,今天正好完全整理一下。是根据github上的电子书进行的整理 。
Learning JavaScript Design Patterns
和阮一峰的es6module进行整理
es6模块
CommonJS以及es6的module
CommonJs主要有一个函数require和一个变量exports组成。
// package/lib is a dependency we require
var lib = require( "package/lib" );
// behaviour for our module
function foo(){
lib.log( "hello world!" );
}
// export (expose) foo to other modules
exports.foo = foo;
值得注意的是CommonJS的引入方式是运行时引入。
let { stat, exists, readFile } = require('fs');
// 等同于
let _fs = require('fs');
let stat = _fs.stat;
let exists = _fs.exists;
let readfile = _fs.readfile;
es6 module
而在es6的模块中有两个变量一个是import 一个是export非常方便。
在es6的模块中,有几个需要注意的点:
编译时引入模块。
import { stat, exists, readFile } from 'fs';
上面代码的实质是从fs模块加载3个方法,其他方法不加载。这种加载称为“编译时加载”或者静态加载,即 ES6 可以在编译时就完成模块加载,效率要比 CommonJS 模块的加载方式高。当然,这也导致了没法引用 ES6 模块本身,因为它不是对象。
因为这个属性,在react或者vue的服务端渲染方式下,某些模块可能会报错,因为其无法在运行时加载,所以当某些模块带有document或者window等node不存在的对象时,就会报错。
if(document) {
import react from 'react'
}
//这种写法会直接报错 error: 'import' and 'export' may only appear at the top level (10:6)
//运行时引入例子。
if(document) {
const react = require('react') //ok
import('react').then(react => {}) //ok
}
理解运行时引入,还是编译时引入真的很重要。
AMD: Asynchronous Module Definition
在浏览器端异步加载模块的模块定义格式。
有两个方法值得学习define和require
define
首先define是具体定义一个amd模块的方式。他的大体格式就像这样:
define(
module_id /*optional*/,
[dependencies] /*optional*/,
definition function /*function for instantiating the module or object*/
);
//举个例子:
define( "myModule",
["foo", "bar"],
// module definition function
// dependencies (foo and bar) are mapped to function parameters
function ( foo, bar ) {
// return a value that defines the module export
// (i.e the functionality we want to expose for consumption)
// create your module here
var myModule = {
doStuff: function () {
console.log( "Yay! Stuff" );
}
};
return myModule;
});
require
require是一个js文件动态加载模块或依赖项的方法。
require(["foo", "bar"], function ( foo, bar ) {
// rest of your code here
foo.doSomething();
});