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

資訊專(zhuān)欄INFORMATION COLUMN

再談JavaScript模塊化

MorePainMoreGain / 3538人閱讀

摘要:應(yīng)用日益復(fù)雜,模塊化已經(jīng)成為一個(gè)迫切需求。異步模塊加載機(jī)制。引用的資源列表太長(zhǎng),懶得回調(diào)函數(shù)中寫(xiě)一一對(duì)應(yīng)的相關(guān)參數(shù)假定這里引用的資源有數(shù)十個(gè),回調(diào)函數(shù)的參數(shù)必定非常多這就是傳說(shuō)中的

簡(jiǎn)述 緣起

模塊通常是指編程語(yǔ)言所提供的代碼組織機(jī)制,利用此機(jī)制可將程序拆解為獨(dú)立且通用的代碼單元。

模塊化主要是解決代碼分割、作用域隔離、模塊之間的依賴(lài)管理以及發(fā)布到生產(chǎn)環(huán)境時(shí)的自動(dòng)化打包與處理等多個(gè)方面。

javascript應(yīng)用日益復(fù)雜,模塊化已經(jīng)成為一個(gè)迫切需求。但是作為一個(gè)模塊化方案,它至少要解決如下問(wèn)題:

可維護(hù)性

避免作用域污染

代碼重用

依賴(lài)管理

script

最原始的方式就是,每個(gè)文件就是一個(gè)模塊,然后使用script的方式進(jìn)行引入。

但是此方式有以下問(wèn)題:

全局作用域污染

無(wú)依賴(lài)管理,執(zhí)行順序依賴(lài)script標(biāo)簽的順序,如果采用異步加載,那會(huì)亂套,先下載的先執(zhí)行

IIFE 和 模塊對(duì)象

為了解決作用域污染的問(wèn)題,就產(chǎn)生了立即執(zhí)行函數(shù) + 模塊對(duì)象模式:

// app1.js
var app = {};
// app2.js
(function(){
  app.a = function(a, b) {
    // code
  }  
})();
// app3.js
(function(app){
  var temp = [ 1, 2];
  var a = app.a(temp)
})(app);

具體的可以查閱阮一峰老師的博客Javascript模塊化編程(一):模塊的寫(xiě)法

在ES6之前,js沒(méi)有塊級(jí)作用域,所以采用此方式建立一個(gè)函數(shù)作用域。但是在ES6之后,可以使用塊級(jí)作用域。

由于使用了IIFE,所以減少了全局作用域污染,但并不是徹底消除,因?yàn)檫€定義了一個(gè)appa模塊對(duì)象呢。

所以這也僅僅只是減少了作用域污染,還是會(huì)有其他缺點(diǎn)。

CommonJS

后來(lái),有人試圖將javascript引入服務(wù)端,由于服務(wù)端編程相對(duì)比較復(fù)雜,就急需一種模塊化的方案,所以就誕生了commonjs,有require + module.exports實(shí)現(xiàn)模塊的加載和導(dǎo)出。

CommonJS采用同步的方式加載模塊,主要使用場(chǎng)景為服務(wù)端編程。因?yàn)榉?wù)器一般都是本地加載,速度較快。

AMD 和 CMD

后來(lái),隨著前端業(yè)務(wù)的日漸復(fù)雜,瀏覽器端也需要模塊化,但是commonjs是同步加載的,這意味著加載模塊時(shí),瀏覽器會(huì)凍結(jié),什么都干不了,這在瀏覽器肯定是不行的,這就誕生了AMD和CMD規(guī)范,分別以requirejs和seajs為代表。

這兩貨都采用異步方式加載模塊。

AMD

AMD(Asynchronous Module Defination)異步模塊加載機(jī)制。

define(
    [module_id,] // 模塊名字,如果缺省則為匿名模塊
    [dependenciesArray,] // 模塊依賴(lài) 
    definition function | object // 模塊內(nèi)容,可以為函數(shù)或者對(duì)象
);
CMD

CMD(Common Module Defination)通用模塊加載機(jī)制

// 方式一
define(function(require, exports, module) { 
    // 模塊代碼
    var a = require("a")
});
// 方式二
define( "module", ["module1", "module2"], function( require, exports, module ){
    // 模塊代碼
} );
區(qū)別

對(duì)于依賴(lài)的模塊,AMD 是提前執(zhí)行( RequireJS 從 2.0 開(kāi)始,也改成可以延遲執(zhí)行),CMD 是延遲執(zhí)行

CMD 推崇依賴(lài)就近,AMD 推崇依賴(lài)前置

AMD 的 API 默認(rèn)是一個(gè)當(dāng)多個(gè)用,CMD 的 API 嚴(yán)格區(qū)分,推崇職責(zé)單一

