ES6標(biāo)準(zhǔn)入門 摘要 (Reflect)

Reflect

概述
  • 將Object對(duì)象的一些明顯屬于語(yǔ)言內(nèi)部的方法(比如Object.defineProperty)杈湾,放到Reflect對(duì)象上∽阜纾現(xiàn)階段喉祭,某些方法同時(shí)在Object和Reflect對(duì)象上部署觉渴,未來(lái)的新方法將只部署在Reflect對(duì)象上检痰。也就是說(shuō),從Reflect對(duì)象上可以拿到語(yǔ)言內(nèi)部的方法苇经。

  • 修改某些Object方法的返回結(jié)果赘理,讓其變得更合理。比如扇单,Object.defineProperty(obj, name, desc)在無(wú)法定義屬性時(shí)商模,會(huì)拋出一個(gè)錯(cuò)誤,而Reflect.defineProperty(obj, name, desc)則會(huì)返回false蜘澜。

  • 讓Object操作都變成函數(shù)行為施流。某些Object操作是命令式,比如name in obj和delete obj[name]鄙信,而Reflect.has(obj, name)和Reflect.deleteProperty(obj, name)讓它們變成了函數(shù)行為瞪醋。

  • Reflect對(duì)象的方法與Proxy對(duì)象的方法一一對(duì)應(yīng),只要是Proxy對(duì)象的方法装诡,就能在Reflect對(duì)象上找到對(duì)應(yīng)的方法趟章。這就讓Proxy對(duì)象可以方便地調(diào)用對(duì)應(yīng)的Reflect方法,完成默認(rèn)行為慎王,作為修改行為的基礎(chǔ)蚓土。也就是說(shuō),不管Proxy怎么修改默認(rèn)行為赖淤,你總可以在Reflect上獲取默認(rèn)行為蜀漆。

var loggedObj = new Proxy(obj, {
  get(target, name) {
    console.log('get', target, name);
    return Reflect.get(target, name);
  },
  deleteProperty(target, name) {
    console.log('delete' + name);
    return Reflect.deleteProperty(target, name);
  },
  has(target, name) {
    console.log('has' + name);
    return Reflect.has(target, name);
  }
});

// 每一個(gè)Proxy對(duì)象的攔截操作(get、delete咱旱、has)确丢,內(nèi)部都調(diào)用對(duì)應(yīng)的Reflect方法
// 保證原生行為能夠正常執(zhí)行。添加的工作吐限,就是將每一個(gè)操作輸出一行日志鲜侥。

靜態(tài)方法

大部分與Object對(duì)象的同名方法的作用都是相同的,而且它與Proxy對(duì)象的方法是一一對(duì)應(yīng)的诸典。

Reflect.get(target, name, receiver)

Reflect.get方法查找并返回target對(duì)象的name屬性描函,如果沒(méi)有該屬性,則返回undefined狐粱。如果第一個(gè)參數(shù)不是對(duì)象舀寓,Reflect.get方法會(huì)報(bào)錯(cuò)。

如果name屬性部署了讀取函數(shù)(getter)肌蜻,則讀取函數(shù)的this綁定receiver互墓。

var myObject = {
  foo: 1,
  bar: 2,
  get baz() {
    return this.foo + this.bar;
  },
};

var myReceiverObject = {
  foo: 4,
  bar: 4,
};

Reflect.get(myObject, 'baz', myReceiverObject) // 8
Reflect.get(myObject, 'baz') // 3
Reflect.set(target, name, value, receiver)

Reflect.set方法設(shè)置target對(duì)象的name屬性等于value。如果第一個(gè)參數(shù)不是對(duì)象蒋搜,Reflect.set會(huì)報(bào)錯(cuò)篡撵。

如果name屬性設(shè)置了賦值函數(shù)(setter)判莉,則賦值函數(shù)的this綁定receiver。

