重温前端开发【模块化】&转载自【蚂蚁号】

??榛睦斫?/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规范包含内容:

  1. ??榈谋晔队ψ裱墓嬖颍ㄊ樾垂娣叮?/p>

  2. 定义全局函数require,通过传入??楸晔独匆肫渌?椋葱械慕峁次?楸┞冻隼吹腁PI;

  3. 如果被require函数引入的??橹幸舶览?,那么依次加载这些依赖;

  4. 如果引入??槭О埽敲磖equire函数应该报一个异常;

  5. ??橥ü淞縠xports来向外暴露API,exports赋值暴露的只能是一个对象exports = {Obj},暴露的API须作为此对象的属性。exports本质是引入了module.exports的对象。不能直接将exports变量指向一个值,因为这样等于切断了exports与module.exports的联系。

  6. 如果暴露的不是变量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

  1. 下载browserify

  2. 定义??榇耄篿ndex.html文件要运行在浏览器上,需要借助browserify将app.js文件打包编译,如果直接在index.html引入app.js就会报错。

  3. 打包处理js:根目录下运行browserify js/src/app.js -o js/dist/bundle.js

  4. 页面使用引入:

  1. 创建项目结构

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使用教程
  1. 下载require.js, 并引入

  1. 创建项目结构

|-js???
|-libs?????
|-require.js?//?引入的require.js???
|-modules?????
|-alerter.js?????
|-dataService.js???
|-main.js?
|-index.html
  1. 定义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简单使用教程

    1. 下载sea.js, 并引入

      define()?exports?module.exports
    • 如何依赖??椋?code>require()

    • 如何使用??椋?seajs.use()

  • 创建项目结构

  • |-js???
    |-libs?????
    |-sea.js???
    |-modules?????
    |-module1.js?????
    |-module2.js?????
    |-module3.js?????
    |-module4.js?????
    |-main.js?
    |-index.html
    1. 定义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'
    1. 通过通配符暴露其他引入的模块

    1. 还可以通过as改变输出名称

    1. 一起暴露,推荐使用这种写法,这样可以写在脚本尾部,一眼就看清楚输出了哪些变量。

    1. 分别暴露

  • 暴露一个对象,默认暴露

    //?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----浏览器可以运行

    1. 定义package.json文件

    {???"name"?:?"es6-babel-browserify",???"version"?:?"1.0.0"?}
    1. 安装babel-cli, babel-preset-es2015和browserify

    npm?install?babel-cli?browserify?-g?
    npm?install?babel-preset-es2015?--save-dev
    1. 定义.babelrc文件,这是一个babel的设置文件

    {????"presets":?["es2015"]??}
    1. 编码

    //?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);
    1. 编译

    • 使用Babel将ES6编译为ES5代码(但包含CommonJS语法) : babel js/src -d js/lib

    • 使用Browserify编译js : browserify js/lib/app.js -o js/lib/bundle.js

    1. 页面中引入测试

    <script?type="text/javascript"?src="js/lib/bundle.js"></script>
    1. 引入第三方???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区别:

    • 权威参考:github.com/seajs/seajs…

    • 对于依赖的???,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 都简单纯粹。

    • 还有一些细节差异,具体看这个规范的定义就好,就不多说了。

    参考:使用 AMD、CommonJS 及 ES Harmony 编写??榛?JavaScript

    作者:木头房子
    链接:https://juejin.im/post/5cb004da5188251b130c773e

    原文地址:https://www.v5ant.com/details/BE-2nAjNn.html

    ?著作权归作者所有,转载或内容合作请联系作者
    • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
      沈念sama阅读 214,029评论 6 493
    • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
      沈念sama阅读 91,238评论 3 388
    • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事?!?“怎么了?”我有些...
      开封第一讲书人阅读 159,576评论 0 349
    • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
      开封第一讲书人阅读 57,214评论 1 287
    • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
      茶点故事阅读 66,324评论 6 386
    • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
      开封第一讲书人阅读 50,392评论 1 292
    • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
      沈念sama阅读 39,416评论 3 412
    • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
      开封第一讲书人阅读 38,196评论 0 269
    • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
      沈念sama阅读 44,631评论 1 306
    • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
      茶点故事阅读 36,919评论 2 328
    • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
      茶点故事阅读 39,090评论 1 342
    • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
      沈念sama阅读 34,767评论 4 337
    • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
      茶点故事阅读 40,410评论 3 322
    • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
      开封第一讲书人阅读 31,090评论 0 21
    • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
      开封第一讲书人阅读 32,328评论 1 267
    • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
      沈念sama阅读 46,952评论 2 365
    • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
      茶点故事阅读 43,979评论 2 351

    推荐阅读更多精彩内容