学习并记录是一个好的习惯
Object.defineProperty(obj, prop, descriptor)说明
Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。
一般通过为对象的属性赋值的情况下,对象的属性可以修改也可以删除,但是通过Object.defineProperty()定义属性,
通过描述符的设置可以进行更精准的控制对象属性。
描述符
在JS中对象具有两种属性,分别是数据属性和访问器属性,所以其描述符也根据属性分类,分为数据描述符和读取描述符。
在使用描述符时,必须是两种形式之一,且两者不能同时使用。
读取描述符
- 读取描述符特有键值:get与set
- get在读取属性时调用的函数 默认值为undefined
- set在设置属性时调用的函数 默认值为undefined
function test1() {
let obj = {}
Object.defineProperty(obj,'name',{
get() {
return this._name === undefined ? undefined : this._name
},
set(v) {
console.log('执行其他操作')
this._name = v + '执行了set'
}
})
console.log(obj); //{}
console.log(obj.name);//undefined
obj.name = 'dj' // 执行其他操作
console.log(obj); //{_name: "dj执行了set"}
console.log(obj.name); //dj执行了set
}
数据描述符
- 数据描述符特有键值:value和writable
- value该属性对应的值。可以是任何有效的 JavaScript 值(数值,对象,函数等)。读取属性的时候就是通过这里开始读 默认值为undefined
- writable表示能否修改属性的值赋值运算符(assignment operator)基于右值(right operand)的值,给左值(left operand)赋值。")改变 默认值为false
function test2() {
let obj = {}
Object.defineProperty(obj,'name',{
value:'dj',
writable:false,//不可赋值
})
console.log('obj对象 ' + obj.name + ' 显示我们填入的值'); //obj对象 dj 显示我们填入的值
obj.name = 'DJ'
console.log('obj对象 ' + obj.name + ' 赋值失败了,依旧为dj'); // obj对象 dj 赋值失败了,依旧为dj
let obj1 = {}
Object.defineProperty(obj1,'name',{
value:'dj',
writable:true,//可赋值
})
console.log('obj1对象 ' + obj1.name); // obj1对象 dj
obj1.name = 'DJ'
console.log('obj1对象 ' + obj1.name + ' 赋值成功'); //obj1对象 DJ 赋值成功
}
共有键值
- 数据描述符和读取描述符 共有键值:configurable和enumerable
- configurable 为 true 时,该属性描述符才能够被改变,表示对象的属性是否可以被删除,以及除writable特性外的其他特性是否可以被修改。默认值为false
- enumerable 为true时,该属性在对象中才是可枚举的(fon in或者Object.keys()、Object.values()、Object.entries()) 默认值为false
function test3() {
let obj = {}
Object.defineProperty(obj,'name',{
value:'dj',
configurable:false,
})
console.log('obj对象 ' + obj.name + ' 显示我们填入的值'); //obj对象 dj 显示我们填入的值
delete obj.name
console.log('obj对象 ' + obj.name + ' 删除失败') //obj对象 dj 删除失败
let obj1 = {}
Object.defineProperty(obj1,'name',{
value:'dj',
configurable:true,
})
console.log('obj1对象 ' + obj1.name + ' 显示我们填入的值'); //obj1对象 dj 显示我们填入的值
delete obj1.name
console.log('obj1对象 ' + obj1.name + ' 删除成功') //obj1对象 undefined 删除成功
let obj2 = {}
Object.defineProperty(obj2,'name',{
value:'dj',
enumerable:false,
})
console.log('obj2对象 ' + obj2.name + ' 显示我们填入的值'); //obj2对象 dj 显示我们填入的值
console.log(Object.keys(obj2),Object.values(obj2),Object.entries(obj2)) //[] [] []
let obj3 = {}
Object.defineProperty(obj3,'name',{
value:'dj',
enumerable:true,
})
console.log('obj3对象 ' + obj3.name + ' 显示我们填入的值'); //obj3对象 dj 显示我们填入的值
console.log(Object.keys(obj3),Object.values(obj3),Object.entries(obj3)) //["name"] ["dj"] [Array(2)]
}
拓展
拓展1:若configurable未设置未false,同一属性不能被配置两次
function Expand1() {
let obj = {}
Object.defineProperty(obj,'name',{
value:'dj',
configurable:false,
})
Object.defineProperty(obj,'name',{
value:'DJ',
}) //Cannot redefine property: name
}
拓展2:writable为false,属性值不能被修改,但若configurable为true,可以通过重新配置该属性来赋值
function Expand2() {
let obj = {}
Object.defineProperty(obj,'name',{
value:'dj',
writable:false,
configurable:true,
})
console.log(obj.name); //dj
Object.defineProperty(obj,'name',{
value:'DJ',
})
console.log(obj.name); //DJ
}
用法注意
- 数据描述符特有键值和读取描述符特有键值不能共存
- 通过writable: false 和 configurable: false 可以创建一个不变的常量
- get与set中不能调用本身,不然就会死循环
总结与相关
- Object.defineProperties(obj,{name:{...},sex:{...}}) 就是批量的Object.defineProperty
- Object.defineProperty(obj,'name',{val:''}) 与 obj.name = '' 这两种,前者创建了一个不可修改、不可删除、不可枚举的属性,而后者可修改、可删除、可枚举
- 可以通过Object.getOwnPropertyDescriptors(obj) ,返回所指定对象的所有自身属性的描述符,如果没有任何自身属性,则返回空对象。包含了可枚举属性与不可枚举属性
- Object.getOwnPropertyDescriptor(obj,'name') ,该方法返回指定对象上一个自有属性对应的属性描述符。
- Object.getOwnPropertyNames(obj) ,返回一个由指定对象的所有自身属性的属性名(包括不可枚举属性但不包括Symbol值作为名称的属性)组成的数组。
- Object.getOwnPropertySymbols(obj) ,方法返回一个给定对象自身的所有 Symbol 属性的数组。
- Object.preventExtensions()
- Object.preventExtensions()方法让一个对象变的不可扩展,也就是永远不能再添加新的属性。一旦将对象变为不可扩展的对象,就再也不能使其可扩展。它仅阻止添加自身的属性。但其对象类型的原型依然可以添加新的属性。但是不可扩展对象的原型是不可变的
- Object.seal()
- Object.seal()方法封闭一个对象,阻止添加新属性并将所有现有属性标记为不可配置。当前属性的值只要原来是可写的就可以改变。意思就是在Object.preventExtensions基础上 将内部所有属性的configurable修改成了false
- Object.freeze()
- Object.freeze()方法冻结一个对象一个被冻结的对象再也不能被修改;冻结了一个对象则不能向这个对象添加新的属性,不能删除已有属性,不能修改该对象已有属性的可枚举性、可配置性、可写性,以及不能修改已有属性的值。相当于在Object.preventExtensions()的基础上将configurable、writable修改成了false