Object.defineProperty和Object.defineProperties()

概述

JavaScript提供了一個內部數(shù)據(jù)結構蚕甥,用來描述一個對象的屬性的行為却妨,控制它的行為耗帕。這被稱為“屬性描述對象”(attributes object)另玖。每個屬性都有自己對應的屬性描述對象佣赖,保存該屬性的一些元信息恰矩。

下面是屬性描述對象的一個實例。

{
  value: 123,
  writable: false,
  enumerable: true,
  configurable: false,
  get: undefined,
  set: undefined
}

屬性描述對象提供6個元屬性憎蛤。

  • (1)value

value存放該屬性的屬性值外傅,默認為undefined。

  • (2)writable

writable存放一個布爾值俩檬,表示屬性值(value)是否可改變萎胰,默認為true。

  • (3)enumerable

enumerable存放一個布爾值棚辽,表示該屬性是否可枚舉技竟,默認為true。如果設為false屈藐,會使得某些操作(比如for...in循環(huán)榔组、Object.keys())跳過該屬性。

  • (4)configurable

configurable存放一個布爾值联逻,表示“可配置性”搓扯,默認為true。如果設為false包归,將阻止某些操作改寫該屬性锨推,比如,無法刪除該屬性,也不得改變該屬性的屬性描述對象(value屬性除外)爱态。也就是說谭贪,configurable屬性控制了屬性描述對象的可寫性。

  • (5)get

get存放一個函數(shù)锦担,表示該屬性的取值函數(shù)(getter)俭识,默認為undefined。

  • (6)set

set存放一個函數(shù)洞渔,表示該屬性的存值函數(shù)(setter)套媚,默認為undefined。


Object.getOwnPropertyDescriptor()

Object.getOwnPropertyDescriptor()方法可以讀出對象自身屬性的屬性描述對象磁椒。

var o = { p: 'a' };

Object.getOwnPropertyDescriptor(o, 'p')
// Object { value: "a",
//   writable: true,            默認都是true
//   enumerable: true,
//   configurable: true
// }

上面代碼表示堤瘤,使用Object.getOwnPropertyDescriptor()方法,讀取o對象的p屬性的屬性描述對象浆熔。


Object.defineProperty()本辐,Object.defineProperties()

Object.defineProperty()方法允許通過定義屬性描述對象,來定義或修改一個屬性医增,然后返回修改后的對象慎皱。它的格式如下。

Object.defineProperty(object, propertyName, attributesObject)

上面代碼中叶骨,Object.defineProperty()方法接受三個參數(shù):

  • 第一個是屬性所在的對象茫多,
  • 第二個是屬性名(它應該是一個字符串),
  • 第三個是屬性的描述對象忽刽。比如天揖,新建一個o對象,并定義它的p屬性跪帝,寫法如下今膊。
var o = Object.defineProperty({}, 'p', {
  value: 123,
  writable: false,
  enumerable: true,
  configurable: false
});

o.p
// 123

o.p = 246;
o.p
// 123
// 因為writable為false,所以無法改變該屬性的值

如果屬性已經存在伞剑,Object.defineProperty()方法相當于更新該屬性的屬性描述對象万细。
需要注意的是,Object.defineProperty方法和后面的Object.defineProperties方法纸泄,都有性能損耗,會拖慢執(zhí)行速度腰素,不宜大量使用聘裁。
如果一次性定義或修改多個屬性,可以使用Object.defineProperties()方法弓千。

var o = Object.defineProperties({}, {
  p1: { value: 123, enumerable: true },
  p2: { value: 'abc', enumerable: true },
  p3: { get: function () { return this.p1 + this.p2 },
    enumerable:true,
    configurable:true
  }
});

o.p1 // 123
o.p2 // "abc"
o.p3 // "123abc"

上面代碼中的p3屬性衡便,定義了取值函數(shù)get。這時需要注意的是,一旦定義了取值函數(shù)get(或存值函數(shù)set)镣陕,就不能將writable設為true谴餐,或者同時定義value屬性會報錯呆抑。

var o = {};

Object.defineProperty(o, 'p', {
  value: 123,
  get: function() { return 456; }
});
//上面代碼同時定義了get屬性和value屬性岂嗓,結果就報錯。
// TypeError: Invalid property.  無效的屬性
// A property cannot both have accessors and be writable or have a value,  一個屬性不能同時有訪問器和可寫值或者value值
Object.defineProperty()Object.defineProperties()的第三個參數(shù)鹊碍,是一個屬性對象厌殉。它的writable、configurable侈咕、enumerable這三個屬性的默認值都為false
var o = {};

