日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) >

javascript模块化简介

發(fā)布時(shí)間:2025/6/15 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 javascript模块化简介 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

所有原創(chuàng)并不精彩,所有精彩并非原創(chuàng)

歷史

JavaScript 隨著時(shí)間的推移所負(fù)責(zé)的責(zé)任越來(lái)越重從最開(kāi)始的添加表單驗(yàn)證功能之類的腳本到angular 應(yīng)用開(kāi)發(fā)框架,隨著js任務(wù)越來(lái)越重就急需模塊化的解決方案。

模塊化的基礎(chǔ)條件就是開(kāi)辟一片獨(dú)立的上下文,那些擁有模塊化功能的語(yǔ)言或通過(guò)物理文件組織模塊,或以抽象的 namespace package 組織模塊,而JavaScript 并沒(méi)這種能力只能從語(yǔ)法上開(kāi)辟獨(dú)立的上下文,就目前瀏覽器端運(yùn)行的js來(lái)說(shuō)能開(kāi)辟獨(dú)立上下文的方式只有一種方式 function(閉包)

  • 最開(kāi)始的刀耕火種用閉包各種全局變量組織結(jié)構(gòu)
  • AMD UMD commonjs es6
  • 現(xiàn)在webpack 支持 AMD commonjs es6 ,不過(guò)webpack更多的只是格式上的支持

對(duì)比一下各個(gè)模塊化方案代碼寫(xiě)法

仔細(xì)觀察一下下面列舉的幾個(gè)例子不難發(fā)現(xiàn)根上還是閉包

AMD

define(['requrie','exports','module'],function(require, exports, module) {var a = require('a'),b = require('b');exports.A=a}) ; 復(fù)制代碼

angular

angular.module('myApp', []).controller('Ctl', ['$scope', '$log', function ($scope, $log) {$scope.name = 'leonwgc';$log.log('hello,world'); }]); 復(fù)制代碼

webpack

(function(modules) { // webpackBootstrap/******/ // The module cache/******/ var installedModules = {};/******//******/ // The require function/******/ function __webpack_require__(moduleId) {/******//******/ // Check if module is in cache/******/ if(installedModules[moduleId]) {/******/ return installedModules[moduleId].exports;/******/ }/******/ // Create a new module (and put it into the cache)/******/ var module = installedModules[moduleId] = {/******/ i: moduleId,/******/ l: false,/******/ exports: {}/******/ };/******//******/ // Execute the module function/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);/******//******/ // Flag the module as loaded/******/ module.l = true;/******//******/ // Return the exports of the module/******/ return module.exports;/******/ }/******//******/ // Load entry module and return exports/******/ return __webpack_require__(__webpack_require__.s = 81);/******/ })/************************************************************************//******/ ([/* 0 */ /***/ (function(module, exports, __webpack_require__) {/***/ }), /* 1 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; ; exports.cla = cla;/***/ }), /* 2 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var e = 2.71828182846; function math(x) {return Math.exp(x); }module.exports = math;/***/ })]); 復(fù)制代碼

對(duì)比完代碼接下來(lái)簡(jiǎn)要介紹一下AMD,Commonjs ,ES6模塊化的語(yǔ)法于定義

AMD

define(id?, dependencies?, factory);

id

第一個(gè)參數(shù),id,是個(gè)字符串。它指的是定義中模塊的名字,這個(gè)參數(shù)是可選的。如果沒(méi)有提供該參數(shù),模塊的名字應(yīng)該默認(rèn)為模塊加載器請(qǐng)求的指定腳本的名字。如果提供了該參數(shù),模塊名必須是“頂級(jí)”的和絕對(duì)的(不允許相對(duì)名字)。

模塊格式

模塊名用來(lái)唯一標(biāo)識(shí)定義中模塊,它們同樣在依賴數(shù)組中使用。AMD的模塊名規(guī)范是CommonJS模塊名規(guī)范的超集。引用如下:

  • 模塊名是由一個(gè)或多個(gè)單詞以正斜杠為分隔符拼接成的字符串
  • 單詞須為駝峰形式,或者".",".."
  • 模塊名不允許文件擴(kuò)展名的形式,如".js"
  • 模塊名可以為 "相對(duì)的" 或 "頂級(jí)的"。如果首字符為"."或".."則為"相對(duì)的"模塊名
  • 頂級(jí)的模塊名從根命名空間的概念模塊解析
  • 相對(duì)的模塊名從 "require" 書(shū)寫(xiě)和調(diào)用的模塊解析 上文引用的CommonJS模塊id屬性常被用于JavaScript模塊。

相對(duì)模塊名解析示例:

  • 如果模塊 "a/b/c" 請(qǐng)求 "../d", 則解析為"a/d"
  • 如果模塊 "a/b/c" 請(qǐng)求 "./e", 則解析為"a/b/e"

依賴

第二個(gè)參數(shù),dependencies,是個(gè)定義中模塊所依賴模塊的數(shù)組。依賴模塊必須根據(jù)模塊的工廠方法優(yōu)先級(jí)執(zhí)行,并且執(zhí)行的結(jié)果應(yīng)該按照依賴數(shù)組中的位置順序以參數(shù)的形式傳入(定義中模塊的)工廠方法中。

依賴的模塊名如果是相對(duì)的,應(yīng)該解析為相對(duì)定義中的模塊。換句話來(lái)說(shuō),相對(duì)名解析為相對(duì)于模塊的名字,并非相對(duì)于尋找該模塊的名字的路徑。

本規(guī)范定義了三種特殊的依賴關(guān)鍵字。如果"require","exports", 或 "module"出現(xiàn)在依賴列表中,參數(shù)應(yīng)該按照CommonJS模塊規(guī)范自由變量去解析。

依賴參數(shù)是可選的,如果忽略此參數(shù),它應(yīng)該默認(rèn)為["require", "exports", "module"]。然而,如果工廠方法的形參個(gè)數(shù)小于3,加載器會(huì)選擇以函數(shù)指定的參數(shù)個(gè)數(shù)調(diào)用工廠方法。

工廠方法

第三個(gè)參數(shù),factory,為模塊初始化要執(zhí)行的函數(shù)或?qū)ο蟆H绻麨楹瘮?shù),它應(yīng)該只被執(zhí)行一次。如果是對(duì)象,此對(duì)象應(yīng)該為模塊的輸出值。

