裝飾器主要有兩個用處:
裝飾類裝飾方法或屬性
廢話不多說,先上**感受一下
下面是裝飾類的:
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...