摘要:使用既然初衷是為了方便管理,那么就做一個關于的。打開這個的情況下,還會獲得一些調試用的信息。如果需要,可以在中對實際入參進行特殊處理,比如轉換對象特定屬性檢查等等。
在 JavaScript 中使用接口
這篇是 js-interface 的 README,雖然并不是很復雜的一個東西,如果有人看的話我就寫寫源碼思路了 ORZ
介紹在做一個前后分離的項目時,有些頭疼 Api 之類的東西要怎么管理,在閱讀 《JavaScript 設計模式》 一書時,第二章提到了在 JavaScript 中模擬接口 (interface) 的概念,以方便使用眾多設計模式,因此嘗試著做一個接口的模擬。由于我本職是一名后端 Java 開發,因此希望在這個模擬層可以加入 接口默認實現、接口繼承、方法重載 等能力,雖然這些東西加上之后不可避免得會在性能上有所犧牲,但對我來說可以提升一些開發體驗(我知道 TypeScript,只是想搞個輪子試試 :P)。
使用既然初衷是為了方便管理 Api,那么就做一個關于 Api 的 demo。
創建一個接口const config = { // 接口的名字 name: "IApi", // 是否打開此接口的 debug 開關 // 開發時必須打開,否則不會啟動 (方法聲明、方法實現等)入參的類型檢查。 // 打開這個的情況下,還會獲得一些調試用的信息。 debug: true, } let IApi = new Interface(config)聲明方法
最簡單的聲明方式:
IApi.method({name: "getName"}) // 等價于 IApi.method({name: "getName", args: undefined})
這樣就聲明了 IApi 接口含有一個 getName 方法,它沒有任何參數,也沒有默認實現,這就要求在后面任何 IApi 的子接口或實現類必須實現該方法,否則會拋出一個異常。
如果想指定方法的參數列表:
IApi.method({ name: "getName", args: null })
注意!
args 為 null 時表示該方法可以接受任意數量的任意參數,如果重載了一個方法(詳細的請參閱后面關于重載的說明):
// 聲明一個空參方法 IApi.method({ id: 0, name: "getName", args: null }) // 重載上面的方法,使其有且只有一個 "string" 類型,名為 name 的參數 IApi.method({ id: 1, name: "getName", args: [ {name: "name", type: "string", support: val => typeof val === "string"} ] })
注意!
在參數描述中,type 屬性只是一個字符串值,它并不真的代表參數的實際類型。它跟 name 屬性一樣只是提供用于調試的信息,因此你可以填入任何你認為合適的、足以標記該參數一些信息的字符串值。
真正決定方法是否接受該參數的是 support 屬性,當它返回 true 時會檢查下一個參數直到所有參數檢查完畢或某個位置的參數不被接受。
如果需要,可以在 support 中對實際入參進行特殊處理,比如轉換對象、特定屬性檢查等等。
如果想為方法提供默認實現:
IApi.method({ name: "getName", // 默認實現,不能為箭頭函數! implement: function() { return "IApi" } })
回到我們的 demo,綜合運用一下:
// 聲明兩個方法,它們都沒有參數,也不需要重載因此這樣就可以了 IApi .method({ name: "getName" }) // 項目中使用 Axios,因此這里需要一個方法來獲取 axios 實例 .method({ name: "getAxios" }) // 聲明四個請求方式對應的方法 const methods = ["get", "post", "put", "delete"] methods.forEach(method => { IApi.method({ name: method, args: null, implement: function() { // 處理了 this 指向問題,放心用吧 return this.getAxios()[method].apply(this, arguments) .then(responseHandler) .catch(errorHandler) } }) })繼承接口
假定我們要創建接口 A,要繼承 B、C、D、E 等接口,使用如下語句:
const A = new Interface({ name: "A", debug: true }).extends([B, C, D, E])
extends 方法會將傳入的接口所持有的所有方法聲明(即通過 Interface.method(config) 所聲明的那些方法 )拷貝至接口 A,包括那些方法聲明的默認實現。
注意!
一般來說,不會在多個接口中重載同一個方法簽名,但如果真的有這樣的需求,可以自行設置 id 的規則,比如:
const B = new Interface(...) .method({ id: "B00", name: "getName", args = [...] }) .method({ id: "B01", name: "getName", args = [...] }) const C = new Interface(...) .method({ id: "C00", name: "getName", args = [...] })
然后實現該方法時指定要實現哪一個聲明:
// 注意!如果一個方法被重載,則不能在 class 中聲明該方法。 class AImpl { ... } const AInstance = new AImpl(...) B.implement({ object: AInstance, id: "B00", // 指定要實現的方法聲明 name: "getName" })
再次回到我們的 demo,綜合運用一下:
const IAuthenticationApi = new Interface({ name: "IAuthentication", debug: true }) // 指明 IAuthenticationApi 繼承自 IApi 接口 .extends(IApi) IAuthenticationApi // 重載方法 login // loin (username :string, password :string) .method({ id: 0, name: "login", args: [ {name: "username", type: "string", support: val => typeof val === "string"}, {name: "password", type: "string", support: val => typeof val === "string"} ] }) // login() .method({ id: 1, name: "login" })實現接口
// 編寫一個實現類 class AuthenticationApi { constructor(axios) { this.axios = axios } // 直接實現 getName 方法 getName() { return "AuthenticationApi" } // 直接實現 getAxios 方法 getAxios() { return this.axios } } // 實現重載方法 IAuthenticationApi .implement({ // 指定掛載實現到 AuthenticationApi 上 object: AuthenticationApi, // 指定此實現是對應 id 為 0 的方法聲明 id: 0, name: "login", implement: function(username, password) { console.log("帶參數的 login") // 還記得我們在 IApi 接口中定義了 get 方法(包括默認實現)嗎? this.get("https://www.baidu.com") return Promise.resolve("hello") } }) .implement({ object: AuthenticationApi, id: 1, name: "login", implement: function () { console.log("無參數的 login") }, }) IAuthenticationApi.ensureImplements(AuthenticationApi)使用接口實現類
let authenticationService = new AuthenticationApi(axios) // 掛載代理函數到實例上,否則會提示 // Uncaught TypeError: authenticationService.login is not a function IAuthenticationApi.ensureImplements(authenticationService) authenticationService .login("sitdownload", "1498696873") // login(string, string) 會返回一個 Promise 還記得嗎 :P .then(str => alert(`${str} world!`)) authenticationService.login()關于日志
首先確保在創建接口時打開了 debug 開關({ debug: true })。
上面的 demo 運行正常的話你將會得到下面的日志:
// 注冊方法 Interface 注冊方法: IApi.getName() Interface 注冊方法: IApi.getAxios() Interface 注冊方法: IApi.get(any) Interface 注冊方法: IApi.post(any) Interface 注冊方法: IApi.put(any) Interface 注冊方法: IApi.delete(any) Interface 注冊方法: IAuthentication extends IApi.getName() Interface 注冊方法: IAuthentication extends IApi.getAxios() Interface 注冊方法: IAuthentication extends IApi.get(any) Interface 注冊方法: IAuthentication extends IApi.post(any) Interface 注冊方法: IAuthentication extends IApi.put(any) Interface 注冊方法: IAuthentication extends IApi.delete(any) Interface 注冊方法: [0]IAuthentication.login(username :string, password :string) Interface 注冊方法: [1]IAuthentication.login() // 實現方法 Interface 實現方法: 保存 [0]IAuthentication.login(...) 實現: ? implement(username, password) Interface 實現方法: 保存 [1]IAuthentication.login(...) 實現: ? implement() // 匹配方法 Interface 方法匹配: 精準匹配 IAuthentication.login({ username: "sitdownload" } :string, { password: "1498696873" } :string). // 在控制臺這行是可以打開實現的具體位置的 ? implement(username, password) // 方法輸出 AuthenticationApi.js?7b55:25 帶參數的 login // 匹配方法 Interface 方法匹配: 無法精準匹配 IAuthentication.get("https://www.baidu.com"),使用 any 實現匹配: ? implement() Interface 方法匹配: 精準匹配 IAuthentication.login(). ? implement() // 方法輸出 AuthenticationApi.js?7b55:35 無參數的 login // AuthenticationApi.login(username, password) 中請求了 "https://www.baidu.com" Failed to load https://www.baidu.com/: No "Access-Control-Allow-Origin" header is present on the requested resource. Origin "http://127.0.0.1" is therefore not allowed access. // IApi.get(any) 中將異常直接向下拋了 Uncaught (in promise) {type: "network", payload: Error: Network Error at createError (webpack-internal:///./node_modules/_axios@0.18.0@axios/lib/…}后續
如果要發版了,確認所有的接口方法都正確實現后,就可以把 debug 關掉,這樣就不會有 Interface 內部的一些入參檢查和調試輸出。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/95204.html
摘要:它就是一套兼容方案,目前兼容的有以及原生支持。返回值問題在第一次使用時,。具體是什么意義呢的返回值,其實就是插件提供的對外接口,而實際上,就是一個對象。而在環境下,只需要將這個返回值賦予即可完成該模塊的接口。 有更新,請到github上看源碼 什么是OMD 在node.js流行起來之前,javascript的開發方式都是函數式的順序依賴關系,直到node火起來。CommonJS其實首先...
摘要:前面講泛型的時候,提到了接口。和泛型一樣,接口也是目前中并不存在的語法。不過可不吃這一套,所以這里通過注釋關閉了對該接口的命名檢查。這樣的接口不能由類實現。 前面講 泛型 的時候,提到了接口。和泛型一樣,接口也是目前 JavaScript 中并不存在的語法。 由于泛型語法總是附加在類或函數語法中,所以從 TypeScript 轉譯成 JavaScript 之后,至少還存在類和函數(只是...
摘要:以這個工具庫作為依賴,只需要編寫實際通訊接口目前混合開發的方案包括就是一種簡單的解決方案。基于接口粒度的安全控制策略每一個實例也都會持有一個的實例,用于針對具體的開發接口設置安全檢查規則。 EasyBridge是一個簡單易用的js-bridge的工具庫,提供了日常開發中,JavaScript與Java之間通訊的能力,與其他常見的js-bridge工具庫實現方案不同,EasyBridge...
摘要:前言本章我們要講解的是五大原則語言實現的第篇,接口隔離原則。接口隔離原則和單一職責有點類似,都是用于聚集功能職責的,實際上可以被理解才具有單一職責的程序轉化到一個具有公共接口的對象。與我們下面討論的一些小節是里關于違反接口隔離原則的影響。 前言 本章我們要講解的是S.O.L.I.D五大原則JavaScript語言實現的第4篇,接口隔離原則ISP(The Interface Segreg...
摘要:例如允許的對象默認情況下,通過使用內置宏將核心對象和方法映射到。例如這被轉換為以下代碼類可以定義構造函數,具有超類,并且可以像在中一樣實例化。因此,它不違反原則。用于聲明該對象可以用作構造函數。 這個工具可以將java代碼轉為js代碼,從而可以使用java編寫前端代碼 如果排版看著費勁可以下載下方html,打開html后使用google翻譯 JSweet語言規范版本:2.x(快照) 作...
摘要:例如允許的對象默認情況下,通過使用內置宏將核心對象和方法映射到。例如這被轉換為以下代碼類可以定義構造函數,具有超類,并且可以像在中一樣實例化。因此,它不違反原則。用于聲明該對象可以用作構造函數。 這個工具可以將java代碼轉為js代碼,從而可以使用java編寫前端代碼 如果排版看著費勁可以下載下方html,打開html后使用google翻譯 JSweet語言規范版本:2.x(快照) 作...
閱讀 2953·2021-11-23 09:51
閱讀 1006·2021-09-26 09:55
閱讀 3935·2021-09-22 14:58
閱讀 1468·2021-09-08 09:35
閱讀 1078·2021-08-26 14:16
閱讀 882·2019-08-23 18:17
閱讀 2054·2019-08-23 16:45
閱讀 700·2019-08-23 15:55