響應(yīng)式原理一——Proxy-Reflect

監(jiān)聽對象

Object.defineProperty 的存儲屬性描述符來對
屬性的操作進(jìn)行監(jiān)聽凳干。

image.png

缺點:

  • Object.defineProperty在設(shè)計之初并沒有考慮監(jiān)聽對象的實現(xiàn)摄狱,只是為了定義對象的屬性
  • 對于一些對對象的操作,無法監(jiān)聽铝阐,如新增屬性椭符、刪除屬性跟伏,只能監(jiān)聽獲取和設(shè)置屬性

Proxy

在ES6中,新增了一個Proxy類秧了,這個類從名字就可以看出來跨扮,是用于幫助我們創(chuàng)建一個代理的:

  • 此時,如果我們希望監(jiān)聽一個對象的相關(guān)操作,那么我們可以先創(chuàng)建一個代理對象(Proxy對象)衡创;
  • 之后對該對象的所有操作帝嗡,都通過代理對象來完成,代理對象可以監(jiān)聽我們想要對原對象進(jìn)行哪些操作璃氢;
    將上面的案例用Proxy來實現(xiàn):
    new Proxy對象哟玷,并且傳入需要偵聽的對象以及一個處理對象,可以稱之為handler一也;
    const p = new Proxy(target, handler)
    之后的操作都是對Proxy的操作巢寡,而不是原有的對象,因為我們需要在handler里面進(jìn)行偵聽椰苟;
const obj = {
  name: "zs",
  age: 18,
};
const objProxy = new Proxy(obj, {});

有了代理對象讼渊,就可以監(jiān)聽到具體的操作,只需要在handler中添加對應(yīng)的捕捉器(trap)
set和get分別對應(yīng)的是函數(shù)類型尊剔;
pset函數(shù)有四個參數(shù):

  • target:目標(biāo)對象(偵聽的對象)爪幻;
  • property:將被設(shè)置的屬性key;
  • value:新屬性值须误;
  • receiver:調(diào)用的代理對象挨稿;
    get函數(shù)有三個參數(shù):
  • target:目標(biāo)對象(偵聽的對象);
  • property:被獲取的屬性key京痢;
  • receiver:調(diào)用的代理對象奶甘;

使用案列:

const obj = {
  name: "zs",
  age: 18,
};
const objProxy = new Proxy(obj, {
  set: function (target, propety, newValue, receiver) {
    target[propety] = newValue;
  },
  has: function (target, key) {
    console.log("has捕捉器", key);
    return key in target;
  },

  get: function (target, key) {
    console.log("get捕捉器", key);
    return target[key];
  },

  deleteProperty: function (target, key) {
    console.log("delete捕捉器");
    delete target[key];
  },
});

console.log(objProxy.name);  //get捕捉器 name
                                                //zs

所有捕捉器

Proxy共有13個捕捉器

  • handler.getPrototypeOf()
    Object.getPrototypeOf 方法的捕捉器。
  • handler.setPrototypeOf()
    Object.setPrototypeOf 方法的捕捉器祭椰。
  • handler.isExtensible()
    Object.isExtensible 方法的捕捉器臭家。
  • handler.preventExtensions()
    Object.preventExtensions 方法的捕捉器。
  • handler.getOwnPropertyDescriptor()
    Object.getOwnPropertyDescriptor 方法的捕捉器方淤。
  • handler.defineProperty()
    Object.defineProperty 方法的捕捉器钉赁。
  • handler.ownKeys()
    Object.getOwnPropertyNames 方法和
    Object.getOwnPropertySymbols 方法的捕捉器。
  • handler.has()
    in 操作符的捕捉器携茂。
  • handler.get()
    屬性讀取操作的捕捉器你踩。
  • handler.set()
    屬性設(shè)置操作的捕捉器。
  • handler.deleteProperty()
    delete 操作符的捕捉器讳苦。
  • handler.apply()
    函數(shù)調(diào)用操作的捕捉器带膜。
  • handler.construct()
    new 操作符的捕捉器

construct和apply

