摘要:需被定義或修改的屬性名。當且僅當該屬性出現在相應的對象枚舉屬性中。可以是任何有效的值數值,對象,函數等。方法將返回用作屬性的值。該方法將收到作為唯一參數的新值分配給屬性。屬性用來聲明欲修飾屬性是否可以被枚舉。
定義 getter 與 setter
通過對象初始化器定義
使用 Object.create 方法
使用 Object.defineProperty 方法
使用 Object.defineProperties 方法
使用 Object.prototype.__defineGetter__ 以及 Object.prototype.__defineSetter__ 方法
什么是屬性描述符
創建屬性不可配置不可枚舉的對象
Enumerable 特性
Configurable 特新
提高及擴展
定義 getter 與 setter
1.通過對象初始化器在創建對象的時候指明(也可以稱為通過字面值創建對象時聲明)
(function () { var o = { a : 7, get b(){return this.a +1;},//通過 get,set的 b,c方法間接性修改 a 屬性 set c(x){this.a = x/2} }; console.log(o.a); console.log(o.b); o.c = 50; console.log(o.a); })();
在 chrome 中調試視圖如下:
可以看到對象下多了 get 屬性以及 set 屬性
輸出結果如下:
當然 get 語句與 set 語句可以聲明多次用來對應多個 getter 和 setter
使用這種方法的好處是可以在聲明屬性的時候同時聲明對應的 getter 和 setter
這里就有人問了,能不能將o 對象的 get 及 set 方法的方法名都改成 “a”,這樣就可以直接通過“.”來訪問方法直接操作
(function () { var o = { a : 7, get a(){return this.a +1;},//死循環 set a(x){this.a = x/2} }; console.log(o.a); console.log(o.b); o.c = 50; console.log(o.a); })();
打開 chrome 查看創建后的視圖如下:
可以看到這個時候的 get 與 set 方法已經和上面不同,但是是否真的能起作用呢,答案是否定的,當我們通過 o.a 調用的是 get語句 聲明的 a方法,進入到該方法后遇到 this.a 方法繼續調用該方法形成死循環最終導致死循環報內存溢出錯誤。
新語法(ES6):暫時只有 firefox 支持,其他瀏覽器會報錯
(function () { var b = "bb"; var c = "cc"; var o = { a : 7, get [b](){return this.a +1;}, set [c](x){this.a = x/2}, }; console.log(o.a); console.log(o[b]); o["cc"] = 50; console.log(o.a); })();
打開 firefox 查看調試:
輸出結果如下:
2.使用 Object.create 方法
引用 MDN:
概述 Object.create() 方法創建一個擁有指定原型和若干個指定屬性的對象。 語法 Object.create(proto, [ propertiesObject ])
我們都知道使用 Object.create 方法傳遞一個參數的時候可以創建一個以該參數為原型的對象 淺談 JS 創建對象的 8 種模式
第二個參數是可選項,是一個匿名的參數對象,該參數對象是一組屬性與值,該對象的屬性名稱將是新創建的對象的屬性名稱,值是屬性描述符(包擴數據描述符或存取描述符,具體解釋看后面的內容 什么是屬性描述符)。
通過屬性描述符我們可以實現為新創建的對象添加 get 方法以及 set 方法
(function () { var o = null; o = Object.create(Object.prototype,//指定原型為 Object.prototype { bar:{ get :function(){ return 10; }, set : function (val) { console.log("Setting `o.bar` to ",val); } } }//第二個參數 ); console.log(o.bar); o.bar = 12; })();
在 chrome 中調試試圖如下:
可以看到新創建對象通用多了 get 以及 set 屬性
輸出結果如下:
上面這個例子并沒有用來針對的 get 方法以及 set 方法使用的屬性
(function () { var o = null; o = Object.create(Object.prototype,//指定原型為 Object.prototype { bar:{ get :function(){ return this.a; }, set : function (val) { console.log("Setting `o.bar` to ",val); this.a = val; }, configurable :true } }//第二個參數 ); o.a = 10; console.log(o.bar); o.bar = 12; console.log(o.bar); })();
亦或:
(function () { var o = {a:10}; o = Object.create(o,//指定原型為 o 這里實際可以理解為繼承 { bar:{ get :function(){ return this.a; }, set : function (val) { console.log("Setting `o.bar` to ",val); this.a = val; }, configurable :true } }//第二個參數 ); console.log(o.bar); o.bar = 12; console.log(o.bar); })();
輸出結果如下:
使用這種方式的好處是可配置性高,但初學者容易迷糊。
3.使用 Object.defineProperty 方法
引用 MDN:
概要 Object.defineProperty() 方法直接在一個對象上定義一個新屬性,或者修改一個已經存在的屬性, 并返回這個對象。 語法 Object.defineProperty(obj, prop, descriptor) 參數 obj 需要定義屬性的對象。 prop 需被定義或修改的屬性名。 descriptor 需被定義或修改的屬性的描述符。
(function () { var o = { a : 1}//聲明一個對象,包含一個 a 屬性,值為1 Object.defineProperty(o,"b",{ get: function () { return this.a; }, set : function (val) { this.a = val; }, configurable : true }); console.log(o.b); o.b = 2; console.log(o.b); })();
這個方法與前面兩種的區別是:使用前面兩種只能在聲明定義的時候指定 getter 與 setter,使用該方法可以隨時的添加或修改。
如果說需要一次性批量添加 getter 與 setter 也是沒問題的,使用如下方法:
4.使用 Object.defineProperties方法
MDN:
概述 Object.defineProperties() 方法在一個對象上添加或修改一個或者多個自有屬性,并返回該對象。 語法 Object.defineProperties(obj, props) 參數 obj 將要被添加屬性或修改屬性的對象 props 該對象的一個或多個鍵值對定義了將要為對象添加或修改的屬性的具體配置
不難看出用法與 Object.defineProperty 方法類似
(function () { var obj = {a:1,b:"string"}; Object.defineProperties(obj,{ "A":{ get:function(){return this.a+1;}, set:function(val){this.a = val;} }, "B":{ get:function(){return this.b+2;}, set:function(val){this.b = val} } }); console.log(obj.A); console.log(obj.B); obj.A = 3; obj.B = "hello"; console.log(obj.A); console.log(obj.B); })();
輸出結果如下:
5.使用 Object.prototype.__defineGetter__ 以及 Object.prototype.__defineSetter__ 方法
(function () { var o = {a:1}; o.__defineGetter__("giveMeA", function () { return this.a; }); o.__defineSetter__("setMeNew", function (val) { this.a = val; }) console.log(o.giveMeA); o.setMeNew = 2; console.log(o.giveMeA); })(); 輸出結果為1和2
查看 MDN 有如下說明:
什么是屬性描述符
MDN:
對象里目前存在的屬性描述符有兩種主要形式:數據描述符和存取描述符。
數據描述符是一個擁有可寫或不可寫值的屬性。
存取描述符是由一對 getter-setter 函數功能來描述的屬性。
描述符必須是兩種形式之一;不能同時是兩者。
數據描述符和存取描述符均具有以下可選鍵值:
configurable 當且僅當這個屬性描述符值為 true 時,該屬性可能會改變,也可能會被從相應的對象刪除。默認為 false。 enumerable true 當且僅當該屬性出現在相應的對象枚舉屬性中。默認為 false。
數據描述符同時具有以下可選鍵值:
value 與屬性相關的值??梢允侨魏斡行У?JavaScript 值(數值,對象,函數等)。默認為 undefined。 writable true 當且僅當可能用 賦值運算符 改變與屬性相關的值。默認為 false。
存取描述符同時具有以下可選鍵值:
get 一個給屬性提供 getter 的方法,如果沒有 getter 則為 undefined。方法將返回用作屬性的值。默認為 undefined。 set 一個給屬性提供 setter 的方法,如果沒有 setter 則為 undefined。該方法將收到作為唯一參數的新值分配給屬性。默認為 undefined。
以上是摘自MDN的解釋,看起來是很晦澀的,具體什么意思呢:
首先我們從以上解釋知道該匿名參數對象有個很好聽的名字叫屬性描述符,屬性描述符又分成兩大塊:數據描述符以及存取描述符(其實只是一個外號,給指定的屬性集合起個外號)。
數據描述符包括兩個屬性 : value 屬性以及 writable 屬性,第一個屬性用來聲明當前欲修飾的屬性的值,第二個屬性用來聲明當前對象是否可寫即是否可以修改
存取描述符就包括 get 與 set 屬性用來聲明欲修飾的象屬性的 getter 及 setter
屬性描述符內部,數據描述符與存取描述符只能存在其中之一,但是不論使用哪個描述符都可以同時設置 configurable 屬性以及enumerable 屬性。
configurable屬性用來聲明欲修飾的屬性是否能夠配置,僅有當其值為 true 時,被修飾的屬性才有可能能夠被刪除,或者重新配置。
enumerable 屬性用來聲明欲修飾屬性是否可以被枚舉。
知道了什么是屬性描述符,我們就可以開始著手創建一些對象并開始配置其屬性
創建屬性不可配置不可枚舉的對象
//使用默認值配置 (function () { var obj = {};//聲明一個空對象 Object.defineProperty(obj,"key",{ value:"static" //沒有設置 enumerable 使用默認值 false //沒有 configurable 使用默認值 false //沒有 writable 使用默認值 false }); console.log(obj.key); //輸出 “static” obj.key = "new" //嘗試修改其值,修改將失敗,因為 writable 為 false console.log(obj.key); //輸出 “static” obj.a = 1;//動態添加一個屬性 for(var item in obj){ //遍歷所有 obj 的可枚舉屬性 console.log(item); }//只輸出一個 “a” 因為 “key”的 enumerable為 false })();
//顯示配置 等價于上面 (function () { var obj = {}; Object.defineProperty(obj,"key",{ enumerable : false, configurable : false, writable : false, value : "static" }) })();
//等價配置 (function () { var o = {}; o.a = 1; //等價于 Object.defineProperty(o,"a",{value : 1, writable : true, configurable : true, enumerable : true}); Object.defineProperty(o,"a",{value :1}); //等價于 Object.defineProperty(o,"a",{value : 1, writable : false, configurable : false, enumerable : false}); })();
Enumerable 特性
屬性特性 enumerable 決定屬性是否能被 for...in 循環或 Object.keys 方法遍歷得到
(function () { var o = {}; Object.defineProperty(o,"a",{value :1,enumerable :true}); Object.defineProperty(o,"b",{value :2,enumerable :false}); Object.defineProperty(o,"c",{value :2});//enumerable default to false o.d = 4;//如果直接賦值的方式創建對象的屬性,則這個屬性的 enumerable 為 true for(var item in o){ //遍歷所有可枚舉屬性包括繼承的屬性 console.log(item); } console.log(Object.keys(o));//獲取 o 對象的所有可遍歷屬性不包括繼承的屬性 console.log(o.propertyIsEnumerable("a"));//true console.log(o.propertyIsEnumerable("b"));//false console.log(o.propertyIsEnumerable("c"));//false })();
輸出結果如下:
Configurable 特性
(function () { var o = {}; Object.defineProperty(o,"a",{get: function () {return 1;}, configurable : false} ); //enumerable 默認為 false, //value 默認為 undefined, //writable 默認為 false, //set 默認為 undefined //拋出異常,因為最開始定義了 configurable 為 false,故后期無法對其進行再配置 Object.defineProperty(o,"a",{configurable : true} ); //拋出異常,因為最開始定義了 configurable 為 false,故后期無法對其進行再配置,enumerable 的原值為 false Object.defineProperty(o,"a",{enumerable : true} ); //拋出異常,因為最開始定義了 configurable 為 false,set的原值為 undefined Object.defineProperty(o,"a",{set : function(val){}} ); //拋出異常,因為最開始定義了 configurable 為 false,故無法進行覆蓋,盡管想用一樣的來覆蓋 Object.defineProperty(o,"a",{get : function(){return 1}}); //拋出異常,因為最開始定義了 configurable 為 false,故無法將其進行重新配置把屬性描述符從存取描述符改為數據描述符 Object.defineProperty(o,"a",{value : 12}); console.log(o.a);//輸出1 delete o.a; //想要刪除屬性,將失敗 console.log(o.a);//輸出1 })();
提高及擴展
1.屬性描述符中容易被誤導的地方之 writable 與 configurable
(function () { var o = {}; Object.defineProperties(o,{ "a": { value:1, writable:true,//可寫 configurable:false//不可配置 //enumerable 默認為 false 不可枚舉 }, "b":{ get :function(){ return this.a; }, configurable:false } }); console.log(o.a); //1 o.a = 2; //修改值成功,writable 為 true console.log(o.a); //2 Object.defineProperty(o,"a",{value:3});//同樣為修改值成功 console.log(o.a); //3 //將其屬性 b 的屬性描述符從存取描述符重新配置為數據描述符 Object.defineProperty(o,"b",{value:3});//拋出異常,因為 configurable 為 false })();
2.通過上面的學習,我們都知道傳遞屬性描述符參數時,是定義一個匿名的對象,里面包含屬性描述符內容,若每定義一次便要創建一個匿名對象傳入,將會造成內存浪費。故優化如下:
(function () { var obj = {}; //回收同一對象,即減少內存浪費 function withValue(value){ var d = withValue.d ||( withValue.d = { enumerable : false, configurable : false, writable : false, value :null } ); d.value = value; return d; } Object.defineProperty(obj,"key",withValue("static")) })();
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/86080.html
摘要:嘗試刪除一個密封對象的屬性或者將某個密封對象的屬性從數據屬性轉換成訪問器屬性,結果會靜默失敗或拋出異常嚴格模式。 擴展特性 Object.isExtensible 方法 Object.preventExtensions 方法 密封特性 Object.isSealed 方法 Object.seal 方法 凍結特性 Object.isFrozen 方法 Object...
摘要:通過對返回字符串切片第位到倒數第位即可獲得對象的類型。測試對象是的深拷貝是的子集,不能表示中所有值。序列化結果是,對象序列化結果是日期字符串不能表示函數對象和只能序列化對象自有的可枚舉屬性。 對象 對象是JavaScript的基本數據類型:屬性的無序集合。每個屬性key: value和屬性描述符descripter組成。 屬性名key:字符串或合法的變量標識符; 屬性值value:...
摘要:對象是的數據類型。對象是動態的,可以隨時新增和刪除自有屬性??蛻舳酥斜硎揪W頁結構的對象均是宿主對象。提供第二個可選參數,用以對對象的屬性進行進一步描述。沒有原型的對象為數不多,就是其中之一。運算符的左側是屬性名字符串,右側是對象。 對象是 JavaScript 的數據類型。它將很多值(原始值或者其他對象)聚合在一起,可通過名字訪問這些值,因此我們可以把它看成是從字符串到值的映射。對象是...
摘要:屬性名可以是包含空字符串在內的任意字符串,但對象中不能存在兩個同名的屬性。客戶端中表示網頁結構的對象均是宿主對象。這里的函數稱做構造函數,構造函數用以初始化一個新創建的對象。通過關鍵字和構造函數調用創建的對象的原型就是構造函數的屬性的值。 對象是 JavaScript 的數據類型。它將很多值(原始值或者其他對象)聚合在一起,可通過名字訪問這些值,因此我們可以把它看成是從字符串到值的映射...
摘要:屬性描述符升級打怪必備技能對象有自己的屬性和方法,對于我們對象的屬性來講,屬性還有自己的屬性,又稱為屬性描述符。這個方法接受三個參數,第一個是指定的對象,第二個是指定的對象參數,第三個當然是要修改的屬性描述符了。 對象的聲明有倆種: 字面量 通過new一個構造函數Object 兩者唯一的區別就是,字面量形式,可以一次賦值多個,通過new Object就得一個一個賦值 數據類型 ...
閱讀 3527·2021-10-09 09:41
閱讀 2733·2021-10-08 10:18
閱讀 2164·2021-09-10 10:51
閱讀 2668·2021-09-10 10:50
閱讀 763·2021-09-09 09:33
閱讀 3369·2021-09-06 15:14
閱讀 3002·2019-08-30 11:06
閱讀 3230·2019-08-29 14:04