在javascript中,接口是指對(duì)協(xié)定進(jìn)行定義的引用類型,接口其實(shí)就是告訴我們一個(gè)類實(shí)現(xiàn)了哪些方法,從而幫助其使用這個(gè)類;接口可以讓代碼變得更穩(wěn)定。
本教程操作環(huán)境:windows7系統(tǒng)、javascript1.8.5版、Dell G3電腦。
JavaScript中沒(méi)有內(nèi)置的創(chuàng)建或?qū)崿F(xiàn)接口的方法。它也沒(méi)有內(nèi)置的方法用于判斷該一個(gè)對(duì)象是否實(shí)現(xiàn)了與另一個(gè)對(duì)象相同的一套方法。這使對(duì)象很難互換使用。但是JavaScript很靈活,我們可以通過(guò)別的方式去實(shí)現(xiàn)。
什么是接口
接口其實(shí)就是定義了對(duì)象內(nèi)應(yīng)該有哪些方法。他不用去考慮這些方法是怎么去實(shí)現(xiàn)的,而是定義該對(duì)象有這些方法。
接口是指對(duì)協(xié)定進(jìn)行定義的引用類型。其他類型實(shí)現(xiàn)接口,以保證它們支持某些操作。接口指定必須由類提供的成員或?qū)崿F(xiàn)它的其他接口。與類相似,接口可以包含方法、屬性、索引器和事件作為成員。
接口的好處
接口其實(shí)就是告訴我們一個(gè)類實(shí)現(xiàn)了哪些方法。從而幫助其使用這個(gè)類。接口可以讓我們的代碼變得更穩(wěn)定,如果我們給接口添加了一個(gè)方法。而某個(gè)實(shí)現(xiàn)它的類沒(méi)有相應(yīng)的添加這個(gè)方法,那肯定會(huì)拋出一個(gè)錯(cuò)誤。
javascript模仿接口
JavaScript模仿接口有三種方法:
-
注釋法
-
屬性檢查法
-
鴨式變型法
用注釋描述接口
用注釋描述接口是最簡(jiǎn)單的方法,但是效果是最差的。
/* interface Composite { function add(child); function remove(child); function getChild(index); } interface FormItem { function save(); } */ class CompositeForm { add(child) { //... } remove(child) { } getChild(index) { //... } save() { //... } }
這種模仿方法不是很好,它沒(méi)有檢查CompositeForm是否正確的實(shí)現(xiàn)了方法,完全是通過(guò)程序員們自覺(jué)去實(shí)現(xiàn)注釋中的接口。不過(guò)這種實(shí)現(xiàn)方式非常的簡(jiǎn)單,但是它對(duì)測(cè)試和調(diào)試沒(méi)有任何幫助。
屬性檢查法模仿接口
這個(gè)方法會(huì)更謹(jǐn)慎一點(diǎn),但是接口也是注釋的形式寫出來(lái),只是可以通過(guò)檢查一個(gè)屬性得知某個(gè)類自稱實(shí)現(xiàn)了什么接口。
class CompositeForm { constructor() { this.implementsInterface = ['Composite', 'FormItem']; } } function addForm(formInstance) { if (!implements(formInstance, 'Composite', 'FormItem')) { throw new Error('對(duì)象沒(méi)有實(shí)現(xiàn)接口方法'); } } function implements(obj) { // 這個(gè)方法查詢接口 for (let i = 1; i < arguments.length; i++) { let interfaceName = arguments[i]; let interfaceFound = false; for (let j = 1; j < obj.implementsInterface.length; j++) { if (obj.implementsInterface[j] == interfaceName) { interfaceFound = true; break; } } if (!interfaceFound) { return false; } return true; } } addForm(new CompositeForm());
這種方法的優(yōu)點(diǎn)是他對(duì)類所實(shí)現(xiàn)的接口提供了文檔說(shuō)明,如果需要的接口不在我這個(gè)類宣稱支持的接口之列(也就是說(shuō)不在我的this.implementsInterface里),你就會(huì)看到錯(cuò)誤信息。
缺點(diǎn)也顯而易見(jiàn),如果我的this.implementsInterface里宣稱的和我注釋里所定義的接口不一樣但檢查還是能通過(guò)的,就是調(diào)用addForm方法是不會(huì)爆破錯(cuò)的
用鴨式變型法模擬接口
其實(shí),類是否聲明自己支持哪些接口并不重要,只要具有這些接口中的方法就行。鴨式變型法把對(duì)象的方法集作為判斷它是不是某個(gè)實(shí)例的唯一標(biāo)準(zhǔn)。實(shí)現(xiàn)原理也非常的簡(jiǎn)單:如果對(duì)象具有與接口定義的方法同名的方法,那么就可以認(rèn)為他實(shí)現(xiàn)了這個(gè)接口。
// interface class Interface { constructor(name, method) { if (arguments.length != 2) { throw new Error('兩個(gè)參數(shù):name method'); } this.name = name; this.method = []; for (let i in method) { if (typeof method[i] != 'string') { throw new Error('method 必須是字符串'); } this.method.push(method[i]); } } //檢查接口方法 static ensureImplements(obj) { if (arguments.length < 2) { throw new Error('參數(shù)小于兩個(gè)'); } for (let i = 1; i < arguments.length; i++) { var instanceInterface = arguments[i]; if (instanceInterface.constructor !== Interface) { throw new Error('你要檢查的參數(shù)不屬于Interface接口') } for (let j in instanceInterface.method) { let methodName = instanceInterface.method[j]; if (!obj[methodName] || typeof obj[methodName] !== 'function') { throw new Error(`請(qǐng)實(shí)現(xiàn)接口的${methodName}方法`) } } } } } // 實(shí)例化接口對(duì)象 var Composite = new Interface('Composite', ['add', 'remove', 'getChild']); var FormItem = new Interface('FormItem', ['save']); // CompositeForm 類 class CompositeForm { //... add() {} remove() {} getChild() {} } let c1 = new CompositeForm(); Interface.ensureImplements(c1, Composite, FormItem); function addForm(formInterface) { ensureImplements(formInterface, Composite, FormItem); }
上面代碼中的CompositeForm類中我沒(méi)有實(shí)現(xiàn)save方法。運(yùn)行這段代碼就會(huì)報(bào)錯(cuò)。
但是鴨式變型法也是有缺點(diǎn)的,各個(gè)檢查方面都是強(qiáng)制實(shí)施的。
本菜鳥(niǎo)實(shí)現(xiàn)方法 > 我自稱繼承法
我用了類的繼承來(lái)模擬接口,具體實(shí)現(xiàn)請(qǐng)看代碼。
首先我們定義一個(gè)用作接口的類,屬性method代表接口的方法集
class Interface { constructor() { this.mehods = ['add', 'save', 'remove', 'save']; } static ensureImplements(obj) { //... } }
定義一個(gè)CompositeForm類繼承這個(gè)接口,并且在該類里面調(diào)用父類的ensureImplements方法檢測(cè)接口
class CompositeForm extends Interface{ constructor() { super().ensureImplements(this); } }
完善ensureImplements方法
class Interface { constructor() { this.mehods = ['add', 'save', 'remove', 'save']; } static ensureImplements(obj) { for (let i in this.mehods) { let methodName = this.mehods[i] if (!obj[methodName] || typeof obj[methodName] !== 'function') { let err = '請(qǐng)實(shí)現(xiàn)接口' + methodName + '的方法'; throw new Error(err); } } } }
【推薦學(xué)習(xí):javascript高級(jí)教程】