注意育谬,如果 Proxy對(duì)象和 Reflect對(duì)象聯(lián)合使用骂租,前者攔截賦值操作,后者完成賦值的默認(rèn)行為斑司,而且傳入了receiver渗饮,那么Reflect.set會(huì)觸發(fā)Proxy.defineProperty攔截。

let p = {
  a: 'a'
};

let handler = {
  set(target, key, value, receiver) {
    console.log('set');
    Reflect.set(target, key, value, receiver)
  },
  defineProperty(target, key, attribute) {
    console.log('defineProperty');
    Reflect.defineProperty(target, key, attribute);
  }
};

let obj = new Proxy(p, handler);
obj.a = 'A';
// set
// defineProperty

這是因?yàn)镻roxy.set的receiver參數(shù)總是指向當(dāng)前的 Proxy實(shí)例(即上例的obj)宿刮,而Reflect.set一旦傳入receiver互站,就會(huì)將屬性賦值到receiver上面(即obj),導(dǎo)致觸發(fā)defineProperty攔截僵缺。如果Reflect.set沒(méi)有傳入receiver胡桃,那么就不會(huì)觸發(fā)defineProperty攔截

Reflect.has(obj, name)

Reflect.has方法對(duì)應(yīng)name in obj里面的in運(yùn)算符。如果第一個(gè)參數(shù)不是對(duì)象磕潮,會(huì)報(bào)錯(cuò)

// 舊寫(xiě)法
'foo' in myObject // Boolean

// 新寫(xiě)法
Reflect.has(myObject, 'foo') // Boolean
Reflect.construct(target, args)

Reflect.construct方法等同于new target(...args)翠胰,這提供了一種不使用new,來(lái)調(diào)用構(gòu)造函數(shù)的方法自脯。如果Reflect.construct()方法的第一個(gè)參數(shù)不是函數(shù)之景,會(huì)報(bào)錯(cuò)。

function Greeting(name) {
  this.name = name;
}

// new 的寫(xiě)法
const instance = new Greeting('張三');

// Reflect.construct 的寫(xiě)法
const instance = Reflect.construct(Greeting, ['張三']);
Reflect.getPrototypeOf(obj)

Reflect.getPrototypeOf方法用于讀取對(duì)象的proto屬性膏潮,對(duì)應(yīng)Object.getPrototypeOf(obj)锻狗。

Reflect.getPrototypeOf和Object.getPrototypeOf的一個(gè)區(qū)別是,如果參數(shù)不是對(duì)象焕参,Object.getPrototypeOf會(huì)將這個(gè)參數(shù)轉(zhuǎn)為對(duì)象轻纪,然后再運(yùn)行,而Reflect.getPrototypeOf會(huì)報(bào)錯(cuò)叠纷。

Reflect.setPrototypeOf(obj, newProto)

Reflect.setPrototypeOf方法用于設(shè)置目標(biāo)對(duì)象的原型(prototype)刻帚,對(duì)應(yīng)Object.setPrototypeOf(obj, newProto)方法。它返回一個(gè)布爾值涩嚣,表示是否設(shè)置成功崇众。

如果第一個(gè)參數(shù)是undefined或null,Object.setPrototypeOf和Reflect.setPrototypeOf都會(huì)報(bào)錯(cuò)缓艳。

如果第一個(gè)參數(shù)不是對(duì)象校摩,Object.setPrototypeOf會(huì)返回第一個(gè)參數(shù)本身,而Reflect.setPrototypeOf會(huì)報(bào)錯(cuò)阶淘。

如果無(wú)法設(shè)置目標(biāo)對(duì)象的原型(比如,目標(biāo)對(duì)象禁止擴(kuò)展)互妓,Reflect.setPrototypeOf方法返回false溪窒。

Reflect.apply(func, thisArg, args)

一般來(lái)說(shuō)坤塞,如果要綁定一個(gè)函數(shù)的this對(duì)象,可以這樣寫(xiě)fn.apply(obj, args)澈蚌,但是如果函數(shù)定義了自己的apply方法摹芙,就只能寫(xiě)成Function.prototype.apply.call(fn, obj, args)調(diào)用Function原型上定義的apply方法,采用Reflect對(duì)象可以簡(jiǎn)化這種操作宛瞄。

