<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Proxy使用詳解

          共 8367字,需瀏覽 17分鐘

           ·

          2020-09-29 21:42

          來源 |?https://www.cnblogs.com/chuaWeb/p/13676000.html

          通用

          1、Proxy可以包裝任何形式的對象:包括原生數(shù)組,函數(shù),甚至另一個(gè)代理。
          2、代理實(shí)例中沒有指定的handler,實(shí)際就是操作原對象target:實(shí)例:打開控制臺(tái)查看:http://jsrun.net/3RLKp/edit
          let target = function(){return 'ddd'}let proxy = new Proxy(target, {});proxy.prototype.age = 12console.log(proxy.prototype === target.prototype) // true
          3、代理實(shí)例只是返回對象target的一個(gè)代理包裝(只有在觸發(fā)handler時(shí),handler中可以操作target),target的更改不會(huì)觸發(fā)代理實(shí)例的handler:實(shí)例:打開控制臺(tái)查看:http://jsrun.net/7BLKp/edit
          來看一下具體的運(yùn)用
          MDN上有一個(gè)實(shí)例比較特別【拓展構(gòu)造函數(shù)】,來看一下:在線例子:http://jsrun.net/cRLKp/edit
          function extend(sup, base) { var descriptor = Object.getOwnPropertyDescriptor( base.prototype, 'constructor' ); base.prototype = Object.create(sup.prototype); var handler = { construct: function(target, args) { var obj = Object.create(base.prototype); this.apply(target, obj, args); return obj; }, apply: function(target, that, args) { sup.apply(that, args); base.apply(that, args); } }; var proxy = new Proxy(base, handler); descriptor.value = proxy; Object.defineProperty(base.prototype, 'constructor', descriptor); return proxy;}
          var Person = function(name) { this.name = name;};
          var Boy = extend(Person, function(name, age) { this.age = age;});
          Boy.prototype.gender = 'M';
          var Peter = new Boy('Peter', 13);
          console.log(Peter.gender); // "M"console.log(Peter.name); // "Peter"console.log(Peter.age); // 13
          執(zhí)行完Boy.prototype.gender = 'M'后,數(shù)據(jù)結(jié)構(gòu)是下面這個(gè)樣子的

          執(zhí)行 var Peter = new Boy('Peter', 13);
          new操作進(jìn)入到handler.construct,里面的上下文環(huán)境this綁定在handler(可以查看MDN文檔描述)。直接調(diào)用this.apply進(jìn)入handler.apply執(zhí)行。new操作執(zhí)行完畢之后的數(shù)據(jù)結(jié)構(gòu)


          巧妙利用原型鏈和代理

          handler形參中的receiver

          receiver是代理或繼承代理的對象。通俗來講,就是觸發(fā)了handler的源頭對象。一般receiver即是target的代理實(shí)例。
          但是如果對象繼承了代理對象的情況,如下:
          "use strict"const proxy = new Proxy({}, { get: function(target, prop, receiver) { if(proxy === receiver){ console.log('receiver為proxy') } else if(obj === receiver){ console.log('receiver為obj') }else{ console.log('receiver不為proxy也不為obj') } return 'chua'; }});proxy.dd // receiver為proxylet obj = Object.create(proxy);obj.msg // receiver為obj
          proxy對象是obj對象的原型,obj對象本身并沒有msg屬性,所以根據(jù)原型鏈,會(huì)在proxy對象上讀取該屬性,導(dǎo)致被攔截。
          obj是obj.msg觸發(fā)handler的原始調(diào)用(源頭)

          handler.set

          set必須返回一個(gè)boolean類型

          必須返回一個(gè)boolean類型,true表示設(shè)置成功,返回false表示失敗,嚴(yán)格模式下會(huì)拋錯(cuò)(下面的例子全部在嚴(yán)格模式下執(zhí)行)
          注意:返回的數(shù)據(jù)如果不是boolean類型,會(huì)轉(zhuǎn)換成布爾類型,假值包括:undefined,null,false, +0, -0, NaN, ""?:實(shí)例
          const target = { msg: "hello"};
          const handler = { set: function(target, prop, value, receiver){ target[prop] = value // return true }};
          const proxy = new Proxy(target, handler);proxy.msg = 'wow' // Uncaught TypeError: 'set' on proxy: trap returned falsish for property 'msg'
          handler.set在以下情況會(huì)拋錯(cuò)
          1、如果相應(yīng)的目標(biāo)對象屬性是不可寫的數(shù)據(jù)屬性,則無法將屬性的值更改為與相應(yīng)目標(biāo)對象屬性的值不同的值。實(shí)例:嚴(yán)格模式
          var obj = {}Object.defineProperty(obj, 'year', { // configurable: false, 默認(rèn)false // writable: false, 默認(rèn)false value: 2})Object.defineProperty(obj, 'class', { configurable: true, // writable: false, 默認(rèn)false value: 'chua'})var proxy = new Proxy(obj, { set(target, prop, val){ target[prop] = val return true }})proxy.card = 'sdf' // 設(shè)置成功proxy.year = 10 // Uncaught TypeError: Cannot assign to read only property 'year' of object proxy.class = 'dd' // Uncaught TypeError: Cannot assign to read only property 'class' of object
          2、如果相應(yīng)的目標(biāo)對象屬性配置了[[Set]]為undefined,實(shí)例
          var obj = {}const definereactive = function(data, key, val) { Object.defineProperty(data, key, { get: function(){ return val }, set: undefined // 應(yīng)該設(shè)置成下面這個(gè)正確的函數(shù) // function(newVal) { // val = newVal; // } });}definereactive(obj, 'year', obj.year)var proxy = new Proxy(obj, { set(target, prop, val){ target[prop] = val return true }})obj.year = 20 // Uncaught TypeError: Cannot set property year of # which has only a getterproxy.year = 30 // Uncaught TypeError: Cannot set property year of # which has only a getter
          3、在嚴(yán)格模式下,handler.set錯(cuò)誤返回值(轉(zhuǎn)換為boolean后為false)將引發(fā)TypeError異常。

          復(fù)雜對象

          Proxy只對其根屬性(原型鏈上的也算)的值的更改做監(jiān)聽,如果某個(gè)屬性key對應(yīng)的值為一個(gè)引用類型,引用地址沒有發(fā)生改變則不會(huì)進(jìn)入到handler.set
          const target = { info: { name: 'chua', age: 18 }};
          const handler = { set: function(target, prop, value, receiver){ console.log('in handler.set', target, prop, value, receiver) target[prop] = value return true }};
          const proxy = new Proxy(target, handler);proxy.info.name = 'chua1989' // 沒有進(jìn)入handler.set, 需要直接更改info屬性才行console.log(proxy.info.name) // chua1989

          handler.has

          報(bào)錯(cuò)的情況
          1、target的某屬性為不可配置,則該屬性不能被代理隱藏(即handle.has不能返回false):?在線運(yùn)行
          var obj = {}Object.defineProperty(obj, 'year', { configurable: false, value: 2})var proxy = new Proxy(obj, { has: function(target, prop) { console.log('called: ' + prop); return false; }})console.log('year' in proxy); // Uncaught TypeError: 'has' on proxy: trap returned falsish for property 'year' which exists in the proxy target as non-configurable
          2、target對象不可拓展,則已經(jīng)存在的屬性不能被代理隱藏:在線運(yùn)行
          var obj = { year: 2}Object.preventExtensions(obj);
          var proxy = new Proxy(obj, { has: function(target, prop) { console.log('called: ' + prop); return false; }})console.log('a' in proxy); // 不存在的屬性沒有問題console.log('year' in proxy); // Uncaught TypeError: 'has' on proxy: trap returned falsish for property 'year' but the proxy target is not extensible

          handler.construct

          只有當(dāng)target能使用new方法該配置才能起作用。即target必須是函數(shù)
          const p = new Proxy({}, { construct: function(target, argumentsList, newTarget) { return function(){}; }});
          new p(); // proxy.html:16 Uncaught TypeError: p is not a constructor
          而且handler.construct必須返回一個(gè)Object引用類型就行
          const p = new Proxy(function() {}, { construct: function(target, argumentsList, newTarget) { return 1; }});
          new p(); // TypeError is thrown
          下面這個(gè)就不會(huì)報(bào)錯(cuò)
          const p = new Proxy(function() {}, { construct: function(target, argumentsList, newTarget) { return function(){}; }});
          new p();
          handler.construct中的this指向的是handler

          handler.deleteProperty

          deleteProperty 必須返回一個(gè) Boolean 類型的值,表示了該屬性是否被成功刪除。嚴(yán)格模式下false會(huì)報(bào)錯(cuò)
          var p = new Proxy({}, { deleteProperty: function(target, prop) { console.log('called: ' + prop); return false; }});
          delete p.a; // "called: a"
          如果目標(biāo)對象的屬性是不可配置的,那么該屬性不能被刪除
          var obj = {}Object.defineProperty(obj, 'a', { configurable: false})var p = new Proxy(obj, { deleteProperty: function(target, prop) { console.log('called: ' + prop); return true; }});
          delete p.a; // "called: a" // Uncaught TypeError: 'deleteProperty' on proxy: trap returned truish for property 'a' which is non-configurable in the proxy target

          handler.defineProperty

          如果目標(biāo)對象不可擴(kuò)展(non-extensible),則defineProperty()不能增加目標(biāo)對象上不存在的屬性,否則會(huì)報(bào)錯(cuò)。
          如果目標(biāo)對象的某個(gè)屬性不可寫(writable)或不可配置(configurable),則defineProperty()方法不得改變這兩個(gè)設(shè)置(這是Object.defineProperty的特性)。

          handler.getPrototypeOf

          如果遇到了下面兩種情況,js?引擎會(huì)拋出 TypeError 異常:
          getPrototypeOf() 方法返回的不是對象也不是 null。
          目標(biāo)對象是不可擴(kuò)展的,且 getPrototypeOf() 方法返回的原型不是目標(biāo)對象本身的原型。

          handler.isExtensible

          isExtensible方法必須返回一個(gè) Boolean值或可轉(zhuǎn)換成Boolean的值。
          Object.isExtensible(proxy) 必須同Object.isExtensible(target)返回相同值。也就是必須返回true或者為true的值,返回false和為false的值都會(huì)報(bào)錯(cuò)。

          handler.ownKeys

          有三類屬性會(huì)被ownKeys()方法自動(dòng)過濾,不會(huì)返回。
          1、目標(biāo)對象上不存在的屬性
          2、屬性名為 Symbol 值
          3、不可遍歷(enumerable)的屬性
          如果違反了下面的約束,proxy將拋出錯(cuò)誤 TypeError:
          1、ownKeys 的結(jié)果必須是一個(gè)數(shù)組.
          2、數(shù)組的元素類型要么是一個(gè) String ,要么是一個(gè) Symbol.
          3、結(jié)果列表必須包含目標(biāo)對象的所有不可配置(non-configurable )、自有(own)屬性的key.
          4、如果目標(biāo)對象不可擴(kuò)展,那么結(jié)果列表必須包含目標(biāo)對象的所有自有(own)屬性的key,不能有其它值.

          handler.preventExtensions

          如果目標(biāo)對象是可擴(kuò)展的,那么只能返回 false。否則拋錯(cuò)

          handler.setPrototypeOf

          如果 target 不可擴(kuò)展, 原型參數(shù)必須與Object.getPrototypeOf(target) 的值相同. 否則拋錯(cuò)
          如果你不想為你的對象設(shè)置一個(gè)新的原型,你的handler's的setPrototypeOf方法可以返回false,也可以拋出異常。
          var handlerReturnsFalse = { setPrototypeOf(target, newProto) { return false; }};
          var newProto = {}, target = {};
          var p1 = new Proxy(target, handlerReturnsFalse);Object.setPrototypeOf(p1, newProto); // throws a TypeErrorReflect.setPrototypeOf(p1, newProto); // returns false
          為什么Object和Reflect調(diào)用setPrototypeOf結(jié)果會(huì)不同。這便是Reflect被例入標(biāo)準(zhǔn)的一個(gè)原因之一:操作對象時(shí)出現(xiàn)報(bào)錯(cuò)返回false。這樣可以直接使用如下的方式
          if(Reflect.setPrototypeOf(p1, newProto)){ ...}

          handler的屬性方法中的this

          正常情況,handler的屬性方法中this指向的是proxy實(shí)例,而不是target,要特別注意
          const target = new Date();const handler = {};const proxy = new Proxy(target, handler);
          proxy.getDate();// TypeError: this is not a Date object.
          由于getDate必須要是Date實(shí)例才能有作用,所以此處報(bào)錯(cuò)。
          handler.construct中的this指向的是handler

          瀏覽 43
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                    <th id="afajh"><progress id="afajh"></progress></th>
                    爱爱爱爱爱免费视频 | 理论片在线免费视频 | 欧美自拍视频在线 | 国产午夜福利免费视频在线观看 | 国产精品无码在线观看视频 |