日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

ES6-proxy

發(fā)布時間:2024/8/26 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 ES6-proxy 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

前言

我們或多或少都聽過“數(shù)據(jù)綁定”這個詞,“數(shù)據(jù)綁定”的關鍵在于監(jiān)聽數(shù)據(jù)的變化,可是對于這樣一個對象:var obj = {value: 1},我們該怎么知道 obj 發(fā)生了改變呢?

definePropety

ES5 提供了 Object.defineProperty 方法,該方法可以在一個對象上定義一個新屬性,或者修改一個對象的現(xiàn)有屬性,并返回這個對象。

語法

Object.defineProperty(obj, prop, descriptor)

參數(shù)

obj: 要在其上定義屬性的對象。prop: 要定義或修改的屬性的名稱。descriptor: 將被定義或修改的屬性的描述符。

舉個例子:

var obj = {}; Object.defineProperty(obj, "num", {value : 1, writable : true, enumerable : true, configurable : true }); // 對象 obj 擁有屬性 num,值為 1

雖然我們可以直接添加屬性和值,但是使用這種方式,我們能進行更多的配置。

函數(shù)的第三個參數(shù) descriptor 所表示的屬性描述符有兩種形式:數(shù)據(jù)描述符和存取描述符

兩者均具有以下兩種鍵值

configurable

當且僅當該屬性的 configurable true 時,該屬性描述符才能夠被改變,也能夠被刪除。默認為 false

enumerable

當且僅當該屬性的 enumerable true 時,該屬性才能夠出現(xiàn)在對象的枚舉屬性中。默認為 false

數(shù)據(jù)描述符同時具有以下可選鍵值

value

該屬性對應的值。可以是任何有效的 JavaScript 值(數(shù)值,對象,函數(shù)等)。默認為 undefined。

writable

當且僅當該屬性的 writable true 時,該屬性才能被賦值運算符改變。默認為 false

存取描述符同時具有以下可選鍵值

get

一個給屬性提供 getter 的方法,如果沒有 getter 則為 undefined。該方法返回值被用作屬性值。默認為 undefined。

set

一個給屬性提供 setter 的方法,如果沒有 setter 則為 undefined。該方法將接受唯一參數(shù),并將該參數(shù)的新值分配給該屬性。默認為 undefined。

值得注意的是:

屬性描述符必須是數(shù)據(jù)描述符或者存取描述符兩種形式之一,不能同時是兩者。這就意味著你可以:

Object.defineProperty({}, "num", {value: 1, writable: true, enumerable: true, configurable: true });

也可以:

var value = 1; Object.defineProperty({}, "num", { get : function(){ return value; }, set : function(newValue){ value = newValue; }, enumerable : true, configurable : true });

但是不可以:

// 報錯 Object.defineProperty({}, "num", {value: 1, get: function() { return 1; } });

此外,所有的屬性描述符都是非必須的,但是 descriptor 這個字段是必須的,如果不進行任何配置,你可以這樣:

var obj = Object.defineProperty({}, "num", {}); console.log(obj.num); // undefined

Setters 和 Getters

之所以講到 defineProperty,是因為我們要使用存取描述符中的 get 和 set,這兩個方法又被稱為 getter 和 setter。由 getter 和 setter 定義的屬性稱做”存取器屬性“。

當程序查詢存取器屬性的值時,JavaScript 調(diào)用 getter方法。這個方法的返回值就是屬性存取表達式的值。當程序設置一個存取器屬性的值時,JavaScript 調(diào)用 setter 方法,將賦值表達式右側(cè)的值當做參數(shù)傳入 setter。從某種意義上講,這個方法負責“設置”屬性值。可以忽略 setter 方法的返回值。

舉個例子:

var obj = {}, value = null; Object.defineProperty(obj, "num", { get: function(){ console.log('執(zhí)行了 get 操作') return value; }, set: function(newValue) { console.log('執(zhí)行了 set 操作') value = newValue; } }) obj.value = 1 // 執(zhí)行了 set 操作 console.log(obj.value); // 執(zhí)行了 get 操作 // 1

這不就是我們要的監(jiān)控數(shù)據(jù)改變的方法嗎?我們再來封裝一下:

