1.AMD 是RequireJS 在推廣過程中對模塊定義的規範化產出(AMD 是提前執行),不過在requireJS的2.0開始也改成了延遲執行(寫法不同,處理方式不同)
AMD 即Asynchronous Module Definition
,中文名是“異步模塊定義”的意思。它是一個在瀏覽器端模塊化開發的規範,服務器端的規範是CommonJS。
模塊將被異步加載,模塊加載不影響後面語句的運行。所有依賴某些模塊的語句均放置在回調函數中。
AMD規範只定義了一個函數 define
,它是全局變量。函數爲:define(id,dependencies,factory);
define函數裏面的:
id (模塊名)
是唯一確定的值,不可重複,可選。
模塊名是用正斜槓分割的有意義的字符串,單詞爲駝峯命名法(或者 " . " " , " " .. " ),不允許文件擴展名
模塊名可以是相對的或者頂級的, 如果首字符爲 " . " " .. " 則爲相對的模塊名
dependencies(依賴)
是一個當前模塊依賴,模塊定義的模板標識的數字字面量。
當然依賴參數也是可選的 它默認爲 [ 'require' , 'exports' , ' module ' ] , 如果factory的長度屬性小於3,加載器會選擇以函數的長度屬性指定的參數個數調用factory方法
factory(工廠方法)
模塊初始化要是行的函數或者對象。依賴模塊必須根據模塊的factor優先級執行,並且執行的結果應該按照依賴數組組的位置順序傳入(定義模塊中)的工廠方法。如果爲函數,它應該只被執行一次。如果是對象,此對象應該爲模塊的輸出值。
創建一個id(模板名)爲“alpha”的模塊,使用了名爲:require, exports, beta 的模塊。
define("alpha", ["require", "exports", "beta"], function (require, exports, beta) {
exports.verb=function() {
return beta.verb();
//Or:returnrequire("beta").verb();
}
});
一個返回對象的匿名模塊:
define(["alpha"], function (alpha) {
return {
verb:function(){
return alpha.verb() +2;
}
};
});
一個沒有依賴性的模塊可以直接定義對象:
define({
add:function(x, y){
return x + y;
}
});
一個使用了簡單CommonJS轉換的模塊定義:
define(function (require, exports, module) {
var a =require('a'),
b =require('b');
exports.action=function () {};
});
實現AMD的庫有RequireJS 、curl 、Dojo 、Nodules
等。
2.CMD 是 SeaJS 在推廣過程中對模塊定義的規範化產出。(CMD 是延遲執行)
CMD 推崇依賴就近,AMD 推崇依賴前置。
// CMD
define(function(require, exports, module) {
// 依賴可以就近書寫
var a = require('./a')
a.doSomething()
// 此處略去 1000 行
var b = require('./b')
b.doSomething()
})
// AMD 默認推薦的是:
define(['./a', './b'], function(a, b) {// 依賴必須一開始就寫好
a.doSomething()
// 此處略去 1000 行
b.doSomething()
...
})
AMD 的 API 默認是一個當多個用,CMD 的 API 嚴格區分,推崇職責單一。比如 AMD 裏,require 分全局 require 和局部 require,都叫 require。CMD 裏,沒有全局 require,而是根據模塊系統的完備性,提供 seajs.use 來實現模塊系統的加載啓動。CMD 裏,每個 API 都簡單純粹。
3.CommonJS模塊輸出的是一個值的拷貝,而且是在運行時加載
commonJS {
module.exports = ... : '只能輸出一個,且後面的會覆蓋上面的' ,
exports. ... : ' 可以輸出多個',
運行階段確定接口,運行時纔會加載模塊,
模塊是對象,加載的是該對象,
加載的是整個模塊,即將所有的接口全部加載進來,
輸出是值的拷貝,即原來模塊中的值改變不會影響已經加載的該值,
this 指向當前模塊
}
commonJS是使用require來引入其他模塊的代碼,使用module.exports來引出:
//exportsDemo.js
count = 1;
module.exports.count = count;
module.exports.Hello = function
() {
var
name;
this
.setName =
function
(newName) {
name = newName;
}
this
.sayHello =
function
() {
console.log(
"hello Mr."
+ name);
}
this
.getId =
function
() {
return
count++
}
}
用require引入上面的模塊
// requireDemo.js
var
{Hello} = require(
"./demo"
)
var
hello =
new
Hello();
hello.setName(
"Blank"
);
hello.sayHello();
4.ES6模塊是編譯時輸出接口,也是輸出的值的引用
ES6模塊不是對象,它的對外接口只是一種靜態定義,在代碼靜態解析階段就會生成。
ES6 模塊不會緩存運行結果,而是動態地去被加載的模塊取值,並且變量總是綁定其所在的模塊。
ES6的循環引用要特別注意變量是否已被聲明,若未被聲明的塊級作用域變量被其他模塊引用時,會報錯。
es6 {
export : '可以輸出多個,輸出方式爲 {}' ,
export default : ' 只能輸出一個 ,可以與export 同時輸出,但是不建議這麼做',
解析階段確定對外輸出的接口,解析階段生成接口,
模塊不是對象,加載的不是對象,
可以單獨加載其中的某個接口(方法),
靜態分析,動態引用,輸出的是值的引用,值改變,引用也改變,即原來模塊中的值改變則該加載的值也改變,
this 指向undefined
}
es6模塊中的值屬於【動態只讀引用】。只說明一下複雜數據類型。
對於只讀來說,即不允許修改引入變量的值,import的變量是隻讀的,不論是基本數據類型還是複雜數據類型。當模塊遇到import命令時,就會生成一個只讀引用。等到腳本真正執行時,再根據這個只讀引用,到被加載的那個模塊裏面去取值。
對於動態來說,原始值發生變化,import加載的值也會發生變化。不論是基本數據類型還是複雜數據類型。
// b.js
export let counter = {
count: 1
}
setTimeout(() => {
console.log('b.js-1', counter.count) }
, 1000
)
// a.js
import { counter } from './b.js'
counter = {}
console.log('a.js-1', counter)
雖然不能將counter重新賦值一個新的對象,但是可以給對象添加屬性和方法。此時不會報錯。這種行爲類型與關鍵字const的用法。
// a.js
import { counter } from './b.js'
counter.count++
console.log(counter)
循環加載時,ES6模塊是動態引用。只要兩個模塊之間存在某個引用,代碼就能夠執行。
// b.js
import {foo} from './a.js';
export function bar() {
console.log('bar');
if (Math.random() > 0.5) {
foo();
}
}
// a.js i
mport {bar} from './b.js';
export function foo() {
console.log('foo');
bar();
console.log('執行完畢');
}
foo();