??榛睦斫?/h2>
什么是??椋?/p>
将一个复杂的程序依据一定的规则(规范)封装成几个块(文件), 并进行组合在一起;
块的内部数据/实现是私有的, 只是向外部暴露一些接口(方法)与外部其它??橥ㄐ?;
一个??榈淖槌?/p>
数据--->内部的属性;
操作数据的行为--->内部的函数;
模块化是指解决一个复杂的问题时自顶向下把系统划分成若干??榈墓蹋卸嘀质粜?,分别反映其内部特性;
模块化编码:编码时是按照??橐桓鲆桓霰嗦氲? 整个项目就是一个??榛南钅?;
非??榛奈侍?/h3>页面加载多个js的问题:
<script?type="text/javascript"?src="module1.js"></script>?
<script?type="text/javascript"?src="module2.js"></script>?
<script?type="text/javascript"?src="module3.js"></script>?
<script?type="text/javascript"?src="module4.js"></script>
发生问题:
难以维护 ;
依赖模糊;
请求过多;
所以,这些问题可以通过现代模块化编码和项目构建来解决;
模块化的优点
更好地分离:避免一个页面中放置多个script标签,而只需加载一个需要的整体模块即可,这样对于HTML和JavaScript分离很有好处;
更好的代码组织方式:有利于后期更好的维护代码;
按需加载:提高使用性能,和下载速度,按需求加载需要的模块
避免命名冲突:JavaScript本身是没有命名空间,经常会有命名冲突,??榛湍苁鼓?槟诘娜魏涡问降拿疾换嵩俸推渌?橛谐逋?。
更好的依赖处理:使用模块化,只需要在??槟诓可昝骱靡览档木托?,增加删除都直接修改模块即可,在调用的时候也不用管该模块依赖了哪些其他???。
??榛姆⒄估?/h3>原始写法
只是把不同的函数简单地放在一起,就算一个??椋?/p>
function?fun1(){//...?}?
function?fun2(){//...?}?
//上面的函数fun1,fun2组成了一个???,使用的时候直接调用某个函数就行了。
缺点:
"污染"了全局变量,无法保证不与其他??榉⑸淞棵逋?;
模块成员之间看不出直接关系。
对象写法
为了解决污染全局变量的问题,可以把??樾闯梢桓龆韵螅械哪?槌稍倍挤诺秸飧龆韵罄锩?。
var?module1?=?new?Object({?count?:?0,?fun1?:?function?(){?//...???},?
fun2?:?function?(){?//...?}?});?
//这个里面的fun1和fun2都封装在一个赌侠宁里,可以通过对象.方法的形式进行调用;?
module1.fun1();
优点:
减少了全局上的变量数目;
缺点:
本质是对象,而这个对象会暴露所有??槌稍?,内部状态可以被外部改写。
立即执行函数(IIFE模式)
避免暴露私有成员,所以使用立即执行函数(自调函数,IIFE);
作用: 数据是私有的, 外部只能通过暴露的方法操作
var?module1?=?(function(){?
????var?count?=?0;?
????var?fun1?=?function(){?//...?}?
????var?fun2?=?function(){?//...?}?
????//将想要暴露的内容放置到一个对象中,通过return返回到全局作用域。?
????return{?fun1:fun1,?fun2:fun2?}?})()?
????//这样的话只能在全局作用域中读到fun1和fun2,但是读不到变量count,也修改不了了。?
????//问题:当前这个??橐览盗硪桓瞿?樵趺窗??
IIFE的增强(引入依赖)
如果一个??楹艽?,必须分成几个部分,或者一个模块需要继承另一个???,这时就有必要采用"增强模式";
IIFE模式增强:引入依赖;
这就是现代??槭迪值幕?;
var?module1?=?(function?(mod){?
????mod.fun3?=?function?()?{?//...?};?
????return?mod;?})(module1);?
????
?//为module1??樘砑恿艘桓鲂路椒╢un3(),然后返回新的module1??椤?
?//引入jquery到项目中;?
var?Module?=?(function($){????
????var?_$body?=?$("body");?????
????var?foo?=?function(){?????console.log(_$body);????//?特权方法?????}???
????//?Revelation?Pattern???return?{???????foo:?foo???}?})(jQuery)?
??Module.foo();
js模块化需要解决那些问题:
1.如何安全的包装一个??榈拇耄浚ú晃廴灸?橥獾娜魏未耄?/p>
2.如何唯一标识一个模块?
3.如何优雅的把??榈腁PI暴漏出去?(不能增加全局变量)
4.如何方便的使用所依赖的????
模块化规范
Node: 服务器端
Browserify : 浏览器端
CommonJS:服务器端
概述
Node 应用由??樽槌?,采用 CommonJS ??楣娣?。
CommonJS规范规定,每个模块内部,module变量代表当前模块。这个变量是一个对象,它的exports属性(即module.exports)是对外的接口。加载某个??椋涫凳羌釉馗媚?榈膍odule.exports属性。
特点
所有代码都运行在??樽饔糜?,不会污染全局作用域。
??榭梢远啻渭釉兀侵换嵩诘谝淮渭釉厥痹诵幸淮?,然后运行结果就被缓存了,以后再加载,就直接读取缓存结果。要想让??樵俅卧诵校匦肭宄捍?。
??榧釉氐乃承?,按照其在代码中出现的顺序。
-
基本语法:
exports.xxx?=?value?//?通过module.exports指定暴露的对象value?
module.exports?=?value
var?module?=?require('??橄喽月肪?)
引入模块 : require
定义暴露???: exports
引入??榉⑸谑裁词焙?
Node:运行时, 动态同步引入;
Browserify:在运行前对??榻斜嘁?转译/打包的处理(已经将依赖的??榘戳?, 运行的是打包生成的js, 运行时不需要再从远程引入依赖??椋?/p>
CommonJS通用的??楣娣叮ㄍ剑?/h4>
Node内部提供一个Module构建函数。所有模块都是Module的实例。
每个模块内部,都有一个module对象,代表当前???。
module.exports属性表示当前??槎酝馐涑龅慕涌?,其他文件加载该???,实际上就是读取module.exports变量。
Node为每个??樘峁┮桓鰁xports变量,指向module.exports。
如果一个??榈亩酝饨涌?,就是一个单一的值,不能使用exports输出,只能使用module.exports输出。
Modules/1.0规范包含内容:
??榈谋晔队ψ裱墓嬖颍ㄊ樾垂娣叮?/p>
定义全局函数require,通过传入??楸晔独匆肫渌?椋葱械慕峁次?楸┞冻隼吹腁PI;
如果被require函数引入的??橹幸舶览?,那么依次加载这些依赖;
如果引入??槭О埽敲磖equire函数应该报一个异常;
??橥ü淞縠xports来向外暴露API,exports赋值暴露的只能是一个对象exports = {Obj}
,暴露的API须作为此对象的属性。exports本质是引入了module.exports的对象。不能直接将exports变量指向一个值,因为这样等于切断了exports与module.exports的联系。
如果暴露的不是变量exports,而是module.exports。module变量代表当前???,这个变量是一个对象,它的exports属性(即module.exports)是对外的接口。加载某个模块,其实是加载该模块的module.exports属性。exports=module.exports={Obj}
node中的commonJS教程
1.安装node.js;
2.创建项目结构
//结构如下?
|-modules?
|-module1.js//待引入模块1?
|-module2.js//待引入????
|-module3.js//待引入????
|-app.js//主???
|-package.json?{???"name":?"commonjsnode",???"version":?"1.0.0"?}
-
3.下载第三方??椋壕倮齟xpress
npm?i?express?--save
4.模块化编码
//?module1??//?使用module.exports?=?value向外暴露一个对象?
module.exports?=?{?
????name:?'this?is?module1',?????
????foo(){?????????console.log('module1?foo()');?????}?
}?
//?module2??//?使用module.exports?=?value向外暴露一个函数??
module.exports?=?function?()?{?????
????console.log('module2()');?
}?
//?module3??
//?使用exports.xxx?=?value向外暴露一个对象??
exports.foo?=?function?()?{??????
????console.log('module3?foo()');??
};??
exports.bar?=?function?()?{??????
????console.log('module3?bar()');??
};??
exports.name?=?'this?is?module3'?//app.js文件?
var?uniq?=?require('uniq');?//引用???
let?module1?=?require('./modules/module1');?
let?module2?=?require('./modules/module2');?
let?module3?=?require('./modules/module3');?//使用???
module1.foo();?
module2();?
module3.foo();?
module3.bar();?
module3.name;
5.通过node运行app.js
命令:node.app.js
工具:右键-->运行
浏览器中的commonJS教程
借助Browserify
-
步骤
|-js??
|-dist?//打包生成文件的目录??
|-src?//源码所在的目录????
|-module1.js????
|-module2.js????
|-module3.js????
|-app.js?//应用主源文件?
|-index.html?//浏览器上的页面?
|-package.json?{????"name":?"browserify-test",????"version":?"1.0.0"?}
<script?type="text/javascript"?src="js/dist/bundle.js"></script>
全局: npm install browserify -g
局部: npm install browserify --save-dev
下载browserify
定义??榇耄篿ndex.html文件要运行在浏览器上,需要借助browserify将app.js文件打包编译,如果直接在index.html引入app.js就会报错。
打包处理js:根目录下运行browserify js/src/app.js -o js/dist/bundle.js
页面使用引入:
创建项目结构
AMD : 浏览器端
CommonJS规范加载??槭峭降?,也就是说,只有加载完成,才能执行后面的操作。
AMD规范则是非同步加载???,允许指定回调函数,可以实现异步加载依赖模块,并且会提前加载;
由于Node.js主要用于服务器编程,??槲募话愣家丫嬖谟诒镜赜才?,所以加载起来比较快,不用考虑非同步加载的方式,所以CommonJS规范比较适用。
如果是浏览器环境,要从服务器端加载模块,这时就必须采用非同步模式,因此浏览器端一般采用AMD规范。
语法
AMD规范基本语法
定义暴露模块: define([依赖??槊鸧, function(){return 模块对象})
引入??? require(['???', '???', '模块3'], function(m1, m2){//使用??槎韵髛)
兼容CommonJS规范的输出???/h5>define(function?(require,?exports,?module)?{??????
????var?reqModule?=?require("./someModule");?????
????requModule.test();?????
exports.asplode?=?function?()?{?????????//someing?????}?});
AMD:异步模块定义规范(预加载)
AMD规范:github.com/amdjs/amdjs…
AMD是"Asynchronous Module Definition"的缩写,意思就是"异步??槎ㄒ?。
它采用异步方式加载??椋?榈募釉夭挥跋焖竺嬗锞涞脑诵?。所有依赖这个??榈挠锞洌级ㄒ逶谝桓龌氐骱?,等到加载完成之后,这个回调函数才会运行。
-
AMD也采用require()语句加载模块,但是不同于CommonJS,它要求两个参数:
require([module],?callback);
第一个参数[module],是一个数组,里面的成员就是要加载的??椋?/p>
第二个参数callback,则是加载成功之后的回调函数。
目前,主要有两个Javascript库实现了AMD规范:RequireJS和curl.js。
RequireJS
优点
实现js文件的异步加载,避免网页失去响应;
管理??橹涞囊览敌裕阌诖氲谋嘈春臀?。
require.js使用教程
下载require.js, 并引入
官网: requirejs.org/
github : github.com/requirejs/r…
将require.js导入项目: js/libs/require.js
创建项目结构
|-js???
|-libs?????
|-require.js?//?引入的require.js???
|-modules?????
|-alerter.js?????
|-dataService.js???
|-main.js?
|-index.html
-
定义require.js的??榇?/p>
define(['myLib'],?function(myLib){??
function?foo(){?myLib.doSomething();?}?//?暴露???
return?{foo?:?foo};?});?
//当require()函数加载上面这个??榈氖焙?,就会先加载myLib.js文件。
?-?如果这个模块还依赖其他???,那么define()函数的第一个参数,必须是一个数组,指明该??榈囊览敌裕??```??//?dataService.js??define(function?()?{????let?msg?=?'this?is?dataService'????function?getMsg()?{???return?msg.toUpperCase()????}????return?{getMsg}??})????//?alerter.js??define(['dataService',?'jquery'],?function?(dataService,?$)?{????let?name?=?'Tom2'????function?showMsg()?{??????$('body').css('background',?'gray')??????alert(dataService.getMsg()?+?',?'?+?name)????}????return?{showMsg}??})??```
如果一个??椴灰览灯渌??,那么可以直接定义在define()函数之中。
require.js加载的??椋捎肁MD规范。也就是说,??楸匦氚凑誂MD的规定来写。
具体来说,就是??楸匦氩捎锰囟ǖ膁efine()函数来定义;
什么是??椋?/p>
将一个复杂的程序依据一定的规则(规范)封装成几个块(文件), 并进行组合在一起;
块的内部数据/实现是私有的, 只是向外部暴露一些接口(方法)与外部其它??橥ㄐ?;
一个??榈淖槌?/p>
数据--->内部的属性;
操作数据的行为--->内部的函数;
模块化是指解决一个复杂的问题时自顶向下把系统划分成若干??榈墓蹋卸嘀质粜?,分别反映其内部特性;
模块化编码:编码时是按照??橐桓鲆桓霰嗦氲? 整个项目就是一个??榛南钅?;
页面加载多个js的问题:
<script?type="text/javascript"?src="module1.js"></script>? <script?type="text/javascript"?src="module2.js"></script>? <script?type="text/javascript"?src="module3.js"></script>? <script?type="text/javascript"?src="module4.js"></script>
发生问题:
难以维护 ;
依赖模糊;
请求过多;
所以,这些问题可以通过现代模块化编码和项目构建来解决;
模块化的优点
更好地分离:避免一个页面中放置多个script标签,而只需加载一个需要的整体模块即可,这样对于HTML和JavaScript分离很有好处;
更好的代码组织方式:有利于后期更好的维护代码;
按需加载:提高使用性能,和下载速度,按需求加载需要的模块
避免命名冲突:JavaScript本身是没有命名空间,经常会有命名冲突,??榛湍苁鼓?槟诘娜魏涡问降拿疾换嵩俸推渌?橛谐逋?。
更好的依赖处理:使用模块化,只需要在??槟诓可昝骱靡览档木托?,增加删除都直接修改模块即可,在调用的时候也不用管该模块依赖了哪些其他???。
??榛姆⒄估?/h3>原始写法
只是把不同的函数简单地放在一起,就算一个??椋?/p>
function?fun1(){//...?}?
function?fun2(){//...?}?
//上面的函数fun1,fun2组成了一个???,使用的时候直接调用某个函数就行了。
缺点:
"污染"了全局变量,无法保证不与其他??榉⑸淞棵逋?;
模块成员之间看不出直接关系。
对象写法
为了解决污染全局变量的问题,可以把??樾闯梢桓龆韵螅械哪?槌稍倍挤诺秸飧龆韵罄锩?。
var?module1?=?new?Object({?count?:?0,?fun1?:?function?(){?//...???},?
fun2?:?function?(){?//...?}?});?
//这个里面的fun1和fun2都封装在一个赌侠宁里,可以通过对象.方法的形式进行调用;?
module1.fun1();
优点:
减少了全局上的变量数目;
缺点:
本质是对象,而这个对象会暴露所有??槌稍?,内部状态可以被外部改写。
立即执行函数(IIFE模式)
避免暴露私有成员,所以使用立即执行函数(自调函数,IIFE);
作用: 数据是私有的, 外部只能通过暴露的方法操作
var?module1?=?(function(){?
????var?count?=?0;?
????var?fun1?=?function(){?//...?}?
????var?fun2?=?function(){?//...?}?
????//将想要暴露的内容放置到一个对象中,通过return返回到全局作用域。?
????return{?fun1:fun1,?fun2:fun2?}?})()?
????//这样的话只能在全局作用域中读到fun1和fun2,但是读不到变量count,也修改不了了。?
????//问题:当前这个??橐览盗硪桓瞿?樵趺窗??
IIFE的增强(引入依赖)
如果一个??楹艽?,必须分成几个部分,或者一个模块需要继承另一个???,这时就有必要采用"增强模式";
IIFE模式增强:引入依赖;
这就是现代??槭迪值幕?;
var?module1?=?(function?(mod){?
????mod.fun3?=?function?()?{?//...?};?
????return?mod;?})(module1);?
????
?//为module1??樘砑恿艘桓鲂路椒╢un3(),然后返回新的module1??椤?
?//引入jquery到项目中;?
var?Module?=?(function($){????
????var?_$body?=?$("body");?????
????var?foo?=?function(){?????console.log(_$body);????//?特权方法?????}???
????//?Revelation?Pattern???return?{???????foo:?foo???}?})(jQuery)?
??Module.foo();
js模块化需要解决那些问题:
1.如何安全的包装一个??榈拇耄浚ú晃廴灸?橥獾娜魏未耄?/p>
2.如何唯一标识一个模块?
3.如何优雅的把??榈腁PI暴漏出去?(不能增加全局变量)
4.如何方便的使用所依赖的????
模块化规范
Node: 服务器端
Browserify : 浏览器端
CommonJS:服务器端
概述
Node 应用由??樽槌?,采用 CommonJS ??楣娣?。
CommonJS规范规定,每个模块内部,module变量代表当前模块。这个变量是一个对象,它的exports属性(即module.exports)是对外的接口。加载某个??椋涫凳羌釉馗媚?榈膍odule.exports属性。
特点
所有代码都运行在??樽饔糜?,不会污染全局作用域。
??榭梢远啻渭釉兀侵换嵩诘谝淮渭釉厥痹诵幸淮?,然后运行结果就被缓存了,以后再加载,就直接读取缓存结果。要想让??樵俅卧诵校匦肭宄捍?。
??榧釉氐乃承?,按照其在代码中出现的顺序。
-
基本语法:
exports.xxx?=?value?//?通过module.exports指定暴露的对象value?
module.exports?=?value
var?module?=?require('??橄喽月肪?)
引入模块 : require
定义暴露???: exports
引入??榉⑸谑裁词焙?
Node:运行时, 动态同步引入;
Browserify:在运行前对??榻斜嘁?转译/打包的处理(已经将依赖的??榘戳?, 运行的是打包生成的js, 运行时不需要再从远程引入依赖??椋?/p>
CommonJS通用的??楣娣叮ㄍ剑?/h4>
Node内部提供一个Module构建函数。所有模块都是Module的实例。
每个模块内部,都有一个module对象,代表当前???。
module.exports属性表示当前??槎酝馐涑龅慕涌?,其他文件加载该???,实际上就是读取module.exports变量。
Node为每个??樘峁┮桓鰁xports变量,指向module.exports。
如果一个??榈亩酝饨涌?,就是一个单一的值,不能使用exports输出,只能使用module.exports输出。
Modules/1.0规范包含内容:
??榈谋晔队ψ裱墓嬖颍ㄊ樾垂娣叮?/p>
定义全局函数require,通过传入??楸晔独匆肫渌?椋葱械慕峁次?楸┞冻隼吹腁PI;
如果被require函数引入的??橹幸舶览?,那么依次加载这些依赖;
如果引入??槭О埽敲磖equire函数应该报一个异常;
??橥ü淞縠xports来向外暴露API,exports赋值暴露的只能是一个对象exports = {Obj}
,暴露的API须作为此对象的属性。exports本质是引入了module.exports的对象。不能直接将exports变量指向一个值,因为这样等于切断了exports与module.exports的联系。
如果暴露的不是变量exports,而是module.exports。module变量代表当前???,这个变量是一个对象,它的exports属性(即module.exports)是对外的接口。加载某个模块,其实是加载该模块的module.exports属性。exports=module.exports={Obj}
node中的commonJS教程
1.安装node.js;
2.创建项目结构
//结构如下?
|-modules?
|-module1.js//待引入模块1?
|-module2.js//待引入????
|-module3.js//待引入????
|-app.js//主???
|-package.json?{???"name":?"commonjsnode",???"version":?"1.0.0"?}
-
3.下载第三方??椋壕倮齟xpress
npm?i?express?--save
4.模块化编码
//?module1??//?使用module.exports?=?value向外暴露一个对象?
module.exports?=?{?
????name:?'this?is?module1',?????
????foo(){?????????console.log('module1?foo()');?????}?
}?
//?module2??//?使用module.exports?=?value向外暴露一个函数??
module.exports?=?function?()?{?????
????console.log('module2()');?
}?
//?module3??
//?使用exports.xxx?=?value向外暴露一个对象??
exports.foo?=?function?()?{??????
????console.log('module3?foo()');??
};??
exports.bar?=?function?()?{??????
????console.log('module3?bar()');??
};??
exports.name?=?'this?is?module3'?//app.js文件?
var?uniq?=?require('uniq');?//引用???
let?module1?=?require('./modules/module1');?
let?module2?=?require('./modules/module2');?
let?module3?=?require('./modules/module3');?//使用???
module1.foo();?
module2();?
module3.foo();?
module3.bar();?
module3.name;
5.通过node运行app.js
命令:node.app.js
工具:右键-->运行
浏览器中的commonJS教程
借助Browserify
-
步骤
|-js??
|-dist?//打包生成文件的目录??
|-src?//源码所在的目录????
|-module1.js????
|-module2.js????
|-module3.js????
|-app.js?//应用主源文件?
|-index.html?//浏览器上的页面?
|-package.json?{????"name":?"browserify-test",????"version":?"1.0.0"?}
<script?type="text/javascript"?src="js/dist/bundle.js"></script>
全局: npm install browserify -g
局部: npm install browserify --save-dev
下载browserify
定义??榇耄篿ndex.html文件要运行在浏览器上,需要借助browserify将app.js文件打包编译,如果直接在index.html引入app.js就会报错。
打包处理js:根目录下运行browserify js/src/app.js -o js/dist/bundle.js
页面使用引入:
创建项目结构
AMD : 浏览器端
CommonJS规范加载??槭峭降?,也就是说,只有加载完成,才能执行后面的操作。
AMD规范则是非同步加载???,允许指定回调函数,可以实现异步加载依赖模块,并且会提前加载;
由于Node.js主要用于服务器编程,??槲募话愣家丫嬖谟诒镜赜才?,所以加载起来比较快,不用考虑非同步加载的方式,所以CommonJS规范比较适用。
如果是浏览器环境,要从服务器端加载模块,这时就必须采用非同步模式,因此浏览器端一般采用AMD规范。
语法
AMD规范基本语法
定义暴露模块: define([依赖??槊鸧, function(){return 模块对象})
引入??? require(['???', '???', '模块3'], function(m1, m2){//使用??槎韵髛)
兼容CommonJS规范的输出???/h5>define(function?(require,?exports,?module)?{??????
????var?reqModule?=?require("./someModule");?????
????requModule.test();?????
exports.asplode?=?function?()?{?????????//someing?????}?});
AMD:异步模块定义规范(预加载)
AMD规范:github.com/amdjs/amdjs…
AMD是"Asynchronous Module Definition"的缩写,意思就是"异步??槎ㄒ?。
它采用异步方式加载??椋?榈募釉夭挥跋焖竺嬗锞涞脑诵?。所有依赖这个??榈挠锞洌级ㄒ逶谝桓龌氐骱?,等到加载完成之后,这个回调函数才会运行。
-
AMD也采用require()语句加载模块,但是不同于CommonJS,它要求两个参数:
require([module],?callback);
第一个参数[module],是一个数组,里面的成员就是要加载的??椋?/p>
第二个参数callback,则是加载成功之后的回调函数。
目前,主要有两个Javascript库实现了AMD规范:RequireJS和curl.js。
RequireJS
优点
实现js文件的异步加载,避免网页失去响应;
管理??橹涞囊览敌裕阌诖氲谋嘈春臀?。
require.js使用教程
下载require.js, 并引入
官网: requirejs.org/
github : github.com/requirejs/r…
将require.js导入项目: js/libs/require.js
创建项目结构
|-js???
|-libs?????
|-require.js?//?引入的require.js???
|-modules?????
|-alerter.js?????
|-dataService.js???
|-main.js?
|-index.html
-
定义require.js的??榇?/p>
define(['myLib'],?function(myLib){??
function?foo(){?myLib.doSomething();?}?//?暴露???
return?{foo?:?foo};?});?
//当require()函数加载上面这个??榈氖焙?,就会先加载myLib.js文件。
?-?如果这个模块还依赖其他???,那么define()函数的第一个参数,必须是一个数组,指明该??榈囊览敌裕??```??//?dataService.js??define(function?()?{????let?msg?=?'this?is?dataService'????function?getMsg()?{???return?msg.toUpperCase()????}????return?{getMsg}??})????//?alerter.js??define(['dataService',?'jquery'],?function?(dataService,?$)?{????let?name?=?'Tom2'????function?showMsg()?{??????$('body').css('background',?'gray')??????alert(dataService.getMsg()?+?',?'?+?name)????}????return?{showMsg}??})??```
如果一个??椴灰览灯渌??,那么可以直接定义在define()函数之中。
require.js加载的??椋捎肁MD规范。也就是说,??楸匦氚凑誂MD的规定来写。
具体来说,就是??楸匦氩捎锰囟ǖ膁efine()函数来定义;
只是把不同的函数简单地放在一起,就算一个??椋?/p>
缺点:
"污染"了全局变量,无法保证不与其他??榉⑸淞棵逋?;
模块成员之间看不出直接关系。
为了解决污染全局变量的问题,可以把??樾闯梢桓龆韵螅械哪?槌稍倍挤诺秸飧龆韵罄锩?。
优点:
减少了全局上的变量数目;
缺点:
本质是对象,而这个对象会暴露所有??槌稍?,内部状态可以被外部改写。
避免暴露私有成员,所以使用立即执行函数(自调函数,IIFE);
作用: 数据是私有的, 外部只能通过暴露的方法操作
如果一个??楹艽?,必须分成几个部分,或者一个模块需要继承另一个???,这时就有必要采用"增强模式";
IIFE模式增强:引入依赖;
这就是现代??槭迪值幕?;
1.如何安全的包装一个??榈拇耄浚ú晃廴灸?橥獾娜魏未耄?/p>
2.如何唯一标识一个模块?
3.如何优雅的把??榈腁PI暴漏出去?(不能增加全局变量)
4.如何方便的使用所依赖的????
Node: 服务器端
Browserify : 浏览器端
概述
Node 应用由??樽槌?,采用 CommonJS ??楣娣?。
CommonJS规范规定,每个模块内部,module变量代表当前模块。这个变量是一个对象,它的exports属性(即module.exports)是对外的接口。加载某个??椋涫凳羌釉馗媚?榈膍odule.exports属性。
特点
所有代码都运行在??樽饔糜?,不会污染全局作用域。
??榭梢远啻渭釉兀侵换嵩诘谝淮渭釉厥痹诵幸淮?,然后运行结果就被缓存了,以后再加载,就直接读取缓存结果。要想让??樵俅卧诵校匦肭宄捍?。
??榧釉氐乃承?,按照其在代码中出现的顺序。
基本语法:
exports.xxx?=?value?//?通过module.exports指定暴露的对象value? module.exports?=?value
var?module?=?require('??橄喽月肪?)
引入模块 : require
定义暴露???: exports
引入??榉⑸谑裁词焙?
Node:运行时, 动态同步引入;
Browserify:在运行前对??榻斜嘁?转译/打包的处理(已经将依赖的??榘戳?, 运行的是打包生成的js, 运行时不需要再从远程引入依赖??椋?/p>
Node内部提供一个Module构建函数。所有模块都是Module的实例。
每个模块内部,都有一个module对象,代表当前???。
module.exports属性表示当前??槎酝馐涑龅慕涌?,其他文件加载该???,实际上就是读取module.exports变量。
Node为每个??樘峁┮桓鰁xports变量,指向module.exports。
如果一个??榈亩酝饨涌?,就是一个单一的值,不能使用exports输出,只能使用module.exports输出。
Modules/1.0规范包含内容:
??榈谋晔队ψ裱墓嬖颍ㄊ樾垂娣叮?/p>
定义全局函数require,通过传入??楸晔独匆肫渌?椋葱械慕峁次?楸┞冻隼吹腁PI;
如果被require函数引入的??橹幸舶览?,那么依次加载这些依赖;
如果引入??槭О埽敲磖equire函数应该报一个异常;
??橥ü淞縠xports来向外暴露API,exports赋值暴露的只能是一个对象
exports = {Obj}
,暴露的API须作为此对象的属性。exports本质是引入了module.exports的对象。不能直接将exports变量指向一个值,因为这样等于切断了exports与module.exports的联系。如果暴露的不是变量exports,而是module.exports。module变量代表当前???,这个变量是一个对象,它的exports属性(即module.exports)是对外的接口。加载某个模块,其实是加载该模块的module.exports属性。
exports=module.exports={Obj}
node中的commonJS教程
1.安装node.js;
2.创建项目结构
//结构如下? |-modules? |-module1.js//待引入模块1? |-module2.js//待引入???? |-module3.js//待引入???? |-app.js//主??? |-package.json?{???"name":?"commonjsnode",???"version":?"1.0.0"?}
-
3.下载第三方??椋壕倮齟xpress
npm?i?express?--save
4.模块化编码
//?module1??//?使用module.exports?=?value向外暴露一个对象? module.exports?=?{? ????name:?'this?is?module1',????? ????foo(){?????????console.log('module1?foo()');?????}? }? //?module2??//?使用module.exports?=?value向外暴露一个函数?? module.exports?=?function?()?{????? ????console.log('module2()');? }? //?module3?? //?使用exports.xxx?=?value向外暴露一个对象?? exports.foo?=?function?()?{?????? ????console.log('module3?foo()');?? };?? exports.bar?=?function?()?{?????? ????console.log('module3?bar()');?? };?? exports.name?=?'this?is?module3'?//app.js文件? var?uniq?=?require('uniq');?//引用??? let?module1?=?require('./modules/module1');? let?module2?=?require('./modules/module2');? let?module3?=?require('./modules/module3');?//使用??? module1.foo();? module2();? module3.foo();? module3.bar();? module3.name;
5.通过node运行app.js
命令:node.app.js
工具:右键-->运行
浏览器中的commonJS教程
借助Browserify
-
步骤
|-js?? |-dist?//打包生成文件的目录?? |-src?//源码所在的目录???? |-module1.js???? |-module2.js???? |-module3.js???? |-app.js?//应用主源文件? |-index.html?//浏览器上的页面? |-package.json?{????"name":?"browserify-test",????"version":?"1.0.0"?}
<script?type="text/javascript"?src="js/dist/bundle.js"></script>
全局: npm install browserify -g
局部: npm install browserify --save-dev
下载browserify
定义??榇耄篿ndex.html文件要运行在浏览器上,需要借助browserify将app.js文件打包编译,如果直接在index.html引入app.js就会报错。
打包处理js:根目录下运行
browserify js/src/app.js -o js/dist/bundle.js
页面使用引入:
创建项目结构
AMD : 浏览器端
CommonJS规范加载??槭峭降?,也就是说,只有加载完成,才能执行后面的操作。
AMD规范则是非同步加载???,允许指定回调函数,可以实现异步加载依赖模块,并且会提前加载;
由于Node.js主要用于服务器编程,??槲募话愣家丫嬖谟诒镜赜才?,所以加载起来比较快,不用考虑非同步加载的方式,所以CommonJS规范比较适用。
如果是浏览器环境,要从服务器端加载模块,这时就必须采用非同步模式,因此浏览器端一般采用AMD规范。
语法
AMD规范基本语法
定义暴露模块:
define([依赖??槊鸧, function(){return 模块对象})
引入???
require(['???', '???', '模块3'], function(m1, m2){//使用??槎韵髛)
兼容CommonJS规范的输出???/h5>define(function?(require,?exports,?module)?{??????
????var?reqModule?=?require("./someModule");?????
????requModule.test();?????
exports.asplode?=?function?()?{?????????//someing?????}?});
AMD:异步模块定义规范(预加载)
AMD规范:github.com/amdjs/amdjs…
AMD是"Asynchronous Module Definition"的缩写,意思就是"异步??槎ㄒ?。
它采用异步方式加载??椋?榈募釉夭挥跋焖竺嬗锞涞脑诵?。所有依赖这个??榈挠锞洌级ㄒ逶谝桓龌氐骱?,等到加载完成之后,这个回调函数才会运行。
-
AMD也采用require()语句加载模块,但是不同于CommonJS,它要求两个参数:
require([module],?callback);
第一个参数[module],是一个数组,里面的成员就是要加载的??椋?/p>
第二个参数callback,则是加载成功之后的回调函数。
目前,主要有两个Javascript库实现了AMD规范:RequireJS和curl.js。
RequireJS
优点
实现js文件的异步加载,避免网页失去响应;
管理??橹涞囊览敌裕阌诖氲谋嘈春臀?。
require.js使用教程
下载require.js, 并引入
官网: requirejs.org/
github : github.com/requirejs/r…
将require.js导入项目: js/libs/require.js
创建项目结构
|-js???
|-libs?????
|-require.js?//?引入的require.js???
|-modules?????
|-alerter.js?????
|-dataService.js???
|-main.js?
|-index.html
-
定义require.js的??榇?/p>
define(['myLib'],?function(myLib){??
function?foo(){?myLib.doSomething();?}?//?暴露???
return?{foo?:?foo};?});?
//当require()函数加载上面这个??榈氖焙?,就会先加载myLib.js文件。
?-?如果这个模块还依赖其他???,那么define()函数的第一个参数,必须是一个数组,指明该??榈囊览敌裕??```??//?dataService.js??define(function?()?{????let?msg?=?'this?is?dataService'????function?getMsg()?{???return?msg.toUpperCase()????}????return?{getMsg}??})????//?alerter.js??define(['dataService',?'jquery'],?function?(dataService,?$)?{????let?name?=?'Tom2'????function?showMsg()?{??????$('body').css('background',?'gray')??????alert(dataService.getMsg()?+?',?'?+?name)????}????return?{showMsg}??})??```
如果一个??椴灰览灯渌??,那么可以直接定义在define()函数之中。
require.js加载的??椋捎肁MD规范。也就是说,??楸匦氚凑誂MD的规定来写。
具体来说,就是??楸匦氩捎锰囟ǖ膁efine()函数来定义;
AMD规范:github.com/amdjs/amdjs…
AMD是"Asynchronous Module Definition"的缩写,意思就是"异步??槎ㄒ?。
它采用异步方式加载??椋?榈募釉夭挥跋焖竺嬗锞涞脑诵?。所有依赖这个??榈挠锞洌级ㄒ逶谝桓龌氐骱?,等到加载完成之后,这个回调函数才会运行。
AMD也采用require()语句加载模块,但是不同于CommonJS,它要求两个参数:
require([module],?callback);
第一个参数[module],是一个数组,里面的成员就是要加载的??椋?/p>
第二个参数callback,则是加载成功之后的回调函数。
目前,主要有两个Javascript库实现了AMD规范:RequireJS和curl.js。
优点
实现js文件的异步加载,避免网页失去响应;
管理??橹涞囊览敌裕阌诖氲谋嘈春臀?。
下载require.js, 并引入
官网: requirejs.org/
github : github.com/requirejs/r…
将require.js导入项目: js/libs/require.js
创建项目结构
定义require.js的??榇?/p>
define(['myLib'],?function(myLib){?? function?foo(){?myLib.doSomething();?}?//?暴露??? return?{foo?:?foo};?});? //当require()函数加载上面这个??榈氖焙?,就会先加载myLib.js文件。
?-?如果这个模块还依赖其他???,那么define()函数的第一个参数,必须是一个数组,指明该??榈囊览敌裕??```??//?dataService.js??define(function?()?{????let?msg?=?'this?is?dataService'????function?getMsg()?{???return?msg.toUpperCase()????}????return?{getMsg}??})????//?alerter.js??define(['dataService',?'jquery'],?function?(dataService,?$)?{????let?name?=?'Tom2'????function?showMsg()?{??????$('body').css('background',?'gray')??????alert(dataService.getMsg()?+?',?'?+?name)????}????return?{showMsg}??})??```
如果一个??椴灰览灯渌??,那么可以直接定义在define()函数之中。
require.js加载的??椋捎肁MD规范。也就是说,??楸匦氚凑誂MD的规定来写。
具体来说,就是??楸匦氩捎锰囟ǖ膁efine()函数来定义;
应用主(入口)js: main.js
?(function?()?{????? ?//配置????? ?require.config({??????? ?//基本路径??????? ?baseUrl:?"js/",??????? ?//??楸晔睹肽?槁肪队成??????? ?paths:?{???????? ?"alerter":?"modules/alerter",//此处不能写成alerter.js,会报错????????? ?"dataService":?"modules/dataService",???????}????? ?})??????????//引入使用模块????? ?require(?['alerter'],?function(alerter)?{??????? ?????alerter.showMsg()????? ?})?})()
使用require.config()方法,我们可以对??榈募釉匦形凶远ㄒ?。require.config()就写在主??閙ain.js的头部,参数就是一个对象,这个对象的paths属性指定各个??榈募釉芈肪?。
页面使用???
<script?data-main="js/main"?src="js/libs/require.js"></script>
定义???/h6>
require.config()接受一个配置对象,这个对象除了有前面说过的paths属性之外,还有一个shim属性,专门用来配置不兼容的??椤?/p>
具体来说,每个模块要定义:
1、exports值(输出的变量名),表明这个模块外部调用时的名称;
2、deps数组,表明该??榈囊览敌浴?/p>
支持的配置项:
设置path时起始位置是相对于baseUrl的,除非该path设置以"/"开头或含有URL协议(如http:)。
用于??槊膒ath不应含有.js后缀,因为一个path有可能映射到一个目录。路径解析机制会自动在映射??槊絧ath时添加上.js后缀。在文本模版之类的场景中使用require.toUrl()时它也会添加合适的后缀。
在浏览器中运行时,可指定路径的备选(fallbacks),以实现诸如首先指定了从CDN中加载,一旦CDN加载失败则从本地位置中加载这类的机制;
当加载纯.js文件(依赖字串以/开头,或者以.js结尾,或者含有协议),不会使用baseUrl。
如未显式设置baseUrl,则默认值是加载require.js的HTML所处的位置。如果用了data-main属性,则该路径就变成baseUrl。
baseUrl可跟require.js页面处于不同的域下,RequireJS脚本的加载是跨域的。唯一的限制是使用text! plugins加载文本内容时,这些路径应跟页面同域,至少在开发时应这样。优化工具会将text! plugin资源内联,因此在使用优化工具之后你可以使用跨域引用text! plugin资源的那些资源。
baseUrl :所有模块的查找根路径。
paths:path映射那些不直接放置于baseUrl下的模块名。
shim: 为那些没有使用define()来声明依赖关系、设置??榈?浏览器全局变量注入"型脚本做依赖和导出配置。
使用第三方基于require.js的框架(jquery)
将jquery的库文件导入到项目: js/libs/jquery-1.10.1.js
在main.js中配置jquery路径
paths:?{????'jquery':?'libs/jquery-1.10.1'?}
在alerter.js中使用jquery
define(['dataService',?'jquery'],?function?(dataService,?\$)?{??????
????var?name?=?'xfzhang'??????
????function?showMsg()?{??????????
????$('body').css({background?:?'red'})??????????
????alert(name?+?'?'+dataService.getMsg())??????}??????
????return?{showMsg}??
})
使用第三方不基于require.js的框架(angular)
将angular.js导入项目:js/libs/angular.js
流行的函数库(比如jQuery)符合AMD规范,更多的库并不符合。这样的??樵谟胷equire()加载之前,要先用require.config()方法,定义它们的一些特征。
//?main.js中配置?
(function?()?{??//配置??
????require.config({????//基本路径????
????????baseUrl:?"js/",????//??楸晔睹肽?槁肪队成????
????????paths:?{??????//第三方库作为????????
????????????'jquery'?:?'./libs/jquery-1.10.1',??????
????????????'angular'?:?'./libs/angular',??????//自定义模块??????
????????????"alerter":?"./modules/alerter",??????
????????????"dataService":?"./modules/dataService"????
????????},????/*?????配置不兼容AMD的???????
????????exports?:?指定与相对应的??槊杂Φ哪?槎韵?????*/????
????????shim:?{??????
????????????'angular'?:?{????????
????????????????exports?:?'angular'??????
?????????????}????
????????}??})??
????????//引入使用????
????????require(?['alerter',?'angular'],?function(alerter,?angular)?{?????
?????????????alerter.showMsg()??????
?????????????console.log(angular);??})?
????????})()
CMD : 浏览器端
CMD规范:github.com/seajs/seajs…
CMD规范专门用于浏览器端,??榈募釉厥且觳降?,模块使用时才会加载执行。
CMD规范整合了CommonJS和AMD规范的特点。
在 Sea.js 中,所有 JavaScript ??槎甲裱?CMD??槎ㄒ骞娣?/p>
基本语法
-
定义暴露模块:
//?没有依赖的???define(function(require,?module,?exports){????
let?value?=?'xxx';????//通过require引入依赖模块????
//通过module.exports/exports来暴露??????
exports.xxx?=?value????
module.exports?=?value?})?//?有依赖的???
define(function(require,?exports,?module){????//引入依赖???同步)???
?????var?module2?=?require('./module2')????//引入依赖???异步)????
?????require.async('./module3',?function?(m3)?{?????......????})????
?????//暴露??????exports.xxx?=?value?
})
使用??閟eajs.use(['???', '模块2'])
sea.js简单使用教程
-
下载sea.js, 并引入
define()?exports?module.exports
如何依赖??椋?code>require()
如何使用??椋?seajs.use()
官网: seajs.org/
github : github.com/seajs/seajs
将sea.js导入项目: js/libs/sea.js
如何定义导出???:
require.config()接受一个配置对象,这个对象除了有前面说过的paths属性之外,还有一个shim属性,专门用来配置不兼容的??椤?/p>
具体来说,每个模块要定义:
1、exports值(输出的变量名),表明这个模块外部调用时的名称;
2、deps数组,表明该??榈囊览敌浴?/p>
支持的配置项:
设置path时起始位置是相对于baseUrl的,除非该path设置以"/"开头或含有URL协议(如http:)。
用于??槊膒ath不应含有.js后缀,因为一个path有可能映射到一个目录。路径解析机制会自动在映射??槊絧ath时添加上.js后缀。在文本模版之类的场景中使用require.toUrl()时它也会添加合适的后缀。
在浏览器中运行时,可指定路径的备选(fallbacks),以实现诸如首先指定了从CDN中加载,一旦CDN加载失败则从本地位置中加载这类的机制;
当加载纯.js文件(依赖字串以/开头,或者以.js结尾,或者含有协议),不会使用baseUrl。
如未显式设置baseUrl,则默认值是加载require.js的HTML所处的位置。如果用了data-main属性,则该路径就变成baseUrl。
baseUrl可跟require.js页面处于不同的域下,RequireJS脚本的加载是跨域的。唯一的限制是使用text! plugins加载文本内容时,这些路径应跟页面同域,至少在开发时应这样。优化工具会将text! plugin资源内联,因此在使用优化工具之后你可以使用跨域引用text! plugin资源的那些资源。
baseUrl :所有模块的查找根路径。
paths:path映射那些不直接放置于baseUrl下的模块名。
shim: 为那些没有使用define()来声明依赖关系、设置??榈?浏览器全局变量注入"型脚本做依赖和导出配置。
将jquery的库文件导入到项目: js/libs/jquery-1.10.1.js
在main.js中配置jquery路径
在alerter.js中使用jquery
将angular.js导入项目:js/libs/angular.js
流行的函数库(比如jQuery)符合AMD规范,更多的库并不符合。这样的??樵谟胷equire()加载之前,要先用require.config()方法,定义它们的一些特征。
CMD规范:github.com/seajs/seajs…
CMD规范专门用于浏览器端,??榈募釉厥且觳降?,模块使用时才会加载执行。
CMD规范整合了CommonJS和AMD规范的特点。
在 Sea.js 中,所有 JavaScript ??槎甲裱?CMD??槎ㄒ骞娣?/p>
基本语法
-
定义暴露模块:
//?没有依赖的???define(function(require,?module,?exports){???? let?value?=?'xxx';????//通过require引入依赖模块???? //通过module.exports/exports来暴露?????? exports.xxx?=?value???? module.exports?=?value?})?//?有依赖的??? define(function(require,?exports,?module){????//引入依赖???同步)??? ?????var?module2?=?require('./module2')????//引入依赖???异步)???? ?????require.async('./module3',?function?(m3)?{?????......????})???? ?????//暴露??????exports.xxx?=?value? })
使用??閟eajs.use(['???', '模块2'])
下载sea.js, 并引入
define()?exports?module.exports
如何依赖??椋?code>require()
如何使用??椋?seajs.use()
官网: seajs.org/
github : github.com/seajs/seajs
将sea.js导入项目: js/libs/sea.js
如何定义导出???:
创建项目结构
|-js??? |-libs????? |-sea.js??? |-modules????? |-module1.js????? |-module2.js????? |-module3.js????? |-module4.js????? |-main.js? |-index.html
-
定义sea.js的模块代码
define(function?(require,?exports,?module)?{??? ????//内部变量数据??? ????var?data?=?'this?is?module1'??? ????//内部函数???function?show()?{????? ????console.log('module1?show()?'?+?data)???}???//向外暴露?? ?????exports.show?=?show })
define(function?(require,?exports,?module)?{??? ????module.exports?=?{?????msg:?'I?Will?Back'???}? })
define(function?(require,?exports,?module)?{?? ????const?API_KEY?=?'abc123'??exports.API_KEY?=?API_KEY? })
define(function?(require,?exports,?module)?{?? ????//引入依赖???同步)?? ????var?module2?=?require('./module2');?? ????function?show()?{???? ????????console.log('module4?show()?'?+?module2.msg)?? ????}?? ????exports.show?=?show??//引入依赖模块(异步)?? ????require.async('./module3',?function?(m3)?{???? ????????console.log('异步引入依赖?????'?+?m3.API_KEY)??})? })
define(function?(require)?{??? ????var?m1?=?require('./module1')??? ????var?m4?=?require('./module4')??? ????m1.show()??? ????m4.show()? })
main.js : 主(入口)???/p>
module4.js
module3.js
module2.js
module1.js
index.html:
<script?type="text/javascript"?src="js/libs/sea.js"></script>? <script?type="text/javascript">??? ????seajs.use('./js/modules/main')? </script>
ES6??榛?/h3>
??榛墓娣叮篊ommonJS和AMD两种。前者用于服务器,后者用于浏览器。
而ES6 中提供了简单的模块系统,完全可以取代现有的CommonJS和AMD规范,成为浏览器和服务器通用的??榻饩龇桨?。
ES6 ??榈纳杓扑枷?,是尽量的静态化,使得编译时就能确定??榈囊览倒叵担约笆淙牒褪涑龅谋淞?。CommonJS 和 AMD ??椋贾荒茉谠诵惺比范ㄕ庑┒?。
基本用法
-
es6 中新增了两个命令 export 和 import ;
//?math.js?
export?const?add?=?function?(a,?b)?{?????return?a?+?b?}?
export?const?subtract?=?function?(a,?b)?{?????return?a?-?b?}
//?main.js?
import?{?add,?subtract?}?from?'./math.js'?
add(1,?2)?
substract(3,?2)
使用export命令定义了模块的对外接口以后,其他JS文件就可以通过import命令加载这个模块(文件)。
export 命令用于规定??榈亩酝饨涌?;
import 命令用于输入其他模块提供的功能。
一个模块就是一个独立的文件。该文件内部的所有变量,外部无法获取。
如果你希望外部能够读取模块内部的某个变量,就必须使用export关键字输出该变量。
下面是一个JS文件,里面使用export命令输出变量。
定义暴露???: export
常规暴露,暴露的本质是对象,接收的时候只能以对象的解构赋值的方式来接收值
默认暴露,暴露任意数据类型,暴露什么数据类型,接收什么数据类型
-
暴露一个对象:
export?default?对象
-
暴露多个:
export?var?xxx?=?value1?
export?let?yyy?=?value2?//?暴露一个对象?
var?xxx?=?value1?let?yyy?=?value2?
export?{xxx,?yyy}
-
引入使用???: import
import?xxx??from?'模块路径/模块名'
import?{xxx,?yyy}?from?'??槁肪???槊??
import?*?as?module1?from?'??槁肪?模块名'
其它???/p>
default???
export 详细用法
export不止可以导出函数,还可以导出,对象、类、字符串等等;
-
暴露多个:
export?const?obj?=?{test1:?''}?
export?const?test?=?''?
export?class?Test?{????constuctor()?{????}?}?
//?或者,直接在暴露的地方定义导出函数或者变量?
export?let?foo?=?()=>{
????console.log('fnFoo');return?"foo"
},bar="stringBar"
let?a=1?
let?b=2?
let?c=3?
export?{?a,b,c?}
//?test.js?
let?a?=?1?
let?b?=?2?
let?c?=?3?
export?{?????a?as?test,?????b,?????c?};?
import?{?test,?b,?c?}?from?'./test.js'?//?改变命名后只能写?as?后的命名
//?test.js?
let?a?=?1?
let?b?=?2?
let?c?=?3?
export?{?????a?as?test,?????b,?????c?};?//?lib.js引入test.js的内容?
export?*?from?'./test.js'?//?引入?
import?{test,b,c}?from?'./lib.js'
通过通配符暴露其他引入的模块
还可以通过as改变输出名称
一起暴露,推荐使用这种写法,这样可以写在脚本尾部,一眼就看清楚输出了哪些变量。
分别暴露
??榛墓娣叮篊ommonJS和AMD两种。前者用于服务器,后者用于浏览器。
而ES6 中提供了简单的模块系统,完全可以取代现有的CommonJS和AMD规范,成为浏览器和服务器通用的??榻饩龇桨?。
ES6 ??榈纳杓扑枷?,是尽量的静态化,使得编译时就能确定??榈囊览倒叵担约笆淙牒褪涑龅谋淞?。CommonJS 和 AMD ??椋贾荒茉谠诵惺比范ㄕ庑┒?。
es6 中新增了两个命令 export 和 import ;
//?math.js? export?const?add?=?function?(a,?b)?{?????return?a?+?b?}? export?const?subtract?=?function?(a,?b)?{?????return?a?-?b?}
//?main.js? import?{?add,?subtract?}?from?'./math.js'? add(1,?2)? substract(3,?2)
使用export命令定义了模块的对外接口以后,其他JS文件就可以通过import命令加载这个模块(文件)。
export 命令用于规定??榈亩酝饨涌?;
import 命令用于输入其他模块提供的功能。
一个模块就是一个独立的文件。该文件内部的所有变量,外部无法获取。
如果你希望外部能够读取模块内部的某个变量,就必须使用export关键字输出该变量。
下面是一个JS文件,里面使用export命令输出变量。
定义暴露???: export
常规暴露,暴露的本质是对象,接收的时候只能以对象的解构赋值的方式来接收值
默认暴露,暴露任意数据类型,暴露什么数据类型,接收什么数据类型
-
暴露一个对象:
export?default?对象
-
暴露多个:
export?var?xxx?=?value1? export?let?yyy?=?value2?//?暴露一个对象? var?xxx?=?value1?let?yyy?=?value2? export?{xxx,?yyy}
引入使用???: import
import?xxx??from?'模块路径/模块名'
import?{xxx,?yyy}?from?'??槁肪???槊?? import?*?as?module1?from?'??槁肪?模块名'
其它???/p>
default???
export不止可以导出函数,还可以导出,对象、类、字符串等等;
暴露多个:
export?const?obj?=?{test1:?''}? export?const?test?=?''? export?class?Test?{????constuctor()?{????}?}? //?或者,直接在暴露的地方定义导出函数或者变量? export?let?foo?=?()=>{ ????console.log('fnFoo');return?"foo" },bar="stringBar"
let?a=1? let?b=2? let?c=3? export?{?a,b,c?}
//?test.js? let?a?=?1? let?b?=?2? let?c?=?3? export?{?????a?as?test,?????b,?????c?};? import?{?test,?b,?c?}?from?'./test.js'?//?改变命名后只能写?as?后的命名
//?test.js? let?a?=?1? let?b?=?2? let?c?=?3? export?{?????a?as?test,?????b,?????c?};?//?lib.js引入test.js的内容? export?*?from?'./test.js'?//?引入? import?{test,b,c}?from?'./lib.js'
通过通配符暴露其他引入的模块
还可以通过as改变输出名称
一起暴露,推荐使用这种写法,这样可以写在脚本尾部,一眼就看清楚输出了哪些变量。
分别暴露
暴露一个对象,默认暴露
//?test.js? export?default?function?()?{????? ????console.log('hello?world')? }?//引入?import?say?from?'./test.js'?//?这里可以指定任意变量名? say()?//?hello?world
import?$?from?'jQuery'???//?加载jQuery?库? import?_?from?'lodash'???//?加载?lodash? import?moment?from?'moment'?//?加载?moment
常用的???/p>
export default指定默认输出,import无需知道变量名就可以直接使用
import详细用法
import 为加载??榈拿?,基础使用方式和之前一样
//?main.js? import?{?add,?subtract?}?from?'./test'? //?对于export?default?导出的? import?say?from?'./test'
通过 as 命令修改导入的变量名
import?{add?as?sum,?subtract}?from?'./test'? sum?(1,?2)
加载模块的全部,除了指定输出变量名或者 export.default 定义的导入, 还可以通过 * 号加载??榈娜俊?/p>
//?math.js? export?const?add?=?function?(a,?b)?{????? ????return?a?+?b? }? export?const?subtract?=?function?(a,?b)?{????? ????return?a?-?b? }? //引入? import?*?as?math?from?'./test.js'? math.add(1,?2)? math.subtract(1,?2)
ES6-Babel-Browserify使用教程
问题: 所有浏览器还不能直接识别ES6模块化的语法
解决:
使用Babel将ES6--->ES5(使用了CommonJS) ----浏览器还不能直接执行;
使用Browserify--->打包处理js----浏览器可以运行
定义package.json文件
{???"name"?:?"es6-babel-browserify",???"version"?:?"1.0.0"?}
安装babel-cli, babel-preset-es2015和browserify
npm?install?babel-cli?browserify?-g? npm?install?babel-preset-es2015?--save-dev
定义.babelrc文件,这是一个babel的设置文件
{????"presets":?["es2015"]??}
编码
//?js/src/module1.js? export?function?foo()?{??console.log('module1?foo()');?};? export?let?bar?=?function?()?{??console.log('module1?bar()');?};? export?const?DATA_ARR?=?[1,?3,?5,?1];? //?js/src/module2.js? let?data?=?'module2?data';?? function?fun1()?{?console.log('module2?fun1()?'?+?data);?};? function?fun2()?{?console.log('module2?fun2()?'?+?data);?};? export?{fun1,?fun2};?//?js/src/module3.js? export?default?{??? ????name:?'Tom',??? ????setName:?function?(name)?{????? ????????????????this.name?=?name??? ????????????}? }? //?js/src/app.js? import?{foo,?bar}?from?'./module1'? import?{DATA_ARR}?from?'./module1'? import?{fun1,?fun2}?from?'./module2'? import?person?from?'./module3'? import?$?from?'jquery'?//引入完毕? $('body').css('background',?'red')? foo()? bar()? console.log(DATA_ARR);?fun1()?fun2()?person.setName('JACK')? console.log(person.name);
编译
使用Babel将ES6编译为ES5代码(但包含CommonJS语法) : babel js/src -d js/lib
使用Browserify编译js : browserify js/lib/app.js -o js/lib/bundle.js
页面中引入测试
<script?type="text/javascript"?src="js/lib/bundle.js"></script>
-
引入第三方???jQuery)
npm?install?jquery@1?--save
import?$?from?'jquery'? $('body').css('background',?'red')
2). 在app.js中引入并使用
1). 下载jQuery???
总结
模块化方案 | 优点 | 缺点 |
---|---|---|
commonJS | 复用性强; 使用简单; 实现简单; |
有不少可以拿来即用的???,生态不错; 同步加载不适合浏览器,浏览器的请求都是异步加载; 不能并行加载多个???。 |
AMD | 异步加载适合浏览器 | 可并行加载多个??椋?br>??槎ㄒ宸绞讲挥叛?,不符合标准模块化 |
ES6 | 可静态分析,提前编译 | 面向未来的标准; 浏览器原生兼容性差,所以一般都编译成ES5; 目前可以拿来即用的??樯?,生态差 |
AMD和CMD区别:
对于依赖的???,AMD 是提前执行,CMD 是延迟执行。
不过 RequireJS 从 2.0 开始,也改成可以延迟执行(根据写法不同,处理方式不同)。CMD 推崇 as lazy as possible.
-
CMD 推崇依赖就近,AMD 推崇依赖前置。
//?CMD? define(function(require,?exports,?module)?{???? ????var?a?=?require('./a');? ????a.doSomething()???//?此处略去?100?行???? ????var?b?=?require('./b')?//?依赖可以就近书写???? ????b.doSomething()???//?...?})? //?AMD?默认推荐的是? define(['./a',?'./b'],?function(a,?b)?{??? ????//?依赖必须一开始就写好????? ????a.doSomething()????//?此处略去?100?行????? ????b.doSomething()?????...} )
虽然 AMD 也支持 CMD 的写法,同时还支持将 require 作为依赖项传递,但 RequireJS 的作者默认是最喜欢上面的写法,也是官方文档里默认的模块定义写法。
AMD 的 API 默认是一个当多个用,CMD 的 API 严格区分,推崇职责单一。比如 AMD 里,require 分全局 require 和局部 require,都叫 require。CMD 里,没有全局 require,而是根据??橄低车耐瓯感裕峁?seajs.use 来实现??橄低车募釉仄舳MD 里,每个 API 都简单纯粹。
还有一些细节差异,具体看这个规范的定义就好,就不多说了。
作者:木头房子
链接:https://juejin.im/post/5cb004da5188251b130c773e