EMCAScript6(ES6)是最新的Javascript,它包含了一些很棒的新特性。這些特性擁有不同程度的復(fù)雜性,對于簡單的腳本和復(fù)雜的應(yīng)用程序都非常的有用。\x0d\x0a\x0d\x0a增加的新特性:\x0d\x0a\x0d\x0a1.箭頭操作符\x0d\x0a 如果你會C#或者Java,你肯定知道lambda表達(dá)式,ES6中新增的箭頭操作符=便有異曲同工之妙。它簡化了函數(shù)的書寫。操作符左邊為輸入的參數(shù),而右邊則是進(jìn)行的操作以及返回的值Inputs=outputs。\x0d\x0a 我們知道在JS中回調(diào)是經(jīng)常的事,而一般回調(diào)又以匿名函數(shù)的形式出現(xiàn),每次都需要寫一個function,甚是繁瑣。當(dāng)引入箭頭操作符后可以方便地寫回調(diào)了。\x0d\x0a\x0d\x0a2.類的支持\x0d\x0a ES6中添加了對類的支持,引入了class關(guān)鍵字(其實(shí)class在JavaScript中一直是保留字,目的就是考慮到可能在以后的新版本中會用到,現(xiàn)在終于派上用場了)。JS本身就是面向?qū)ο蟮模珽S6中提供的類實(shí)際上只是JS原型模式的包裝。現(xiàn)在提供原生的class支持后,對象的創(chuàng)建,繼承更加直觀了,并且父類方法的調(diào)用,實(shí)例化,靜態(tài)方法和構(gòu)造函數(shù)等概念都更加形象化。\x0d\x0a\x0d\x0a3.增強(qiáng)的對象字面量\x0d\x0a 對象字面量被增強(qiáng)了,寫法更加簡潔與靈活,同時在定義對象的時候能夠做的事情更多了。具體表現(xiàn)在:\x0d\x0a(1).可以在對象字面量里面定義原型\x0d\x0a(2).定義方法可以不用function關(guān)鍵字\x0d\x0a(3).直接調(diào)用父類方法\x0d\x0a\x0d\x0a4.字符串模板\x0d\x0a 字符串模板相對簡單易懂些。ES6中允許使用反引號 ` 來創(chuàng)建字符串,此種方法創(chuàng)建的字符串里面可以包含由美元符號加花括號包裹的變量${vraible}。如果你使用過像C#等后端強(qiáng)類型語言的話,對此功能應(yīng)該不會陌生。\x0d\x0a\x0d\x0a5.解構(gòu)\x0d\x0a 自動解析數(shù)組或?qū)ο笾械闹怠1热缛粢粋€函數(shù)要返回多個值,常規(guī)的做法是返回一個對象,將每個值做為這個對象的屬性返回。但在ES6中,利用解構(gòu)這一特性,可以直接返回一個數(shù)組,然后數(shù)組中的值會自動被解析到對應(yīng)接收該值的變量中。\x0d\x0a\x0d\x0a6.參數(shù)默認(rèn)值,不定參數(shù),拓展參數(shù)\x0d\x0a(1).默認(rèn)參數(shù)值\x0d\x0a 現(xiàn)在可以在定義函數(shù)的時候指定參數(shù)的默認(rèn)值了,而不用像以前那樣通過邏輯或操作符來達(dá)到目的了。\x0d\x0a(2).不定參數(shù)\x0d\x0a 不定參數(shù)是在函數(shù)中使用命名參數(shù)同時接收不定數(shù)量的未命名參數(shù)。這只是一種語法糖,在以前的JavaScript代碼中我們可以通過arguments變量來達(dá)到這一目的。不定參數(shù)的格式是三個句點(diǎn)后跟代表所有不定參數(shù)的變量名。比如下面這個例子中,?x代表了所有傳入add函數(shù)的參數(shù).\x0d\x0a(3).拓展參數(shù)\x0d\x0a 拓展參數(shù)則是另一種形式的語法糖,它允許傳遞數(shù)組或者類數(shù)組直接做為函數(shù)的參數(shù)而不用通過apply。\x0d\x0a\x0d\x0a6.let與const 關(guān)鍵字\x0d\x0a 可以把let看成var,只是它定義的變量被限定在了特定范圍內(nèi)才能使用,而離開這個范圍則無效。const則很直觀,用來定義常量,即無法被更改值的變量。\x0d\x0a\x0d\x0a7.for of 值遍歷\x0d\x0a 我們都知道for in 循環(huán)用于遍歷數(shù)組,類數(shù)組或?qū)ο螅珽S6中新引入的for of循環(huán)功能相似,不同的是每次循環(huán)它提供的不是序號而是值。\x0d\x0a8.模塊\x0d\x0a 在ES6標(biāo)準(zhǔn)中,JavaScript原生支持module了。這種將JS代碼分割成不同功能的小塊進(jìn)行模塊化的概念是在一些三方規(guī)范中流行起來的,比如CommonJS和AMD模式。\x0d\x0a\x0d\x0a9.Map,Set 和 WeakMap,WeakSet\x0d\x0a 這些是新加的集合類型,提供了更加方便的獲取屬性值的方法,不用像以前一樣用hasOwnProperty來檢查某個屬性是屬于原型鏈上的呢還是當(dāng)前對象的。同時,在進(jìn)行屬性值添加與獲取時有專門的get,set方法。\x0d\x0a\x0d\x0a10.Proxies\x0d\x0a Proxy可以監(jiān)聽對象身上發(fā)生了什么事情,并在這些事情發(fā)生后執(zhí)行一些相應(yīng)的操作。一下子讓我們對一個對象有了很強(qiáng)的追蹤能力,同時在數(shù)據(jù)綁定方面也很有用處。\x0d\x0a\x0d\x0a11.Symbols\x0d\x0a 我們知道對象其實(shí)是鍵值對的集合,而鍵通常來說是字符串。而現(xiàn)在除了字符串外,我們還可以用symbol這種值來做為對象的鍵。Symbol是一種基本類型,像數(shù)字,字符串還有布爾一樣,它不是一個對象。Symbol 通過調(diào)用symbol函數(shù)產(chǎn)生,它接收一個可選的名字參數(shù),該函數(shù)返回的symbol是唯一的。之后就可以用這個返回值做為對象的鍵了。Symbol還可以用來創(chuàng)建私有屬性,外部無法直接訪問由symbol做為鍵的屬性值。\x0d\x0a\x0d\x0a12.Math,Number,String,Object 的新API\x0d\x0a 對Math,Number,String還有Object等添加了許多新的API。下面代碼同樣來自es6features,對這些新API進(jìn)行了簡單展示。\x0d\x0a\x0d\x0a13.Promises\x0d\x0a Promises是處理異步操作的一種模式,之前在很多三方庫中有實(shí)現(xiàn),比如jQuery的deferred 對象。當(dāng)你發(fā)起一個異步請求,并綁定了.when(), .done()等事件處理程序時,其實(shí)就是在應(yīng)用promise模式。

