ECMA-262定义了内部才用的特性是为了实现JavaScript引擎用的,因此在JS中不能直接访问它们。
数据属性
可以获取和设置值的属性
数据属性包含了一个数据值的位置,在这个位置可以读取和写入值。也就是说,数据属性可以通过 对象.属性 访问,就是我么平常接触的用户赋什么值,它们就返回什么,不会做额外的事情。
数据属性有4个描述其行为的特性(为了表示内部值,把属性放在两对方括号中),称为描述符对象。
属性 | 解释 | 默认值 |
---|---|---|
[[Configurable]] | 能否通过delete删除属性从而重新定义属性; 能否修改属性的特性; 能否把属性修改为访问器属性 | true |
[[Enumerable]] | 能否通过for-in循环返回属性 | true |
[[Writable]] | 能否修改属性的值 | true |
[[Value]] | 包含这个属性的数据值 | undefined |
通过上述属性的默认值我们能看出我们能直接修改数据属性的属性特性,能用for-in循环返回属性,能修改属性的值,用undefined定义没有属性的数据值。这符合我们平常对对象属性的操作。
例子:
var person = {};
person.name='grace';
person.age=18;
console.log(person.name,person.age); //结果:'grace 18'
person.name='alice';
console.log(person.name,person.age); //结果:'alice 18'
但是如果已经给person.name赋过值了,我不希望再有人更改这个名字,因此需要调用person对象的内部属性,来控制对这个属性的操作权限。
要修改属性默认的特性,必须使用EM5的Object.defineProperty()方法。
格式
Object.defineProperty(属性所在的对象,属性的名字,一个描述符对象); //可以创建数据属性(并设定其内部属性)
例子:设定名字属性不可修改
var person={};
Object.defineProperty(person,"name",{
writable:false, //将能否修改属性的值设置为false,意思是不能修改person的name属性
value:'grace' //将person的name默认属性设置为grace
})
person.age=18;
console.log(person.name,person.age); //结果:'grace 18'
person.name='alice';
person.age=16;
console.log(person.name,person.age); //结果:'grace 16' 此时无法修改name属性值
访问器属性
允许用户在赋值或取值都经过预先设定的函数,从而实现内部属性的那一种特殊效果
访问器属性不包含数据值,他们有一对儿getter和setter函数(不过这两个函数不是必须的)。
- 在读取访问器属性时,会调用getter函数,这个函数负责返回有效的值。
- 在写入访问器属性时,会调用setter函数,这个函数负责决定如何处理数据。
访问器属性有如下4个特性:
属性 | 解释 | 默认值 |
---|---|---|
[[Configurable]] | 能否通过delete删除属性从而重新定义属性; 能否修改属性的特性; 能否把属性修改为数据属性 | true |
[[Enumerable]] | 能否通过for-in循环返回属性 | true |
[[Get]] | 在读取属性时调用的函数 | undefined |
[[Set]] | 在写入属性时调用的函数 | undefined |
要修改属性默认的特性,必须使用EM5的Object.defineProperty()方法。
格式
Object.defineProperty(属性所在的对象,属性的名字,一个描述符对象); //也可以创建访问器属性
例子
var book = {
_year : 2004,
edition : 1
};
Object.defineProperty(book,"year",{
get : function () {
alert(this._year);
},
set : function (newValue) {
if (newValue > 2004) {
this._year = newValue;
this.edition += newValue - 2004;
}
}
});
book.year; // 结果:2004
book.year = 2005; //设置的属性要和defineProperty()函数里面的属性相同
console.log(book.edition); // 结果:2
year 是 book 对象一个访问器属性。直接调用 book.year,即调用了这个访问器属性中定义的 get 方法(读取属性时调用),返回 book._year 这个数据属性。如果给 book.year 赋值,就是调用了这个访问器属性中定义的 set 方法(在写入属性时调用)。此时判断2005>2004,if条件为true,继续执行更改了_year属性值和edition属性值。
结论:数据属性不仅可以直接访问,也可以通过定义的访问器来专门访问。
定义多个属性
由于为对象定义多个属性的可能性很大,ECMAScript 5又定义了一个Object.defineProperties()方法。
格式
Object.defineProperties(添加和修改其属性的对象,{具体的属性})
例子:
var book={};
Object.defineProperties(book,{
_year:{
writable: true,
value: 2004
},
edition:{
writable: true,
value: 1
},
year: {
get: function(){
return this._year;
},
set: function(newValue){
if (newValue>2004){
this._year = newValue;
this.edition += newValue - 2004;
}
}
})
以上代码在book对象上定义了两个数据属性(_year和 edition)和一个访问器属性(year)。
读取属性的特性
使用ECMAScript 5的Object.getOwnPropertyDescriptor()方法,可以取得给定属性的描述符。
格式
Object.getOwnPropertyDescriptor(属性所在的对象,要读取其描述符的属性名称) //返回值是一个对象
参考文献:
https://www.zhihu.com/question/40648241?from=profile_question_card
https://segmentfault.com/q/1010000002664970