const ages = [11, 33, 12, 54, 18, 96];

// 舊寫(xiě)法
const youngest = Math.min.apply(Math, ages);
const type = Object.prototype.toString.call(youngest);

// 新寫(xiě)法
const youngest = Reflect.apply(Math.min, Math, ages);
const type = Reflect.apply(Object.prototype.toString, youngest, []);
Reflect.defineProperty(target, propertyKey, attributes)

Reflect.defineProperty方法基本等同于Object.defineProperty浮禾,用來(lái)為對(duì)象定義屬性。未來(lái)份汗,后者會(huì)被逐漸廢除盈电,請(qǐng)從現(xiàn)在開(kāi)始就使用Reflect.defineProperty代替它。第一個(gè)參數(shù)不是對(duì)象杯活,就會(huì)拋出錯(cuò)誤匆帚。

Reflect.getOwnPropertyDescriptor(target, propertyKey)

Reflect.getOwnPropertyDescriptor基本等同于Object.getOwnPropertyDescriptor,用于得到指定屬性的描述對(duì)象旁钧,將來(lái)會(huì)替代掉后者吸重。

如果第一個(gè)參數(shù)不是對(duì)象,Object.getOwnPropertyDescriptor(1, 'foo')不報(bào)錯(cuò)歪今,返回undefined嚎幸,而Reflect.getOwnPropertyDescriptor(1, 'foo')會(huì)拋出錯(cuò)誤,表示參數(shù)非法寄猩。

Reflect.isExtensible (target)

Reflect.isExtensible方法對(duì)應(yīng)Object.isExtensible鞭铆,返回一個(gè)布爾值,表示當(dāng)前對(duì)象是否可擴(kuò)展焦影。

如果參數(shù)不是對(duì)象车遂,Object.isExtensible會(huì)返回false,因?yàn)榉菍?duì)象本來(lái)就是不可擴(kuò)展的斯辰,而Reflect.isExtensible會(huì)報(bào)錯(cuò)舶担。

Reflect.preventExtensions(target)

Reflect.preventExtensions對(duì)應(yīng)Object.preventExtensions方法,用于讓一個(gè)對(duì)象變?yōu)椴豢蓴U(kuò)展彬呻。它返回一個(gè)布爾值衣陶,表示是否操作成功。

如果參數(shù)不是對(duì)象闸氮,Object.preventExtensions在 ES5 環(huán)境報(bào)錯(cuò)剪况,在 ES6 環(huán)境返回傳入的參數(shù),而Reflect.preventExtensions會(huì)報(bào)錯(cuò)蒲跨。

Reflect.ownKeys (target)

Reflect.ownKeys方法用于返回對(duì)象的所有屬性译断,基本等同于Object.getOwnPropertyNames與Object.getOwnPropertySymbols之和。

如果Reflect.ownKeys()方法的第一個(gè)參數(shù)不是對(duì)象或悲,會(huì)報(bào)錯(cuò)孙咪。

實(shí)例:使用 Proxy 實(shí)現(xiàn)觀察者模式

觀察者模式(Observer mode)指的是函數(shù)自動(dòng)觀察數(shù)據(jù)對(duì)象堪唐,一旦對(duì)象有變化,函數(shù)就會(huì)自動(dòng)執(zhí)行翎蹈。

const queuedObservers = new Set();

const observe = fn => queuedObservers.add(fn);
const observable = obj => new Proxy(obj, {handler});

function handler(target, key, value, receiver) {
  const result = Reflect.set(target, key, value, receiver);
  queuedObservers.forEach(observer => observer());
  return result;
}

const person = observable({
  name: '張三',
  age: 20
});

function print() {
  console.log(`${person.name}, ${person.age}`)
}