如果工廠方法返回一個(gè)值(對(duì)象,函數(shù),或任意強(qiáng)制類型轉(zhuǎn)換為true的值),應(yīng)該為設(shè)置為模塊的輸出值。

簡(jiǎn)單的 CommonJS 轉(zhuǎn)換

如果依賴性參數(shù)被忽略,模塊加載器可以選擇掃描工廠方法中的require語(yǔ)句以獲得依賴性(字面量形為require("module-id"))。第一個(gè)參數(shù)必須字面量為require從而使此機(jī)制正常工作。

在某些情況下,因?yàn)槟_本大小的限制或函數(shù)不支持toString方法(Opera Mobile是已知的不支持函數(shù)的toString方法),模塊加載器可以選擇掃描不掃描依賴性。

如果有依賴參數(shù),模塊加載器不應(yīng)該在工廠方法中掃描依賴性。

Simple Name/Value Pairs

If the module does not have any dependencies, and it is just a collection of name/value pairs, then just pass an object literal to define():

//Inside file my/shirt.js: define({color: "black",size: "unisize" }); 復(fù)制代碼

Definition Functions

If the module does not have dependencies, but needs to use a function to do some setup work, then define itself, pass a function to define():

//my/shirt.js now does setup work //before returning its module definition. define(function () {//Do setup work herereturn {color: "black",size: "unisize"} }); 復(fù)制代碼

Definition Functions with Dependencies

If the module has dependencies, the first argument should be an array of dependency names, and the second argument should be a definition function. The function will be called to define the module once all dependencies have loaded. The function should return an object that defines the module. The dependencies will be passed to the definition function as function arguments, listed in the same order as the order in the dependency array:

//my/shirt.js now has some dependencies, a cart and inventory //module in the same directory as shirt.js define(["./cart", "./inventory"], function(cart, inventory) {//return an object to define the "my/shirt" module.return {color: "blue",size: "large",addToCart: function() {inventory.decrement(this);cart.add(this);}}} ); 復(fù)制代碼

Define a Module with Simplified CommonJS Wrapper

If you wish to reuse some code that was written in the traditional CommonJS module format it may be difficult to re-work to the array of dependencies used above, and you may prefer to have direct alignment of dependency name to the local variable used for that dependency. You can use the simplified CommonJS wrapper for those cases:

define(function(require, exports, module) {var a = require('a'),b = require('b');exports.A=a} );define(['requrie','exports','module'],function(require, exports, module) {var a = require('a'),b = require('b');exports.A=a} ); 復(fù)制代碼

r.js

babel

commonjs js 規(guī)范是 AMD 的子集 看一下demo

  • babel-plugin-transform-es2015-modules-amd
  • babel-plugin-transform-es2015-modules-commonjs
  • babel-plugin-transform-es2015-modules-systemjs
  • babel-plugin-transform-es2015-modules-umd
