摘要:額,經歷過上面的知識了解,應該能大概夠理解這段代碼了吧小結修飾器允許你在類和方法定義的時候去注釋或者修改它。
閑言
一切都要從公司里的一位老哥給我看的一段代碼說起。。。
@controller("/user") @auth @post("/login") async userLogin = (name, pass) => { @required // ... }
以下為對話:
我:這不是修飾器嗎(因為之前看到過@這個東西)老哥:還不錯嘛,知道是修飾器,那你知道這一段想表達什么意思嗎
我:這是路由?(一臉懵逼,但是看到了/user和post還有/login,心里想難道這是路由)
老哥:穩!
我:震驚了,還能夠這樣寫路由。不行,回去我要好好看看這個破@
由此開始了修飾器的學習~~~
嚶嚶嚶~~
首先說明,修飾器在JavaScript中還處于提議階段,目前還不能夠被大部分環境支持,并且之后還有可能會改變。如果想要使用該特性請用Babel進行轉碼或者使用JavaScript的超集TypeScript
在ES6中增加了類的相關定義和操作(比如class和extends),這樣方便了我們單個類的操作,但是當我們想要在多個不同類之間共享、復用一些方法的時候,會發現變得不那么優雅,所以decorator被提了出來。
小小的demo:以@作為標識符,既可以作用于類,也可以作用于類屬性
@decorator class Cat {} class Dog { @decorator run() {} }修飾器的使用
既然decorator與類相關,我們先了解一下類(這里只是簡單介紹,想要詳細了解的,請自行查閱相關資料,推薦阮一峰的ES6入門)
class Cat { constructor(name) { this.name = name } say () { console.log("miao ~") } }
這其實是一個語法糖,具體的實現是通過Object.defineProperty()方法來操作的,該方法語法如下:
Object.defineProperty(obj, prop, descriptor) -> obj: 要在其上定義屬性的對象 -> prop: 要定義或修改的屬性的名稱 -> descriptor:要被定義或修改的屬性描述符 返回:傳遞給該方法的對象(即obj)
所以上面那個Cat的代碼實際上在執行時是這樣的:
function Cat() {} Object.defineProperty(Cat.prototype, "say", { value: function() {console.log("miao ~")}, // 該屬性對應的值 enumerable: false, // 為true時,才能夠出現在對象的枚舉屬性中 configurable: true, // 為true時,該屬性描述符才能夠被改變 writable: true // 為true時,value才能被賦值運算符改變 }) // 返回Cat.prototype作用于類的修飾器
function isAnimal(target) { target.isAnimal = true return target // 返回的是傳遞給該函數的對象 } @isAnimal class Cat { // ... } console.log(Cat.isAnimal) // true
上面的代碼基本等同于:
Cat = isAnimal(function Cat() {})作用于類屬性的修飾器
function readonly(target, name, descriptor) { descriptor.writable = false return descriptor } class Cat { @readonly say () { console.log("miao ~") } } let kitty = new Cat() kitty.say = function () { console.log("wow ~") } kitty.say() // miao ~
通過將descriptor屬性描述符的writable設置為false,使得say方法只讀,后面對它進行的賦值操作不會生效,調用的依舊是之前的方法。
有木有覺得readonly()方法的參數似曾相識?它和上文介紹ES6中的類中提到的Object.defineProperty()是一樣的。
其實修飾器在作用于屬性的時候,實際上是通過Object.defineProperty進行擴展和封裝的。所以上面的代碼實際上是這樣的:
let descriptor = { value: function() { console.log("miao ~") }, enumerable: false, configurable: true, writable: true } descriptor = readonly(Cat.prototype, "say", descriptor) || descriptor Object.defineProperty(Cat.prototype, "say", descriptor)
當修飾器作用于類時,我們操作的對象是類本身,當修飾器作用于類屬性時,我們操作的對象既不是類本身也不是類屬性,而是它的描述符(descriptor)。
當然了,你也可以直接在target上進行擴展和封裝。
function fast(target, name, descriptor) { target.speed = 20 let run = descriptor.value() descriptor.value = function() { run() console.log(`speed ${this.speed}`) } return descriptor } class Rabbit { @fast run() { console.log("running~") } } let bunny = new Rabbit() bunny.run() // running ~ // speed 20 console.log(bunny.speed) // 20回到文章開始
讓我們回到文章開始講到的代碼,它怎么閱讀呢
@controller("/api/user") export class userController { @post("/add") @required({ body: ["telephone", "key1"] }) async addUser(ctx, next) {} @get("/userlist") async userList(ctx, next) {} }
讓我們先看@controller("/api/user")
const symbolPrefix = Symbol("prefix") export const controller = path => target => (target.prototype[symbolPrefix] = path)
作用是將/api/user作為prefixPath,此時target為userController {},在該target的原型上設置path
再接著看@post("/add")
// 以下代碼省略了部分細節 ... // export const post = path => (target, name, descriptor) => {} routerMap.set({ target: target, ...conf }, target[name]) // name為addUser for(let [conf, func] of routerMap) { // conf為{target, path} 該target為userController {},path為@post()傳遞進來的參數 let prefixPath = conf.target[symbolPrefix] // 為 /api/user let routePath = prefix + path // 為 /api/user/add } // 得到了api路徑(routePath),也得到了該api路徑所執行的方法(func) // get同理 ...
原理基本上都是類似的,處理修飾器傳遞的參數,得到自己想要的結果。
額,經歷過上面的知識了解,應該能大概夠理解這段代碼了吧~
小結修飾器允許你在類和方法定義的時候去注釋或者修改它。修飾器是一個作用于函數的表達式,它接收三個參數 target、 name 和 descriptor , 然后可選性的返回被裝飾之后的 descriptor 對象。
你也可以疊加使用,就像這樣
@post("/add") @required({ body: ["telephone", "key1"] }) async xxx {}參考:
https://aotu.io/notes/2016/10/24/decorator/index.html
http://taobaofed.org/blog/2015/11/16/es7-decorator/
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/94340.html
摘要:結合工作中使用情況,簡單對進行一些復習總結,包括常用的語法,等,以及短時間內要上手需要重點學習的知識點不同工作環境可能有一些差別,主要參考鏈接是阮一峰的博客以及外文博客阮老師大部分文章是直接翻譯的這個博客簡介先說一下,是一個標準化組織,他們 結合工作中使用情況,簡單對es6進行一些復習總結,包括常用的語法,api等,以及短時間內要上手需要重點學習的知識點(不同工作環境可能有一些差別),...
ES6 Decorators(修飾器) 修飾器(Decorator)是一個函數,用來修改類的行為。這是ES7的一個提案,目前Babel轉碼器已經支持 我們在游戲大型項目種經常會用到的方法,現在es6直接支持 想要使用Decorator的話需要我們配置一下文件夾,配置一下環境 npm install babel-plugin-transform-decorators-legacy --save-de...
摘要:前言本章介紹正則的擴展。屬性屬性表明正則表達式帶有標志。行終止符所謂行終止符,就是該字符表示一行的終結。比如,只匹配不在美元符號后面的數字,要寫成。前言本章介紹正則的擴展。有些不常用的知識了解即可。本章原文鏈接:正則的擴展RegExp 構造函數從 ES6 開始,如果RegExp構造函數第一個參數是一個正則對象,并且第二個標志存在且為標志參數,將不再拋出 TypeError ,將使用這些參數創...
摘要:方法返回一個布爾值,表示某個數組是否包含給定的值,與字符串的方法類似。不可以當作構造函數,也就是說,不可以使用命令,否則會拋出一個錯誤。本身是一個構造函數,用來生成數據結構。返回一個布爾值,表示該值是否為的成員。清除所有成員,沒有返回值。 在學習es6的過程中,為了方便自己復習,以及查看,對api做了一個極簡用例介紹。如有錯誤多多指正。 一 let和const 1.let (1)一個大...
摘要:攔截實例作為構造函數調用的操作,比如。方法等同于,這提供了一種不使用,來調用構造函數的方法。方法對應,返回一個布爾值,表示當前對象是否可擴展。這是的一個提案,目前轉碼器已經支持。別名或修飾器在控制臺顯示一條警告,表示該方法將廢除。 Proxy Proxy 這個詞的原意是代理,用在這里表示由它來代理某些操作,可以譯為代理器,即用自己的定義覆蓋了語言的原始定義。ES6 原生提供 Proxy...
閱讀 2617·2021-11-22 15:25
閱讀 1446·2021-11-15 17:59
閱讀 1148·2021-09-29 09:34
閱讀 1557·2021-09-26 09:46
閱讀 3041·2021-09-02 15:40
閱讀 1200·2019-08-30 15:56
閱讀 3294·2019-08-30 15:55
閱讀 702·2019-08-29 17:08