observe(print);
person.name = '李四';
// 李四, 20
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末淮菠,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子荤堪,更是在濱河造成了極大的恐慌合陵,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,695評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件澄阳,死亡現(xiàn)場(chǎng)離奇詭異拥知,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)寇荧,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,569評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門举庶,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人揩抡,你說(shuō)我怎么就攤上這事户侥。” “怎么了峦嗤?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,130評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵蕊唐,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我烁设,道長(zhǎng)替梨,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,648評(píng)論 1 297
  • 正文 為了忘掉前任装黑,我火速辦了婚禮副瀑,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘恋谭。我一直安慰自己糠睡,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,655評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布疚颊。 她就那樣靜靜地躺著狈孔,像睡著了一般。 火紅的嫁衣襯著肌膚如雪材义。 梳的紋絲不亂的頭發(fā)上均抽,一...
    開(kāi)封第一講書(shū)人閱讀 52,268評(píng)論 1 309
  • 那天止潘,我揣著相機(jī)與錄音失晴,去河邊找鬼本昏。 笑死仔戈,一個(gè)胖子當(dāng)著我的面吹牛涉枫,可吹牛的內(nèi)容都是我干的尺铣。 我是一名探鬼主播描验,決...
    沈念sama閱讀 40,835評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼占哟,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼华烟!你這毒婦竟也來(lái)了翩迈?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,740評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤盔夜,失蹤者是張志新(化名)和其女友劉穎负饲,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體喂链,經(jīng)...
    沈念sama閱讀 46,286評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡返十,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,375評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了椭微。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片洞坑。...
    茶點(diǎn)故事閱讀 40,505評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖蝇率,靈堂內(nèi)的尸體忽然破棺而出迟杂,到底是詐尸還是另有隱情,我是刑警寧澤本慕,帶...
    沈念sama閱讀 36,185評(píng)論 5 350
  • 正文 年R本政府宣布排拷,位于F島的核電站,受9級(jí)特大地震影響锅尘,放射性物質(zhì)發(fā)生泄漏监氢。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,873評(píng)論 3 333
  • 文/蒙蒙 一藤违、第九天 我趴在偏房一處隱蔽的房頂上張望浪腐。 院中可真熱鬧,春花似錦顿乒、人聲如沸议街。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,357評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)傍睹。三九已至,卻和暖如春犹菱,著一層夾襖步出監(jiān)牢的瞬間拾稳,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,466評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工腊脱, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留访得,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,921評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像悍抑,于是被迫代替她去往敵國(guó)和親鳄炉。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,515評(píng)論 2 359

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

  • Reflect 對(duì)象與 Proxy 對(duì)象一樣搜骡,也是 ES6 為了操作對(duì)象而提供的新的API拂盯。Reflect 對(duì)象的...
    了凡和纖風(fēng)閱讀 629評(píng)論 0 2
  • 本人自學(xué)es6已經(jīng)有一段時(shí)間了,只覺(jué)得有些時(shí)候很是枯燥無(wú)味记靡, 時(shí)而又覺(jué)得在以后的職業(yè)生涯中會(huì)很有用谈竿,因?yàn)閑s6的很...
    可樂(lè)_37d3閱讀 1,533評(píng)論 0 0
  • defineProperty() 學(xué)習(xí)書(shū)籍《ECMAScript 6 入門 》 Proxy Proxy 用于修改某...
    Bui_vlee閱讀 657評(píng)論 0 1
  • Proxy Proxy可以理解成,在目標(biāo)對(duì)象之前架一層‘?dāng)r截’摸吠,外界對(duì)該對(duì)象的訪問(wèn)空凸,都必須先通過(guò)這層攔截,因此提供...
    nomooo閱讀 1,002評(píng)論 0 4
  • 早上,小王偷偷把我拉到一邊啼止,激動(dòng)地指著手機(jī)屏幕給我看:“芳姐道逗,我昨天幣 乎的文章收益是185元了,終于超過(guò)了我的工...
    就可以很好閱讀 117評(píng)論 0 0