不完美

盡管以上方案解決了上面說(shuō)的問(wèn)題,但是也帶來(lái)了一些新問(wèn)題:

語(yǔ)法冗余,所有東西都要封裝在define中

AMD中的依賴(lài)列表必須與函數(shù)的參數(shù)列表匹配,易錯(cuò)且修改苦難

Browserify

由于上述這些原因,有些人想在瀏覽器使用 CommonJS 規(guī)范,但 CommonJS 語(yǔ)法主要是針對(duì)服務(wù)端且是同步的,所以就產(chǎn)生了Browserify,它是一個(gè) 模塊打包器(module bundler),可以打包c(diǎn)ommonjs規(guī)范的模塊到瀏覽器中使用。

UMD

UMD(Universal Module Definition) 統(tǒng)一模塊定義。

AMD 與 CommonJS 雖然師出同源,但還是分道揚(yáng)鑣,關(guān)注于代碼異步加載與最小化入口模塊的開(kāi)發(fā)者將目光投注于 AMD;而隨著 Node.js 以及 Browserify 的流行,越來(lái)越多的開(kāi)發(fā)者也接受了 CommonJS 規(guī)范。令人扼腕嘆息的是,符合 AMD 規(guī)范的模塊并不能直接運(yùn)行于 CommonJS 模塊規(guī)范的環(huán)境中,符合 CommonJS 規(guī)范的模塊也不能由 AMD 進(jìn)行異步加載。

而且有這么多種規(guī)范,如果我們要發(fā)布一個(gè)模塊供其他人用,我們不可能為每種規(guī)范發(fā)布一個(gè)版本,就算你蛋疼這樣做了,別人使用的時(shí)候還得下載對(duì)應(yīng)版本,所以現(xiàn)在需要一種方案來(lái)兼容這些規(guī)范。

實(shí)現(xiàn)的方式就是在代碼前面做下判斷,根據(jù)不同的規(guī)范使用對(duì)應(yīng)的加載方式。