Object.defineProperty(o, 'p', {
  value: "bar"
});

o.p // bar

o.p = 'foobar';
o.p // bar

Object.defineProperty(o, 'p', {
  value: 'foobar',
});
// TypeError: Cannot redefine property: p 不能重新定義P屬性公罕;

上面代碼由于writable屬性默認為false,導致無法對p屬性重新賦值耀销;

configurable屬性為false楼眷,將無法刪除該屬性,也無法修改attributes對象(value屬性除外)熊尉。

var o = {};

Object.defineProperty(o, 'p', {
  value: 'bar',
});

delete o.p
o.p // "bar"

上面代碼中罐柳,由于configurable屬性默認為false,導致無法刪除某個屬性帽揪。

enumerable屬性為false硝清,表示對應的屬性不會出現(xiàn)在for...in循環(huán)和Object.keys方法中。

var o = {
  p1: 10,
  p2: 13,
};

Object.defineProperty(o, 'p3', {
  value: 3,
});

for (var i in o) {
  console.log(i, o[i]);
}
// p1 10
// p2 13

上面代碼中转晰,p3屬性是用Object.defineProperty方法定義的芦拿,由于enumerable屬性默認為false,所以不出現(xiàn)在for...in循環(huán)中查邢。

可枚舉性(enumerable)用來控制所描述的屬性蔗崎,是否將被包括在for...in循環(huán)之中。具體來說扰藕,如果一個屬性的enumerable為false缓苛,下面三個操作不會取到該屬性。

  • for..in循環(huán)
  • Object.keys方法
  • JSON.stringify方法
    因此邓深,enumerable可以用來設置“秘密”屬性未桥。
var o = {a: 1, b: 2};

o.c = 3;
Object.defineProperty(o, 'd', {
  value: 4,
  enumerable: false
});

o.d // 4

for (var key in o) {
  console.log(o[key]);
}
// 1
// 2
// 3

Object.keys(o)  // ["a", "b", "c"]

JSON.stringify(o) // "{a:1, b:2, c:3}"

上面代碼中,d屬性的enumerablefalse芥备,所以一般的遍歷操作都無法獲取該屬性冬耿,使得它有點像“秘密”屬性,但不是真正的私有屬性萌壳,還是可以直接獲取它的值亦镶。

基本上日月,JavaScript原生提供的屬性都是不可枚舉的,用戶自定義的屬性都是可枚舉的缤骨。

可配置性(configurable)
可配置性(configurable)決定了是否可以修改屬性描述對象爱咬。也就是說,當configurable為false的時候绊起,value精拟、writable、enumerable和configurable都不能被修改了勒庄。

var o = Object.defineProperty({}, 'p', {
  value: 1,
  writable: false,
  enumerable: false,
  configurable: false
});

Object.defineProperty(o,'p', {value: 2})
// TypeError: Cannot redefine property: p

Object.defineProperty(o,'p', {writable: true})
// TypeError: Cannot redefine property: p

Object.defineProperty(o,'p', {enumerable: true})
// TypeError: Cannot redefine property: p

Object.defineProperties(o,'p',{configurable: true})
// TypeError: Cannot redefine property: p

上面代碼首先定義對象o串前,并且定義o的屬性p的configurable為false。然后实蔽,逐一改動value荡碾、writable、enumerable局装、configurable坛吁,結果都報錯。

存取器(accessor)
除了直接定義以外铐尚,屬性還可以用存取器(accessor)定義拨脉。

其中:
存值函數(shù)稱為setter,使用set命令宣增;
取值函數(shù)稱為getter玫膀,使用get命令。

存取器提供的是虛擬屬性爹脾,即該屬性的值不是實際存在的帖旨,而是每次讀取時計算生成的。利用這個功能灵妨,可以實現(xiàn)許多高級特性解阅,比如每個屬性禁止賦值。

var o = {
  get p() {
    return 'getter';
  },
  set p(value) {
    console.log('setter: ' + value);
  }
};
o.p // "getter"
o.p = 123 // "setter: 123"

注意泌霍,取值函數(shù)Getter不能接受參數(shù)货抄,存值函數(shù)Setter只能接受一個參數(shù)(即屬性的值)。另外朱转,對象也不能有與取值函數(shù)同名的屬性蟹地。比如,上面的對象o設置了取值函數(shù)p以后藤为,就不能再另外定義一個p屬性锈津。

