2020-09-05

一牡直、前端模塊化

(1)什么是模塊化救恨?

從廣義的理解來說贸辈,模塊化是一個具有特定功能的對象。

模塊化就是有組織地把一個大文件拆成并互相依賴的小模塊肠槽,一個文件對應(yīng)一個模塊擎淤,模塊的作用域是私有化的,在其內(nèi)部定義的變量或者函數(shù)都是只能在當前的文件使用秸仙,只向外暴露一部分公開的接口嘴拢,如可以修改私有屬性的方法等。

//a.js文件中
var a = 10;
var add = function(val){
    return val + a;
};
//在此模塊中定義的變量和函數(shù)是私有的寂纪,在其他文件中不可見

//如果想在多個文件分享某個變量席吴,那么就要定義其為global對象的屬性
global.xx = true;
//此時赌结,xx變量可以被所有文件讀取,但一般不推薦這種寫法孝冒,一般遵循模塊化規(guī)范來寫
const {PI} = Math;
module.exports.getArea = (r)=> PI*r*r; //向外暴露的getArea方法

(2)為什么要模塊化柬姚?

? 隨著程序代碼越寫越多,體系越來越龐大庄涡,不管從開發(fā)角度來說量承,還是從維護的角度來說,都非常地不方便穴店,如果不進行模塊化撕捍,就可能引發(fā)命名沖突,造成不容易復(fù)用代碼泣洞,維護性高忧风。

在此簡單描述一下兩個東西,‘命名沖突’ 和 ‘文件依賴’:

命名沖突:

//a.js文件中
var a = 11;

//b.js文件中
var a = 22;

文件依賴:

//b.js文件依賴于a.js文件球凰,那么標簽的書寫順序必須是:
<script src='a.js' type='text/javascript'></script>
<script src='b.js' type='text/javascript'></script>

類似地狮腿,在開發(fā)中,有時候不可避免地會出現(xiàn) ‘命名沖突’ 或 ‘文件依賴’或其他的問題弟蚀,如果用了模塊化蚤霞,就能比較好地解決這些問題;

使用模塊化的好處:

最大的好處就是大大提高了代碼的可維護性义钉;

其次昧绣,增強了代碼的復(fù)用性;

使用模塊還可以避免函數(shù)名和變量名沖突捶闸;

通俗地來說夜畴,主要就是方便項目的開發(fā)和維護

(3)怎么樣模塊化删壮?(模塊化的使用)

模塊的定義流程: 1. 定義模塊

? 2.導(dǎo)出模塊

? 3.引用模塊

模塊化的定義規(guī)范有四種: AMD規(guī)范(require.js)贪绘、CMD規(guī)范(Sea.js)、CommonJs的Modules規(guī)范(NodeJs)央碟、ES6模塊化規(guī)范税灌,今天主要只是討論一下CommonJs和ES6兩種模塊化規(guī)范的具體用法,通過閱讀了別的很多資料亿虽,得到如下總結(jié)菱涤。

CommonJs(用于服務(wù)端環(huán)境)

? CommonJs運用于Node.js環(huán)境下(服務(wù)端),換句話說洛勉,Node.js使用了Common.js的規(guī)范粘秆,但是不能理解為common.js是屬于node的,node屬于common.js,這兩種理解都是錯誤的收毫。

? 根據(jù)CommonJs規(guī)范攻走,每個文件就是一個模塊殷勘,有自己的作用域,在一個文件里定義的變量昔搂、函數(shù)都是私有的玲销,對其他文件不可見,CommonJs規(guī)范加載模塊是同步的巩趁,也就是說痒玩,加載完成才可以執(zhí)行后面 的操作,Node.js主要用于服務(wù)器編程议慰,模塊一般都是存在本地硬盤中,加載比較快奴曙,所以Node.js采用CommonJs規(guī)范别凹。

? Common.js的核心思想是通過require方法來同步加載依賴的其他模塊,通過module.exports導(dǎo)出需要暴露的接口洽糟,CommonJS 還可以細分為 CommonJSl 和 CommonJS2炉菲,區(qū)別在于 CommonJSl 只能通過 exports . XX = XX 的方式導(dǎo)出,而 CommonJS2 在 CommonJSl 的基礎(chǔ)上加入了 module.exports = XX 的導(dǎo)出方式坤溃。 CommonJS 通常指 CommonJS2拍霜。

Node.js中Common.js規(guī)范的使用有三種類型:

第一種內(nèi)置模塊( 內(nèi)置模塊指的是掛載在Node.js全局對象身上的api )
內(nèi)置模塊可以直接使用 ( require中直接書寫模塊名稱 )
格式:const/let/var 變量名 = require( '模塊名稱' )

第二種自定義模塊,比如:

1)薪介、模塊的定義(創(chuàng)建模塊)

const person = {
    id : 1,
    name: '張三',
    age: 20
}
const fn = function(){}

2)祠饺、模塊的導(dǎo)出: (兩種方式)

//第一種
module.exports = person; //默認導(dǎo)出一個,這種安全性不高