// 以vue為例
(function (global, factory) {
  typeof exports === "object" && typeof module !== "undefined" ? module.exports = factory() :
  typeof define === "function" && define.amd ? define(factory) :
  (global = global || self, global.Vue = factory());
}(this, function () { 
    // vue code ...
})

由于目前ES6瀏覽器支持還不夠好,所以很多第三方庫(kù)都采用了這種方式。

ESModule

ES6引入了ESModule規(guī)范,主要通過(guò)export + import來(lái)實(shí)現(xiàn),最終一統(tǒng)江湖??墒乾F(xiàn)實(shí)很骨感,一些瀏覽器并不支持(IE,說(shuō)的就是你),所以還不能直接在瀏覽器中直接使用。

常用的兩種方案

在線編譯:requirejs/seajs/sytemjs

在頁(yè)面上加載一個(gè)AMD/CMD模塊格式解釋器。這樣瀏覽器就認(rèn)識(shí)了define, exports,module這些東西,也就實(shí)現(xiàn)了模塊化。

SystemJS 是一個(gè)通用的模塊加載器,它能在瀏覽器或者 NodeJS 上動(dòng)態(tài)加載模塊,并且支持 CommonJS、AMD、全局模塊對(duì)象和 ES6 模塊。通過(guò)使用插件,它不僅可以加載 JavaScript,還可以加載 CoffeeScript 和 TypeScript。配合jspm也是不錯(cuò)的搭配。

預(yù)編譯:browserify/webpack

相比于第一種方案,這個(gè)方案更加智能。由于是預(yù)編譯的,不需要在瀏覽器中加載解釋器。你在本地直接寫(xiě)JS,不管是AMD/CMD/ES6風(fēng)格的模塊化,它都能認(rèn)識(shí),并且編譯成瀏覽器認(rèn)識(shí)的JS。

注意: browerify只支持Commonjs模塊,如需兼容AMD模塊,則需要plugin轉(zhuǎn)換

CommonJS

前身為ServerJS。
我們可以理解為代碼會(huì)被如下內(nèi)建輔助函數(shù)包裹:

(function (exports, require, module, __filename, __dirname) {
    // ...
    // Your code
    // ...
});
加載

通過(guò)require加載模塊。

const a = require("a")
導(dǎo)出

通過(guò)exportsmodule.exports進(jìn)行模塊導(dǎo)出。

exportsexportsmodule.exports的一個(gè)引用,一個(gè)模塊可以使用多次,但是不能直接對(duì)exports重新賦值,只能通過(guò)如下方式使用

exports.a = function(){
    // code...
}

module.exports:一個(gè)模塊只能使用一次

module.exports = function(){
    // code...
}
特點(diǎn)

同步加載,定位于服務(wù)端,不適合瀏覽器

requirejs 特點(diǎn)

支持同步和異步兩種方式

大多數(shù)第三方庫(kù)都有兼容AMD,即時(shí)不兼容也可以通過(guò)配置使其可用

異步加載,不阻塞瀏覽器

依賴(lài)前置,可以很清楚看到當(dāng)前模塊的依賴(lài)

引入

在引入requirejs的script標(biāo)簽上添加data-main屬性定義入口文件,該文件會(huì)在requirejs加載完后立即執(zhí)行。

如果baseUrl未多帶帶配置,則默認(rèn)為引入require的文件的路徑。

config
requirejs.config({
    // 為模塊加上query參數(shù),解決瀏覽器緩存,只在開(kāi)發(fā)環(huán)境使用
    urlArgs: "yn-course=" + (new Date()).getTime(),
    // 配置所有模塊加載的初始路徑,所有模塊都是基于此路徑加載
    baseUrl: "./", 
    // 映射一些快捷路徑,相當(dāng)于別名
    paths: {
        "~": "assets",
        "@": "components",
        "vue": "assets/lib/vue/vue",
        "vueRouter": "assets/lib/vue-router/vue-router",
        "jquery" : ["http://libs.baidu.com/jquery/2.0.3/jquery"]
    },
    //  對(duì)于匹配的模塊前綴,使用一個(gè)不同的模塊ID來(lái)加載該模塊
    map: {
        "layer": {
            "jquery": "http://libs.baidu.com/jquery/2.0.3/jquery"
        }
    },
    // 從CommonJS包(package)中加載模塊
    packages:{},
    // 加載上下文
    context:{},
    // 超時(shí),默認(rèn)7S
    waitSeconds: 7,
    // 定義應(yīng)用依賴(lài)的模塊,在啟動(dòng)后會(huì)加載此數(shù)組中的模塊
    deps: [],
    // 在deps加載完畢后執(zhí)行的函數(shù)
    callback:function(){},
    // 用來(lái)加載非AMD規(guī)范的模塊,以瀏覽器全局變量注入,此處僅作映射,需要在需要時(shí)手動(dòng)載入
    shim: { 
        // "backbone": {
        //     deps: ["underscore", "jquery"], // 模塊依賴(lài)
        //     exports: "Backbone" // 導(dǎo)出的名稱(chēng)
        // }
    },
    // 全局配置信息,可在模塊中通過(guò)module.config()訪問(wèn)
    config:{
        color:"red"
    },
    // 如果設(shè)置為true,則當(dāng)一個(gè)腳本不是通過(guò)define()定義且不具備可供檢查的shim導(dǎo)出字串值時(shí),就會(huì)拋出錯(cuò)誤
    enforceDefine:false,
    // 如果設(shè)置為true,則使用document.createElementNS()去創(chuàng)建script元素
    xhtm: false,
    //指定RequireJS將script標(biāo)簽插入document時(shí)所用的type=""值
    scriptType:"text/javascript"
});

默認(rèn)requirejs會(huì)根據(jù)baseUrl+paths配置去查找模塊,但是如下情況例外:

路徑以.js結(jié)尾,比如lib/hello.js、hello.js

以“/”開(kāi)始

包含url協(xié)議:如"http:"、"https"

設(shè)置baseURl的方式有如下三種:

requirejs.config指定;

如指data-main,則baseUrl為data-main所對(duì)應(yīng)的js的目錄

如果上述均未指定,則baseUrl為運(yùn)行RequireJS的HTML文件所在目錄

map配置對(duì)于大型項(xiàng)目很重要:如有兩類(lèi)模塊需要使用不同版本的"foo",但它們之間仍需要一定的協(xié)同。
在那些基于上下文的多版本實(shí)現(xiàn)中很難做到這一點(diǎn)。而且,paths配置僅用于為模塊ID設(shè)置root paths,而不是為了將一個(gè)模塊ID映射到另一個(gè)。

requirejs.config({
    map: {
        "some/newmodule": {
            "foo": "foo1.2"
        },
        "some/oldmodule": {
            "foo": "foo1.0"
        }
    }
});
define

通過(guò)define來(lái)定義模塊,推薦依賴(lài)前置原則,當(dāng)然也可以使用require動(dòng)態(tài)按需加載。

define(
    [module_id,] // 模塊名字,如果缺省則為匿名模塊
    [dependencies,] // 模塊依賴(lài) 
    definition function | object // 模塊內(nèi)容,可以為函數(shù)或者對(duì)象
);
// 如果僅僅返回一個(gè)鍵值對(duì),可以采用如下格式,類(lèi)似JSONP
define({
    color: "black",
    size: "unisize"
})
//如果沒(méi)有依賴(lài)
define(function () {
    return {
        color: "black",
        size: "unisize"
    }
})
// 有依賴(lài)
define(["./a", "./b"], function(a, b) {
    
})
// 具名模塊
define("name",
    ["c", "d"],
    function(cart, inventory) {
    //此處定義foo/title object
    }   
)

如要在define()內(nèi)部使用諸如require("./a/b")相對(duì)路徑,記得將"require"本身作為一個(gè)依賴(lài)注入到模塊中:

define(["require", "./a/b"], function(require) {
    var mod = require("./a/b");
});

或者使用如下方式:

define(function(require) {
    var mod = require("./a/b");
})
標(biāo)識(shí)

require加載的所有模塊都是單例的,每個(gè)模塊都有一個(gè)唯一的標(biāo)識(shí),這個(gè)標(biāo)識(shí)是模塊的名字或者模塊的相對(duì)路徑(如匿名模塊)。

模塊的唯一性與它們的訪問(wèn)路徑無(wú)關(guān),即使是地址完全相同的一份JS文件,如果引用的方式與模塊的配置方式不一致,依舊會(huì)產(chǎn)生多個(gè)模塊。

// User.js
define([], function() {
    return {
        username : "yiifaa",
        age       : 20
    };
});
require(["user/User"], function(user) {
    //  修改了User模塊的內(nèi)容
    user.username = "yiifee";
    //  em/User以baseUrl定義的模塊進(jìn)行訪問(wèn)
    //  "user/User"以path定義的模塊進(jìn)行訪問(wèn)
    require(["em/User", "user/User"], function(u1, u2) {
        //  輸出的結(jié)果完全不相同,u1為yiifaa,u2為修改后的內(nèi)容yiifee
        console.log(u1, u2);
    })
})
依賴(lài)

requirejs推薦依賴(lài)前置,在define或者require模塊的時(shí)候,可以將需要依賴(lài)的模塊作為第一個(gè)參數(shù),以數(shù)組的方式聲明,然后在回調(diào)函數(shù)中,依賴(lài)會(huì)以參數(shù)的形式注入到該函數(shù)上,參數(shù)列表需要和依賴(lài)數(shù)組中位置一一對(duì)應(yīng)。

define(["./a", "./b"], function(a, b) {
    
})
導(dǎo)出

在requirejs中,有3中方式進(jìn)行模塊導(dǎo)出:

通過(guò)return方式導(dǎo)出,優(yōu)先級(jí)最高(推薦);

define(function(require, exports, module) {
    return {
        a : "a"
    }
});

通關(guān)module.exports對(duì)象賦值導(dǎo)出,優(yōu)先級(jí)次之;

define(function(require, exports, module) {
    module.exports = {
        a : "a"
    }
});

通過(guò)exports對(duì)象賦值導(dǎo)出,優(yōu)先級(jí)最低;

define(function(require, exports, module) {
    exports.a = "a"
});
require

requirejs提供了兩個(gè)全局變量requirerequirejs供我們加載模塊,這二者是完全等價(jià)的。

// 此處require 和 define 函數(shù)僅僅是一個(gè)參數(shù)(模塊標(biāo)識(shí))的差異,
// 一般require用于沒(méi)有返回的模塊,如應(yīng)用頂層模塊
require(
    [dependencies,] // 模塊依賴(lài) 
    definition function // 模塊內(nèi)容
);

require是內(nèi)置模塊,不用在配置中定義,直接進(jìn)行引用即可。

define(["require"], function(require) {
    var $ = require("jquery");
})

requirejs支持異步(require([module]))和同步(require(module))兩種方式加載,即require參數(shù)為數(shù)組即為異步加載,反之為同步。

同步加載

在requirejs中,執(zhí)行同步加載必須滿足兩點(diǎn)要求:

必須在定義模塊時(shí)使用,亦即define函數(shù)中;

引用的資源必須是之前異步加載過(guò)的(不必在同一個(gè)模塊),換句話說(shuō),同步載入的模塊是不會(huì)發(fā)網(wǎng)絡(luò)請(qǐng)求的,只會(huì)調(diào)取之前緩存的模塊;

define(function(require, exports, module) { })中可以同步加載模塊

應(yīng)用場(chǎng)景

明確知道模塊的先后順序,確認(rèn)此模塊已經(jīng)被加載過(guò),例如系統(tǒng)通用模塊,在載入完成后,之后的模塊就可以進(jìn)行同步的引用,或者在Vue等前端技術(shù)框架中,在應(yīng)用模塊同步加載vue模塊。

引用的資源列表太長(zhǎng),懶得回調(diào)函數(shù)中寫(xiě)一一對(duì)應(yīng)的相關(guān)參數(shù)

//  假定這里引用的資源有數(shù)十個(gè),回調(diào)函數(shù)的參數(shù)必定非常多
define(["jquery"], function() {
    return function(el) {
        //  這就是傳說(shuō)中的同步調(diào)用
        var $ = require("jquery");
        $(el).html("Hello, World!");
    }
})

可以減少命名或者命名空間沖突,例如prototype與jquery的沖突問(wèn)題

define(["jquery", "prototype"], function() {
    var export = {};
    export.jquery = function(el) {
        //  這就是傳說(shuō)中的同步調(diào)用
        var $ = require("jquery");
        $(el).html("Hello, World!");
    }

    export.proto = function(el) {
        //  這就是傳說(shuō)中的同步調(diào)用
        var $ = require("prototype");
        $(el).html("Hello, World!");
    }
    return export;
})

處女座專(zhuān)用,代碼顯得更整潔漂亮了,硬是把回調(diào)函數(shù)寫(xiě)出了同步的感覺(jué)

異步加載

define([],function()):依賴(lài)數(shù)組中的模塊會(huì)異步加載,所有模塊加載完成后混執(zhí)行回調(diào)函數(shù)

require([]):傳入數(shù)組格式即表示需要異步加載

require === requirejs //=> true
require.toUrl("./a.css"): 獲取模塊url 模塊卸載

只要頁(yè)面不刷新,被requirejs加載的模塊只會(huì)執(zhí)行一次,后面會(huì)一直緩存在內(nèi)存中,即時(shí)重新引入模塊也不會(huì)再進(jìn)行初始化。
我們可以通過(guò)undef卸載已加載的模塊。

require.undef("moduleName") // moduleName是模塊標(biāo)識(shí)
其他 插件

css:加載css

text:加載HTML及其他文本

domReady

模塊加載錯(cuò)誤

Module name has not been loaded yet for context: _

此錯(cuò)誤表示執(zhí)行時(shí)模塊還未加載成功,一般為異步加載所致,改成同步加載即可。

借助類(lèi)解決模塊間的相互干擾
//C模塊
define([],function(){
 
 // 定義一個(gè)類(lèi)
 function DemoClass()
 {
    var count = 0;
    this.say = function(){
        count++;
        return count;
    };
 }
 
 return function(){
    //每次都返回一個(gè)新對(duì)象
    return new DemoClass();
 };
 
});
 
// A模塊
require(["C"],
  function(module) {
         cosole.log(module().say());//1
});
 
// B模塊
require(["C"],
  function(module) {
        cosole.log(module().say());//1
});

文檔:官方文檔,

[中文版](https://blog.csdn.net/wangzhanzheng/article/details/79050033)
seajs

Sea.js 追求簡(jiǎn)單、自然的代碼書(shū)寫(xiě)和組織方式,具有以下核心特性:

簡(jiǎn)單友好的模塊定義規(guī)范:Sea.js 遵循 CMD 規(guī)范,可以像 Node.js 一般書(shū)寫(xiě)模塊代碼。

自然直觀的代碼組織方式:依賴(lài)的自動(dòng)加載、配置的簡(jiǎn)潔清晰,可以讓我們更多地享受編碼的樂(lè)趣。

通過(guò)exports + require實(shí)現(xiàn)模塊的加載與導(dǎo)出。

引入


config
//seajs配置
seajs.config({

    //1.頂級(jí)標(biāo)識(shí)始終相對(duì) base 基礎(chǔ)路徑解析。
    //2.絕對(duì)路徑和根路徑始終相對(duì)當(dāng)前頁(yè)面解析。
    //3.require 和 require.async 中的相對(duì)路徑相對(duì)當(dāng)前模塊路徑來(lái)解析。
    //4.seajs.use 中的相對(duì)路徑始終相對(duì)當(dāng)前頁(yè)面來(lái)解析。

    // Sea.js 的基礎(chǔ)路徑  在解析頂級(jí)標(biāo)識(shí)時(shí),會(huì)相對(duì) base 路徑來(lái)解析   base 的默認(rèn)值為 sea.js 的訪問(wèn)路徑的父級(jí)
    base: "./",

    // 路徑配置  當(dāng)目錄比較深,或需要跨目錄調(diào)用模塊時(shí),可以使用 paths 來(lái)簡(jiǎn)化書(shū)寫(xiě)
    paths: {
        gallery: "https://a.alipayobjects.com/gallery"
        /*
            var underscore = require("gallery/underscore");
            //=> 加載的是 https://a.alipayobjects.com/gallery/underscore.js
         */
    },

    // 別名配置  當(dāng)模塊標(biāo)識(shí)很長(zhǎng)時(shí),可以使用 alias 來(lái)簡(jiǎn)化(相當(dāng)于 base 設(shè)置的目錄為基礎(chǔ))
    //Sea.js 在解析模塊標(biāo)識(shí)時(shí), 除非在路徑中有問(wèn)號(hào)(?)或最后一個(gè)字符是井號(hào)(#),否則都會(huì)自動(dòng)添加 JS 擴(kuò)展名(.js)。如果不想自動(dòng)添加擴(kuò)展名,可以在路徑末尾加上井號(hào)(#)。
    alias: {
        "seajs-css": "~/lib/seajs/plugins/seajs-css",
        "seajs-text": "~/lib/seajs/plugins/seajs-text",
        "$": "~/lib/zepto/zepto"
    },

    // 變量配置  有些場(chǎng)景下,模塊路徑在運(yùn)行時(shí)才能確定,這時(shí)可以使用 vars 變量來(lái)配置
    vars: {
        //locale: "zh-cn"
        /*
            var lang = require("./i18n/{locale}.js");
            //=> 加載的是 path/to/i18n/zh-cn.js
         */
    },

    // 映射配置  該配置可對(duì)模塊路徑進(jìn)行映射修改,可用于路徑轉(zhuǎn)換、在線調(diào)試等
    map: [
        //[".js", "-debug.js"]
        /*
            var a = require("./a");
            //=> 加載的是 ./js/a-debug.js
        */
    ],

    // 預(yù)加載項(xiàng)  在普通模塊加載前,提前加載并初始化好指定模塊  preload 中的配置,需要等到 use 時(shí)才加載
    preload: ["seajs-css","seajs-text"],

    // 調(diào)試模式  值為 true 時(shí),加載器不會(huì)刪除動(dòng)態(tài)插入的 script 標(biāo)簽。插件也可以根據(jù) debug 配置,來(lái)決策 log 等信息的輸出
    debug: true,

    // 文件編碼  獲取模塊文件時(shí), 一樣,會(huì)相對(duì)當(dāng)前頁(yè)面解析

use

用來(lái)在頁(yè)面中加載一個(gè)或多個(gè)模塊。seajs.use 理論上只用于加載啟動(dòng),不應(yīng)該出現(xiàn)在 define 中的模塊代碼里。在模塊代碼里需要異步加載其他模塊時(shí),推薦使用 require.async 方法。

// 加載一個(gè)模塊
seajs.use("./a");

// 加載一個(gè)模塊,在加載完成時(shí),執(zhí)行回調(diào)
seajs.use("./a", function(a) {
  a.doSomething();
});

// 加載多個(gè)模塊,在加載完成時(shí),執(zhí)行回調(diào)
seajs.use(["./a", "./b"], function(a, b) {
  a.doSomething();
  b.doSomething();
});
define
// 方式一
define(function(require, exports, module) { 
    // 模塊代碼
    var a = require("a")
});
// 方式二,此方法嚴(yán)格來(lái)說(shuō)不屬于CMD規(guī)范
define( "module", ["module1", "module2"], function( require, exports, module ){
    // 模塊代碼
});
// 如果模塊內(nèi)容僅是對(duì)象或者字符串
define({ "foo": "bar" });
define("I am a template. My name is {{name}}.");
require

require 是一個(gè)方法,接受 模塊標(biāo)識(shí)作為唯一參數(shù),用來(lái)獲取其他模塊提供的接口。

同步執(zhí)行

此方式,require 的參數(shù)值 必須 是字符串直接量。

var a = require("./a");
異步回調(diào)執(zhí)行

require.async 方法用來(lái)在模塊內(nèi)部異步加載模塊,并在加載完成后執(zhí)行指定回調(diào)。callback 參數(shù)可選。
此時(shí),參數(shù)值可以是動(dòng)態(tài)的,以實(shí)現(xiàn)動(dòng)態(tài)加載。

define(function(require, exports, module) {

  // 異步加載一個(gè)模塊,在加載完成時(shí),執(zhí)行回調(diào)
  require.async("./b", function(b) {
    b.doSomething();
  });

  // 異步加載多個(gè)模塊,在加載完成時(shí),執(zhí)行回調(diào)
  require.async(["./c", "./d"], function(c, d) {
    c.doSomething();
    d.doSomething();
  });

});

require.resolve 使用模塊系統(tǒng)內(nèi)部的路徑解析機(jī)制來(lái)解析并返回模塊絕對(duì)路徑。

define(function(require, exports) {

  console.log(require.resolve("./b"));
  // ==> http://example.com/path/to/b.js

});
exports

exports 是一個(gè)對(duì)象,用來(lái)向外提供模塊接口,也可以使用return或者module.exports來(lái)進(jìn)行導(dǎo)出

define(function(require, exports) {

  // 對(duì)外提供 foo 屬性
  exports.foo = "bar";
  // return 
  return {
    foo: "bar",
    doSomething: function() {}
  };
  // module.exports
  module.exports = {
    foo: "bar",
    doSomething: function() {}
  };
});
module

module 是一個(gè)對(duì)象,上面存儲(chǔ)了與當(dāng)前模塊相關(guān)聯(lián)的一些屬性和方法。

module.id 模塊的唯一標(biāo)識(shí)

module.uri 根據(jù)模塊系統(tǒng)的路徑解析規(guī)則得到的模塊絕對(duì)路徑

module.dependencies 表示當(dāng)前模塊的依賴(lài)

module.exports 當(dāng)前模塊對(duì)外提供的接口

其他 插件

seajs-css

seajs-preload

seajs-text

seajs-style

seajs-combo

seajs-flush

seajs-debug

seajs-log

seajs-health

文檔:官方文檔

ESModule 簡(jiǎn)介

在 ES6 之前,社區(qū)制定了一些模塊加載方案,最主要的有 CommonJS 和 AMD 兩種。前者用于服務(wù)器,后者用于瀏覽器。ES6 在語(yǔ)言標(biāo)準(zhǔn)的層面上,實(shí)現(xiàn)了模塊功能,而且實(shí)現(xiàn)得相當(dāng)簡(jiǎn)單,完全可以取代 CommonJS 和 AMD 規(guī)范,成為瀏覽器和服務(wù)器通用的模塊解決方案。

嚴(yán)格模式

ES6 的模塊自動(dòng)采用嚴(yán)格模式,不管你有沒(méi)有在模塊頭部加上"use strict";

嚴(yán)格模式主要有以下限制:

變量必須聲明后再使用

函數(shù)的參數(shù)不能有同名屬性,否則報(bào)錯(cuò)

不能使用with語(yǔ)句

不能對(duì)只讀屬性賦值,否則報(bào)錯(cuò)

不能使用前綴 0 表示八進(jìn)制數(shù),否則報(bào)錯(cuò)

不能刪除不可刪除的屬性,否則報(bào)錯(cuò)

不能刪除變量delete prop,會(huì)報(bào)錯(cuò),只能刪除屬性delete global[prop]

eval不會(huì)在它的外層作用域引入變量

eval和arguments不能被重新賦值

arguments不會(huì)自動(dòng)反映函數(shù)參數(shù)的變化

不能使用arguments.callee

不能使用arguments.caller

禁止this指向全局對(duì)象

不能使用fn.caller和fn.arguments獲取函數(shù)調(diào)用的堆棧

增加了保留字(比如protected、static和interface)

export 命令

定義模塊的對(duì)外接口。
一個(gè)模塊就是一個(gè)獨(dú)立的文件。該文件內(nèi)部的所有變量,外部無(wú)法獲取。如果你希望外部能夠讀取模塊內(nèi)部的某個(gè)變量,就必須使用export關(guān)鍵字輸出該變量。
以下是幾種用法:

//------輸出變量------
export var firstName = "Michael";
export var lastName = "Jackson";
//等價(jià)于
var firstName = "Michael";
export {firstName}; //推薦,能清除知道輸出了哪些變量
//------輸出函數(shù)或類(lèi)------
export function multiply(x, y) {
  return x * y;
};
//------輸出并as重命名------
var v1 = "Michael";
function v2() { ... }
export {
  v1 as streamV1,
  v2 as streamV2
};
//------輸出default------
export default function () { ... }

注意:export default在一個(gè)模塊中只能有一個(gè)。

import 命令

使用export命令定義了模塊的對(duì)外接口以后,其他 JS 文件就可以通過(guò)import命令加載這個(gè)模塊。
以下是幾種用法,必須和上面的export對(duì)應(yīng):

//------加載變量、函數(shù)或類(lèi)------
import {firstName, lastName} from "./profile.js";
//------加載并as重命名------
import { lastName as surname } from "./profile.js";
//------加載有default輸出的模塊------
import v1 from "./profile.js";
//------執(zhí)行所加載的模塊------
import "lodash";
//------加載模塊所有輸出------
import  * as surname from "./profile.js";
復(fù)合寫(xiě)法

如果在一個(gè)模塊之中,先輸入后輸出同一個(gè)模塊,import語(yǔ)句可以與export語(yǔ)句寫(xiě)在一起。

export { foo, bar } from "my_module";

// 等同于
import { foo, bar } from "my_module";
export { foo, bar };
不完美

只能出現(xiàn)在模塊頂層,不能在其他語(yǔ)句中

無(wú)法動(dòng)態(tài)加載,其實(shí)這點(diǎn)主要是為了保證靜態(tài)分析,所有的模塊都要在解析階段確定它的依賴(lài)

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

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

相關(guān)文章

  • 再談 JavaScript 異步編程

    摘要:隨著前端的發(fā)展,異步這個(gè)詞真是越來(lái)越常見(jiàn)了。真正帶來(lái)革命性改變的是規(guī)范。借助,我們可以這樣完成異步任務(wù)好棒寫(xiě)起來(lái)像同步處理的函數(shù)一樣別著急,少年??偨Y(jié)以上就是筆者總結(jié)的幾種異步編程模式。 隨著前端的發(fā)展,異步這個(gè)詞真是越來(lái)越常見(jiàn)了。假設(shè)我們現(xiàn)在有這么一個(gè)異步任務(wù): 向服務(wù)器發(fā)起數(shù)次請(qǐng)求,每次請(qǐng)求的結(jié)果作為下次請(qǐng)求的參數(shù)。 來(lái)看看我們都有哪些處理方法: Callbacks ...

    RobinQu 評(píng)論0 收藏0
  • JS或Jquery

    摘要:大潮來(lái)襲前端開(kāi)發(fā)能做些什么去年谷歌和火狐針對(duì)提出了的標(biāo)準(zhǔn),顧名思義,即的體驗(yàn)方式,我們可以戴著頭顯享受沉浸式的網(wǎng)頁(yè),新的標(biāo)準(zhǔn)讓我們可以使用語(yǔ)言來(lái)開(kāi)發(fā)。 VR 大潮來(lái)襲 --- 前端開(kāi)發(fā)能做些什么 去年谷歌和火狐針對(duì) WebVR 提出了 WebVR API 的標(biāo)準(zhǔn),顧名思義,WebVR 即 web + VR 的體驗(yàn)方式,我們可以戴著頭顯享受沉浸式的網(wǎng)頁(yè),新的 API 標(biāo)準(zhǔn)讓我們可以使用 ...

    CatalpaFlat 評(píng)論0 收藏0
  • JavaScript設(shè)計(jì)模式(八):組合模式

    摘要:不同于其它靜態(tài)編程語(yǔ)言,實(shí)現(xiàn)組合模式的難點(diǎn)是保持樹(shù)對(duì)象與葉對(duì)象之間接口保持統(tǒng)一,可借助定制接口規(guī)范,實(shí)現(xiàn)類(lèi)型約束。誤區(qū)規(guī)避組合不是繼承,樹(shù)葉對(duì)象并不是父子對(duì)象組合模式的樹(shù)型結(jié)構(gòu)是一種聚合的關(guān)系,而不是。 showImg(https://segmentfault.com/img/bVbu79V?w=800&h=600); 組合模式:又叫 部分整體 模式,將對(duì)象組合成樹(shù)形結(jié)構(gòu),以表示 部分...

    leon 評(píng)論0 收藏0
  • 再談閉包-詞法作用域

    摘要:權(quán)威指南第六版關(guān)于閉包的說(shuō)明采用詞法作用域,也就是說(shuō)函數(shù)的執(zhí)行依賴(lài)于變量的作用域,這個(gè)作用域是在函數(shù)定義時(shí)決定的,而不是函數(shù)調(diào)用時(shí)決定的。閉包這個(gè)術(shù)語(yǔ)的來(lái)源指函數(shù)變量可以被隱藏于作用域鏈之內(nèi),因此看起來(lái)是函數(shù)將變量包裹了起來(lái)。 最近打算換工作,所以參加了幾次面試(國(guó)內(nèi)比較知名的幾家互聯(lián)網(wǎng)公司)。在面試的過(guò)程中每當(dāng)被問(wèn)起閉包,我都會(huì)說(shuō)閉包是作用域的問(wèn)題?令人驚訝的是幾乎無(wú)一例外的當(dāng)我提到...

    Ku_Andrew 評(píng)論0 收藏0
  • 再談Javascript原型繼承

    摘要:原型繼承基本模式這種是最簡(jiǎn)單實(shí)現(xiàn)原型繼承的方法,直接把父類(lèi)的對(duì)象賦值給子類(lèi)構(gòu)造函數(shù)的原型,這樣子類(lèi)的對(duì)象就可以訪問(wèn)到父類(lèi)以及父類(lèi)構(gòu)造函數(shù)的中的屬性。 真正意義上來(lái)說(shuō)Javascript并不是一門(mén)面向?qū)ο蟮恼Z(yǔ)言,沒(méi)有提供傳統(tǒng)的繼承方式,但是它提供了一種原型繼承的方式,利用自身提供的原型屬性來(lái)實(shí)現(xiàn)繼承。Javascript原型繼承是一個(gè)被說(shuō)爛掉了的話題,但是自己對(duì)于這個(gè)問(wèn)題一直沒(méi)有徹底理解...

    ThinkSNS 評(píng)論0 收藏0

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

0條評(píng)論

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