前言
在進(jìn)行ts項(xiàng)目的時(shí)候孽水,總是報(bào)錯(cuò)找不到模塊相艇,查了很多資料發(fā)現(xiàn)自己這塊的內(nèi)容還是不怎么熟悉唯笙,今天總結(jié)下方便今后查詢
規(guī)范
我的理解是amd,cmd,commonJS,umd,es6并不是什么新的語(yǔ)言肌访,他們就是寫(xiě)法上的不一樣找默,從而引出了不同的寫(xiě)法對(duì)應(yīng)這個(gè)不同的規(guī)范。我們用的最多的應(yīng)該是commonJS和es6一個(gè)用于服務(wù)器吼驶,一個(gè)用于瀏覽器惩激。下面我們來(lái)看看這些規(guī)范的寫(xiě)法和使用情況
amd
amd是最早的模塊規(guī)范,在amd之前我們引入的js文件都是通過(guò)script標(biāo)簽蟹演,但是這有一些問(wèn)題风钻,首先引入會(huì)導(dǎo)致全局變量沖突,污染酒请。然后就是需要確保順序骡技。由于這些原因開(kāi)發(fā)者一直在找一個(gè)合理的解決方法,此時(shí)amd規(guī)范應(yīng)運(yùn)而生蚌父。
amd用法
// 定義
define('demo', ['helper'] 哮兰,function(helper) {
function init() {
console.log('init')
}
return { init }
})
// 定義
define(function(require, exports, module) {
exports.init = function(){}
});
// 使用
require(['demo'], function(demo) {
demo.init();
})
- 每個(gè)js的變量都是定義在function里面不會(huì)造成全局的污染,
- amd是異步加載的苟弛,并且加載完之后立馬執(zhí)行
- 如何確保加載時(shí)候的依賴了喝滞,模塊定義的時(shí)候會(huì)傳入一個(gè)依賴數(shù)組,根據(jù)這個(gè)依賴數(shù)組去加載依賴
- amd推崇依賴前置膏秫,先把依賴寫(xiě)好
cmd
cmd的寫(xiě)法其實(shí)和amd很像的是推廣 seajs孕畜出的一種規(guī)范
define(function(require, exports, module) {
const test = require('./test.js');
// exports.test = test;
module.exports.test = test;
})
// cmd也可以寫(xiě)成amd的依賴形式
define('demo', ['helper'] 右遭,function(helper) {
function init() {
console.log('init')
}
return { init }
})
// 使用
require(['demo'], function(demo) {
demo.test();
})
- cmd只能寫(xiě)成局部的reqiure,不能像amd那樣可以引入require,生成全局的require
- cmd默認(rèn)是同步加載的缤削,當(dāng)然讓我們也可以設(shè)置異步加載 require.async
- 其實(shí)amd,cmd都需要和require打交道窘哈,我們的例子是最簡(jiǎn)單的用法,require中有許多比較重要的配置比如paths, shim, map等亭敢,因?yàn)楝F(xiàn)在的amd,cmd用的比較少滚婉,今后遇到實(shí)際項(xiàng)目再去講require相關(guān)的配置
- cmd推薦就近依賴,依賴下載完之后遇到require才去執(zhí)行
- cmd規(guī)范推崇一個(gè)文件就是一個(gè)模塊帅刀,所以模塊名一般定義為文件名
commonJs
commonJs規(guī)范是定義在node里面的让腹,node環(huán)境提供了一個(gè)全局變量exports,后來(lái)又允許了module.exports的寫(xiě)法,以下是commonJS規(guī)范的寫(xiě)法
// test.js
function test() {
console.log('test');
}
exports.test = test;
// 使用
const test = require('./test');
- 這樣的寫(xiě)法就更加的簡(jiǎn)潔了,但是記住在瀏覽器不借助其他工具扣溺,直接運(yùn)行時(shí)會(huì)報(bào)錯(cuò)的骇窍,因?yàn)闆](méi)有exports
- commonJs雖然是同步加載,但是運(yùn)行在服務(wù)器端锥余,讀取文件更快
- 我們經(jīng)常在react項(xiàng)目里面寫(xiě)的const style = require('./index.less');能這么寫(xiě)是因?yàn)槟阌衱ebpack工具幫你轉(zhuǎn)換了腹纳,查看打包之后的結(jié)果你會(huì)發(fā)現(xiàn),他其實(shí)把commonJS語(yǔ)法打包成了瀏覽器可識(shí)別的amd語(yǔ)法
exports 和module.exports的區(qū)別
說(shuō)到他們的區(qū)別你只需要記住以下三點(diǎn)就行
- module.exports默認(rèn)是空對(duì)象{}
- exports 是module.exports的引用
- 模塊導(dǎo)出的是module.exports的內(nèi)容
所以以下代碼就是這樣
exports.init 等價(jià)于 module.exports.init
exports.init = function() {};
module.exports = { name: 2}; // 由于module.exports地址更新,默認(rèn)又是導(dǎo)出module.exports嘲恍,所以exports.init 無(wú)效足画,最終結(jié)果是{ name: 2}
umd
umd就比較簡(jiǎn)單一點(diǎn),就是amd規(guī)范和commonJS規(guī)范的合并蛔钙,判斷支不支持define,支持的話就用amd,不支持的話在看看支持module.exports么,支持的話就用coomonJS,以下是他的代碼
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define(['b'], factory);
} else if (typeof module === 'object' && module.exports) {
// Node. Does not work with strict CommonJS, but
// only CommonJS-like environments that support module.exports,
// like Node.
module.exports = factory(require('b'));
} else {
// Browser globals (root is window)
root.returnExports = factory(root.b);
}
}(this, function (b) {
//use b in some fashion.
// Just return a value to define the module export.
// This example returns an object, but the module
// can return a function as the exported value.
return {};
}));
es6模塊
es6的語(yǔ)法應(yīng)該是我們最熟悉的了锌云,不過(guò)低版本的瀏覽器不會(huì)識(shí)別,所以需要借助打包工具去解析吁脱。以下是es6模塊的代碼
// 定義test.js
export var a = 3;
// 引入
import { a } from './test'
es6 export的講解
之前對(duì)export比較了解桑涎,但是看了阮一峰老師的es6模塊講解,覺(jué)得還是有必要在總結(jié)下兼贡。
export必須要一個(gè)接口
這個(gè)是什么意思攻冷,就是說(shuō)export出去的東西,是要具有名字的遍希,一個(gè)特定的值等曼。你需要給名字,import才能接收凿蒜,看以下代碼
var a = 2;
export a; // error 錯(cuò)誤a還是一個(gè)值
var a = function() {}
export a; // erro 錯(cuò)誤a是一個(gè)匿名函數(shù)禁谦,但是如果是一個(gè)具名函數(shù)就行
export function a () {};; // right 這樣就是可以的
export const a = function() {} // right 或者這樣也是可以的
// 如果要寫(xiě)成匿名函數(shù)拋出的話可以放在{}里面
var a = function() {}
var b = 4;
export { a, b } // 此時(shí)接口就是a, b了;
// export可以拋出多個(gè)
export var a = 1;
export var b = 2;
// 對(duì)應(yīng)的接收就是
import * as demo from './test';
// 接收一個(gè)就是
import { a } from './test';
export default
上面說(shuō)了export的幾種情況,在來(lái)看看export default,他和export正好相反不需要接口因?yàn)閐efault就是接口废封。并且只能有一個(gè)export default,看以下代碼的講解
var a = 1;
export default a; // right
export default var a = 1; // error 錯(cuò)誤default已經(jīng)是接口了州泊,不需要再定義接口
// 只能有一個(gè)export default
export default 1;
export default 2; // 錯(cuò)誤只能有一個(gè)export default
// import的接收
import test from './test'; test可以是任意的
疑問(wèn)
注意:測(cè)試都是在webpack打包環(huán)境下測(cè)試的
- demo文件里面既有export var demo = 12還有export default 13那么import demo from返回的是什么
解釋import demo返回的是export default 的內(nèi)容,如果沒(méi)有export default了漂洋?沒(méi)有export default返回的是undefined遥皂,記住返回undefined是因?yàn)閐emo文件里面寫(xiě)了 export var demo = 12,如果都沒(méi)寫(xiě)的話返回{}
- 文件里面既有export還有export default那么import * 返回的是什么
import * 返回的是export和export default的合集刽漂,形式如這樣{a: 1, default: 2};演训,因?yàn)閐efault也是一個(gè)默認(rèn)接口
- 文件里面既沒(méi)有export也沒(méi)有export default。import * , import test from 和import { test } from 返回什么
都沒(méi)有的話import *會(huì)返回一個(gè)空對(duì)象贝咙, import test from也會(huì)返回一個(gè){},import {test} from 會(huì)返回undefined
- 文件里面是module.exports={test: 12},import *, impoert test from , import { test } from 返回什么
import * 返回{test: 12}, import test from返回{test: 12}样悟, import { test } from 返回12