属性的类别
有人会问:对象属性也分类别?!是指函数和变量的不同吗?还是分为可枚举属性或者是不可枚举属性,其实属性分为两个大类,一种为数据属性,一种为访问器属性
数据属性
数据属性的作用如其名,起到存放数据的作用,比如描述对象的属性,对象的方法。而作为数据属性,其中有四个特性来描述数据属性的状态,分别为:Configurable
,Enumerable
,Writable
,Value
,而我们可以通过Object.getOwnPropertyDescriptor()
方法访问他们,除此之外还可以使用Object.defineProperty
方法修改这四个特性。
let obj = { name: "猪痞恶霸", code: function () { console.log("猪痞恶霸最帅"); }, }; Object.defineProperty(obj, "name", { value: "战场小包" }); Object.getOwnPropertyDescriptor(obj, "name"); // { // configurable: true // enumerable: true // value: "战场小包" // writable: true // } obj.name // 战场小包 复制代码
在上面的代码中我们修改了描述属性的value
特性并访问了描述属性的对象得到了包裹四个特性的对象,不难看出当我们修改value
这个特性后对象的name
值发生了改变,说明改变value
属性,相当于间接改变相应属性的值。
Very Good!现在我们已经掌握了Object.getOwnPropertyDescriptor()
与Object.defineProperty
,让我们带着这两个方法来探学习这四个特性的具体作用。
configurable
:它控制了属性的可删除或者修改的状态,当值为true
(默认为true
)的时候我们可以修改或者删除属性的值,反之,我们将这个特性修改为false
的时候,当前属性将无法进行删除或者重新定义。
let obj = { name: "猪痞恶霸", code: function () { console.log("猪痞恶霸最帅"); }, }; Object.defineProperty(obj, "name", { configurable: false, }); delete obj.name // false obj 复制代码
- 如上,我们将
name
属性的configurable
状态更改为false
,当我们使用selete
关键字的时候,是无法删除的,返回false
。这个时候有人问了,删除操作我知道,那么重新定义又是怎么一回事呢?其实无法重新定义就是我们无法再使用Object.defineProperty
对这个属性进行修改了~ enumerable
:可枚举的,这个概念很是熟悉,你想的没错,它控制属性是否可以被遍历到,默认为true
,当值为true
的时候,可以被遍历到,反之为ralse
时则会在遍历的时候被忽略
let obj = { name: "猪痞恶霸", age:20, }; Object.defineProperty(obj, "name", { enumerable: false, }); for(item in obj) { console.log(item) } // age 复制代码
- 我们将
obj
的name
属性的enumerable
可枚举描述设为false
,不可枚举,使用for in
遍历obj
的时候跳过了name
,所以只打印出了age
value
:value
在介绍修改与访问属性特性的方法部分提到过,它存储了属性值,当修改value
值的时候,属性的值也会发生变化。
let obj = { name: "猪痞恶霸", code: function () { console.log("猪痞恶霸最帅"); }, }; Object.defineProperty(obj, "code", { value:function() { console.log("猪痞恶霸最可爱"); } }); obj.code() // 猪痞恶霸最可爱 复制代码
- 我带着好奇的心去尝试修改函数值,果不其然,函数值也可以被修改,因为其也是数据属性,只不过存储的是函数。
writable
:控制着属性的值是否可以被修改。默认为true
是可以被修改的,而当我们手动赋为false
后将无法被修改
let obj = { name: "猪痞恶霸", }; Object.defineProperty(obj, "name", { writable:false }); obj.name = "Ned" obj.name // 猪痞恶霸 复制代码
- 看到结果后说明我们无法修改
writable
状态为false
的属性
其实writable
与configurable
的作用有些像冻结对象,Object.freeze
与Object.seal
分别对应着writable
与configurable
无法修改与无法删除,大家可以自己试一下。
访问器属性
访问器属性就是我们熟知的getter
与setter
存取器,我们可以通过绑定存取器来对对象属性读取或者修改操作进行拦截,在其中进行一些操作
let obj = { count:20, get counts() { console.log("get函数被调用") return this.count+10 }, set counts(value) { console.log("set函数被调用") this.count = value } } obj.counts // 30 get函数被调用 obj.counts = 100 // 100 set函数被调用 复制代码
上面的示例代码,在对象初始化的时候为其添加get
与set
函数,当我们访问这些函数的时候,调用内部的代码,通过this
来为对象的其他属性进行操作。
问题来了,如果我们在对象初始化之后想为其添加get
和set
该怎么做呢?答案是使用Object.defineProperty
方法
let obj = { _name:"猪痞恶霸" } Object.defineProperty(obj, "name", { get () { console.log("调用了get函数") return this._name }, set (value) { console.log("调用了set函数") this._name = value } }) obj.name // 调用了get函数 obj.name = "战场小包" // 调用了set函数 '战场小包' 复制代码
上面的例子是在我们初始化之后使用Object.defineProperty
为其添加get
与set
,传入目标对象,对外属性值以及保护get
与set
函数的对象。