重温JavaScript(lesson10):面向对象(3)

大家好,又见面了,我们一起重温JavaScript。上一次我们一起重温了对象的属性相关内容,重点是getter和setter。我们来一张导图回顾一下上次的内容吧:

图片

 

如果这些字已经不认识你了(其实是你把人家忘了),那就常回家看看吧~ https://blog.csdn.net/dupeng15bs/article/details/116379950

这次我们一起学继续学习对象的属性,来看看对象属性的特征。属性的特征定义了属性的工作模式。这些特征包括:[[Enumerable]]、[[Configurable]]、[[Writable]]、[[Value]]、[[Get]]、[[Set]]。我们可以使用Object.defineProperty()或者Object.defineProperties()改变这些特征,用Object.getOwnPropertyDescriptor()获取它们。我们来详细学习:

在接下来的代码中我们总会用到Object.defineProperty()方法,此方法用于改变对象属性特征,该方法接受3个参数:具有某属性对象、属性名和属性特征的描述对象。还有一个方法是可以同时为对象定义多个属性的,就是Object.defineProperties(),此方法的详细使用这里就不再具体介绍了,感兴趣的童鞋自己查一下哦。

1.对象属性的通用特征

有两个属性特征是数据和访问器属性都拥有的,就是[[Enumerable]]和[[Configurable]] 。[[Enumerable]]决定是否可以遍历属性,[[Configurable]]决定是否可以配置属性。我们看代码:

var person = {
  name: 'New_Name'
};
Object.defineProperty(person,"name",{
  enumerable: false
})
console.log("name" in person);
//true
console.log(person.propertyIsEnumerable("name"));
//false
console.log(person.name);
//New_Name
console.log(person.hasOwnProperty('name'));
//true

​​​​​​​如上代码中,为person对象定义了name属性,然后设置它的[[Enumerable]]为false,那么使用person调用propertyIsEnumerable,则返回的结果为false。但是我们发现依然可以访问name属性的值,那么设置某个属性的[[Enumerable]]特征为false,到底对属性有什么影响呢?看代码:

var person = {
  age: 18,
  name: 'New_Name'
};
Object.defineProperty(person,"name",{
  enumerable: false
})
console.log("name" in person);
//true
for(var x in person) {
  console.log(x);
}
//age (只输出age)
console.log(Object.keys(person));
//["age"]

​​​​​​​我们发现name属性不可以被遍历出来,也就是我们说的[[Enumerable]]决定是否可以遍历属性。我们再来看对象的[[Configurable]]特征:

var person = {
  age: 18,
  name: 'New_Name'
};
Object.defineProperty(person,"name",{
  configurable: false
})
console.log("name" in person);
//true
console.log(person.name);
//New_Name
//delete person.name;
//delete操作在严格模式下报错 非严格模式下执行不成功
person.name = "重温新知";
console.log(person.name);
//重温新知

​​​​​​​如上代码所示:设置对象的[[Configurable]]属性为false,则意味着不允许删除这个属性,但是可以改变这个属性的值。再看一段代码:

var person = {
  age: 18,
  name: 'New_Name'
};
Object.defineProperty(person,"name",{
  configurable: false
})
Object.defineProperty(person,"name",{
  configurable: true
})
//报错Uncaught TypeError: Cannot redefine property

​​​​​​​从这段代码我们可以看出,我们不可以把一个不可配置的属性变成可配置的

以上就是我们要说明的对象属性的通用特征,下面我们分别看看数据属性特征和访问器属性特征。

2.数据属性特征

数据属性拥有两个独有的特征,这两个特征是访问器属性没有的,分别是[[Value]]和[[Writable]],一个指定属性的值,一个说明属性是否可以写入

当我们在对象上创建属性时,[[Value]]特征便会被自动赋值。所有属性的值(包括函数),都会保存在[[Value]]特征中,我们看代码:

var person = {
  name: 'New_Name'
}
Object.defineProperty(person,"age",{
  value: 18,
  enumerable: true,
  configurable: true,
  writable: true
})
console.log(person.age);
//18

​​​​​​​当Object.defineProperty()被调用时,首先检查属性是否存在,如果不存在,将根据属性描述对象指定的特征指定一个值。我们再来看代码:

