前端模块化
模块化是一种将系统分离成独立功能部分的方法,一个模块是为完成一个功能的一段程序或子程序。"模块"是系统中功能单一且可替换的部分。
模块化思想是从java上衍生过来的,他将所需要的功能封装成一个类,哪里需要就在哪里调用,JS中没有类的说法,但它引入了这种思想,在js中用对象或构造函数来模拟类的封装实现模块化,而在html上,则使用import和require。
所属规范
require/exports 是 CommonJS/AMD 中为了解决模块化语法而引入的。
import/export 是ES6引入的新规范,因为浏览器引擎兼容问题,需要在node中用babel将ES6语法编译成ES5语法。
关于import在浏览器中被支持的情况如下
调用时间
require 是运行时调用,所以理论上可以运作在代码的任何地方。
import 是编译时调用,所以必须放在文件的开头。
原理
require 是赋值过程,其实require的结果就是对象、数字、字符串、函数等,再把结果赋值给某个变量。它是普通的值拷贝传递。
import 是解构过程。使用import导入模块的属性或者方法是引用传递。且import是read-only的,值是单向传递的。default是ES6 模块化所独有的关键字,export default {} 输出默认的接口对象,如果没有命名,则在import时可以自定义一个名称用来关联这个对象。
require & exports & module.exports
module.exports是真正的接口,exports只不过是它的辅助工具;最终返回给调用的是Module.exports而不是exports。
module.exports 导出的为具体类型的实例化对象,而exports 则不是。
其实,Module.exports才是真正的接口,exports只不过是它的一个辅助工具。最终返回给调用的是Module.exports而不是exports。
注意: 所有的exports收集到的属性和方法,都赋值给了Module.exports。当然,这有个前提,就是Module.exports本身不具备任何属性和方法。如果,Module.exports已经具备一些属性和方法,那么exports收集来的信息将被忽略。
exports
//导出文件module.js
function outputA(){
console.log("this is output A");
}
function outputB(){
console.log("this is output B");
}
`会形成一个对象
{
outputA:[Function: exports.outputA],
outputB:[Function: exports.outputB]
}`
exports.outputA = outputA; //通过exports写法
exports.outputB = outputB;//通过exports写法
//导入文件module.js
// 方式1
let mod = require("./mout.js");
// 方式2
let {outputA, outputB} = require("./mout.js");
module.exports
// 导出
module.exports = function(name, age) {
this.name = name;
this.age = age;
this.about = function() {
console.log(this.name +' is '+ this.age +' years old');
};
};
// 导入
var Rocker = require('./rocker.js');
var r = new Rocker('Ozzy', 62);
r.about(); // Ozzy is 62 years old
exports + module.exports
// 导出
const outputA = 'this is outputA'
const outputB = 'this is outputB'
exports.outputA = outputA
exports.outputB = outputB
module.exports = function(name){
console.log('name: ', name)
}
// 导入
const someModule = require('./module.js')
someModule.outputA // 报错,outputA和outputB被覆盖了
someModule('tom')
export & export default
// 导出 module.js
export function test(args) {
console.log(args);
}
// 定义一个默认导出文件, 一个文件只能定义一次
export default {
a: function() {
console.log('export from module');
}
}
export const name = 'gzc'
// 倒入
import common, { test } from './module.js'
common.a() // 打印 export from module
test(`my name is harry`) // 打印 my name is harry
注意
有可能报这个错
Cannot assign to read only property 'exports' of object '#<Object>'
在同一个文件中,导入方式可以两种一起用,但是导出方式要注意,module.exports不能和import同时出现。
总结
-
通过
require引入基础数据类型时,属于复制该变量。 -
通过
require引入复杂数据类型时, 属于浅拷贝该对象。 -
出现模块之间循环引用时, 会输出已执行的模块, 未执行模块不会输出。
-
CommonJS规范默认
export的是一个对象,即使导出的是基础数据类型。