关于模块化:
- 基本的模块化
对象写法
1 | var Module = { |
减少 Global 上的变量数目,起到了一点点的命名空间作用
同样缺点明显: 会暴露所有模块成员,内部状态可以被外部改写
匿名闭包 :IIFE 模式
1 | var Module = (function(){ |
可以很好的保护私有变量,通过return来设置公开的方法
动态添加方法的时候比较麻烦,且无法修改内部私有变量.
引用全局变量
1 | var Module = (function($){ |
全局变量当成一个参数传入到匿名函数然后使用.
1 | var Module = (function () { |
全局变量Module带有2个可访问的属性Module.method和Module.,除此之外,其它代码都在匿名函数的闭包里保持着私有状态。
module 扩展
将一个功能分离成多个文件
1 | var Module = (function (m) { |
松耦合扩展
解决顺序问题
1 | var Module = (function (m) { |
首个被引入的文件会创建Module命名空间(就是个JavaScript对象),而且所有使用这种结构的后续文件都只是重用此现有实例。
紧耦合扩展
紧耦合扩展限制了加载顺序,但是提供了我们重载的机会
1 | var Module = (function (m) { |
缺点:
- 全局作用域下容易造成变量冲突
- 文件只能按照 script 的书写顺序进行加载
- 开发人员必须主观解决模块和代码库的依赖关系
- 在大型项目中各种资源难以管理,长期积累的问题导致代码库混乱不堪
模块规范
- COMMONJS
CommonJS中,一个单独的文件就是一个模块。每一个模块都是一个单独的作用域,也就是说,在一个文件定义的变量(还包括函数和类),都是私有的,对其他文件是不可见的,除非定义为global对象的属性。
通过 require 方法来同步加载所要依赖的其他模块,然后通过 exports 或 module.exports 来导出需要暴露的接口
CommonJS规范加载模块是同步的,也就是说,只有加载完成,才能执行后面的操作。由于Node.js主要用于服务器编程,模块文件一般都已经存在于本地硬盘,所以加载起来比较快,不用考虑非同步加载的方式,所以CommonJS规范比较适用。
more AMD
AMD模式可以用于浏览器环境,并且允许非同步加载模块,也可以根据需要动态加载模块。RequireJS遵守AMD规范
模块通过 define 函数定义在闭包中,格式如下
define(id?, dependencies?, factory);
id 是模块的名字,它是可选的参数。
dependencies 指定了所要依赖的模块列表,它是一个数组,也是可选的参数,每个依赖的模块的输出将作为参数一次传入 factory 中。如果没有指定 dependencies,那么它的默认值是 [“require”, “exports”, “module”]
factory 是最后一个参数,它包裹了模块的具体实现,它是一个函数或者对象。如果是函数,那么它的返回值就是模块的输出接口或值。
moreCMD
AMD 很相似,尽量保持简单,并与 CommonJS 和 Node.js 的 Modules 规范保持了很大的兼容性。- 依赖就近,延迟执行
- 可以很容易在 Node.js 中运行
- AMD VS CMD
- CMD推崇依赖就近,可以把依赖写进你的代码中的任意一行,代码在运行时,首先是不知道依赖的,需要遍历所有的require关键字,找出后面的依赖。具体做法是将function toString后,用正则匹配出require关键字后面的依赖。显然,这是一种牺牲性能来换取更多开发便利的方法。
- 而AMD是依赖前置的,换句话说,在解析和执行当前模块之前,模块作者必须指明当前模块所依赖的模块,无需遍历整个函数体找到它的依赖,因此性能有所提升,缺点就是开发者必须显式得指明依赖——这会使得开发工作量变大
大势所趋:
- Browserify - CommonJS In Browser
Browserify是一个node.js模块,主要用于改写现有的CommonJS模块,使得浏览器端也可以使用这些模块 - Webpack - Module Bundler
Webpack 是一个模块打包器。它将根据模块的依赖关系进行静态分析,然后将这些模块按照指定的规则生成对应的静态资源。
requirejs是一种在线”编译” 模块的方案,相当于在页面上加载一个AMD 解释器,以便于览器能够识别 define、exports、module,而这些东西就是用于模块化的关键。
而browserify / webpack,则是一个预编译模块的方案。它是预编译的,不需要在浏览器中加载解释器。
ES6 Module
ES6模块的设计思想,是尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量。CommonJS和AMD模块,都只能在运行时确定这些东西模块功能主要由两个命令构成:export和import。export命令用于规定模块的对外接口,import命令用于输入其他模块提供的功能。
more