媒介:很久没写文章总结了,此次重要大略的总结一下 js中的模块化
1.模块
模块的职责:封装完成,暴露接口,声明依靠。先来一个对照,下面代码没有运用任何模块体系
(1)无封装
math.js
:(1)没有封装性(2)接口不明显
function add(a,b){
return a+ b
}
function sub(a,b){
return a - b
}
caculator.js
:(1)依靠math.js然则没有依靠声明 (2)运用全局状况
var action = "add";
function compute(a,b){
switch (action){
case "add": return add(a,b)
case "sub": return add(a,b)
}
}
(2)字面量
math.js
:(1)结构性好(2)接见掌握没有
var math = {
add:function add(a,b){
return a+ b
},
sub:function sub(a,b){
return a - b
}
}
caculator.js
:(1)依靠math.js然则没有依靠声明 (2)没法标明属性是私有,无封装
var caculator = {
action:'add';
compute:function compute(a,b){
switch (action){
case "add": return math.add(a,b)
case "sub": return math.add(a,b)
}
}
}
(3)IIFE:字值型的函数表达式
能够建立一个部份作用域,封装内部成员变量,经由历程return输出须要输出的接口
版本一:caculator-1.js
:(1)完成了接见掌握(2)依旧没有依靠声明
var caculator = (function(){
var action = "add";
return{
compute:function compute(a,b){
switch (action){
case "add": return math.add(a,b)
case "sub": return math.add(a,b)
}
}
}
})()
版本二:caculator-2.js
:(1)显现依靠声明(2)依然污染了全局变量(3)必需手动举行依靠治理
揭破模块情势:return部份与版本一不太一样,把要领定义在函数体内里,return的只是要领。详细可参考这位童鞋的文章:Javascript 设想情势 — Revealing Module(展现模块)情势
var caculator = (function(m){
var action = "add";
function compute(a,b(){
switch (action){
case "add": return m.add(a,b)
case "sub": return m.add(a,b)
}
}
return{
compute:compute
}
})(math)
(4)定名空间
处置惩罚暴露全局变量的题目,只暴露一个相似namespace的全局变量就完成一切模块的声明
math.js
:(1)第一个参数是模块声明;(2)第二个参数是声明依靠,现在是没有依靠的;(3)第三个参数是模块的组成
namespace("math",[],function(){
function add(a,b){
return a+ b
}
function sub(a,b){
return a - b
}
return{
add:add,
sub:sub
}
})
caculator.js
:(1)有依靠性命(2)依靠math被当作参数传入
namespace("caculator",["math"],function(m){
var action = "add"
function compute(a,b){
return m[action](a,b)
}
return{
compute:compute
}
})
namespace
的代码:照样没有处置惩罚依靠治理的题目,假如各个模块疏散在差别的文件中,就要对剧本加载递次举行手动的排序
var namespace = (function(){
//缓存一切的模块
var cache = {}
function createModule(name,deps,definition){ //参数是:模块名,依靠列表,定义
//先对参数举行推断,假如只要一个参数,就返回
if(arguments.length === 1){
return cache[name]
}
//必需获得一切依靠的模块,要保证前面的模块已被定义好了
deps = deps.map(function(depName){
return ns(depName)
})
//初始化模块并返回
cache[name] = definition.apply(null,deps)
return cache[name];
}
return createModule
})()
2.模块体系
职责:(1)依靠治理:加载/剖析/注入/初始化 (2)决议模块的写法
下面总结三种典范的模块体系的写法
(1)commonjs
长处:
依靠治理成熟牢靠
社区活泼,范例接收度高
运行时支撑,模块定义异常简朴
文件级别的模块作用域断绝
能够处置惩罚轮回依靠
瑕玷:
不是规范构造的范例
同步的require,没有斟酌浏览器异步加载的历程
然则照样有方法运用的,现在有许多东西能够把多个模块的文件打包成一个文件:
browserify,webpack,component
看下面用commonjs
写就的代码:math.js
:
function add(a,b){
return a+ b
}
function sub(a,b){
return a - b
}
exports.add = add
exports.sub = sub
caculator.js
:
var math = require("./math"); //依靠声明
function Caculator(container){
this.left = container.querySelector(".j-left" );
this.right = container.querySelector(".j-right" );
this.add = container.querySelector(".j-add" );
this.result = container.querySelector(".j-result");
this.add.addEventListener("click",this.compute.bind(this));
}
Caculator.prototype.compute = function(){
this.result.textContent = math.add(+this.left.value, +this.right.value)
}
exports.Caculator = Caculator; //暴露接口
用前端打包东西举行打包math.js
和caculator.js
起首装置browserify
,在敕令行输入敕令:browserify caculator.js > caculator-bundle.js
打包成形如定名空间的文件情势
(2)AMD
自然的作用于异步环境
AMD代码写法:math.js
:第一个参数是依靠列表
define([],function(){
function add(a,b){
return a+ b
}
function sub(a,b){
return a - b
}
return{ //接口暴露
add:add,
sub:sub
}
})
caculator.js
:参数一是依靠声明,参数二是依靠注入
define(["./math"],function(math){
function Caculator(container){
this.left = container.querySelector(".j-left" );
this.right = container.querySelector(".j-right" );
this.add = container.querySelector(".j-add" );
this.result = container.querySelector(".j-result");
this.add.addEventListener("click",this.compute.bind(this));
}
Caculator.prototype.compute = function(){}
return{
Caculator:Caculator
}
})
AMD还支撑一个叫Simplified CommonJS wrapping
define(function(require,exports){
var math = require("./math");
function Caculator(container){
this.left = container.querySelector(".j-left" );
this.right = container.querySelector(".j-right" );
this.add = container.querySelector(".j-add" );
this.result = container.querySelector(".j-result");
this.add.addEventListener("click",this.compute.bind(this));
}
Caculator.prototype.compute = function(){}
exports.Caculator = Caculator;
})
上述怎样猎取依靠列表呢?
函数经由历程toString能够打印出它的函数体,然后用正则表达式提取出来factory.toString()
/require\(['"]([^'"]*)['"]\)/.exec(factory.toString())[1]
长处:
依靠治理成熟牢靠
社区活泼,范例接收度高
专为
异步IO打造
,合适浏览器环境支撑相似Commonjs的誊写体式格局
经由历程插件api可支撑加载非js资本
成熟的打包构建东西,并可连系插件
瑕玷:
模块定义烦琐,须要分外嵌套
只是库级别的支撑,须要引入分外的库
没法处置惩罚轮回依靠
没法完成前提加载
(3)ES6/module
言语级别的支撑,将来的模块化