成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專(zhuān)欄INFORMATION COLUMN

js中的模塊化——commonjs,AMD,CMD,UMD,ES6

qpal / 546人閱讀

摘要:若不存在則模塊標(biāo)識(shí)應(yīng)該默認(rèn)定義為在加載器中被請(qǐng)求腳本的標(biāo)識(shí)。這也是目前很多插件頭部的寫(xiě)法,就是用來(lái)兼容各種不同模塊化的寫(xiě)法。語(yǔ)句輸出的值是動(dòng)態(tài)綁定的,綁定其所在的模塊。

前言

歷史上,js沒(méi)有模塊化的概念,不能把一個(gè)大工程分解成很多小模塊。這對(duì)于多人開(kāi)發(fā)大型,復(fù)雜的項(xiàng)目形成了巨大的障礙,明顯降低了開(kāi)發(fā)效率,java,Python有import,甚至連css都有@import,但是令人費(fèi)解的是js居然沒(méi)有這方面的支持。es6出現(xiàn)之后才解決了這個(gè)問(wèn)題,在這之前,各大社區(qū)也都出現(xiàn)了很多解決方法,比較出色的被大家廣為流傳的就有AMD,CMD,commonjs,UMD,今天我們就來(lái)分析這幾個(gè)模塊化的解決方案。

模塊加載

上面提到的幾種模塊化的方案的模塊加載有何異同呢?
先來(lái)說(shuō)下es6模塊,es6模塊的設(shè)計(jì)思想是盡量靜態(tài)化,使得編譯時(shí)就能確定依賴(lài)關(guān)系,被稱(chēng)為編譯時(shí)加載。其余的都只能在運(yùn)行時(shí)確定依賴(lài)關(guān)系,這種被稱(chēng)為運(yùn)行時(shí)加載。下面來(lái)看下例子就明白了,比如下面這段代碼

let {a,b,c} = require("util");//會(huì)加載util里的所有方法,使用時(shí)只用到3個(gè)方法
import {a,b,c} from "util";//從util中加載3個(gè)方法,其余不加載
模塊化的幾種方案

下面簡(jiǎn)單介紹一下AMD,CMD,commonjs,UMD這幾種模塊化方案。

commonjs

commonjs是服務(wù)端模塊化采用的規(guī)范,nodejs就采用了這個(gè)規(guī)范。
根據(jù)commonjs的規(guī)范,一個(gè)多帶帶的文件就是一個(gè)模塊,加載模塊使用require方法,該方法讀取文件并執(zhí)行,返回export對(duì)象。

// foobar.js
//私有變量
var test = 123;
//公有方法
function foobar () {
 
    this.foo = function () {
        // do someing ...
    }
    this.bar = function () {
        //do someing ...
    }
}
//exports對(duì)象上的方法和變量是公有的
var foobar = new foobar();
exports.foobar = foobar;
//讀取
var test = require("./foobar").foobar;
test.bar();

CommonJS 加載模塊是同步的,所以只有加載完成才能執(zhí)行后面的操作。像Node.js主要用于服務(wù)器的編程,加載的模塊文件一般都已經(jīng)存在本地硬盤(pán),所以加載起來(lái)比較快,不用考慮異步加載的方式,所以CommonJS規(guī)范比較適用。但如果是瀏覽器環(huán)境,要從服務(wù)器加載模塊,這是就必須采用異步模式。所以就有了 AMD CMD 解決方案。

AMD

AMD是"Asynchronous Module Definition"的縮寫(xiě),意思就是"異步模塊定義"
AMD設(shè)計(jì)出一個(gè)簡(jiǎn)潔的寫(xiě)模塊API:

define(id?, dependencies?, factory);

第一個(gè)參數(shù) id 為字符串類(lèi)型,表示了模塊標(biāo)識(shí),為可選參數(shù)。若不存在則模塊標(biāo)識(shí)應(yīng)該默認(rèn)定義為在加載器中被請(qǐng)求腳本的標(biāo)識(shí)。如果存在,那么模塊標(biāo)識(shí)必須為頂層的或者一個(gè)絕對(duì)的標(biāo)識(shí)。
第二個(gè)參數(shù),dependencies ,是一個(gè)當(dāng)前模塊依賴(lài)的,已被模塊定義的模塊標(biāo)識(shí)的數(shù)組字面量。
第三個(gè)參數(shù),factory,是一個(gè)需要進(jìn)行實(shí)例化的函數(shù)或者一個(gè)對(duì)象。

看下下面的例子就明白了

define("alpha", [ "require", "exports", "beta" ], function( require, exports, beta ){
    export.verb = function(){
        return beta.verb();
        // or:
        return require("beta").verb();
    }
});

