|
導讀網頁的本質就是超級文本標記語言,通過結合使用其他的Web技術(如:腳本語言、公共網關接口、組件等),可以創(chuàng)造出功能強大的網頁。因而,超級文本標記語言是萬維網(Web)編程的基礎,也就是說萬維網是建立... 網頁的本質就是超級文本標記語言,通過結合使用其他的Web技術(如:腳本語言、公共網關接口、組件等),可以創(chuàng)造出功能強大的網頁。因而,超級文本標記語言是萬維網(Web)編程的基礎,也就是說萬維網是建立在超文本基礎之上的。超級文本標記語言之所以稱為超文本標記語言,是因為文本中包含了所謂“超級鏈接”點。 本篇文章給大家?guī)淼膬热菔顷P于ES6中defineProperty與proxy的詳細介紹(代碼示例),有一定的參考價值,有需要的朋友可以參考一下,希望對你有所幫助。我們或多或少都聽過“數據綁定”這個詞,“數據綁定”的關鍵在于監(jiān)聽數據的變化,可是對于這樣一個對象: definePropetyES5 提供了 Object.defineProperty 方法,該方法可以在一個對象上定義一個新屬性,或者修改一個對象的現有屬性,并返回這個對象。 語法 Object.defineProperty(obj, prop, descriptor) 參數 obj: 要在其上定義屬性的對象。 prop: 要定義或修改的屬性的名稱。 descriptor: 將被定義或修改的屬性的描述符。 舉個例子: var obj = {};
Object.defineProperty(obj, "num", {
value : 1,
writable : true,
enumerable : true,
configurable : true
});
// 對象 obj 擁有屬性 num,值為 1雖然我們可以直接添加屬性和值,但是使用這種方式,我們能進行更多的配置。 函數的第三個參數 descriptor 所表示的屬性描述符有兩種形式:數據描述符和存取描述符。 兩者均具有以下兩種鍵值: configurable 當且僅當該屬性的 configurable 為 true 時,該屬性描述符才能夠被改變,也能夠被刪除。默認為 false。 enumerable 當且僅當該屬性的 enumerable 為 true 時,該屬性才能夠出現在對象的枚舉屬性中。默認為 false。 數據描述符同時具有以下可選鍵值: value 該屬性對應的值。可以是任何有效的 JavaScript 值(數值,對象,函數等)。默認為 undefined。 writable 當且僅當該屬性的 writable 為 true 時,該屬性才能被賦值運算符改變。默認為 false。 存取描述符同時具有以下可選鍵值: get 一個給屬性提供 getter 的方法,如果沒有 getter 則為 undefined。該方法返回值被用作屬性值。默認為 undefined。 set 一個給屬性提供 setter 的方法,如果沒有 setter 則為 undefined。該方法將接受唯一參數,并將該參數的新值分配給該屬性。默認為 undefined。 值得注意的是: 屬性描述符必須是數據描述符或者存取描述符兩種形式之一,不能同時是兩者。這就意味著你可以: 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); // undefinedSetters 和 Getters之所以講到 defineProperty,是因為我們要使用存取描述符中的 get 和 set,這兩個方法又被稱為 getter 和 setter。由 getter 和 setter 定義的屬性稱做”存取器屬性“。 當程序查詢存取器屬性的值時,JavaScript 調用 getter方法。這個方法的返回值就是屬性存取表達式的值。當程序設置一個存取器屬性的值時,JavaScript 調用 setter 方法,將賦值表達式右側的值當做參數傳入 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)控數據改變的方法嗎?我們再來封裝一下: 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)控數據的改變,那我可以這樣設想,即當數據改變的時候,自動進行渲染工作。舉個例子: HTML 中有個 span 標簽和 button 標簽 <span id="container">1</span> <button id="button">點擊加 1</button> 當點擊按鈕的時候,span 標簽里的值加 1。 傳統的做法是: 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 的值就可以了。 然而,現在的寫法,我們還需要單獨聲明一個變量存儲 obj.value 的值,因為如果你在 set 中直接 var obj = {
value: 1
}
watch(obj, "num", function(newvalue){
document.getElementById('container').innerHTML = newvalue;
})
document.getElementById('button').addEventListener("click", function(){
obj.value += 1
});我們來寫下這個 watch 函數: (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;
})()現在我們已經可以監(jiān)控對象屬性值的改變,并且可以根據屬性值的改變,添加回調函數,棒棒噠~ proxy使用 defineProperty 只能重定義屬性的讀取(get)和設置(set)行為,到了 ES6,提供了 Proxy,可以重定義更多的行為,比如 in、delete、函數調用等更多行為。 Proxy 這個詞的原意是代理,用在這里表示由它來“代理”某些操作,ES6 原生提供 Proxy 構造函數,用來生成 Proxy 實例。我們來看看它的語法: var proxy = new Proxy(target, handler); proxy 對象的所有用法,都是上面這種形式,不同的只是handler參數的寫法。其中,new Proxy()表示生成一個Proxy實例,target參數表示所要攔截的目標對象,handler參數也是一個對象,用來定制攔截行為。 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ā)現
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 方法攔截函數的調用、call 和 apply 操作。 apply 方法可以接受三個參數,分別是目標對象、目標對象的上下文對象(this)和目標對象的參數數組,不過這里我們簡單演示一下: 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 方法可以攔截對象自身屬性的讀取操作。具體來說,攔截以下操作:
下面的例子是攔截第一個字符為下劃線的屬性名,不讓它被 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 函數。使用效果如下: (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ā)現,使用 defineProperty 和 proxy 的區(qū)別,當使用 defineProperty,我們修改原來的 obj 對象就可以觸發(fā)攔截,而使用 proxy,就必須修改代理對象,即 Proxy 的實例才可以觸發(fā)攔截。 以上就是ES6中defineProperty與proxy的詳細介紹(代碼示例)的詳細內容,更多請關注php中文網其它相關文章! 網站建設是一個廣義的術語,涵蓋了許多不同的技能和學科中所使用的生產和維護的網站。 |
溫馨提示:喜歡本站的話,請收藏一下本站!