捕捉器中的construct和apply,是應(yīng)用于函數(shù)對象的:

onst obj = {
  name: "zs",
  age: 18,
};

function foo() {
  console.log("foo調(diào)用", this, arguments);
  return "foo";
}
const fooProxy = new Proxy(foo, {
  apply: function (target, thisArg, argArray) {
    console.log("函數(shù)的apply監(jiān)聽");
    return target.apply(thisArg, argArray);
  },
  construct(target, argArray, newTarget) {
    console.log(target, argArray, newTarget);
    return new target(...argArray);
  },
});

// 函數(shù)的apply監(jiān)聽
// foo調(diào)用 { name: 'zs', age: 18 } [Arguments] { '0': 1, '1': 2, '2': 3 }
fooProxy.apply(obj,[1,2,3])
//[Function: foo] [ 1, 2 ] [Function: foo]
//foo調(diào)用 foo {} [Arguments] { '0': 1, '1': 2 }
new fooProxy(1,2)

Reflect的使用

Reflect也是ES6新增的一個API鸳谜,它是一個對象膝藕,字面的意思是反射
Reflect作用:提供了很多操作JavaScript對象的方法,有點像Object中操作對象的方法咐扭;

  • Reflect.getPrototypeOf(target)類似于 Object.getPrototypeOf()
  • Reflect.defineProperty(target, propertyKey, attributes)類似于Object.defineProperty()芭挽;

我們有Object可以做這些操作滑废,那么為什么還需要有Reflect這樣的新增對象呢?

  • 在早期的ECMA規(guī)范中沒有考慮到這種對 對象本身 的操作如何設(shè)計會更加規(guī)范览绿,所以將這些API放到了Object上面策严;
  • Object作為一個構(gòu)造函數(shù),這些操作實際上放到它身上并不合適饿敲;
  • 另外還包含一些類似于 in妻导、delete操作符,讓JS看起來是會有一些奇怪的怀各;
  • 在ES6中新增了Reflect倔韭,讓我們這些操作都集中到了Reflect對象上;(專人專辦)

Reflect的常見方法

與Proxy是一一對應(yīng)的瓢对,也是13個:

  • Reflect.getPrototypeOf(target)
    類似于 Object.getPrototypeOf()寿酌。
  • Reflect.setPrototypeOf(target, prototype)
    設(shè)置對象原型的函數(shù). 返回一個 Boolean, 如果更新成功硕蛹,則返
    回true醇疼。
  • Reflect.isExtensible(target)
    類似于 Object.isExtensible()
  • Reflect.preventExtensions(target)
    類似于 Object.preventExtensions()。返回一個Boolean法焰。
  • Reflect.getOwnPropertyDescriptor(target, propertyKey)
    類似于 Object.getOwnPropertyDescriptor()秧荆。如果對象中存在
    該屬性,則返回對應(yīng)的屬性描述符, 否則返回 undefined.
  • Reflect.defineProperty(target, propertyKey, attributes)
    和 Object.defineProperty() 類似埃仪。如果設(shè)置成功就會返回 true
  • Reflect.ownKeys(target)
    返回一個包含所有自身屬性(不包含繼承屬性)的數(shù)組乙濒。(類似于
    Object.keys(), 但不會受enumerable影響).
  • Reflect.has(target, propertyKey)
    判斷一個對象是否存在某個屬性,和 in 運算符 的功能完全相同卵蛉。
  • Reflect.get(target, propertyKey[, receiver])
    獲取對象身上某個屬性的值颁股,類似于 target[name]。
  • Reflect.set(target, propertyKey, value[, receiver])
    將值分配給屬性的函數(shù)傻丝。返回一個Boolean甘有,如果更新成功,則返回true桑滩。
  • Reflect.deleteProperty(target, propertyKey)
    作為函數(shù)的delete操作符梧疲,相當(dāng)于執(zhí)行 delete target[name]。
  • Reflect.apply(target, thisArgument, argumentsList)
    對一個函數(shù)進(jìn)行調(diào)用操作运准,同時可以傳入一個數(shù)組作為調(diào)用參數(shù)。和Function.prototype.apply() 功能類似缭受。
  • Reflect.construct(target, argumentsList[, newTarget])
    對構(gòu)造函數(shù)進(jìn)行 new 操作胁澳,相當(dāng)于執(zhí)行 new target(...args)。
    基于此米者,可以將Proxy中對原代替中的操作進(jìn)行優(yōu)化
 new Proxy(obj, {
  set: function (target, propety, newValue, receiver) {
    Reflect.set(target,key,newValue)
  },
  has: function (target, key) {
    console.log("has捕捉器", key);
    return Reflect.has(target,key)
  },

  get: function (target, key) {
    console.log("get捕捉器", key);
    return Reflect.get(target,key)
  },

  deleteProperty: function (target, key) {
    console.log("delete捕捉器");
    delete Reflect.deleteProperty(target,key)
  },
});

