静态方法:Object.defineProperty();Object.defineProperties();
Object.defineProperty(obj, prop, descriptor)
参数1: 需要添加属性的对象 (一个对象)
参数2: 要添加属性名 (字符串)
参数3: 描述符. 对要添加的属性设置一些特性 (一个对象)
返回值: 参数1传递过去那个对象.
面向对象高级知识加强
一、对象的属性的特性
JavaScript中的属性一共分两种:
- 数据属性。 比如我我们以前接触到的属性都属于数据属性。
- 访问器属性。访问器属性不包含数据值。包含一堆setter和getter函数。
1.1 数据属性
比如我们以前自定义的属性都是数据属性。数据属性包含一个数据值的位置,在这个位置可以读取和写入值。
有4个特性来描述每一个数据属性:
- [[Configurable]]:表示能否通过 delete 删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性。像我们以前自定义的属性,它们的这个特性默认值为 true。
- [[Enumerable]]:表示能否通过 for-in 循环返回属性。我们以前自定义的属性,它们的这个特性默认值为 true。
- [[Writable]]:表示能否修改属性值。我们以前自定义的属性,默认值都是true
- [[value]]:包含这个属性的值。读取属性的时候从这个地方读,写入属性的值的时候会写入到这个值中。这个特性的默认值是undefined。
看下面的代码:
var p = {
name = "lisi"
}
在上面的代码中创建了一个对象p,p有一个属性name,则name属性就有了4个上面说的特性。[[Configurable]]、[[Enumerable]]、[[Writable]]这个3个特性都是默认值。
[[value]]的值被修改为 'lisi'。 以后不管去获取值或者修改name属性的的值都是从这个对这个特性进行操作的。
要修改数据属性的特性的值,则创建对象的属性的时候就不能像以前那样去创建。必须使用ES5提供的心的方法:Object.defineProperty()
Object.definePropery() :这个方法接受三个参数
- 属性所在的对象。 也就是你要把属性添加到那个对象上。
- 属性名。 要添加的属性的名字
- 描述符对象。 就是对这个属性的四个特性进行描述的对象。
<script type="text/javascript">
"use strict"
var person = {
};
Object.defineProperty(person, "name", {
writable : false,
value:"lisi"
})
console.log(person.name);
//因为name属性是不可修改的(只读),所以此处不会起作用。
//非严格模式没有任何反应,严格模式下会抛出异常。
person.name = "zhangsan";
console.log(person.name);
</script>
类似的规则也适用其他其他特性。
<script type="text/javascript">
var a = {};
Object.defineProperty(a, "name", {
value : "李四", // 要添加的属性的属性值. 默认值是undefined
enumerable : true, // 是否可枚举,表示使用for in是否可以访问到. 默认是false.
writable : true, // 是否可写. 表示是否可以修改这个属性的值 默认是false
configurable : false // 是否可配置 表示是否可以更改描述符中的值或是否可以删除这个属性的值 默认是false
});
</script>
注意:在调用Object.definePropery()方法时,如果不指定,则configurable、enumerable 和 writable特性的默认值都是 false。
绝大部分情况下,我们都不需要使用这个种方式定义属性。
1.2 访问器属性
访问器属性不包含数据值;它们包含一对儿 getter 和 setter 函数(不过,这两个函数都不是必需的)。
在读取访问器属性时,会调用 getter 函数,这个函数 返回有效的值;
在写入访问器属性时,会调用setter 函数并传入新值,这个函数 决定如何处理数据。
访问器属性有如下 4 个特性:
- [[Configurable]]:表示能否通过 delete 删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为数据属性。对于直接在对象上定义的属性,这个特性的默认值为true。
- [[Enumerable]]:表示能否通过 for-in 循环返回属性。对于直接在对象上定义的属性,这 个特性的默认值为 true。
- [[Get]]:在读取属性时调用的函数。默认值为 undefined。
- [[Set]]:在写入属性时调用的函数。默认值为 undefined。
注意:访问器属性不能直接定义,只能通过Object.definePropery()方法定义。
<script type="text/javascript">
var book = {
//这个属性用下划线开头表示一种约定:不要直接访问这个属性,用方法访问。
_year: 2004,
edition: 1
}
//定义一个访问器属性.他的configurable 是false。 enumerable也是false
Object.defineProperty(book, "year", {
//访问属性year的时候会调用这个方法
get: function () {
return this._year;
},
//修改访问器属性的时候会调用这个方法
set: function (newValue) {
if (newValue > 2004) {
this._year = newValue;
this.edition += newValue - 2004;
}
}
});
console.log(book.year) // 2004
book.year = 2005;
console.log(book.edition); //2
</script>
[[get]]、[[set]]不一定同时设定,如果只设定[[get]]则是只读,只设定[[set]]则是只写。
1.3 一次性定义多个属性
Object.definePropery()一次性只能定义一个。
Object.defineProperties() 可以同时定义多个属性。
只需要两个参数:
参数1:要添加属性的对象
参数2:对象的属性名做键,属性的特性组成的对象做值,组成的对象。
看下面的代码:
<script type="text/javascript">
var p = {};
Object.defineProperties(p,{
//name属性。
name : {
enumerable:true,
configurable:false,
writable:false,
value:"凤姐"
},
//age属性。
age:{
enumerable : true,
configurable:true,
get:function () {
return 18;
},
set : function () {
console.log("想修改我的年龄没门")
}
}
});
</script>
1.4 读取属性的特性的值
使用Object.getOwnPropertyDescriptor(参数1, 参数2)方法。这个方法接收两个参数。
参数1:属性所在的对象
参数2:属性名称。
返回值:一个对象。 如果是访问器属性,这个对象的属性有 configurable、enumerable、get 和 set;如果是数据属性,这个对象的属性有 configurable、enumerable、writable 和 value。
<script type="text/javascript">
var p = {};
Object.defineProperties(p,{
name : {
enumerable:true,
configurable:false,
writable:false,
value:"凤姐"
},
age:{
enumerable : true,
configurable:true,
get:function () {
return 18;
},
set : function () {
console.log("想修改我的年龄没门")
}
}
});
var pd = Object.getOwnPropertyDescriptor(p, "name");
console.log(pd);
</script>