提到AMD就不得不提requirejs。
RequireJS 是一個(gè)前端的模塊化管理的工具庫(kù),遵循AMD規(guī)范,它的作者就是AMD規(guī)范的創(chuàng)始人 James Burke。
AMD的基本思想就是先加載需要的模塊,然后返回一個(gè)新的函數(shù),所有的操作都在這個(gè)函數(shù)內(nèi)部操作,之前加載的模塊在這個(gè)函數(shù)里是可以調(diào)用的。

CMD

CMD是seajs在推廣的過(guò)程中對(duì)模塊的定義的規(guī)范化產(chǎn)出
和AMD提前執(zhí)行不同的是,CMD是延遲執(zhí)行,不過(guò)requirejs從2.0開(kāi)始也開(kāi)始支持延遲執(zhí)行了,這取決于寫(xiě)法。
AMD推薦的是依賴(lài)前置,CMD推薦的是依賴(lài)就近。
看下AMD和CMD的代碼

//AMD
define(["./a","./b"], function (a, b) {
    //依賴(lài)一開(kāi)始就寫(xiě)好
    a.test();
    b.test();
});
 
//CMD
define(function (requie, exports, module) {
    //依賴(lài)可以就近書(shū)寫(xiě)
    var a = require("./a");
    a.test();
    ...
    //軟依賴(lài)
    if (status) {
        var b = requie("./b");
        b.test();
    }
});
UMD

UMD是AMD和commonjs的結(jié)合
AMD適用瀏覽器,commonjs適用服務(wù)端,如果結(jié)合了兩者就達(dá)到了跨平臺(tái)的解決方案。
UMD先判斷是否支持AMD(define是否存在),存在用AMD模塊的方式加載模塊,再判斷是否支持nodejs的模塊(exports是否存在),存在用nodejs模塊的方式,否則掛在window上,當(dāng)全局變量使用。
這也是目前很多插件頭部的寫(xiě)法,就是用來(lái)兼容各種不同模塊化的寫(xiě)法。

(function(window, factory) {
    //amd
    if (typeof define === "function" && define.amd) {
        define(factory);
    } else if (typeof exports === "object") { //umd
        module.exports = factory();
    } else {
        window.jeDate = factory();
    }
})(this, function() {  
...module..code...
})
ES6

es6的模塊自動(dòng)采用嚴(yán)格模式,不管有沒(méi)有在頭部加上"use strict"
模塊是由export和import兩個(gè)命令構(gòu)成。

export命令

export命令可以出現(xiàn)在模塊的任何位置,只要處于模塊的頂層(不在塊級(jí)作用域內(nèi))即可。如果處于塊級(jí)作用域內(nèi),會(huì)報(bào)錯(cuò)。

export語(yǔ)句輸出的值是動(dòng)態(tài)綁定的,綁定其所在的模塊。

export default命令
//a.js
export default function(){
  console.log("aaa");
}
//b.js
import aaa from "a.js";

1.使用export default的時(shí)候,對(duì)應(yīng)的import不需要使用大括號(hào),import命令可以為default指定任意的名字。
2.不適用export default的時(shí)候,對(duì)應(yīng)的import是需要使用大括號(hào)的
3.一個(gè)export default只能使用一次

import命令

import命令具有提升效果,會(huì)提升到整個(gè)模塊的頭部首先執(zhí)行,所以建議直接寫(xiě)在頭部,這樣也方便查看和管理。

import語(yǔ)句會(huì)執(zhí)行所加載的模塊,因?yàn)橛幸韵碌膶?xiě)法

  import "lodash;

上面的代碼僅僅執(zhí)行了lodash模塊,沒(méi)有輸入任何值

整體加載

整體加載有兩種方式

//import
import * as circle from "./circle"
//module
//module后面跟一個(gè)變量,表示輸入的模塊定義在該變量上
module circle from "./circle"
循環(huán)加載

在講循環(huán)加載前,先了解下commonjs和es6模塊加載的原理

commonjs模塊加載的原理

commonjs的一個(gè)模塊就是一個(gè)腳本文件,require命令第一次加載腳本的時(shí)候就會(huì)執(zhí)行整個(gè)腳本,然后在內(nèi)存中生成一個(gè)對(duì)象

{
  id:"...",
  exports: {...},
  loaded: true,
  ...
}

上面的對(duì)象中,id是模塊名,exports是模塊輸出的各個(gè)接口,loaded是一個(gè)布爾值,表示該模塊的腳本是否執(zhí)行完畢.
之后要用到這個(gè)模塊時(shí),就會(huì)到exports上取值,即使再次執(zhí)行require命令,也不會(huì)執(zhí)行該模塊,而是到緩存中取值