$ babel ES6 --out-dir AMD --plugins=transform-es2015-modules-amd $ babel ES6 --out-dir UMD --plugins=transform-es2015-modules-umd $ babel ES6 --out-dir common --plugins=transform-es2015-modules-commonjs復(fù)制代碼

Commonjs

CommonJS API定義很多普通應(yīng)用程序(主要指非瀏覽器的應(yīng)用)使用的API,從而填補(bǔ)了這個(gè)空白。它的終極目標(biāo)是提供一個(gè)類似Python,Ruby和Java標(biāo) 準(zhǔn)庫(kù)。這樣的話,開(kāi)發(fā)者可以使用CommonJS API編寫(xiě)應(yīng)用程序,然后這些應(yīng)用可以運(yùn)行在不同的JavaScript解釋器和不同的主機(jī)環(huán)境中。在兼容CommonJS的系統(tǒng)中,你可以使用 JavaScript程序開(kāi)發(fā):

  • 服務(wù)器端JavaScript應(yīng)用程序
  • 命令行工具
  • 圖形界面應(yīng)用程序
  • 混合應(yīng)用程序(如,Titanium或Adobe AIR...)

基本語(yǔ)法

var x = 5; var addX = function (value) {return value + x; }; module.exports.x = x; module.exports.addX = addX; // 上面代碼通過(guò)module.exports輸出變量x和函數(shù)addX。// require方法用于加載模塊。 var example = require('./example.js');console.log(example.x); // 5 console.log(example.addX(1)); // 6 復(fù)制代碼

module對(duì)象

  • module.id 模塊的識(shí)別符,通常是帶有絕對(duì)路徑的模塊文件名。
  • module.filename 模塊的文件名,帶有絕對(duì)路徑。
  • module.loaded 返回一個(gè)布爾值,表示模塊是否已經(jīng)完成加載。
  • module.parent 返回一個(gè)對(duì)象,表示調(diào)用該模塊的模塊。
  • module.children 返回一個(gè)數(shù)組,表示該模塊要用到的其他模塊。
  • module.exports 表示模塊對(duì)外輸出的值。
{ id: '.',exports: { '$': [Function] },parent: null,filename: '/path/to/example.js',loaded: false,children:[ { id: '/path/to/node_modules/jquery/dist/jquery.js',exports: [Function],parent: [Circular],filename: '/path/to/node_modules/jquery/dist/jquery.js',loaded: true,children: [],paths: [Object] } ],paths:[ '/home/user/deleted/node_modules','/home/user/node_modules','/home/node_modules','/node_modules' ] } 復(fù)制代碼

exports

exports 要注意的問(wèn)題

exports = function(x) {console.log(x)};復(fù)制代碼

函數(shù)傳參傳入引用的引用

函數(shù)傳參基本是兩種類型 值類型和引用類型 最早接觸這個(gè)問(wèn)題是在湯姆大叔的博客中

var liz={age:18}function fun(liz){liz={age:19} }復(fù)制代碼(function (exports, require, module, __filename, __dirname) {// exports = module.exports }); 復(fù)制代碼

ES6

在 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ù)器通用的模塊解決方案。

ES6 模塊的設(shè)計(jì)思想是盡量的靜態(tài)化,使得編譯時(shí)就能確定模塊的依賴關(guān)系,以及輸入和輸出的變量。CommonJS 和 AMD 模塊,都只能在運(yùn)行時(shí)確定這些東西。比如,CommonJS 模塊就是對(duì)象,輸入時(shí)必須查找對(duì)象屬性。

// CommonJS模塊 let { stat, exists, readFile } = require('fs');// 等同于 let _fs = require('fs'); let stat = _fs.stat; let exists = _fs.exists; let readfile = _fs.readfile; 復(fù)制代碼

上面代碼的實(shí)質(zhì)是整體加載fs模塊(即加載fs的所有方法),生成一個(gè)對(duì)象(_fs),然后再?gòu)倪@個(gè)對(duì)象上面讀取 3 個(gè)方法。這種加載稱為“運(yùn)行時(shí)加載”,因?yàn)橹挥羞\(yùn)行時(shí)才能得到這個(gè)對(duì)象,導(dǎo)致完全沒(méi)辦法在編譯時(shí)做“靜態(tài)優(yōu)化”。

ES6 模塊不是對(duì)象,而是通過(guò)export命令顯式指定輸出的代碼,再通過(guò)import命令輸入。

// ES6模塊 import { stat, exists, readFile } from 'fs'; 復(fù)制代碼