利用存取器,可以實現(xiàn)數(shù)據(jù)對象與DOM對象的雙向綁定凉蜂。

Object.defineProperty(user, 'name', {
  get: function () {
    return document.getElementById('foo').value;
  },
  set: function (newValue) {
    document.getElementById('foo').value = newValue;
  },
  configurable: true
});

上面代碼使用存取函數(shù),將DOM對象foo與數(shù)據(jù)對象user的name屬性,實現(xiàn)了綁定窿吩。兩者之中只要有一個對象發(fā)生變化茎杂,就能在另一個對象上實時反映出來。

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末纫雁,一起剝皮案震驚了整個濱河市煌往,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌轧邪,老刑警劉巖刽脖,帶你破解...
    沈念sama閱讀 211,194評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異忌愚,居然都是意外死亡曲管,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評論 2 385
  • 文/潘曉璐 我一進店門硕糊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來院水,“玉大人,你說我怎么就攤上這事简十∶誓常” “怎么了?”我有些...
    開封第一講書人閱讀 156,780評論 0 346
  • 文/不壞的土叔 我叫張陵螟蝙,是天一觀的道長恢恼。 經常有香客問我,道長胰默,這世上最難降的妖魔是什么场斑? 我笑而不...
    開封第一講書人閱讀 56,388評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮初坠,結果婚禮上和簸,老公的妹妹穿的比我還像新娘。我一直安慰自己碟刺,他們只是感情好锁保,可當我...
    茶點故事閱讀 65,430評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著半沽,像睡著了一般爽柒。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上者填,一...
    開封第一講書人閱讀 49,764評論 1 290
  • 那天浩村,我揣著相機與錄音,去河邊找鬼占哟。 笑死心墅,一個胖子當著我的面吹牛酿矢,可吹牛的內容都是我干的。 我是一名探鬼主播怎燥,決...
    沈念sama閱讀 38,907評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼瘫筐,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了铐姚?” 一聲冷哼從身側響起策肝,我...
    開封第一講書人閱讀 37,679評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎隐绵,沒想到半個月后之众,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 44,122評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡依许,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,459評論 2 325
  • 正文 我和宋清朗相戀三年棺禾,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片悍手。...
    茶點故事閱讀 38,605評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡帘睦,死狀恐怖,靈堂內的尸體忽然破棺而出坦康,到底是詐尸還是另有隱情竣付,我是刑警寧澤,帶...
    沈念sama閱讀 34,270評論 4 329
  • 正文 年R本政府宣布滞欠,位于F島的核電站古胆,受9級特大地震影響,放射性物質發(fā)生泄漏筛璧。R本人自食惡果不足惜逸绎,卻給世界環(huán)境...
    茶點故事閱讀 39,867評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望夭谤。 院中可真熱鬧棺牧,春花似錦、人聲如沸朗儒。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽醉锄。三九已至乏悄,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間恳不,已是汗流浹背檩小。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留烟勋,地道東北人规求。 一個月前我還...
    沈念sama閱讀 46,297評論 2 360
  • 正文 我出身青樓筐付,卻偏偏與公主長得像,于是被迫代替她去往敵國和親颓哮。 傳聞我的和親對象是個殘疾皇子家妆,可洞房花燭夜當晚...
    茶點故事閱讀 43,472評論 2 348

推薦閱讀更多精彩內容

  • 函數(shù)和對象 1、函數(shù) 1.1 函數(shù)概述 函數(shù)對于任何一門語言來說都是核心的概念冕茅。通過函數(shù)可以封裝任意多條語句,而且...
    道無虛閱讀 4,543評論 0 5
  • 對象屬性的特性描述符蛹找,可以理解為對象屬性的屬性姨伤。 一個對象屬性有上面這些屬性,其中value庸疾,和get乍楚,set是用...
    wangxia34閱讀 957評論 0 1
  • 來自:參 考 原 文 對象是由多個名/值對組成的無序的集...
    wyude閱讀 1,245評論 1 7
  • 以下內容出自其他博主 對象是由多個名/值對組成的無序的集合徒溪。對象中每個屬性對應任意類型的值。 定義對象可以使用構造...
    rookie_簡書閱讀 939評論 0 1
  • 概述 JavaScript提供了一個內部數(shù)據(jù)結構金顿,用來描述一個對象的屬性的行為臊泌,控制它的行為。這被稱為“屬性描述對...
    zjh111閱讀 724評論 0 0