//第二種 批量導(dǎo)出,按需引用
module.exports = {
    person,fn
}

3)汁政、模塊的引用

//第一種導(dǎo)出方式的引用
const person = require('./xxx.js')

//第二種導(dǎo)出方式的引用
const {person,fn} require('./xxx/js'); //在自定義模塊引用時道偷,路徑一定要寫對

第三種第三方模塊(別人封裝好的模塊) 格式:var/let/const 變量名 = require( ''模塊名稱'' )

使用npm/cnpm/yarn安裝所需用的模塊; 在文件中引入;一般在www.npmjs.com會有官方文檔记劈,照著文檔來使用即可勺鸦。

module.export跟exports的區(qū)別

  1. module.exports屬性表示當前模塊對外輸出的接口,其他文件加載該模塊目木,實際上就是讀取module.exports變量换途。module.exports 方法還可以單獨返回一個數(shù)據(jù)類型(String、Number刽射、Object...)军拟,而 exports 只能返回一個 Object 對象;

  2. node為每一個模塊提供了一個exports變量(可以說是一個對象)柄冲,指向 module.exports吻谋。這相當于每個模塊中都有一句這樣的命令 var exports = module.exports; 所有的 exports 對象最終都是通過 module.exports 傳遞執(zhí)行,可以更確切地說现横,exports 是給 module.exports 添加屬性和方法漓拾,一個模塊的對外接口阁最,就是一個單一的值,不能使用exports輸出骇两,必須使用 module.exports輸出速种。

exports.name = 'xiaoming';
exports.age = 20;
console.log(modules.exports); //結(jié)果: {name:'xioaming',age:20}

Commonjs的缺點是,無法直接運行于瀏覽器環(huán)境下低千,必須通過工具轉(zhuǎn)換成標準的ES5配阵。

ES6模塊化(用于瀏覽器環(huán)境)

模塊主要由兩個命令構(gòu)成: export 和 import ; export命令用于規(guī)定模塊的對外接口,import命令用于輸入其他模塊提供的功能示血。

一棋傍、默認導(dǎo)入導(dǎo)出;

1难审、默認導(dǎo)出語法 : export default = { };

//a.js
//定義私有成員
let a = 10;
let b = 20;
let c = 30;

//將私有成員暴露出去瘫拣,供其他模塊使用
export default = {
    a,b
}
//c沒有導(dǎo)出,外界就訪問不到

2告喊、使用模塊,導(dǎo)入語法: import 接收名稱 from '某個模塊'麸拄;

import AA from './a.js'

console.log(AA);//輸出結(jié)果: {a: 10, b:20}

注意:

  • 在每一個模塊中只允許使用唯一的一次 export default ,否則會報錯
  • 在一個模塊中如果沒有向外 export default黔姜,則導(dǎo)入該模塊時 默認輸出 { }

二拢切、按需導(dǎo)出導(dǎo)入

1、按需導(dǎo)出

//aa.js
//按需導(dǎo)出 ,一個模塊中 可以使用 n 多次按需導(dǎo)出
//可以在export的地方定義導(dǎo)出的變量或函數(shù)
export let a = 'AAA';
export let b = 'BBB';
export function say(){  
    console.log('hi');
}
1183045044-5cd8319008b05_articlex.jpg

2秆吵、按需導(dǎo)入: improt { } from '某個模塊'

import {a,b,say} from './aa.js';

console.log(a);   // 打印輸出 AAA
console.log(b);   // 打印輸出 BBB
console.log(say); // 打印輸出 [Function: say]

//默認導(dǎo)入和按需導(dǎo)入同時使用
import aa,{a,b,say} from 'aa.js';

三淮椰、直接導(dǎo)入并執(zhí)行

如果單純執(zhí)行某個模塊的代碼,并不需要得到模塊中向外暴露的成員時帮毁,可以直接導(dǎo)入并執(zhí)行实苞;

1、比如: 某個模塊中的一段代碼

//e1.js
for (let i = 0; i < 3; i++){
    console.log(i);
}

2烈疚、直接導(dǎo)出并執(zhí)行

import './e1.js'

兼容性問題:

node.js不支持ES6模塊化規(guī)范的解決方案

//a.js模塊中
export let name = 'nodeJs';
export let age = 10;
//app.js中導(dǎo)入模塊
import {name,age} from './a.js'

在node環(huán)境下運行app.js會報錯黔牵,SyntaxError: Unexpected token ;

此時爷肝,要么將代碼轉(zhuǎn)換一下猾浦,把ES6規(guī)范轉(zhuǎn)換為commojS規(guī)范,可以用第三方工具解決(推薦使用)

1灯抛、安裝第三方工具金赦,全局安裝babel-cli 和 browserify(已初始化的情況下)

yarn global add babel-cli browserify  或者  npm install babel-cli browserify -g 

2、在自己項目目錄下執(zhí)行

yarn add babel-preset-es2015   或者   npm install babel-preset-es2015 --save-dev 

3对嚼、在項目根目錄下新建.babelrc文件

{
  "presets": [
    "es2015"
  ]
}

