<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>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                [TOC] >[success] # 監聽對象 1. 我們希望監聽這個對象中的屬性被設置或獲取的過程,我們可以通過之前的屬性描述符中的存儲屬性描述符來做 也就是利用 **Object.defineProperty** 2. 雖然**Object.defineProperty**能監聽攔截屬性變化,但是其本質是為了直接在一個對象上定義新的屬性或修改現有屬性,并且如果想讓每個屬性都要被監聽到需要利用循環,甚至多層嵌套對象需要遞歸,如新增屬性、刪除屬性也都不會觸發到監聽響應 ~~~ const a = { name: 'w', age: 12, } Object.keys(a).forEach((key) => { let value = a[key] Object.defineProperty(a, key, { set(newVal) { console.log('攔截到') Object[key] = value }, get() { console.log('get') return value }, }) }) a.name = 12 ~~~ >[success] # Proxy 使用 1. ES6 增加了 **Proxy** 是真正意義上代理它可以監聽一個對象的相關操作,然后創建一個對象的代理,之后對**該對象的所有操作**,都通過**代理對象來完成**,代理對象可以**監聽我們想要對原對象進行哪些操作** 2. **Proxy**進行攔截這個攔截實際是處理程序掛鉤 JavaScript 的'**內部方法**'(關于內部方法可以查看代理和發射章節) 3. **new Proxy**對象,并且傳入需要偵聽的對象以及**一個處理對象**,可以稱之為**handler** `const p = new Proxy(target, handler) ` 3.1. **target**要使用 **Proxy** 包裝的目標對象(可以是任何類型的對象,包括**原生數組,函數,甚至另一個代理**) 3.2. **handler** 一個通常以**函數作為屬性的對象**,各屬性中的**函數分別定義了在執行各種操作時代理 對象的行為**(即案例中的**p**對象) 3.3. **handler 作為攔截對象其中屬性如下**,這里這是特意將**Reflect**做對比形成這種**key value形式方便對比** ~~~ proxy = new Proxy({}, { apply: Reflect.apply, construct: Reflect.construct, defineProperty: Reflect.defineProperty, getOwnPropertyDescriptor: Reflect.getOwnPropertyDescriptor, deleteProperty: Reflect.deleteProperty, getPrototypeOf: Reflect.getPrototypeOf, setPrototypeOf: Reflect.setPrototypeOf, isExtensible: Reflect.isExtensible, preventExtensions: Reflect.preventExtensions, get: Reflect.get, set: Reflect.set, has: Reflect.has, ownKeys: Reflect.ownKeys, }); ~~~ 4. 總結:**Proxy**用于修改某些操作的默認行為,等同于在語言層面做出修改,所以屬于一種“**元編程**”(meta programming),即對編程語言進行編程。**Proxy**可以理解成,在目標對象之前架設一層“**攔截**”,**外界對該對象的訪問,都必須先通過這層攔截,因此提供了一種機制**,可以對外界的訪問進行過濾和改寫。 >[info] ## 代理和被代理對象關系 1. 當對象被代理時候,修改代理對象和被代理對象,如果沒有代理配置的代理 即沒有配置**trap** ,由于沒有配置,所有操作proxy都轉發到target,下面案例進行配置時候寫入操作**proxy.test** 和讀取**proxy.test** ,其實觸發的都目標值'**target**' * 如圖 ![](https://img.kancloud.cn/c8/79/c87916c26edc2619971d7d9e5104b5dc_489x222.png) * 代碼 ~~~ let target = {} let proxy = new Proxy(target, {}) // empty handler proxy.test = 5 console.log(target.test) // 5 console.log(proxy.test) // 5 target.test = 10 console.log(target.test) // 10 console.log(proxy.test) // 10 ~~~ 2. 當代理對象配置了**trap**,對于對象上的大多數操作,在 JavaScript 規范中有一個所謂的“內部方法”,它描述了它在最底層的工作方式。例如\[\[ Get \]\] ,讀取屬性的內部方法,\[\[ Set \]\] ,寫入屬性的內部方法,等等。這些方法只在規范中使用,我們不能直接通過名稱調用它們。通過proxy 去操作這些內部方法 * 雖然Proxy 代理了對象,但是配置**trap** 沒有對代理對象攔截后在進行修改,就不會影響被代理對象數據,但實際情況都是會去更改被代理對象,往往是雙向改變,下面案例就沒有對攔截后的被代理對象修改因此二者看起來本質是不想關的,但如果 `target[key] = newValue ` 二者是相互的 ~~~ const obj = { height: 1.88, } // 1.創建一個Proxy對象 const objProxy = new Proxy(obj, { set: function (target, key, newValue) { // console.log(`監聽: 監聽${key}的設置值: `, newValue) // 如果這里不跟目標對象做聯動賦值 其改變代理對象不會影響被代理對象 // target[key] = newValue return true }, get: function (target, key) { // console.log(`監聽: 監聽${key}的獲取`) return 1 }, }) obj.age = 122 objProxy.age = 1555 console.log(objProxy.age) // 1 console.log(obj.age) // 122 obj.zzzz = 1000 console.log(objProxy.zzzz) // 1 ~~~ >[info] ## 配置代理配置 ~~~ 1.配置其實就是針對'內置插槽' 進行代理配置 2.以set 案例做詳細說明,猶豫proxy 中的代理陷阱參數本質和reflect 都是一一對應,對參數具體內容不做解釋,只是對應 案例 ~~~ * 對象代理配置 ~~~ const obj = { height: 1.88 } // 1.創建一個Proxy對象 const objProxy = new Proxy(obj, { set: function(target, key, newValue) { console.log(`監聽: 監聽${key}的設置值: `, newValue) target[key] = newValue }, get: function(target, key) { console.log(`監聽: 監聽${key}的獲取`) return target[key] }, deleteProperty: function(target, key) { console.log(`監聽: 監聽刪除${key}屬性`) delete obj.name }, has: function(target, key) { console.log(`監聽: 監聽in判斷 ${key}屬性`) return key in target } }) ~~~ * 函數代理配置 ~~~ function foo(num1, num2) { console.log(this, num1, num2) } const fooProxy = new Proxy(foo, { apply: function(target, thisArg, otherArgs) { console.log("監聽執行了apply操作") target.apply(thisArg, otherArgs) }, construct: function(target, otherArray) { console.log("監聽執行了new操作") console.log(target, otherArray) return new target(...otherArray) } }) // fooProxy.apply("abc", [111, 222]) new fooProxy("aaa", "bbb") ~~~ >[danger] ##### set ~~~ 1.const p = new Proxy(target, { set: function(target, property, value, receiver) { } }); 1.1.target– 是目標對象,作為第一個參數傳遞給的對象new Proxy, 1.2.property– 屬性名稱, 1.3.value- 設置的值 1.4.receiver– 設置值的this指向,receiver就是this在它的調用中使用的對象。通常這是proxy對象本身 2.通過下面案例可以發現 代理陷阱種 set方法需要有返回值,如果是true則表示賦值成功,Reflect.set 接受的 參數和代理陷阱中set 參數一樣,而且返回值是boolean 其實proxy 的代理陷阱和 reflect 是配套 new Proxy(numbers, { // (*) set(target, prop, val) { // to intercept property writing if (typeof val == 'number') { return Reflect.set(target, prop, val) // Reflect.set(...arguments); } else { return false } }, }) ~~~ * 案例 ~~~ let numbers = [] let pNumbers = new Proxy(numbers, { // (*) set(target, prop, val) { // to intercept property writing if (typeof val == 'number') { target[prop] = val return true } else { return false } }, }) pNumbers.push(1) pNumbers.push(2) console.log(numbers) // [ 1, 2 ] console.log(pNumbers) // [ 1, 2 ] pNumbers.push('1') // 添加失敗 ~~~ >[danger] ##### get ~~~ 1.攔截是獲取屬性值其中 1.1.訪問屬性: proxy[foo]和 proxy.bar 1.2.Reflect.get() ~~~ ~~~ let numbers = [0, 1, 2] numbers = new Proxy(numbers, { get(target, prop, receiver) { if (prop in target) { return Reflect.get(target, prop, receiver) // Reflect.get(...arguments); } else { return 0 // default value } }, }) console.log(numbers[1]) // 1 console.log(numbers[100]) // 0 ~~~ >[danger] ##### has ~~~ 1.has 陷阱攔截 是in ,但是不是for in ,像下面案例只攔截是Proxy 對象 ~~~ ~~~ var obj = { a: 10 } var p = new Proxy(obj, { has: function (target, key) { if (key === 'a') return false return Reflect.set(target, key) }, }) console.log('a' in p) // false console.log('a' in obj) // true for (let key in p) { console.log(key) // a } ~~~ >[danger] ##### deleteProperty ~~~ 1.deleteProperty 攔截 是 delete ~~~ ~~~ var obj = { a: 10, b: 10 } var p = new Proxy(obj, { deleteProperty: function (target, key) { if (key === 'a') return false return Reflect.deleteProperty(target, key) }, }) // 因為設置deleteProperty 所以不能刪除 delete p.a console.log(p) // { a: 10, b: 10 } console.log(obj) // { a: 10, b: 10 } // 只是給proxy 做了設置因此目標對象還是可以刪除 delete obj.a console.log(p) // { b: 10 } console.log(obj) // { b: 10 } ~~~ >[danger] ##### getPrototypeOf ~~~ 1.是對'[[GetPrototypeOf]]' 的攔截,其中有五種形式都可以對其觸發 1.1.Object.getPrototypeOf() 1.2.Reflect.getPrototypeOf() 1.3.__proto__ 1.4.Object.prototype.isPrototypeOf() 1.5.instanceof ~~~ ~~~ var obj = {}; var p = new Proxy(obj, { getPrototypeOf(target) { return Array.prototype; } }); console.log( Object.getPrototypeOf(p) === Array.prototype, // true Reflect.getPrototypeOf(p) === Array.prototype, // true p.__proto__ === Array.prototype, // true Array.prototype.isPrototypeOf(p), // true p instanceof Array // true ); ~~~ >[danger] ##### setPrototypeOf ~~~ 1.可以攔截方法 1.1.Object.setPrototypeOf() 1.2.Reflect.setPrototypeOf() 2.可以用了禁止更改對象的原型 ~~~ ~~~ var p = new Proxy( {}, { setPrototypeOf: function (target, prototype) { return false }, } ) Object.setPrototypeOf(p1, Array.prototype) // throws a TypeError Reflect.setPrototypeOf(p1, Array.prototype) // returns false ~~~ >[danger] ##### 標記文章 https://www.digitalocean.com/community/tutorials/js-proxy-traps https://blog.sessionstack.com/how-javascript-works-proxy-and-reflect-11748452c695 https://www.keithcirkel.co.uk/metaprogramming-in-es6-part-3-proxies/ https://blog.greenroots.info/metaprogramming-an-introduction-to-javascriptes6-proxy https://javascript.info/proxy#proxy https://es6.ruanyifeng.com/#docs/proxy https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Proxy/Proxy/ownKeys * # reflect-metadata https://www.jianshu.com/p/8fffb94b9978 https://juejin.cn/post/7060687817097084935#heading-0 https://medium.com/jspoint/introduction-to-reflect-metadata-package-and-its-ecmascript-proposal-8798405d7d88
                  <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>

                              哎呀哎呀视频在线观看