目录
今天小编带大家了解一下js中的属性描述符
什么是属性描述符
属性描述符:它表达了一个属性的相关信息(元数据),本质上是一个对象
那了解属性描述符之前,先来了解几个关于属性的概念
数据属性
对于常规的对象创建的数据,全都是数据属性
举个例子
var obj = {
x:1
}
obj.y = 2
对于上面obj对象的x属性或者添加的y属性就是数据属性
那么还有那些属性呢,接着往下看
存取器属性
- 当给它赋值时,会自动运行一个函数
- 当获取它的值时,会自动运行一个函数
举个例子,当给某个对象赋值时,会自动运行一个函数,读取它的值时也会运行一个函数,这就叫做存取器属性
var obj = {};
obj.x = 1; //会自动运行一个函数
console.log(obj.x) //会自动运行一个函数
那么怎么知道只是一个存取器属性,又或者说运行哪一个函数呢?
这时就需要我们的属性描述符来解决了
举个例子,如何将数据属性转换为存取器属性
var obj = {};
Object.defineProperty(obj,"x",{}) //这是一个方法
console.log(obj)
了解一下Object.defineProperty(),可以配置对象属性,其中可以传入三个参数,第一个为配置的对象名称,第二个为配置的属性名称,第三个为配置对象,里面可以写入属性描述符
如上图,当我第三个参数传入空对象时,x属性被创建了,但是值为undefined,当然也可也配置值,所对应的属性为value,例如将value的值赋值为1,这时候obj对于的x属性值就为1,相当于直接给obj.x = 1一样
那么如何配置存取器属性呢?官方文档中给出如果配置了get和set属性的那就一定是存取器属性
举个例子
var obj = {};
Object.defineProperty(obj,"x",{
get(){
},
set(){
}
})
此时x属性就变成为存取器属性,但此时你会发现一个问题,当某个属性已经配置为存取器属性时,如果你再给它的value属性赋值,就会报错
意思是,不能同时指定存取器和value值,两个不能同时赋值,这在官方文档中有描述
那么此时obj对象中有哪些属性呢?
给大家了解一下obj中的get和set函数
get函数
get函数的作用:当读取配置属性时,将运行该函数,并且将该函数的返回值,作为读取属性的值
举个例子
var obj = {};
Object.defineProperty(obj,"x",{
get(){
console.log("x属性被读取了"); //输出x属性被读取了
return 1;
},
set(){
},
})
console.log(obj.x) //输出1
上面执行obj.x,相当于调用了get函数,将函数的返回值输出了,因为这时候x已经被设置了存取器属性
set函数
了解了get之后,set相信大家也心里有数了
set函数的作用:当设置配置属性的值时,将运行该函数,并且将给该属性赋的值,作为函数的参数传入
举个例子给大家看看
var obj = {};
Object.defineProperty(obj,"x",{
get(){
},
set(value){
console.log("给x赋值了:" + value); //输出给x赋值了:2
},
})
obj.x = 2
每一次对属性x赋值,都会运行set函数
了解完存取器属性,那到底对于开发者的意义在哪,接着往下看
存取器属性的应用
1.利用存取器属性来限制取值的范围
举个例子,假设这时需要一个用户对象,保存名字和年龄
function User(name,age){
// 假设年龄范围为 0 ~ 150
if (age > 150) {
age = 150;
}
if(age < 0) {
age = 0;
}
this.name = name;
this.age = age;
}
var user = new User("name",18);
console.log(user); // 输出User {name: 'name', age: 18}
这样看起来没啥毛病,但会有个隐患,如果你哪天将年龄重新修改了,但忘了年龄范围,这时就会出现下面的情况
function User(name,age){
if (age > 150) {
age = 150;
}
if(age < 0) {
age = 0;
}
this.name = name;
this.age = age;
}
var user = new User("name",18);
user.age = 1000;
console.log(user); // 输出User {name: 'name', age: 1000}
很明显是不符合你的预期的,那么这时候就需要存取器属性来限制范围了
接着往下看
function User(name, age) {
this.name = name;
var _age
Object.defineProperty(this, "age", {
get() {
return _age
},
set(value) {
if (value < 0) {
value = 0;
} else if (value > 150) {
value = 150;
}
_age = value;
}
})
this.age = _age;
}
var user = new User("name", 18);
user.age = 1000;
console.log(user);
这时候就完全没有隐患,因为每一次赋值后,都会运行set函数,在函数中判断是否需要修改
介绍完存取器属性,接下来再给大家介绍其他的属性描述符
- configurable:当且仅当该属性的
configurable
键值为true
时,该属性的描述符才能够被改变,同时该属性也能从对应的对象上被删除。 默认为false
。- enumerable:当且仅当该属性的
enumerable
键值为true
时,该属性才会出现在对象的枚举属性中。 默认为false
。- writable:当且仅当该属性的
writable
键值为true
时,属性的值,也就是上面的value
,才能被赋值运算符 (en-US)改变。 默认为false
。
属性描述符总结
- 拥有布尔值的键
configurable
、enumerable
和writable
的默认值都是false
。 - 属性值和函数的键
value
、get
和set
字段的默认值为undefined
。 - 如果一个描述符不具有
value
、writable
、get
和set
中的任意一个键,那么它将被认为是一个数据描述符。如果一个描述符同时拥有value
或writable
和get
或set
键,则会产生一个异常。
其实在平时的开发中,可能不习惯用属性描述符,但对于一些大工程,属性描述符是一个不错的选择,你学会了吗?