4夹抗、寫完代碼后,執(zhí)行

babel src -d lib

5纵竖、運行l(wèi)ib下的app.js即可

node lib\app.js

總結(jié)

CommonJS

1.對于基本數(shù)據(jù)類型漠烧,屬于復(fù)制(淺拷貝)杏愤,會被模塊緩存。同時已脓,在另一個模塊可以對該模塊輸出的變量重新賦值珊楼。

2.對于復(fù)雜數(shù)據(jù)類型,屬于淺拷貝度液。由于兩個模塊引用的對象指向同一個內(nèi)存空間厕宗,因此對該模塊的值做修改時會影響另一個模塊。

3.使用require命令加載某個模塊時就會運行整個模塊的代碼堕担。

4.當加載同一個模塊時已慢,不會再執(zhí)行該模塊,而是得到之前緩存過的值霹购。CommonJS模塊無論加載多少次蛇受,都只會在第一次加載時運行一次,如果以后再加載厕鹃,返回的都是第一次運行的結(jié)果,除非我們自己手動清除系統(tǒng)緩存乍丈。

5.循環(huán)加載時剂碴,屬于加載時執(zhí)行。腳本代碼在require的時候轻专,就會全部執(zhí)行忆矛。某個模塊被"循環(huán)加載",就只輸出已經(jīng)執(zhí)行過的部分请垛,還沒有執(zhí)行的部分不會輸出催训。

ES6模塊

1.ES6 模塊的設(shè)計思想是盡量的靜態(tài)化,使得編譯時就能確定模塊的依賴關(guān)系宗收,es6模塊中的值屬于【動態(tài)只讀引用】漫拭。

2.對于只讀來說,即是不允許修改引入變量的值混稽,import的變量是只讀的采驻,不管是基本數(shù)據(jù)類型還是復(fù)雜數(shù)據(jù)類型。當模塊遇到import命令時匈勋,就會生成一個只讀引用礼旅。等到腳本真正執(zhí)行時,再根據(jù)這個只讀引用洽洁,到被加載的那個模塊里面去取值痘系。

3.對于動態(tài)來說,原始值發(fā)生變化饿自,import加載的值也會發(fā)生變化汰翠。不論是基本數(shù)據(jù)類型還是復(fù)雜數(shù)據(jù)類型龄坪。

4.循環(huán)加載時,ES6模塊是動態(tài)引用奴璃。只要兩個模塊之間存在某個引用悉默,代碼就能夠執(zhí)行。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末苟穆,一起剝皮案震驚了整個濱河市抄课,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌雳旅,老刑警劉巖跟磨,帶你破解...
    沈念sama閱讀 217,509評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異攒盈,居然都是意外死亡抵拘,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評論 3 394
  • 文/潘曉璐 我一進店門型豁,熙熙樓的掌柜王于貴愁眉苦臉地迎上來僵蛛,“玉大人,你說我怎么就攤上這事迎变〕湮荆” “怎么了?”我有些...
    開封第一講書人閱讀 163,875評論 0 354
  • 文/不壞的土叔 我叫張陵衣形,是天一觀的道長驼侠。 經(jīng)常有香客問我,道長谆吴,這世上最難降的妖魔是什么倒源? 我笑而不...
    開封第一講書人閱讀 58,441評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮句狼,結(jié)果婚禮上笋熬,老公的妹妹穿的比我還像新娘。我一直安慰自己鲜锚,他們只是感情好突诬,可當我...
    茶點故事閱讀 67,488評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著芜繁,像睡著了一般旺隙。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上骏令,一...
    開封第一講書人閱讀 51,365評論 1 302
  • 那天蔬捷,我揣著相機與錄音,去河邊找鬼。 笑死周拐,一個胖子當著我的面吹牛铡俐,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播妥粟,決...
    沈念sama閱讀 40,190評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼审丘,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了勾给?” 一聲冷哼從身側(cè)響起滩报,我...
    開封第一講書人閱讀 39,062評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎播急,沒想到半個月后脓钾,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,500評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡桩警,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,706評論 3 335
  • 正文 我和宋清朗相戀三年可训,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片捶枢。...
    茶點故事閱讀 39,834評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡握截,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出烂叔,到底是詐尸還是另有隱情川蒙,我是刑警寧澤,帶...
    沈念sama閱讀 35,559評論 5 345
  • 正文 年R本政府宣布长已,位于F島的核電站,受9級特大地震影響昼牛,放射性物質(zhì)發(fā)生泄漏术瓮。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,167評論 3 328
  • 文/蒙蒙 一贰健、第九天 我趴在偏房一處隱蔽的房頂上張望胞四。 院中可真熱鬧,春花似錦伶椿、人聲如沸辜伟。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽导狡。三九已至,卻和暖如春偎痛,著一層夾襖步出監(jiān)牢的瞬間旱捧,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留枚赡,地道東北人氓癌。 一個月前我還...
    沈念sama閱讀 47,958評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像贫橙,于是被迫代替她去往敵國和親贪婉。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,779評論 2 354