JavaScript模块的发展史

273 阅读2分钟

前言

  • 对象模块 最开始模块化的概念,就是将静态对象放入一个单独文件,然后调用,不可复用。
var obj={
	name:"Jane",
    age:18
}
  • 立即执行函数 将对象作为立即执行函数的返回结果,可复用,但依赖外部变量,代码没有标准规范。
var obj=(function(outerVar){
	return {
    	name:"Jane",
        age:18,
        prop:outerVar
    }
})(outerVar)

CommonJS+Browserify

CommonJS提出了以下4个概念:

  • module
  • export
  • require
  • global

我们都知道CommonJS导出变量用module.exports或者exports[property]

/*module.js*/
var name="Jane"
module.exports={
	getName(){
    	return name
    },
    changeName(){
    	name='KangKang'
    }
}

/*demo1.js*/
var obj=require('./module.js')
console.log(obj.getName())  //'Jane'
obj.changeName()
console.log(obj.getName())  //'KangKang'

/*demo2.js*/
var obj=require('./module.js')
console.log(obj.getName)  //'KangKang'  

从demo2.js的返回结果,我们能发现require加载执行模块时会将当前状态缓存下来,当其他地方使用到该模块会优先获取缓存值。

现在有个最大的问题就是浏览器不认识CommonJS的module、exports、require等等,所以需要中间脚本Browserify来编译CommonJS成浏览器支持的格式。如果只是在服务端使用,像nodejs,则不用中间脚本。

编译原理不细讲,可以看看阮一峰博客-commonjs-in-browser

AMD UMD

AMD:异步模块定义。

只需一个define方法就能完成导出加载模块,但也需要中间脚本来转译。在前端领域也流行了几年。 浏览器支持的异步模块加载格式

UMD:统一模块定义。

是CommonJS与AMD的折中,具体使用没了解。

ES6

ES6的语法是根据广大开发者的诉求投票出来的,所以是目前JavaScript认可度和流行度最广的语法,它的导出模块形式是export一个变量、函数、类,import ... from ...

值得注意的是ES6 模块不会缓存运行结果,而是动态异步地去被加载的模块取值,并且变量总是绑定其所在的模块。

  1. CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用。
  2. CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。
  3. CommonJS 模块的require()是同步加载模块,ES6 模块的import命令是异步加载,有一个独立的模块依赖的解析阶段。

也就是说es6模块当导出文件的变量发生改变,则引入文件的变量也随之改变;另外JS引擎解析时遇到import会生成一个只读引用,待到执行时去引用文件读取变量的值;

// module.js
export let count = 1;
export function addCount() {
  count++;
}

// main.js
import { count, addCount } from './module';
console.log(count); // 1
addCount();
console.log(count); // 2