裝飾器的原始碼解讀

2021-10-12 20:24:40 字數 4398 閱讀 5698

裝飾器主要有兩個用處:

裝飾類裝飾方法或屬性

廢話不多說,先上**感受一下

下面是裝飾類的:

function

log(target, name, descriptor)

@log // 裝飾類的裝飾器

class

car}

const c1 =

newcar()

c1.run

()

下面是裝飾方法的:

function

log(target, name, descriptor)

console.

log(name)

//run

console.

log(descriptor)//}

class

car}

const c1 =

newcar()

c1.run

()

今天主要探索一下裝飾方法的原始碼~

首先看一段編譯前的**:

class

myclass

}function

readonly

(target, name, descriptor)

function

unenumerable

(target, name, descriptor)

對類裡面的方法使用不可列舉、唯讀的兩個裝飾器

使用babel編譯後如下,耐心看完後,你會發現很簡單:

var _class;

function

(target, property, decorators, descriptor, context )

; object[

"ke"

+"ys"

](descriptor)

.foreach

(function

(key));

desc.enumerable =

!!desc.enumerable;

desc.configurable =

!!desc.configurable;if(

"value"

in desc || desc.initializer)

/** * 第二部分

* 應用多個 decorators

*/desc = decorators

.slice()

.reverse()

.reduce

(function

(desc, decorator)

, desc)

;/**

* 第三部分

* 設定要 decorators 的屬性

*/if(context && desc.initializer !==

void0)

if(desc.initializer ===

void0)

return desc;

}let myclass =

((_class =

class

myclass})

,(_class.prototype,

"method"

,[readonly]

, object.

getownpropertydescriptor

(_class.prototype,

"method"),

_class.prototype),

_class)

;function

readonly

(target, name, descriptor)

const foo =

;const bar = object.

getownpropertydescriptor

(foo,

"value");

// bar

const foo =};

const bar = object.

getownpropertydescriptor

(foo,

"value");

// bar

就是簡單返回descriptor的方法

第一部分原始碼解析

// 拷貝乙份 descriptor

var desc =

;object[

"ke"

+"ys"

](descriptor)

.foreach

(function

(key));

desc.enumerable =

!!desc.enumerable;

desc.configurable =

!!desc.configurable;

// 如果沒有 value 屬性或者沒有 initializer 屬性,表明是 getter 和 setterif(

"value"

in desc || desc.initializer)

那麼 initializer 屬性是什麼呢?object.getownpropertydescriptor() 返回的物件並不具有這個屬性呀,確實,這是 babel 的 class 為了與 decorator 配合而產生的乙個屬性,比如說對於下面這種**:

class

myclass

function

readonly

(target, name, descriptor)

var foo =

newmyclass()

;console.

log(foo.born)

;

babel 就會編譯為:

// ...

(_descriptor =

(_class.prototype,

"born"

,[readonly],}

))// ...

第二部分原始碼解析

接下是應用多個 decorators:

/**

* 第二部分

* @type

*/desc = decorators

.slice()

.reverse()

.reduce

(function

(desc, decorator)

, desc)

;

對於乙個方法應用了多個 decorator,比如:

class

myclass

}

babel 會編譯為:

( _class.prototype,

"method"

,[unenumerable, readonly]

, object.

getownpropertydescriptor

(_class.prototype,

"method"),

_class.prototype

)在第二部分的原始碼中,執行了 reverse() 和 reduce() 操作,由此我們也可以發現,如果同乙個方法有多個裝飾器,會由內向外執行。

第三部分原始碼解析

/**

* 第三部分

* 設定要 decorators 的屬性

*/if

(context && desc.initializer !==

void0)

if(desc.initializer ===

void0)

return desc;

如果 desc 有 initializer 屬性,意味著當裝飾的是類的屬性時,會將 value 的值設定為:

desc.initializer.

call

(context)

而 context 的值為 _class.prototype,之所以要 call(context),這也很好理解,因為有可能

class

myclass

}

最後無論是裝飾方法還是屬性,都會執行:

object[

"define"

+"property"

](target, property, desc)

;

由此可見,裝飾方法本質上還是使用 object.defineproperty() 來實現的。

SDWebImage的原始碼解讀

sdwebimage共有17個oc檔案以及乙個多餘的標頭檔案,下面將會按照順序乙個乙個進行檔案的解讀 本人學藝不精,如果有不對的地方歡迎指出,有些細節的東西我也不算很理解,寫下這邊也算是方便以後用到的時候回顧 1.imagecontexttype 檔案 主要提供識別資料的格式,是nsdata的分類,...

OkHttp的原始碼解讀

最近這幾天在研究okhttp的原始碼,就順便整理了一些文件。retrofit okhttpcall原始碼解讀 okhttp之dispatcher okhttp之getresponsewithinterceptorchain 一 okhttp之getresponsewithinterceptorcha...

openTLD 原始碼解讀

首先是run tld 在其次就是tldexample 最後到了初始化函式tldinit 第乙個比較關鍵的函式 bb scan 將影象網格化,將首先 scale 1.2.10 10 21 個規格 在每個規格上打網格 這個函式有乙個比較重要的方法 ntuples 就是重複 因為網格上的點很多點有相同的x...