摘要:應(yīng)用日益復(fù)雜,模塊化已經(jīng)成為一個迫切需求。異步模塊加載機(jī)制。引用的資源列表太長,懶得回調(diào)函數(shù)中寫一一對應(yīng)的相關(guān)參數(shù)假定這里引用的資源有數(shù)十個,回調(diào)函數(shù)的參數(shù)必定非常多這就是傳說中的
簡述 緣起
模塊通常是指編程語言所提供的代碼組織機(jī)制,利用此機(jī)制可將程序拆解為獨立且通用的代碼單元。
模塊化主要是解決代碼分割、作用域隔離、模塊之間的依賴管理以及發(fā)布到生產(chǎn)環(huán)境時的自動化打包與處理等多個方面。
javascript應(yīng)用日益復(fù)雜,模塊化已經(jīng)成為一個迫切需求。但是作為一個模塊化方案,它至少要解決如下問題:
可維護(hù)性
避免作用域污染
代碼重用
依賴管理
script最原始的方式就是,每個文件就是一個模塊,然后使用script的方式進(jìn)行引入。
但是此方式有以下問題:
全局作用域污染
無依賴管理,執(zhí)行順序依賴script標(biāo)簽的順序,如果采用異步加載,那會亂套,先下載的先執(zhí)行
IIFE 和 模塊對象為了解決作用域污染的問題,就產(chǎn)生了立即執(zhí)行函數(shù) + 模塊對象模式:
// 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模塊化編程(一):模塊的寫法
在ES6之前,js沒有塊級作用域,所以采用此方式建立一個函數(shù)作用域。但是在ES6之后,可以使用塊級作用域。
由于使用了IIFE,所以減少了全局作用域污染,但并不是徹底消除,因為還定義了一個appa模塊對象呢。
所以這也僅僅只是減少了作用域污染,還是會有其他缺點。
CommonJS后來,有人試圖將javascript引入服務(wù)端,由于服務(wù)端編程相對比較復(fù)雜,就急需一種模塊化的方案,所以就誕生了commonjs,有require + module.exports實現(xiàn)模塊的加載和導(dǎo)出。
CommonJS采用同步的方式加載模塊,主要使用場景為服務(wù)端編程。因為服務(wù)器一般都是本地加載,速度較快。
AMD 和 CMD后來,隨著前端業(yè)務(wù)的日漸復(fù)雜,瀏覽器端也需要模塊化,但是commonjs是同步加載的,這意味著加載模塊時,瀏覽器會凍結(jié),什么都干不了,這在瀏覽器肯定是不行的,這就誕生了AMD和CMD規(guī)范,分別以requirejs和seajs為代表。
這兩貨都采用異步方式加載模塊。
AMDAMD(Asynchronous Module Defination)異步模塊加載機(jī)制。
define( [module_id,] // 模塊名字,如果缺省則為匿名模塊 [dependenciesArray,] // 模塊依賴 definition function | object // 模塊內(nèi)容,可以為函數(shù)或者對象 );CMD
CMD(Common Module Defination)通用模塊加載機(jī)制
// 方式一 define(function(require, exports, module) { // 模塊代碼 var a = require("a") }); // 方式二 define( "module", ["module1", "module2"], function( require, exports, module ){ // 模塊代碼 } );區(qū)別
對于依賴的模塊,AMD 是提前執(zhí)行( RequireJS 從 2.0 開始,也改成可以延遲執(zhí)行),CMD 是延遲執(zhí)行
CMD 推崇依賴就近,AMD 推崇依賴前置
AMD 的 API 默認(rèn)是一個當(dāng)多個用,CMD 的 API 嚴(yán)格區(qū)分,推崇職責(zé)單一
不完美盡管以上方案解決了上面說的問題,但是也帶來了一些新問題:
語法冗余,所有東西都要封裝在define中
AMD中的依賴列表必須與函數(shù)的參數(shù)列表匹配,易錯且修改苦難
Browserify由于上述這些原因,有些人想在瀏覽器使用 CommonJS 規(guī)范,但 CommonJS 語法主要是針對服務(wù)端且是同步的,所以就產(chǎn)生了Browserify,它是一個 模塊打包器(module bundler),可以打包commonjs規(guī)范的模塊到瀏覽器中使用。
UMDUMD(Universal Module Definition) 統(tǒng)一模塊定義。
AMD 與 CommonJS 雖然師出同源,但還是分道揚鑣,關(guān)注于代碼異步加載與最小化入口模塊的開發(fā)者將目光投注于 AMD;而隨著 Node.js 以及 Browserify 的流行,越來越多的開發(fā)者也接受了 CommonJS 規(guī)范。令人扼腕嘆息的是,符合 AMD 規(guī)范的模塊并不能直接運行于 CommonJS 模塊規(guī)范的環(huán)境中,符合 CommonJS 規(guī)范的模塊也不能由 AMD 進(jìn)行異步加載。
而且有這么多種規(guī)范,如果我們要發(fā)布一個模塊供其他人用,我們不可能為每種規(guī)范發(fā)布一個版本,就算你蛋疼這樣做了,別人使用的時候還得下載對應(yīng)版本,所以現(xiàn)在需要一種方案來兼容這些規(guī)范。
實現(xiàn)的方式就是在代碼前面做下判斷,根據(jù)不同的規(guī)范使用對應(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瀏覽器支持還不夠好,所以很多第三方庫都采用了這種方式。
ESModuleES6引入了ESModule規(guī)范,主要通過export + import來實現(xiàn),最終一統(tǒng)江湖??墒乾F(xiàn)實很骨感,一些瀏覽器并不支持(IE,說的就是你),所以還不能直接在瀏覽器中直接使用。
常用的兩種方案在線編譯:requirejs/seajs/sytemjs
在頁面上加載一個AMD/CMD模塊格式解釋器。這樣瀏覽器就認(rèn)識了define, exports,module這些東西,也就實現(xiàn)了模塊化。
SystemJS 是一個通用的模塊加載器,它能在瀏覽器或者 NodeJS 上動態(tài)加載模塊,并且支持 CommonJS、AMD、全局模塊對象和 ES6 模塊。通過使用插件,它不僅可以加載 JavaScript,還可以加載 CoffeeScript 和 TypeScript。配合jspm也是不錯的搭配。
預(yù)編譯:browserify/webpack
相比于第一種方案,這個方案更加智能。由于是預(yù)編譯的,不需要在瀏覽器中加載解釋器。你在本地直接寫JS,不管是AMD/CMD/ES6風(fēng)格的模塊化,它都能認(rèn)識,并且編譯成瀏覽器認(rèn)識的JS。
注意: browerify只支持Commonjs模塊,如需兼容AMD模塊,則需要plugin轉(zhuǎn)換
CommonJS前身為ServerJS。
我們可以理解為代碼會被如下內(nèi)建輔助函數(shù)包裹:
(function (exports, require, module, __filename, __dirname) { // ... // Your code // ... });加載
通過require加載模塊。
const a = require("a")導(dǎo)出
通過exports和module.exports進(jìn)行模塊導(dǎo)出。
exports:exports是module.exports的一個引用,一個模塊可以使用多次,但是不能直接對exports重新賦值,只能通過如下方式使用
exports.a = function(){ // code... }
module.exports:一個模塊只能使用一次
module.exports = function(){ // code... }特點
同步加載,定位于服務(wù)端,不適合瀏覽器
requirejs 特點支持同步和異步兩種方式
大多數(shù)第三方庫都有兼容AMD,即時不兼容也可以通過配置使其可用
異步加載,不阻塞瀏覽器
依賴前置,可以很清楚看到當(dāng)前模塊的依賴
引入在引入requirejs的script標(biāo)簽上添加data-main屬性定義入口文件,該文件會在requirejs加載完后立即執(zhí)行。
如果baseUrl未多帶帶配置,則默認(rèn)為引入require的文件的路徑。
configrequirejs.config({ // 為模塊加上query參數(shù),解決瀏覽器緩存,只在開發(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"] }, // 對于匹配的模塊前綴,使用一個不同的模塊ID來加載該模塊 map: { "layer": { "jquery": "http://libs.baidu.com/jquery/2.0.3/jquery" } }, // 從CommonJS包(package)中加載模塊 packages:{}, // 加載上下文 context:{}, // 超時,默認(rèn)7S waitSeconds: 7, // 定義應(yīng)用依賴的模塊,在啟動后會加載此數(shù)組中的模塊 deps: [], // 在deps加載完畢后執(zhí)行的函數(shù) callback:function(){}, // 用來加載非AMD規(guī)范的模塊,以瀏覽器全局變量注入,此處僅作映射,需要在需要時手動載入 shim: { // "backbone": { // deps: ["underscore", "jquery"], // 模塊依賴 // exports: "Backbone" // 導(dǎo)出的名稱 // } }, // 全局配置信息,可在模塊中通過module.config()訪問 config:{ color:"red" }, // 如果設(shè)置為true,則當(dāng)一個腳本不是通過define()定義且不具備可供檢查的shim導(dǎo)出字串值時,就會拋出錯誤 enforceDefine:false, // 如果設(shè)置為true,則使用document.createElementNS()去創(chuàng)建script元素 xhtm: false, //指定RequireJS將script標(biāo)簽插入document時所用的type=""值 scriptType:"text/javascript" });
默認(rèn)requirejs會根據(jù)baseUrl+paths配置去查找模塊,但是如下情況例外:
路徑以.js結(jié)尾,比如lib/hello.js、hello.js
以“/”開始
包含url協(xié)議:如"http:"、"https"
設(shè)置baseURl的方式有如下三種:
requirejs.config指定;
如指data-main,則baseUrl為data-main所對應(yīng)的js的目錄
如果上述均未指定,則baseUrl為運行RequireJS的HTML文件所在目錄
map配置對于大型項目很重要:如有兩類模塊需要使用不同版本的"foo",但它們之間仍需要一定的協(xié)同。
在那些基于上下文的多版本實現(xiàn)中很難做到這一點。而且,paths配置僅用于為模塊ID設(shè)置root paths,而不是為了將一個模塊ID映射到另一個。
requirejs.config({ map: { "some/newmodule": { "foo": "foo1.2" }, "some/oldmodule": { "foo": "foo1.0" } } });define
通過define來定義模塊,推薦依賴前置原則,當(dāng)然也可以使用require動態(tài)按需加載。
define( [module_id,] // 模塊名字,如果缺省則為匿名模塊 [dependencies,] // 模塊依賴 definition function | object // 模塊內(nèi)容,可以為函數(shù)或者對象 );
// 如果僅僅返回一個鍵值對,可以采用如下格式,類似JSONP define({ color: "black", size: "unisize" }) //如果沒有依賴 define(function () { return { color: "black", size: "unisize" } }) // 有依賴 define(["./a", "./b"], function(a, b) { }) // 具名模塊 define("name", ["c", "d"], function(cart, inventory) { //此處定義foo/title object } )
如要在define()內(nèi)部使用諸如require("./a/b")相對路徑,記得將"require"本身作為一個依賴注入到模塊中:
define(["require", "./a/b"], function(require) { var mod = require("./a/b"); });
或者使用如下方式:
define(function(require) { var mod = require("./a/b"); })標(biāo)識
require加載的所有模塊都是單例的,每個模塊都有一個唯一的標(biāo)識,這個標(biāo)識是模塊的名字或者模塊的相對路徑(如匿名模塊)。
模塊的唯一性與它們的訪問路徑無關(guān),即使是地址完全相同的一份JS文件,如果引用的方式與模塊的配置方式不一致,依舊會產(chǎn)生多個模塊。
// 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)行訪問 // "user/User"以path定義的模塊進(jìn)行訪問 require(["em/User", "user/User"], function(u1, u2) { // 輸出的結(jié)果完全不相同,u1為yiifaa,u2為修改后的內(nèi)容yiifee console.log(u1, u2); }) })依賴
requirejs推薦依賴前置,在define或者require模塊的時候,可以將需要依賴的模塊作為第一個參數(shù),以數(shù)組的方式聲明,然后在回調(diào)函數(shù)中,依賴會以參數(shù)的形式注入到該函數(shù)上,參數(shù)列表需要和依賴數(shù)組中位置一一對應(yīng)。
define(["./a", "./b"], function(a, b) { })導(dǎo)出
在requirejs中,有3中方式進(jìn)行模塊導(dǎo)出:
通過return方式導(dǎo)出,優(yōu)先級最高(推薦);
define(function(require, exports, module) { return { a : "a" } });
通關(guān)module.exports對象賦值導(dǎo)出,優(yōu)先級次之;
define(function(require, exports, module) { module.exports = { a : "a" } });
通過exports對象賦值導(dǎo)出,優(yōu)先級最低;
define(function(require, exports, module) { exports.a = "a" });require
requirejs提供了兩個全局變量require、requirejs供我們加載模塊,這二者是完全等價的。
// 此處require 和 define 函數(shù)僅僅是一個參數(shù)(模塊標(biāo)識)的差異, // 一般require用于沒有返回的模塊,如應(yīng)用頂層模塊 require( [dependencies,] // 模塊依賴 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í)行同步加載必須滿足兩點要求:
必須在定義模塊時使用,亦即define函數(shù)中;
引用的資源必須是之前異步加載過的(不必在同一個模塊),換句話說,同步載入的模塊是不會發(fā)網(wǎng)絡(luò)請求的,只會調(diào)取之前緩存的模塊;
define(function(require, exports, module) { })中可以同步加載模塊
應(yīng)用場景明確知道模塊的先后順序,確認(rèn)此模塊已經(jīng)被加載過,例如系統(tǒng)通用模塊,在載入完成后,之后的模塊就可以進(jìn)行同步的引用,或者在Vue等前端技術(shù)框架中,在應(yīng)用模塊同步加載vue模塊。
引用的資源列表太長,懶得回調(diào)函數(shù)中寫一一對應(yīng)的相關(guān)參數(shù)
// 假定這里引用的資源有數(shù)十個,回調(diào)函數(shù)的參數(shù)必定非常多 define(["jquery"], function() { return function(el) { // 這就是傳說中的同步調(diào)用 var $ = require("jquery"); $(el).html("Hello, World!"); } })
可以減少命名或者命名空間沖突,例如prototype與jquery的沖突問題
define(["jquery", "prototype"], function() { var export = {}; export.jquery = function(el) { // 這就是傳說中的同步調(diào)用 var $ = require("jquery"); $(el).html("Hello, World!"); } export.proto = function(el) { // 這就是傳說中的同步調(diào)用 var $ = require("prototype"); $(el).html("Hello, World!"); } return export; })
處女座專用,代碼顯得更整潔漂亮了,硬是把回調(diào)函數(shù)寫出了同步的感覺
異步加載define([],function()):依賴數(shù)組中的模塊會異步加載,所有模塊加載完成后混執(zhí)行回調(diào)函數(shù)
require([]):傳入數(shù)組格式即表示需要異步加載
require === requirejs //=> truerequire.toUrl("./a.css"): 獲取模塊url 模塊卸載
只要頁面不刷新,被requirejs加載的模塊只會執(zhí)行一次,后面會一直緩存在內(nèi)存中,即時重新引入模塊也不會再進(jìn)行初始化。
我們可以通過undef卸載已加載的模塊。
require.undef("moduleName") // moduleName是模塊標(biāo)識其他 插件
css:加載css
text:加載HTML及其他文本
domReady
模塊加載錯誤Module name has not been loaded yet for context: _:
此錯誤表示執(zhí)行時模塊還未加載成功,一般為異步加載所致,改成同步加載即可。
借助類解決模塊間的相互干擾//C模塊 define([],function(){ // 定義一個類 function DemoClass() { var count = 0; this.say = function(){ count++; return count; }; } return function(){ //每次都返回一個新對象 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 追求簡單、自然的代碼書寫和組織方式,具有以下核心特性:
簡單友好的模塊定義規(guī)范:Sea.js 遵循 CMD 規(guī)范,可以像 Node.js 一般書寫模塊代碼。
自然直觀的代碼組織方式:依賴的自動加載、配置的簡潔清晰,可以讓我們更多地享受編碼的樂趣。
通過exports + require實現(xiàn)模塊的加載與導(dǎo)出。
引入config
//seajs配置 seajs.config({ //1.頂級標(biāo)識始終相對 base 基礎(chǔ)路徑解析。 //2.絕對路徑和根路徑始終相對當(dāng)前頁面解析。 //3.require 和 require.async 中的相對路徑相對當(dāng)前模塊路徑來解析。 //4.seajs.use 中的相對路徑始終相對當(dāng)前頁面來解析。 // Sea.js 的基礎(chǔ)路徑 在解析頂級標(biāo)識時,會相對 base 路徑來解析 base 的默認(rèn)值為 sea.js 的訪問路徑的父級 base: "./", // 路徑配置 當(dāng)目錄比較深,或需要跨目錄調(diào)用模塊時,可以使用 paths 來簡化書寫 paths: { gallery: "https://a.alipayobjects.com/gallery" /* var underscore = require("gallery/underscore"); //=> 加載的是 https://a.alipayobjects.com/gallery/underscore.js */ }, // 別名配置 當(dāng)模塊標(biāo)識很長時,可以使用 alias 來簡化(相當(dāng)于 base 設(shè)置的目錄為基礎(chǔ)) //Sea.js 在解析模塊標(biāo)識時, 除非在路徑中有問號(?)或最后一個字符是井號(#),否則都會自動添加 JS 擴(kuò)展名(.js)。如果不想自動添加擴(kuò)展名,可以在路徑末尾加上井號(#)。 alias: { "seajs-css": "~/lib/seajs/plugins/seajs-css", "seajs-text": "~/lib/seajs/plugins/seajs-text", "$": "~/lib/zepto/zepto" }, // 變量配置 有些場景下,模塊路徑在運行時才能確定,這時可以使用 vars 變量來配置 vars: { //locale: "zh-cn" /* var lang = require("./i18n/{locale}.js"); //=> 加載的是 path/to/i18n/zh-cn.js */ }, // 映射配置 該配置可對模塊路徑進(jìn)行映射修改,可用于路徑轉(zhuǎn)換、在線調(diào)試等 map: [ //[".js", "-debug.js"] /* var a = require("./a"); //=> 加載的是 ./js/a-debug.js */ ], // 預(yù)加載項 在普通模塊加載前,提前加載并初始化好指定模塊 preload 中的配置,需要等到 use 時才加載 preload: ["seajs-css","seajs-text"], // 調(diào)試模式 值為 true 時,加載器不會刪除動態(tài)插入的 script 標(biāo)簽。插件也可以根據(jù) debug 配置,來決策 log 等信息的輸出 debug: true, // 文件編碼 獲取模塊文件時, 一樣,會相對當(dāng)前頁面解析 use用來在頁面中加載一個或多個模塊。seajs.use 理論上只用于加載啟動,不應(yīng)該出現(xiàn)在 define 中的模塊代碼里。在模塊代碼里需要異步加載其他模塊時,推薦使用 require.async 方法。
// 加載一個模塊 seajs.use("./a"); // 加載一個模塊,在加載完成時,執(zhí)行回調(diào) seajs.use("./a", function(a) { a.doSomething(); }); // 加載多個模塊,在加載完成時,執(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)格來說不屬于CMD規(guī)范 define( "module", ["module1", "module2"], function( require, exports, module ){ // 模塊代碼 }); // 如果模塊內(nèi)容僅是對象或者字符串 define({ "foo": "bar" }); define("I am a template. My name is {{name}}.");requirerequire 是一個方法,接受 模塊標(biāo)識作為唯一參數(shù),用來獲取其他模塊提供的接口。
同步執(zhí)行此方式,require 的參數(shù)值 必須 是字符串直接量。
var a = require("./a");異步回調(diào)執(zhí)行require.async 方法用來在模塊內(nèi)部異步加載模塊,并在加載完成后執(zhí)行指定回調(diào)。callback 參數(shù)可選。
此時,參數(shù)值可以是動態(tài)的,以實現(xiàn)動態(tài)加載。define(function(require, exports, module) { // 異步加載一個模塊,在加載完成時,執(zhí)行回調(diào) require.async("./b", function(b) { b.doSomething(); }); // 異步加載多個模塊,在加載完成時,執(zhí)行回調(diào) require.async(["./c", "./d"], function(c, d) { c.doSomething(); d.doSomething(); }); });require.resolve 使用模塊系統(tǒng)內(nèi)部的路徑解析機(jī)制來解析并返回模塊絕對路徑。
define(function(require, exports) { console.log(require.resolve("./b")); // ==> http://example.com/path/to/b.js });exportsexports 是一個對象,用來向外提供模塊接口,也可以使用return或者module.exports來進(jìn)行導(dǎo)出
define(function(require, exports) { // 對外提供 foo 屬性 exports.foo = "bar"; // return return { foo: "bar", doSomething: function() {} }; // module.exports module.exports = { foo: "bar", doSomething: function() {} }; });modulemodule 是一個對象,上面存儲了與當(dāng)前模塊相關(guān)聯(lián)的一些屬性和方法。
module.id 模塊的唯一標(biāo)識
module.uri 根據(jù)模塊系統(tǒng)的路徑解析規(guī)則得到的模塊絕對路徑
module.dependencies 表示當(dāng)前模塊的依賴
module.exports 當(dāng)前模塊對外提供的接口
其他 插件seajs-css
seajs-preload
seajs-text
seajs-style
seajs-combo
seajs-flush
seajs-debug
seajs-log
seajs-health
文檔:官方文檔
ESModule 簡介在 ES6 之前,社區(qū)制定了一些模塊加載方案,最主要的有 CommonJS 和 AMD 兩種。前者用于服務(wù)器,后者用于瀏覽器。ES6 在語言標(biāo)準(zhǔn)的層面上,實現(xiàn)了模塊功能,而且實現(xiàn)得相當(dāng)簡單,完全可以取代 CommonJS 和 AMD 規(guī)范,成為瀏覽器和服務(wù)器通用的模塊解決方案。
嚴(yán)格模式ES6 的模塊自動采用嚴(yán)格模式,不管你有沒有在模塊頭部加上"use strict";。
嚴(yán)格模式主要有以下限制:
變量必須聲明后再使用
函數(shù)的參數(shù)不能有同名屬性,否則報錯
不能使用with語句
不能對只讀屬性賦值,否則報錯
不能使用前綴 0 表示八進(jìn)制數(shù),否則報錯
不能刪除不可刪除的屬性,否則報錯
不能刪除變量delete prop,會報錯,只能刪除屬性delete global[prop]
eval不會在它的外層作用域引入變量
eval和arguments不能被重新賦值
arguments不會自動反映函數(shù)參數(shù)的變化
不能使用arguments.callee
不能使用arguments.caller
禁止this指向全局對象
不能使用fn.caller和fn.arguments獲取函數(shù)調(diào)用的堆棧
增加了保留字(比如protected、static和interface)
export 命令定義模塊的對外接口。
一個模塊就是一個獨立的文件。該文件內(nèi)部的所有變量,外部無法獲取。如果你希望外部能夠讀取模塊內(nèi)部的某個變量,就必須使用export關(guān)鍵字輸出該變量。
以下是幾種用法://------輸出變量------ export var firstName = "Michael"; export var lastName = "Jackson"; //等價于 var firstName = "Michael"; export {firstName}; //推薦,能清除知道輸出了哪些變量 //------輸出函數(shù)或類------ 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在一個模塊中只能有一個。
import 命令使用export命令定義了模塊的對外接口以后,其他 JS 文件就可以通過import命令加載這個模塊。
以下是幾種用法,必須和上面的export對應(yīng)://------加載變量、函數(shù)或類------ 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ù)合寫法如果在一個模塊之中,先輸入后輸出同一個模塊,import語句可以與export語句寫在一起。
export { foo, bar } from "my_module"; // 等同于 import { foo, bar } from "my_module"; export { foo, bar };不完美只能出現(xiàn)在模塊頂層,不能在其他語句中
無法動態(tài)加載,其實這點主要是為了保證靜態(tài)分析,所有的模塊都要在解析階段確定它的依賴
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/105832.html
摘要:隨著前端的發(fā)展,異步這個詞真是越來越常見了。真正帶來革命性改變的是規(guī)范。借助,我們可以這樣完成異步任務(wù)好棒寫起來像同步處理的函數(shù)一樣別著急,少年??偨Y(jié)以上就是筆者總結(jié)的幾種異步編程模式。 隨著前端的發(fā)展,異步這個詞真是越來越常見了。假設(shè)我們現(xiàn)在有這么一個異步任務(wù): 向服務(wù)器發(fā)起數(shù)次請求,每次請求的結(jié)果作為下次請求的參數(shù)。 來看看我們都有哪些處理方法: Callbacks ...
摘要:大潮來襲前端開發(fā)能做些什么去年谷歌和火狐針對提出了的標(biāo)準(zhǔn),顧名思義,即的體驗方式,我們可以戴著頭顯享受沉浸式的網(wǎng)頁,新的標(biāo)準(zhǔn)讓我們可以使用語言來開發(fā)。 VR 大潮來襲 --- 前端開發(fā)能做些什么 去年谷歌和火狐針對 WebVR 提出了 WebVR API 的標(biāo)準(zhǔn),顧名思義,WebVR 即 web + VR 的體驗方式,我們可以戴著頭顯享受沉浸式的網(wǎng)頁,新的 API 標(biāo)準(zhǔn)讓我們可以使用 ...
摘要:不同于其它靜態(tài)編程語言,實現(xiàn)組合模式的難點是保持樹對象與葉對象之間接口保持統(tǒng)一,可借助定制接口規(guī)范,實現(xiàn)類型約束。誤區(qū)規(guī)避組合不是繼承,樹葉對象并不是父子對象組合模式的樹型結(jié)構(gòu)是一種聚合的關(guān)系,而不是。 showImg(https://segmentfault.com/img/bVbu79V?w=800&h=600); 組合模式:又叫 部分整體 模式,將對象組合成樹形結(jié)構(gòu),以表示 部分...
摘要:權(quán)威指南第六版關(guān)于閉包的說明采用詞法作用域,也就是說函數(shù)的執(zhí)行依賴于變量的作用域,這個作用域是在函數(shù)定義時決定的,而不是函數(shù)調(diào)用時決定的。閉包這個術(shù)語的來源指函數(shù)變量可以被隱藏于作用域鏈之內(nèi),因此看起來是函數(shù)將變量包裹了起來。 最近打算換工作,所以參加了幾次面試(國內(nèi)比較知名的幾家互聯(lián)網(wǎng)公司)。在面試的過程中每當(dāng)被問起閉包,我都會說閉包是作用域的問題?令人驚訝的是幾乎無一例外的當(dāng)我提到...
摘要:原型繼承基本模式這種是最簡單實現(xiàn)原型繼承的方法,直接把父類的對象賦值給子類構(gòu)造函數(shù)的原型,這樣子類的對象就可以訪問到父類以及父類構(gòu)造函數(shù)的中的屬性。 真正意義上來說Javascript并不是一門面向?qū)ο蟮恼Z言,沒有提供傳統(tǒng)的繼承方式,但是它提供了一種原型繼承的方式,利用自身提供的原型屬性來實現(xiàn)繼承。Javascript原型繼承是一個被說爛掉了的話題,但是自己對于這個問題一直沒有徹底理解...
閱讀 1486·2021-10-13 09:39
閱讀 1409·2021-09-23 11:22
閱讀 2311·2019-08-30 14:05
閱讀 1131·2019-08-29 17:03
閱讀 873·2019-08-29 16:24
閱讀 2295·2019-08-29 13:51
閱讀 721·2019-08-29 13:00
閱讀 1431·2019-08-29 11:24