為月湖等地區(qū)用戶提供了全套網(wǎng)頁設(shè)計(jì)制作服務(wù),及月湖網(wǎng)站建設(shè)行業(yè)解決方案。主營業(yè)務(wù)為成都網(wǎng)站制作、成都網(wǎng)站建設(shè)、月湖網(wǎng)站設(shè)計(jì),以傳統(tǒng)方式定制建設(shè)網(wǎng)站,并提供域名空間備案等一條龍服務(wù),秉承以專業(yè)、用心的態(tài)度為用戶提供真誠的服務(wù)。我們深信只要達(dá)到每一位用戶的要求,就會得到認(rèn)可,從而選擇與我們長期合作。這樣,我們也可以走得更遠(yuǎn)!
nodejs的幾種模塊加載方式
一.直接在exports對象中添加方法
1. 首先創(chuàng)建一個模塊(module.js)module.js
exports.One = function(){
console.log('first module');
};
2.load.jsvar module =require('./module');
module.One();
這樣我們就可以在引入了該模塊后,返回一個exports對象,這里是指module對象,其實(shí)都只是兩個引用或者句柄,只是都指向了同一個資源,在load.js里,module的名字可以是任意取的,因?yàn)樗鼉H僅是指向require('./module');返回后的一個實(shí)例對象的引用,在load.js文件里的module和在module.js里的exports對象是同一個東西.因此上述兩個文件可以用一個文件來表示:exports.One = function(){
console.log('first module');
};
exports.One();
其運(yùn)行結(jié)果是一致的,這里我們可以很清晰的看到,我們在使用require('./xxxx')后其實(shí)返回的總是在 xxxx.js文件中的exports對象的引用,這個引用的名字我們可以任意取,但是為了規(guī)范我們還是最好取符號某些非標(biāo)準(zhǔn)規(guī)定(后面說道),但是這樣會有不妥的地方,因?yàn)樗鞘冀K指向exports的實(shí)例對象,也就是說,我們雖然有了這個模塊,但是這個模塊我們只能使用一次,這取決于rquire('./module')只會加在一次該模塊.比如我們修改上述代碼,
module.js
var name ;
exports.setName = function(oName){
name = oName;
};
exports.getName = function(){
console.log(name);
};
load.jsvar module1 = require('./module');
module1.setName("felayman1");
module1.getName();
var module2 = require('./module');
module2.setName("felayman2");
module2.getName();
module1.getName();
我們可以看到,雖然我們使用了兩次require('./module');,但是當(dāng)我們修改module2后,module1的內(nèi)容也被修改,這恰恰說明了,module1和module2是指向的同一個對象.有時候這并不影響我們的程序,但是如果我們的module是Person呢?我們希望我們require('./person')后返回的是不同的對象.因此,這種方式是有缺陷的,盡管很方便,這種方式在大部分nodejs的模塊中都是很常見,比如fs模塊,http模塊等.
二.將模塊中的函數(shù)掛載到exports對象的屬性上
person.js
function Person{
var name;
this.setName = function(theName){
name = theName;
};
this.sayHello = function(){
console.log('Hello',name);
};
}
exports.Person = Person;
load.js
var Person = require('./person').Person;
var person1 = new Person();
person1.setName("felayman1");
person1.sayHello();
var person2 = new Person();
person2.setName("felayman2");
person2.sayHello();
person1.sayHello();
這樣我們可以看到,我們就可以引入一個函數(shù)了,我們把在person.js文件中的Person函數(shù)設(shè)置為eports對象的一個屬性,我們只需要在load.js文件中引入該屬性,就可以獲取到多個該函數(shù)的實(shí)例,在nodejs中的EventEmitter就是基于這種方式,但是這樣我們總是在使用 require('./person').Person;這樣的寫法有點(diǎn)太復(fù)雜,因此nodejs允許我們使用其他更簡潔的方式,利用全局變量--module,這樣我們在其他文件中引入其他模塊的時候,就更方便了.
三.利用全局變量module
person.js
function Person(){
var name;
this.setName = function(theName){
name = theName;
};
this.sayHello = function(){
console.log('Hello',name);
};
}
// exports.Person = Person;
module.exports = Person;
load.jsvar Person = require('./person');
var person1 = new Person();
person1.setName("felayman1");
person1.sayHello();
var person2 = new Person();
person2.setName("felayman2");
person2.sayHello();
person1.sayHello();
這樣一修改,我們就在使用require函數(shù)的時候就方便了,如果覺得這里難以理解,我們可以把兩個文件里語法放到一起:var Person = require('./person');
module.exports = Person;
這樣,我們就可以看出,其實(shí)就是這樣var Person = Person.
因?yàn)樯鲜鑫覀兌家呀?jīng)說過,require('./person')其實(shí)就是module.exports 對象的,這里的module我們不用太在意,就跟javascript中的window一樣,是一個全局變量,即 module.exports =exports就類似于window.alert() =alert()差不多的效果,這樣我們就能看出,我們再次使用require('./person')的時候其實(shí)就是導(dǎo)入了我們所需要的exports對象的屬性函數(shù)模板了,這樣我們也可以多次實(shí)例化我們所需要的對象了.這種方式是綜合了前兩種的方法,因此也是官方推薦的使用方法.
模塊化在項(xiàng)目中十分的重要,一個復(fù)雜的項(xiàng)目肯定有很多相似的功能模塊,如果每次都需要重新編寫模塊肯定既費(fèi)時又耗力。但是引用別人編寫模塊的前提是要有統(tǒng)一的“打開姿勢”,如果每個人有各自的寫法,那么肯定會亂套,下面介紹幾種JS的模塊化的規(guī)范。
一:模塊化進(jìn)程一:script標(biāo)簽
這是最原始的 JavaScript 文件加載方式,如果把每一個文件看做是一個模塊,那么他們的接口通常是暴露在全局作用域下,也就是定義在 window 對象中,不同模塊的接口調(diào)用都是一個作用域中,一些復(fù)雜的框架,會使用命名空間的概念來組織這些模塊的接口。
缺點(diǎn):
1、污染全局作用域
2、開發(fā)人員必須主觀解決模塊和代碼庫的依賴關(guān)系
3、文件只能按照script標(biāo)簽的書寫順序進(jìn)行加載
4、在大型項(xiàng)目中各種資源難以管理,長期積累的問題導(dǎo)致代碼庫混亂不堪
二:模塊化進(jìn)程二:CommonJS規(guī)范
該規(guī)范的核心思想是允許模塊通過require方法來同步加載所要依賴的其他模塊,然后通過 exports 或 module.exports 來導(dǎo)出需要暴露的接口。
require("module");
require("../file.js");
exports.doStuff = function(){};
module.exports = someValue;
優(yōu)點(diǎn):
1、簡單并容易使用
2、服務(wù)器端模塊便于重用
缺點(diǎn):
1、同步的模塊加載方式不適合在瀏覽器環(huán)境中,同步意味著阻塞加載,瀏覽器資源是異步加載的
2、不能非阻塞的并行加載多個模塊
module.exports與exports的區(qū)別
1、exports 是指向的 module.exports 的引用
2、module.exports 初始值為一個空對象 {},所以 exports 初始值也是 {}
3、require() 返回的是 module.exports 而不是 exports
exports示例:
// app.js
var circle = require('./circle');
console.log(circle.area(4));
// circle.js
exports.area = function(r){
return r * r * Math.PI;
}
module.exports示例:
// app.js
var area = require('./area');
console.log(area(4));
// area.js
module.exports = function(r){
return r * r * Math.PI;
}
錯誤的情況:
// app.js
var area = require('./area');
console.log(area(4));
// area.js
exports = function(r){
return r * r * Math.PI;
}
其實(shí)是對 exports 進(jìn)行了覆蓋,也就是說 exports 指向了一塊新的內(nèi)存(內(nèi)容為一個計(jì)算圓面積的函數(shù)),也就是說 exports 和 module.exports 不再指向同一塊內(nèi)存,也就是說此時 exports 和 module.exports 毫無聯(lián)系,也就是說 module.exports 指向的那塊內(nèi)存并沒有做任何改變,仍然為一個空對象{},也就是說area.js導(dǎo)出了一個空對象,所以我們在 app.js 中調(diào)用 area(4) 會報(bào) TypeError: object is not a function 的錯誤。
總結(jié):當(dāng)我們想讓模塊導(dǎo)出的是一個對象時, exports 和 module.exports 均可使用(但 exports 也不能重新覆蓋為一個新的對象),而當(dāng)我們想導(dǎo)出非對象接口時,就必須也只能覆蓋 module.exports 。
三:模塊化進(jìn)程三:AMD規(guī)范
由于瀏覽器端的模塊不能采用同步的方式加載,會影響后續(xù)模塊的加載執(zhí)行,因此AMD(Asynchronous Module Definition異步模塊定義)規(guī)范誕生了。
AMD標(biāo)準(zhǔn)中定義了以下兩個API
1、require([module], callback);
2、define(id, [depends], callback);
require接口用來加載一系列模塊,define接口用來定義并暴露一個模塊。
示例:
define("module", ["dep1", "dep2"], function(d1, d2){
return someExportedValue;
});
require(["module", "../file"], function(module, file){ /* ... */ });
優(yōu)點(diǎn):
1、適合在瀏覽器環(huán)境中異步加載模塊
2、可以并行加載多個模塊
缺點(diǎn):
1、提高了開發(fā)成本,代碼的閱讀和書寫比較困難,模塊定義方式的語義不順暢
2、不符合通用的模塊化思維方式,是一種妥協(xié)的實(shí)現(xiàn)
四:模塊化進(jìn)程四:CMD規(guī)范
CMD(Common Module Definition)規(guī)范和AMD很相似,盡量保持簡單,并與CommonJS和Node.js的 Modules 規(guī)范保持了很大的兼容性。在CMD規(guī)范中,一個模塊就是一個文件。
示例:
define(function(require, exports, module){
var $ = require('jquery');
var Spinning = require('./spinning');
exports.doSomething = ...
module.exports = ...
})
優(yōu)點(diǎn):
1、依賴就近,延遲執(zhí)行
2、可以很容易在 Node.js 中運(yùn)行
缺點(diǎn):
1、依賴 SPM 打包,模塊的加載邏輯偏重
AMD和CMD的區(qū)別
AMD和CMD起來很相似,但是還是有一些細(xì)微的差別,讓我們來看一下他們的區(qū)別在哪里:
1、對于依賴的模塊,AMD是提前執(zhí)行,CMD是延遲執(zhí)行。
2、AMD推崇依賴前置;CMD推崇依賴就近,只有在用到某個模塊的時候再去require。看代碼:
// AMD
define(['./a', './b'], function(a, b){ // 依賴必須一開始就寫好
a.doSomething()
// 此處略去 100 行
b.doSomething()
...
});
// CMD
define(function(require, exports, module){
var a = require('./a')
a.doSomething()
// 此處略去 100 行
var b = require('./b')
// 依賴可以就近書寫
b.doSomething()
// ...
});
3、AMD 的 API 默認(rèn)是一個當(dāng)多個用,CMD 的 API 嚴(yán)格區(qū)分,推崇職責(zé)單一。
五:模塊化進(jìn)程五:ES6模塊化
EcmaScript6標(biāo)準(zhǔn)增加了JavaScript語言層面的模塊體系定義。ES6 模塊的設(shè)計(jì)思想,是盡量的靜態(tài)化,使得編譯時就能確定模塊的依賴關(guān)系,以及輸入和輸出的變量。CommonJS和AMD模塊,都只能在運(yùn)行時確定這些東西。
在 ES6 中,我們使用export關(guān)鍵字來導(dǎo)出模塊,使用import關(guān)鍵字引用模塊。需要說明的是,ES6的這套標(biāo)準(zhǔn)和目前的標(biāo)準(zhǔn)沒有直接關(guān)系,目前也很少有JS引擎能直接支持。因此Babel的做法實(shí)際上是將不被支持的import翻譯成目前已被支持的require。
盡管目前使用import和require的區(qū)別不大(本質(zhì)上是一回事),但依然強(qiáng)烈推薦使用import關(guān)鍵字,因?yàn)橐坏㎎S引擎能夠解析ES6的import關(guān)鍵字,整個實(shí)現(xiàn)方式就會和目前發(fā)生比較大的變化。如果目前就開始使用import關(guān)鍵字,將來代碼的改動會非常小。
示例:
import "jquery";
export functiondoStuff(){}
module "localModule" {}
優(yōu)點(diǎn):
1、容易進(jìn)行靜態(tài)分析
2、面向未來的 EcmaScript 標(biāo)準(zhǔn)
缺點(diǎn):
1、原生瀏覽器端還沒有實(shí)現(xiàn)該標(biāo)準(zhǔn)
2、全新的命令字,新版的 Node.js才支持
基礎(chǔ)
我們首先簡單地概述一下,自從三年前Eric Miraglia(YUI的開發(fā)者)第一次發(fā)表博客描述模塊化模式以來的一些模塊化模式。如果你已經(jīng)對于這些模塊化模式非常熟悉了,大可以直接跳過本節(jié),從“進(jìn)階模式”開始閱讀。
匿名閉包
這是一種讓一切變?yōu)榭赡艿幕窘Y(jié)構(gòu),同時它也是Javascript最棒的特性。我們將簡單地創(chuàng)建一個匿名函數(shù)并立即執(zhí)行它。所有的代碼將跑在這個函數(shù)內(nèi),生存在一個提供私有化的閉包中,它足以使得這些閉包中的變量能夠貫穿我們的應(yīng)用的整個生命周期。
復(fù)制代碼 代碼如下:
(function () {
// ... all vars and functions are in this scope only
// still maintains access to all globals
}());
注意這對包裹匿名函數(shù)的最外層括號。因?yàn)镴avascript的語言特性,這對括號是必須的。在js中由關(guān)鍵詞function開頭的語句總是會被認(rèn)為是函數(shù)聲明式。把這段代碼包裹在括號中就可以讓解釋器知道這是個函數(shù)表達(dá)式。
全局變量導(dǎo)入
Javascript有一個特性叫做隱式全局變量。無論一個變量名在哪兒被用到了,解釋器會根據(jù)作用域鏈來反向找到這個變量的var聲明語句。如果沒有找到var聲明語句,那么這個變量就會被視為全局變量。如果這個變量用在一句賦值語句中,同時這個變量又不存在時,就會創(chuàng)建出一個全局變量。這意味著在匿名閉包中使用或創(chuàng)建全局變量是很容易的。不幸的是,這會導(dǎo)致寫出的代碼極難維護(hù),因?yàn)閷τ谌说闹庇^感受來說,一眼根本分不清那些是全局的變量。
幸運(yùn)的是,我們的匿名函數(shù)提供了簡單的變通方法。只要將全局變量作為參數(shù)傳遞到我們的匿名函數(shù)中,就可以得到比隱式全局變量更清晰又快速的代碼了。下面是示例:
復(fù)制代碼 代碼如下:
(function ($, YAHOO) {
// now have access to globals jQuery (as $) and YAHOO in this code
}(jQuery, YAHOO));
模塊導(dǎo)出
有時你不僅想要使用全局變量,你還想要聲明它們,以供反復(fù)使用。我們可以很容易地通過導(dǎo)出它們來做到這一點(diǎn)——通過匿名函數(shù)的返回值。這樣做將會完成一個基本的模塊化模式雛形,接下來會是一個完整的例子:
復(fù)制代碼 代碼如下:
var MODULE = (function () {
var my = {},
privateVariable = 1;
function privateMethod() {
// ...
}
my.moduleProperty = 1;
my.moduleMethod = function () {
// ...
};
return my;
}());
注意我們已經(jīng)聲明了一個叫做MODULE的全局模塊,它擁有2個公有的屬性:一個叫做MODULE.moduleMethod的方法和一個叫做MODULE.moduleProperty的變量。另外,它還維護(hù)了一個利用匿名函數(shù)閉包的、私有的內(nèi)置狀態(tài)。同時,我們可以很容易地導(dǎo)入需要的全局變量,并像之前我們所學(xué)到的那樣來使用這個模塊化模式。
進(jìn)階模式
上面一節(jié)所描述的基礎(chǔ)已經(jīng)足以應(yīng)對許多情況,現(xiàn)在我們可以將這個模塊化模式進(jìn)一步的發(fā)展,創(chuàng)建更多強(qiáng)大的、可擴(kuò)展的結(jié)構(gòu)。讓我們從MODULE模塊開始,一一介紹這些進(jìn)階模式。
放大模式
整個模塊必須在一個文件中是模塊化模式的一個限制。任何一個參與大型項(xiàng)目的人都會明白將js拆分多個文件的價值。幸運(yùn)的是,我們擁有一個很棒的實(shí)現(xiàn)來放大模塊。首先,我們導(dǎo)入一個模塊,并為它添加屬性,最后再導(dǎo)出它。下面是一個例子——從原本的MODULE中放大它:
復(fù)制代碼 代碼如下:
var MODULE = (function (my) {
my.anotherMethod = function () {
// added method...
};
return my;
}(MODULE));
我們用var關(guān)鍵詞來保證一致性,雖然它在此處不是必須的。在這段代碼執(zhí)行完之后,我們的模塊就已經(jīng)擁有了一個新的、叫做MODULE.anotherMethod的公有方法。這個放大文件也會維護(hù)它自己的私有內(nèi)置狀態(tài)和導(dǎo)入的對象。
寬放大模式
我們的上面例子需要我們的初始化模塊最先被執(zhí)行,然后放大模塊才能執(zhí)行,當(dāng)然有時這可能也不一定是必需的。Javascript應(yīng)用可以做到的、用來提升性能的、最棒的事之一就是異步執(zhí)行腳本。我們可以創(chuàng)建靈活的多部分模塊并通過寬放大模式使它們可以以任意順序加載。每一個文件都需要按下面的結(jié)構(gòu)組織:
復(fù)制代碼 代碼如下:
var MODULE = (function (my) {
// add capabilities...
return my;
}(MODULE || {}));
在這個模式中,var表達(dá)式使必需的。注意如果MODULE還未初始化過,這句導(dǎo)入語句會創(chuàng)建MODULE。這意味著你可以用一個像LABjs的工具來并行加載你所有的模塊文件,而不會被阻塞。
緊放大模式
寬放大模式非常不錯,但它也會給你的模塊帶來一些限制。最重要的是,你不能安全地覆蓋模塊的屬性。你也無法在初始化的時候,使用其他文件中的屬性(但你可以在運(yùn)行的時候用)。緊放大模式包含了一個加載的順序序列,并且允許覆蓋屬性。這兒是一個簡單的例子(放大我們的原始MODULE):
復(fù)制代碼 代碼如下:
var MODULE = (function (my) {
var old_moduleMethod = my.moduleMethod;
my.moduleMethod = function () {
// method override, has access to old through old_moduleMethod...
};
return my;
}(MODULE));
我們在上面的例子中覆蓋了MODULE.moduleMethod的實(shí)現(xiàn),但在需要的時候,可以維護(hù)一個對原來方法的引用。
克隆與繼承
復(fù)制代碼 代碼如下:
var MODULE_TWO = (function (old) {
var my = {},
key;
for (key in old) {
if (old.hasOwnProperty(key)) {
my[key] = old[key];
}
}
var super_moduleMethod = old.moduleMethod;
my.moduleMethod = function () {
// override method on the clone, access to super through super_moduleMethod
};
return my;
}(MODULE));
這個模式可能是最缺乏靈活性的一種選擇了。它確實(shí)使得代碼顯得很整潔,但那是用靈活性的代價換來的。正如我上面寫的這段代碼,如果某個屬性是對象或者函數(shù),它將不會被復(fù)制,而是會成為這個對象或函數(shù)的第二個引用。修改了其中的某一個就會同時修改另一個(譯者注:因?yàn)樗鼈兏揪褪且粋€啊!)。這可以通過遞歸克隆過程來解決這個對象克隆問題,但函數(shù)克隆可能無法解決,也許用eval可以解決吧。因此,我在這篇文章中講述這個方法僅僅是考慮到文章的完整性。
跨文件私有變量
把一個模塊分到多個文件中有一個重大的限制:每一個文件都維護(hù)了各自的私有變量,并且無法訪問到其他文件的私有變量。但這個問題是可以解決的。這里有一個維護(hù)跨文件私有變量的、寬放大模塊的例子:
復(fù)制代碼 代碼如下:
var MODULE = (function (my) {
var _private = my._private = my._private || {},
_seal = my._seal = my._seal || function () {
delete my._private;
delete my._seal;
delete my._unseal;
},
_unseal = my._unseal = my._unseal || function () {
my._private = _private;
my._seal = _seal;
my._unseal = _unseal;
};
// permanent access to _private, _seal, and _unseal
return my;
}(MODULE || {}));
所有文件可以在它們各自的_private變量上設(shè)置屬性,并且它理解可以被其他文件訪問。一旦這個模塊加載完成,應(yīng)用程序可以調(diào)用MODULE._seal()來防止外部對內(nèi)部_private的調(diào)用。如果這個模塊需要被重新放大,在任何一個文件中的內(nèi)部方法可以在加載新的文件前調(diào)用_unseal(),并在新文件執(zhí)行好以后再次調(diào)用_seal()。我如今在工作中使用這種模式,而且我在其他地方還沒有見過這種方法。我覺得這是一種非常有用的模式,很值得就這個模式本身寫一篇文章。
子模塊
我們的最后一種進(jìn)階模式是顯而易見最簡單的。創(chuàng)建子模塊有許多優(yōu)秀的實(shí)例。這就像是創(chuàng)建一般的模塊一樣:
復(fù)制代碼 代碼如下:
MODULE.sub = (function () {
var my = {};
// ...
return my;
}());
雖然這看上去很簡單,但我覺得還是值得在這里提一提。子模塊擁有一切一般模塊的進(jìn)階優(yōu)勢,包括了放大模式和私有化狀態(tài)。
在auto就是中使用控件的時候是通過鏈?zhǔn)秸{(diào)用的,就像這樣
? id("recent_chat_list").className("AbsListView").findOne().scrollForward();
js的鏈?zhǔn)秸{(diào)用并不復(fù)雜,就是每次執(zhí)行完返回this對象,這樣后面的方法就可以繼續(xù)在this環(huán)境下執(zhí)行。
先創(chuàng)建一個簡單的模塊
var?P?=?function?()?{
function?Person()?{?};
return?Person;
}();
module.exports?=?P;
給它添加兩個get、set方法
Person.prototype?=?{
setName:?function?(name)?{
? ? ? ? ? ?this.name= name;
return?this;
},?setAge:?function?(age)?{
this.age?=?age
return?this;
},getName:function(){
? ? ? return?this.name;
?},getAge:function(){
? ? ? return?this.age;
}
}
再加init一個方法,返回一個Person對象,
Person.by?=?function?()?{
return?new?Person;
}
如果在模塊里,new一個對象就會在require模塊的時候初始化,導(dǎo)致混淆,所以寫個方法,手動new一個對象。
調(diào)用的方法是
var p = require("p.js");
p.init().setAge(10).setName("小明").getName()
p.init().setAge(20).setName("老王").getAge()
就是這么簡單。
新聞標(biāo)題:javascript創(chuàng)建模塊,js模塊開發(fā)教程
分享地址:http://chinadenli.net/article47/dsihsej.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供ChatGPT、網(wǎng)站導(dǎo)航、App設(shè)計(jì)、網(wǎng)站策劃、響應(yīng)式網(wǎng)站、小程序開發(fā)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)