function Archiver() { var value = null; // archive n. 檔案 var archive = []; Object.defineProperty(this, 'num', { get: function() { console.log('執(zhí)行了 get 操作') return value; }, set: function(value) { console.log('執(zhí)行了 set 操作') value = value; archive.push({ val: value }); } }); this.getArchive = function() { return archive; }; } var arc = new Archiver(); arc.num; // 執(zhí)行了 get 操作 arc.num = 11; // 執(zhí)行了 set 操作 arc.num = 13; // 執(zhí)行了 set 操作 console.log(arc.getArchive()); // [{ val: 11 }, { val: 13 }]

watch API

既然可以監(jiān)控數(shù)據(jù)的改變,那我可以這樣設想,即當數(shù)據(jù)改變的時候,自動進行渲染工作。舉個例子:

HTML 中有個 span 標簽和 button 標簽

<span id="container">1</span> <button id="button">點擊加 1</button>

當點擊按鈕的時候,span 標簽里的值加 1。

傳統(tǒng)的做法是:

document.getElementById('button').addEventListener("click", function(){ var container = document.getElementById("container"); container.innerHTML = Number(container.innerHTML) + 1; });

如果使用了 defineProperty:

var obj = {value: 1 }// 儲存 obj.value 的值 var value = 1; Object.defineProperty(obj, "value", { get: function() { return value; }, set: function(newValue) { value = newValue; document.getElementById('container').innerHTML = newValue; } }); document.getElementById('button').addEventListener("click", function() { obj.value += 1; });

代碼看似增多了,但是當我們需要改變 span 標簽里的值的時候,直接修改 obj.value 的值就可以了。

然而,現(xiàn)在的寫法,我們還需要單獨聲明一個變量存儲 obj.value 的值,因為如果你在 set 中直接?obj.value = newValue就會陷入無限的循環(huán)中。此外,我們可能需要監(jiān)控很多屬性值的改變,要是一個一個寫,也很累吶,所以我們簡單寫個 watch 函數(shù)。使用效果如下:

var obj = {value: 1 }watch(obj, "num", function(newvalue){ document.getElementById('container').innerHTML = newvalue; }) document.getElementById('button').addEventListener("click", function(){ obj.value += 1 });

我們來寫下這個 watch 函數(shù):

(function(){var root = this; function watch(obj, name, func){ var value = obj[name]; Object.defineProperty(obj, name, { get: function() { return value; }, set: function(newValue) { value = newValue; func(value) } }); if (value) obj[name] = value } this.watch = watch; })()

現(xiàn)在我們已經(jīng)可以監(jiān)控對象屬性值的改變,并且可以根據(jù)屬性值的改變,添加回調(diào)函數(shù),棒棒噠~

proxy

使用 defineProperty 只能重定義屬性的讀取(get)和設置(set)行為,到了 ES6,提供了 Proxy,可以重定義更多的行為,比如 in、delete、函數(shù)調(diào)用等更多行為。

Proxy 這個詞的原意是代理,用在這里表示由它來“代理”某些操作,ES6 原生提供 Proxy 構(gòu)造函數(shù),用來生成 Proxy 實例。我們來看看它的語法:

var?proxy =?new?Proxy(target, handler);

proxy 對象的所有用法,都是上面這種形式,不同的只是handler參數(shù)的寫法。其中,new Proxy()表示生成一個Proxy實例,target參數(shù)表示所要攔截的目標對象,handler參數(shù)也是一個對象,用來定制攔截行為。

var proxy = new Proxy({}, {get: function(obj, prop) { console.log('設置 get 操作') return obj[prop]; }, set: function(obj, prop, value) { console.log('設置 set 操作') obj[prop] = value; } }); proxy.time = 35; // 設置 set 操作 console.log(proxy.time); // 設置 get 操作 // 35

除了 get 和 set 之外,proxy 可以攔截多達 13 種操作,比如 has(target, propKey),可以攔截 propKey in proxy 的操作,返回一個布爾值。

// 使用 has 方法隱藏某些屬性,不被 in 運算符發(fā)現(xiàn) var handler = {has (target, key) {if (key[0] === '_') { return false; } return key in target; } }; var target = { _prop: 'foo', prop: 'foo' }; var proxy = new Proxy(target, handler); console.log('_prop' in proxy); // false

又比如說 apply 方法攔截函數(shù)的調(diào)用、call 和 apply 操作。

apply 方法可以接受三個參數(shù),分別是目標對象、目標對象的上下文對象(this)和目標對象的參數(shù)數(shù)組,不過這里我們簡單演示一下:

var target = function () { return 'I am the target'; }; var handler = { apply: function () { return 'I am the proxy'; } }; var p = new Proxy(target, handler); p(); // "I am the proxy"

又比如說 ownKeys 方法可以攔截對象自身屬性的讀取操作。具體來說,攔截以下操作:

  • Object.getOwnPropertyNames()
  • Object.getOwnPropertySymbols()
  • Object.keys()

下面的例子是攔截第一個字符為下劃線的屬性名,不讓它被 for of 遍歷到。

let target = {_bar: 'foo',_prop: 'bar', prop: 'baz' }; let handler = { ownKeys (target) { return Reflect.ownKeys(target).filter(key => key[0] !== '_'); } }; let proxy = new Proxy(target, handler); for (let key of Object.keys(proxy)) { console.log(target[key]); } // "baz"

更多的攔截行為可以查看阮一峰老師的?《ECMAScript 6 入門》

值得注意的是,proxy 的最大問題在于瀏覽器支持度不夠,而且很多效果無法使用 poilyfill 來彌補。

watch API 優(yōu)化

我們使用 proxy 再來寫一下 watch 函數(shù)。使用效果如下:

(function() {var root = this; function watch(target, func) { var proxy = new Proxy(target, { get: function(target, prop) { return target[prop]; }, set: function(target, prop, value) { target[prop] = value; func(prop, value); } }); if(target[name]) proxy[name] = value; return proxy; } this.watch = watch; })() var obj = { value: 1 } var newObj = watch(obj, function(key, newvalue) { if (key == 'value') document.getElementById('container').innerHTML = newvalue; }) document.getElementById('button').addEventListener("click", function() { newObj.value += 1 });

我們也可以發(fā)現(xiàn),使用 defineProperty 和 proxy 的區(qū)別,當使用 defineProperty,我們修改原來的 obj 對象就可以觸發(fā)攔截,而使用 proxy,就必須修改代理對象,即 Proxy 的實例才可以觸發(fā)攔截。

?


https://segmentfault.com/a/1190000016959805

轉(zhuǎn)載于:https://www.cnblogs.com/qdcnbj/p/9945390.html

與50位技術專家面對面20年技術見證,附贈技術全景圖

總結(jié)

以上是生活随笔為你收集整理的ES6-proxy的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。