es6模塊加載的

commonjs模塊輸入的是被輸出值的拷貝,也就是說(shuō)一旦輸出一個(gè)值,模塊內(nèi)部的變化就影響不到這個(gè)值
es6的運(yùn)行機(jī)制和commonjs不一樣,它遇到模塊加載命令import不會(huì)去執(zhí)行模塊,只會(huì)生成一個(gè)動(dòng)態(tài)的只讀引用,等到真正要用的時(shí)候,再到模塊中去取值,由于es6輸入的模塊變量只是一個(gè)‘符號(hào)鏈接’,所以這個(gè)變量是只讀的,對(duì)他進(jìn)行重新賦值會(huì)報(bào)錯(cuò)。

import {obj} from "a.js";
obj.a = "qqq";//ok
obj = {}//typeError

分析完兩者的加載原理,來(lái)看下兩者的循環(huán)加載

commonjs的循環(huán)加載

commonjs模塊的重要特性是加載時(shí)執(zhí)行,即代碼在require的時(shí)候就會(huì)執(zhí)行,commonjs的做法是一旦出現(xiàn)循環(huán)加載,就只輸出已經(jīng)執(zhí)行的部分,還未執(zhí)行的部分不會(huì)輸出.
下面來(lái)看下commonjs中的循環(huán)加載的代碼

//a.js
exports.done = false;
var b = require("./b.js");
console.log("在a.js中,b.done=",b.done);
exports.done = true;
console.log("a.js執(zhí)行完畢")
//b.js
exports.done = false;
var a = require("./a.js");
console.log("在b.js中,a.done=",a.done);
exports.done = true;
console.log("b.js執(zhí)行完畢")
//main.js
var a = require("./a.js");
var b = require("./b.js");
console.log("在main.js中,a.done=",a.done,",b.done=",b.done);

上面的代碼中,執(zhí)行a.js的時(shí)候,a.js先輸出done變量,然后加載另一個(gè)腳本b.js,此時(shí)a的代碼就停在這里,等待b.js執(zhí)行完畢,再往下執(zhí)行。然后看下b.js的代碼,b.js也是先輸出done變量,然后加載a.js,這時(shí)發(fā)生了循環(huán)加載,按照commonjs的機(jī)制,系統(tǒng)會(huì)去a.js中的exports上取值,可是其實(shí)a.js是沒(méi)有執(zhí)行完的,只能輸出已經(jīng)執(zhí)行的部分done=false,然后b.js繼續(xù)執(zhí)行,執(zhí)行完畢后將執(zhí)行權(quán)返回給a.js,于是a.js繼續(xù)執(zhí)行,直到執(zhí)行完畢。
所以執(zhí)行main.js,結(jié)果為
在b.js中,a.done=false
b.js執(zhí)行完畢
在a.js中,b=done=true
a.js執(zhí)行完畢
在main.js中,a.done=true,b.done=true
上面這個(gè)例子說(shuō)了兩點(diǎn)

在b.js中a.js沒(méi)有執(zhí)行完,只執(zhí)行了第一行

2.main.js中執(zhí)行到第二行不會(huì)再次執(zhí)行b.js,而是輸出緩存的b.js的執(zhí)行結(jié)果,即第4行

es6的循環(huán)加載

es6處理循環(huán)加載和commonjs不同,es6是動(dòng)態(tài)引用,遇到模塊加載命令import時(shí)不會(huì)去執(zhí)行模塊,只會(huì)生成一個(gè)指向模塊的引用,需要開(kāi)發(fā)者自己保證能取到輸出的值
看下面的例子

//a.js
import {odd} from "b.js";
export counter = 0;
export function even(n){
  counter++;
  return n==0 || odd(n-1);
}
//b.js
import {even} from "a.js";
export function odd(n){
  return n!=0 && even(n-1);
}
//main.js
import {event,counter } from "./a.js";
event(10)
counter //6

執(zhí)行main.js,按照commonjs的規(guī)范,上面的代碼是無(wú)法執(zhí)行的,因?yàn)閍先加載b,b又加載a,但是a又沒(méi)有輸出值,b的even(n-1)會(huì)報(bào)錯(cuò)
但是es6可以執(zhí)行,結(jié)果是6

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/99618.html

