<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                [TOC] ## 概述 Reflect對象與Proxy對象一樣,也是 ES6 為了操作對象而提供的新 API。Reflect對象的設計目的有這樣幾個。 * 將Object對象的一些明顯屬于語言內部的方法(比如Object.defineProperty),放到Reflect對象上。現階段,某些方法同時在Object和Reflect對象上部署,未來的新方法將只部署在Reflect對象上。也就是說,從Reflect對象上可以拿到語言內部的方法。 * 修改某些Object方法的返回結果,讓其變得更合理。比如,Object.defineProperty(obj, name, desc)在無法定義屬性時,會拋出一個錯誤,而Reflect.defineProperty(obj, name, desc)則會返回false。 ~~~ // 老寫法 try { Object.defineProperty(target, property, attributes); // success } catch (e) { // failure } // 新寫法 if (Reflect.defineProperty(target, property, attributes)) { // success } else { // failure } ~~~ * 讓Object操作都變成函數行為。某些Object操作是命令式,比如name in obj和delete obj[name],而Reflect.has(obj, name)和Reflect.deleteProperty(obj, name)讓它們變成了函數行為。 ~~~ // 老寫法 'assign' in Object // true // 新寫法 Reflect.has(Object, 'assign') // true ~~~ * Reflect對象的方法與Proxy對象的方法一一對應,只要是Proxy對象的方法,就能在Reflect對象上找到對應的方法。這就讓Proxy對象可以方便地調用對應的Reflect方法,完成默認行為,作為修改行為的基礎。也就是說,不管Proxy怎么修改默認行為,你總可以在Reflect上獲取默認行為。 ~~~ Proxy(target, { set: function(target, name, value, receiver) { var success = Reflect.set(target,name, value, receiver); if (success) { log('property ' + name + ' on ' + target + ' set to ' + value); } return success; } }); ~~~ 上面代碼中,Proxy方法攔截target對象的屬性賦值行為。它采用Reflect.set方法將值賦值給對象的屬性,確保完成原有的行為,然后再部署額外的功能。 下面是另一個例子。 ~~~ 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); } }); ~~~ 上面代碼中,每一個Proxy對象的攔截操作(get、delete、has),內部都調用對應的Reflect方法,保證原生行為能夠正常執行。添加的工作,就是將每一個操作輸出一行日志。 有了Reflect對象以后,很多操作會更易讀。 ~~~ // 老寫法 Function.prototype.apply.call(Math.floor, undefined, [1.75]) // 1 // 新寫法 Reflect.apply(Math.floor, undefined, [1.75]) // 1 ## 靜態方法 ## 實例:使用 Proxy 實現觀察者模式 ~~~ ## 靜態方法 Reflect對象一共有 13 個靜態方法。 * Reflect.apply(target, thisArg, args) * Reflect.construct(target, args) * Reflect.get(target, name, receiver) * Reflect.set(target, name, value, receiver) * Reflect.defineProperty(target, name, desc) * Reflect.deleteProperty(target, name) * Reflect.has(target, name) * Reflect.ownKeys(target) * Reflect.isExtensible(target) * Reflect.preventExtensions(target) * Reflect.getOwnPropertyDescriptor(target, name) * Reflect.getPrototypeOf(target) * Reflect.setPrototypeOf(target, prototype) 上面這些方法的作用,大部分與Object對象的同名方法的作用都是相同的,而且它與Proxy對象的方法是一一對應的。下面是對它們的解釋。 * * * * * ### **Reflect.get(target, name, receiver)** > Reflect.get方法查找并返回target對象的name屬性,如果沒有該屬性,則返回undefined。 ~~~ var myObject = { foo: 1, bar: 2, get baz() { return this.foo + this.bar; }, } Reflect.get(myObject, 'foo') // 1 Reflect.get(myObject, 'bar') // 2 Reflect.get(myObject, 'baz') // 3 ~~~ 如果name屬性部署了讀取函數(getter),則讀取函數的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方法會報錯。 ~~~ Reflect.get(1, 'foo') // 報錯 Reflect.get(false, 'foo') // 報錯 ~~~ * * * * * ### **Reflect.set(target, name, value, receiver)** > Reflect.set方法設置target對象的name屬性等于value。 ~~~ var myObject = { foo: 1, set bar(value) { return this.foo = value; }, } myObject.foo // 1 Reflect.set(myObject, 'foo', 2); myObject.foo // 2 Reflect.set(myObject, 'bar', 3) myObject.foo // 3 ~~~ 如果name屬性設置了賦值函數,則賦值函數的this綁定receiver。 ~~~ var myObject = { foo: 4, set bar(value) { return this.foo = value; }, }; var myReceiverObject = { foo: 0, }; Reflect.set(myObject, 'bar', 1, myReceiverObject); myObject.foo // 4 myReceiverObject.foo // 1 ~~~ 注意,如果 Proxy 對象和 Reflect 對象聯合使用,前者攔截賦值操作,后者完成賦值的默認行為,而且傳入了receiver,那么Reflect.set會觸發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 ~~~ 上面代碼中,Proxy.set攔截里面使用了Reflect.set,而且傳入了receiver,導致觸發Proxy.defineProperty攔截。這是因為Proxy.set的receiver參數總是指向當前的 Proxy 實例(即上例的obj),而Reflect.set一旦傳入receiver,就會將屬性賦值到receiver上面(即obj),導致觸發defineProperty攔截。如果Reflect.set沒有傳入receiver,那么就不會觸發defineProperty攔截。 ~~~ let p = { a: 'a' }; let handler = { set(target, key, value, receiver) { console.log('set'); Reflect.set(target, key, value) }, defineProperty(target, key, attribute) { console.log('defineProperty'); Reflect.defineProperty(target, key, attribute); } }; let obj = new Proxy(p, handler); obj.a = 'A'; // set ~~~ * * * * * ### **Reflect.has(obj, name)** > Reflect.has方法對應name in obj里面的in運算符。 ~~~ var myObject = { foo: 1, }; // 舊寫法 'foo' in myObject // true // 新寫法 Reflect.has(myObject, 'foo') // true ~~~ * * * * * ### **Reflect.deleteProperty(obj, name)** > Reflect.deleteProperty方法等同于delete obj[name],用于刪除對象的屬性。 ~~~ const myObj = { foo: 'bar' }; // 舊寫法 delete myObj.foo; // 新寫法 Reflect.deleteProperty(myObj, 'foo'); ~~~ 該方法返回一個布爾值。如果刪除成功,或者被刪除的屬性不存在,返回true;刪除失敗,被刪除的屬性依然存在,返回false。 * * * * * ### **Reflect.construct(target, args)** > Reflect.construct方法等同于new target(...args),這提供了一種不使用new,來調用構造函數的方法。 ~~~ function Greeting(name) { this.name = name; } // new 的寫法 const instance = new Greeting('張三'); // Reflect.construct 的寫法 const instance = Reflect.construct(Greeting, ['張三']); ~~~ ***** ### **Reflect.getPrototypeOf(obj)** > Reflect.getPrototypeOf方法用于讀取對象的__proto__屬性,對應Object.getPrototypeOf(obj)。 ~~~ const myObj = new FancyThing(); // 舊寫法 Object.getPrototypeOf(myObj) === FancyThing.prototype; // 新寫法 Reflect.getPrototypeOf(myObj) === FancyThing.prototype; ~~~ Reflect.getPrototypeOf和Object.getPrototypeOf的一個區別是,如果參數不是對象,Object.getPrototypeOf會將這個參數轉為對象,然后再運行,而Reflect.getPrototypeOf會報錯。 ~~~ Object.getPrototypeOf(1) // Number {[[PrimitiveValue]]: 0} Reflect.getPrototypeOf(1) // 報錯 ~~~ ***** ### **Reflect.setPrototypeOf(obj, newProto) §** > Reflect.setPrototypeOf方法用于設置對象的__proto__屬性,返回第一個參數對象,對應Object.setPrototypeOf(obj, newProto)。 ~~~ const myObj = new FancyThing(); // 舊寫法 Object.setPrototypeOf(myObj, OtherThing.prototype); // 新寫法 Reflect.setPrototypeOf(myObj, OtherThing.prototype); ~~~ *** ### **Reflect.apply(func, thisArg, args)** > Reflect.apply方法等同于Function.prototype.apply.call(func, thisArg, args),用于綁定this對象后執行給定函數。 一般來說,如果要綁定一個函數的this對象,可以這樣寫fn.apply(obj, args),但是如果函數定義了自己的apply方法,就只能寫成Function.prototype.apply.call(fn, obj, args),采用Reflect對象可以簡化這種操作。 ~~~ const ages = [11, 33, 12, 54, 18, 96]; // 舊寫法 const youngest = Math.min.apply(Math, ages); const oldest = Math.max.apply(Math, ages); const type = Object.prototype.toString.call(youngest); // 新寫法 const youngest = Reflect.apply(Math.min, Math, ages); const oldest = Reflect.apply(Math.max, Math, ages); const type = Reflect.apply(Object.prototype.toString, youngest, []); ~~~ * * * * * ### **Reflect.defineProperty(target, propertyKey, attributes)** > Reflect.defineProperty方法基本等同于Object.defineProperty,用來為對象定義屬性。未來,后者會被逐漸廢除,請從現在開始就使用Reflect.defineProperty代替它。 ~~~ function MyDate() { /*…*/ } // 舊寫法 Object.defineProperty(MyDate, 'now', { value: () => Date.now() }); // 新寫法 Reflect.defineProperty(MyDate, 'now', { value: () => Date.now() }); ~~~ * * * * * ### **Reflect.getOwnPropertyDescriptor(target, propertyKey)** >Reflect.getOwnPropertyDescriptor基本等同于Object.getOwnPropertyDescriptor,用于得到指定屬性的描述對象,將來會替代掉后者。 ~~~ var myObject = {}; Object.defineProperty(myObject, 'hidden', { value: true, enumerable: false, }); // 舊寫法 var theDescriptor = Object.getOwnPropertyDescriptor(myObject, 'hidden'); // 新寫法 var theDescriptor = Reflect.getOwnPropertyDescriptor(myObject, 'hidden'); ~~~ Reflect.getOwnPropertyDescriptor和Object.getOwnPropertyDescriptor的一個區別是,如果第一個參數不是對象,Object.getOwnPropertyDescriptor(1, 'foo')不報錯,返回undefined,而Reflect.getOwnPropertyDescriptor(1, 'foo')會拋出錯誤,表示參數非法。 * * * * * ### **Reflect.isExtensible (target)** >Reflect.isExtensible方法對應Object.isExtensible,返回一個布爾值,表示當前對象是否可擴展。 ~~~ const myObject = {}; // 舊寫法 Object.isExtensible(myObject) // true // 新寫法 Reflect.isExtensible(myObject) // true ~~~ * * * * * ### **Reflect.preventExtensions(target)** >Reflect.preventExtensions對應Object.preventExtensions方法,用于讓一個對象變為不可擴展。它返回一個布爾值,表示是否操作成功。 ~~~ var myObject = {}; // 舊寫法 Object.preventExtensions(myObject) // Object {} // 新寫法 Reflect.preventExtensions(myObject) // true ~~~ ***** ### **Reflect.ownKeys (target)** >Reflect.ownKeys方法用于返回對象的所有屬性,基本等同于Object.getOwnPropertyNames與Object.getOwnPropertySymbols之和。 ~~~ var myObject = { foo: 1, bar: 2, [Symbol.for('baz')]: 3, [Symbol.for('bing')]: 4, }; // 舊寫法 Object.getOwnPropertyNames(myObject) // ['foo', 'bar'] Object.getOwnPropertySymbols(myObject) //[Symbol(baz), Symbol(bing)] // 新寫法 Reflect.ownKeys(myObject) // ['foo', 'bar', Symbol(baz), Symbol(bing)] ~~~ ## 實例:使用 Proxy 實現觀察者模式 觀察者模式(Observer mode)指的是函數自動觀察數據對象,一旦對象有變化,函數就會自動執行。 ~~~ const person = observable({ name: '張三', age: 20 }); function print() { console.log(`${person.name}, ${person.age}`) } observe(print); person.name = '李四'; // 輸出 // 李四, 20 ~~~ 上面代碼中,數據對象person是觀察目標,函數print是觀察者。一旦數據對象發生變化,print就會自動執行。 下面,使用 Proxy 寫一個觀察者模式的最簡單實現,即實現observable和observe這兩個函數。思路是observable函數返回一個原始對象的 Proxy 代理,攔截賦值操作,觸發充當觀察者的各個函數。 ~~~ const queuedObservers = new Set(); const observe = fn => queuedObservers.add(fn); const observable = obj => new Proxy(obj, {set}); function set(target, key, value, receiver) { const result = Reflect.set(target, key, value, receiver); queuedObservers.forEach(observer => observer()); return result; } ~~~ 上面代碼中,先定義了一個Set集合,所有觀察者函數都放進這個集合。然后,observable函數返回原始對象的代理,攔截賦值操作。攔截函數set之中,會自動執行所有觀察者。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看