var person = {
  name: 'New_Name'
}
Object.defineProperty(person,"name",{
  value: "重温新知",
  enumerable: true,
  configurable: true,
  writable: true
})
console.log(person.name);
//重温新知

​​​​​​​这段代码表明:当Object.defineProperty()被调用时,首先检查属性是否存在,如果存在,将用属性描述对象指定的值替换原来的值。

我们注意到,以上两段代码在指定name属性的[[Value]]特征的同时,也指定了其他特征,那么不指定其他特征会怎样呢?我们看代码:

var person = {
  name: 'New_Name'
}
Object.defineProperty(person,"age",{
  value: 18
})
console.log(person.age);
//18
console.log(person.propertyIsEnumerable("age"));
//false
//person.age = 28;
// person.age = 28 赋值语句报错:Cannot assign to read only property 'age'
//delete person.age;
// delete 执行报错: Cannot delete property 'age'

​​​​​​​从代码执行结果我们可以看出:如果只为age属性指定了[[Value]] 特征的值,那么像[[Configurable]]特征、[[Enumerable]]特征和[[Writable]]特征的值都为false,也就是不可配置、不可枚举和不可写。在来看通过一段代码理解一下[[Writable]]特征的使用:

var person = {
  name: 'New_Name'
}
Object.defineProperty(person,"age",{
  value: 18,
  writable: false,
  configurable: true,
  enumerable: true
})
console.log(person.age);
//18
person.age = 28;
//Cannot assign to read only property 'age' of object '#<Object>'

​​​​​​​在这段代码中,指定了age属性的[[Writable]]特征的值为false,也就是不可写。那么对其值的修改操作是不被允许的。(严格模式抛出错误,非严格模式下失败)

以上就是关于对象的数据属性的特征,下面来看一下访问器属性特征。

3.访问器属性特征

访问器属性是不需要存储值的,所以没有数据属性的[[Value]]和[[Writable]]特征。但是访问器属性也有独有的属性特征,就是[[Get]]和[[Set]]。它们分别内含getter和setter函数,并且和对象字面形式的getter和setter一样,仅需要定义其中的一个特征就可以创建一个访问器属性。

看一段代码:

var person = {
  _name: 'New_Name'
}
Object.defineProperty(person,"name",{
  get: function() {
    return this._name
  },
  set: function(value) {
    this._name = value;
  },
  enumerable: true,
  configurable: true
})
console.log(person.name);
//New_Name
person.name = "重温新知";
console.log(person.name);
//重温新知
delete person.name;
console.log(person.name);
//undefined

​​​​​​​我们看到使用属性的访问器属性特征和数据属性特征一样,可以在定义属性时候为其指定通用属性特征。上面的代码定义了name属性为可枚举,可写和可配置的。我们再来看一段代码:

var person = {
  _name: 'New_Name'
}
Object.defineProperty(person,"name",{
  get: function() {
    return this._name
  }
})
console.log(person.name);
//New_Name
console.log("name" in person);
//true
console.log(person.propertyIsEnumerable("name"));
//false
//person.name = "重温新知";
//赋值报错:Cannot set property name of #<Object> which has only a getter
// delete person.name;
//删除报错:Cannot delete property 'name' of #<Object>

​​​​​​​在这段代码中,name属性只有一个getter的访问器属性,没有setter所以是不可写的,没有[[Enumerable]]和[[Configurable]]所以是不可枚举和配置的。

学到这里我么知道了对象属性原来还有这么多的特征啊,那么怎么知道一个对象的某个属性的这些特征值呢?那就是通过Object.getOwnPropertyDescriptor()获取它们:

4.获取属性特征

我们来看一下通过getOwnPropertyDescriptor方法获取属性特征的例子:

var person = {
  name: "New_Name"
}
var descriptor = Object.getOwnPropertyDescriptor(person,'name');
console.log(descriptor);
//{value: "New_Name", writable: true, enumerable: true, configurable: true}
console.log(descriptor.enumerable);
//true
console.log(descriptor.configurable);
//true
console.log(descriptor.writable);
//true
console.log(descriptor.value);
//New_Name

​​​​​​​以上就是关于对象属性特征的内容,来张导图总结一下本次内容:

图片

下一次我们学习构造函数和原型相关的内容,加油!

如有错误,请不吝指正。温故而知新,欢迎和我一起重温旧知识,攀登新台阶~

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

重温新知

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值