相關(guān)文章

  • JS常見(jiàn)塊化規(guī)范(CommonJS/AMD/CMD/UMD/ES6 Module)

    摘要:常見(jiàn)模塊化方案是由社區(qū)提出的模塊化方案中的一種,遵循了這套方案。是模塊化規(guī)范中的一種,遵循了這套規(guī)范。中的模塊化能力由兩個(gè)命令構(gòu)成和,命令用于規(guī)定模塊的對(duì)外接口,命令用于輸入其他模塊提供的功能。 為什么需要模塊化 在ES6出現(xiàn)之前,JS語(yǔ)言本身并沒(méi)有提供模塊化能力,這為開(kāi)發(fā)帶來(lái)了一些問(wèn)題,其中最重要的兩個(gè)問(wèn)題應(yīng)當(dāng)是全局污染和依賴(lài)管理混亂。 // file a.js var name =...

    walterrwu 評(píng)論0 收藏0
  • JS塊化——CommonJS AMD CMD UMD ES6 Module 比較

    摘要:即盡早地執(zhí)行依賴(lài)模塊。阮一峰輸出值的引用模塊是動(dòng)態(tài)關(guān)聯(lián)模塊中的值,輸出的是值得引用。的加載實(shí)現(xiàn)阮一峰運(yùn)行時(shí)加載靜態(tài)編譯模塊是運(yùn)行時(shí)加載,模塊是編譯時(shí)輸出接口。 模塊化開(kāi)發(fā) 優(yōu)點(diǎn) 模塊化開(kāi)發(fā)中,通常一個(gè)文件就是一個(gè)模塊,有自己的作用域,只向外暴露特定的變量和函數(shù),并且可以按需加載。 依賴(lài)自動(dòng)加載,按需加載。 提高代碼復(fù)用率,方便進(jìn)行代碼的管理,使得代碼管理更加清晰、規(guī)范。 減少了命名沖...

    shadowbook 評(píng)論0 收藏0
  • JS模塊規(guī)范:AMD、UMD、CMD、commonJS、ES6 module

    摘要:要想讓模塊再次運(yùn)行,必須清除緩存。模塊加載會(huì)阻塞接下來(lái)代碼的執(zhí)行,需要等到模塊加載完成才能繼續(xù)執(zhí)行同步加載。環(huán)境服務(wù)器環(huán)境應(yīng)用的模塊規(guī)范是參照實(shí)現(xiàn)的。這等同在每個(gè)模塊頭部,有一行這樣的命令。 commonJS 特點(diǎn): 1、模塊可以多次加載,但是只會(huì)在第一次加載時(shí)運(yùn)行一次,然后運(yùn)行結(jié)果就被緩存了,以后再加載,就直接讀取緩存結(jié)果。要想讓模塊再次運(yùn)行,必須清除緩存。2、模塊加載會(huì)阻塞接下來(lái)代...

    _ang 評(píng)論0 收藏0
  • JS基礎(chǔ)】一文看懂前端塊化規(guī)范

    摘要:參考資料前端模塊化詳解完整版入門(mén)近一萬(wàn)字的語(yǔ)法知識(shí)點(diǎn)補(bǔ)充徹底搞清楚中的和和詳解 前言 前端的模塊化之路經(jīng)歷了漫長(zhǎng)的過(guò)程,想詳細(xì)了解的小伙伴可以看浪里行舟大神寫(xiě)的前端模塊化詳解(完整版),這里根據(jù)幾位大佬們寫(xiě)的文章,將模塊化規(guī)范部分做了匯總和整理,希望讀完的小伙伴能有些收獲,也希望覺(jué)得有用的小伙伴可以點(diǎn)個(gè)贊,筆芯。 什么是模塊 將一個(gè)復(fù)雜的程序依據(jù)一定的規(guī)則(規(guī)范)封裝成幾個(gè)塊(文件)...

    HelKyle 評(píng)論0 收藏0
  • JS塊化編程

    摘要:也就是說(shuō),外部模塊輸出值變了,當(dāng)前模塊的導(dǎo)入值不會(huì)發(fā)生變化。三規(guī)范的出現(xiàn),使得模塊化在環(huán)境中得到了施展機(jī)會(huì)。模塊化這種加載稱(chēng)為編譯時(shí)加載或者靜態(tài)加載。總結(jié)的模塊化規(guī)范經(jīng)過(guò)了模塊模式的演進(jìn),利用現(xiàn)在常用的打包工具,非常方便我們編寫(xiě)模塊化代碼。 前言 什么是模塊化? 模塊就是實(shí)現(xiàn)特定功能的一組方法,而模塊化是將模塊的代碼創(chuàng)造自己的作用域,只向外部暴露公開(kāi)的方法和變量,而這些方法之間高度解耦...

    騫諱護(hù) 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

qpal

|高級(jí)講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<