上面代碼的實(shí)質(zhì)是從fs模塊加載 3 個(gè)方法,其他方法不加載。這種加載稱為“編譯時(shí)加載”或者靜態(tài)加載,即 ES6 可以在編譯時(shí)就完成模塊加載,效率要比 CommonJS 模塊的加載方式高。當(dāng)然,這也導(dǎo)致了沒(méi)法引用 ES6 模塊本身,因?yàn)樗皇菍?duì)象。

由于 ES6 模塊是編譯時(shí)加載,使得靜態(tài)分析成為可能。有了它,就能進(jìn)一步拓寬 JavaScript 的語(yǔ)法,比如引入宏(macro)和類型檢驗(yàn)(type system)這些只能靠靜態(tài)分析實(shí)現(xiàn)的功能。

除了靜態(tài)加載帶來(lái)的各種好處,ES6 模塊還有以下好處。

  • 不再需要UMD模塊格式了,將來(lái)服務(wù)器和瀏覽器都會(huì)支持 ES6 模塊格式。目前,通過(guò)各種工具庫(kù),其實(shí)已經(jīng)做到了這一點(diǎn)。
  • 將來(lái)瀏覽器的新 API 就能用模塊格式提供,不再必須做成全局變量或者navigator對(duì)象的屬性。
  • 不再需要對(duì)象作為命名空間(比如Math對(duì)象),未來(lái)這些功能可以通過(guò)模塊提供。

module 語(yǔ)法

推薦

工作上的體會(huì)這種模塊加載的語(yǔ)法,就用最簡(jiǎn)單常見(jiàn)的方式就好,千萬(wàn)不要過(guò)多操作

import _default from "xxx" import _default,{a,b,c} from "xxx"export default class xxx{} export class xxx{} export {xx,xxx,xxxx} 復(fù)制代碼

export 與 import 的復(fù)合寫(xiě)法

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

export { foo, bar } from 'my_module';// 可以簡(jiǎn)單理解為 import { foo, bar } from 'my_module'; export { foo, bar }; 上面代碼中,exportimport語(yǔ)句可以結(jié)合在一起,寫(xiě)成一行。但需要注意的是,寫(xiě)成一行以后,foo和bar實(shí)際上并沒(méi)有被導(dǎo)入當(dāng)前模塊,只是相當(dāng)于對(duì)外轉(zhuǎn)發(fā)了這兩個(gè)接口,導(dǎo)致當(dāng)前模塊不能直接使用foo和bar。模塊的接口改名和整體輸出,也可以采用這種寫(xiě)法。// 接口改名 export { foo as myFoo } from 'my_module';// 整體輸出 export * from 'my_module'; 默認(rèn)接口的寫(xiě)法如下。export { default } from 'foo'; 具名接口改為默認(rèn)接口的寫(xiě)法如下。export { es6 as default } from './someModule';// 等同于 import { es6 } from './someModule'; export default es6; 同樣地,默認(rèn)接口也可以改名為具名接口。export { default as es6 } from './someModule'; 下面三種import語(yǔ)句,沒(méi)有對(duì)應(yīng)的復(fù)合寫(xiě)法。import * as someIdentifier from "someModule"; import someIdentifier from "someModule"; import someIdentifier, { namedIdentifier } from "someModule"; 為了做到形式的對(duì)稱,現(xiàn)在有提案,提出補(bǔ)上這三種復(fù)合寫(xiě)法。export * as someIdentifier from "someModule"; export someIdentifier from "someModule"; export someIdentifier, { namedIdentifier } from "someModule"; 復(fù)制代碼

模塊的繼承

模塊之間也可以繼承。

假設(shè)有一個(gè)circleplus模塊,繼承了circle模塊。

// circleplus.jsexport * from 'circle'; export var e = 2.71828182846; export default function(x) {return Math.exp(x); } 上面代碼中的export *,表示再輸出circle模塊的所有屬性和方法。注意,export *命令會(huì)忽略circle模塊的default方法。然后,上面代碼又輸出了自定義的e變量和默認(rèn)方法。這時(shí),也可以將circle的屬性或方法,改名后再輸出。// circleplus.jsexport { area as circleArea } from 'circle'; 上面代碼表示,只輸出circle模塊的area方法,且將其改名為circleArea。加載上面模塊的寫(xiě)法如下。// main.jsimport * as math from 'circleplus'; import exp from 'circleplus'; console.log(exp(math.e)); 上面代碼中的import exp表示,將circleplus模塊的默認(rèn)方法加載為exp方法。 復(fù)制代碼

本文最后推一手我寫(xiě)的自動(dòng)生成模塊索引的工具index-creater

轉(zhuǎn)載于:https://juejin.im/post/5cb0a7e36fb9a0687015c610

總結(jié)

以上是生活随笔為你收集整理的javascript模块化简介的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。