Receiver的作用

如果我們的源對象(obj)有setter韭畸、getter的訪問器屬性宇智,那么可以通過receiver來改變里面的this;


image.png

Reflect的construct

用一個類的構(gòu)造器創(chuàng)建對象胰丁,對象卻是另一個類的子類


image.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末随橘,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子锦庸,更是在濱河造成了極大的恐慌机蔗,老刑警劉巖,帶你破解...
    沈念sama閱讀 210,978評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件甘萧,死亡現(xiàn)場離奇詭異萝嘁,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)扬卷,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評論 2 384
  • 文/潘曉璐 我一進(jìn)店門牙言,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人怪得,你說我怎么就攤上這事咱枉。” “怎么了徒恋?”我有些...
    開封第一講書人閱讀 156,623評論 0 345
  • 文/不壞的土叔 我叫張陵蚕断,是天一觀的道長。 經(jīng)常有香客問我因谎,道長基括,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,324評論 1 282
  • 正文 為了忘掉前任财岔,我火速辦了婚禮风皿,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘匠璧。我一直安慰自己桐款,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,390評論 5 384
  • 文/花漫 我一把揭開白布夷恍。 她就那樣靜靜地躺著魔眨,像睡著了一般。 火紅的嫁衣襯著肌膚如雪酿雪。 梳的紋絲不亂的頭發(fā)上遏暴,一...
    開封第一講書人閱讀 49,741評論 1 289
  • 那天,我揣著相機(jī)與錄音指黎,去河邊找鬼朋凉。 笑死,一個胖子當(dāng)著我的面吹牛醋安,可吹牛的內(nèi)容都是我干的杂彭。 我是一名探鬼主播墓毒,決...
    沈念sama閱讀 38,892評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼亲怠!你這毒婦竟也來了所计?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,655評論 0 266
  • 序言:老撾萬榮一對情侶失蹤团秽,失蹤者是張志新(化名)和其女友劉穎主胧,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體徙垫,經(jīng)...
    沈念sama閱讀 44,104評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡讥裤,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了姻报。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片己英。...
    茶點故事閱讀 38,569評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖吴旋,靈堂內(nèi)的尸體忽然破棺而出损肛,到底是詐尸還是另有隱情,我是刑警寧澤荣瑟,帶...
    沈念sama閱讀 34,254評論 4 328
  • 正文 年R本政府宣布治拿,位于F島的核電站,受9級特大地震影響笆焰,放射性物質(zhì)發(fā)生泄漏劫谅。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,834評論 3 312
  • 文/蒙蒙 一嚷掠、第九天 我趴在偏房一處隱蔽的房頂上張望捏检。 院中可真熱鬧,春花似錦不皆、人聲如沸贯城。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,725評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽能犯。三九已至,卻和暖如春犬耻,著一層夾襖步出監(jiān)牢的瞬間踩晶,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,950評論 1 264
  • 我被黑心中介騙來泰國打工枕磁, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留合瓢,地道東北人。 一個月前我還...
    沈念sama閱讀 46,260評論 2 360
  • 正文 我出身青樓透典,卻偏偏與公主長得像晴楔,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子峭咒,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,446評論 2 348

推薦閱讀更多精彩內(nèi)容