深入了解Object.defineProperty

本文详细解析了JavaScript中对象属性的定义方式,包括常见的赋值方法及Object.defineProperty的高级用法,探讨了属性的可写性、可配置性和可枚举性,并介绍了对象的不变性控制,如禁止扩展、密封和冻结。
摘要由CSDN通过智能技术生成
对象的定义与赋值
obj.prop = value //第一种
obj['prop'] = vlue //第二种
Object.defineProperty(obj,prop,description) //第三种

前两种定义对象并赋值的方法简单明了,为什么还要使用第三种呢?
这是因为,前两种定义的对象的属性可以删除也可以修改。而Object.defineProperty()定义的属性可以设置不能修改或删除等,它可以通过描述符的设置进行更精准地控制对象属性。

javascript对象有三种类型地属性:

  • 命名数据属性: 拥有一个确定的值的属性。这也是最常见的属性。
  • 命名访问器属性: 通过getter和setter进行读取和赋值的属性
  • 内部属性: 由于JS引擎内部使用的数据,不能通过js代码直接访问到,不可以设置。比如,每个对象都有一个内部属性[[Prototype]]
属性描述符

刚才说到,Object.defineProperty()可以通过描述符精准控制对象属性。Object.defineProperty定义属性有两种形式,且不能混用!分别为数据描述符存取描述符

数据描述符
数据描述符有4个属性,如下

属性名默认值
valueundefined
writablefalse
enumerablefalse
configurablefalse
let Person = {}
Object.defineProperty(Person,'name',{
	value: 'jack',
	writable: true // true表示该属性name可改变
})

如果没有设置writable属性,那么默认writable为false。即不可再修改。

Person.name = 'rose'  //无效!打印出来仍然是 ‘Jack’

看完configurable后请回到这里!!!

存取描述符

属性默认值
getundefined
setundefined
enumerablefalse
configurablefalse

getter和setter是设置对象属性的另一种方法,如下

let Person = {}
let temp = null
Object.defineProperty(Person,'name',{
	get: function(){
		return temp
	},
	set: function(val){
		temp = val
	}
})
Person.name = 'jack'
console.log(Person.name)// 打印出jack,成功给Person设置了name属性,且赋值为jack

无论是 数据描述符还是存取描述符都有configrable和enumerable

//数据描述符的方法定义对象属性
let Person = {}
Object.defineProperty(Person,'name',{
	value: 'jack',
	configurable: false//描述属性是否可删除,是否可以重新定义
	writable:true,//属性是否可更改
	enumerable: true
})
delete Person.name //error Cannot delete propety 'name' of <#Object>
Object.defineProperty(Person,'name',{
	value: 'rose'
})// error Cannot redefine property: name

由此可见,若configurable为false则,不可删除和重复定义属性

好了,configurable大致了解了,回到writable的位置。
之前说writable为false的情况下,对象的属性不可修改。
的确,writable为false的清空,对象的属性不可以赋值的方式直接修改

let Person = {}
Object.defineProperty(Person, 'name',{
	value: 'jack',
	writable: false,
	configurable: true //请注意!这里说明可以重新定义属性
})
Object.defineProperty(Person, 'name',{
	value: 'rose'
})
Person.name // 结果为rose

但是这个configurable有一个bug!!

let Person = {}
Object.defineProperty(Person, 'name',{
	value: 'jack',
	writable: true,
	configurable: false //请注意!这里说明可以重新定义属性
})
Object.defineProperty(Person, 'name',{
	value: 'rose'
})
Person.name // 它居然还能打印出rose?!!不管了,记住吧
delete Person.name // false 不能delete!

好了,看看enumerable。

let Person = {}
Object.defineProperty(Person,'name',{
	value: 'jack',
	enumerable: false
})
Person.gender = 'male'
Object.defineProperty(Person,'age',{
	value: '18',
	enumerable: true  //定义数据为可枚举属性
})
Object.keys(Person ) // ['gender','age']
for(let item in Person){
console.log(item) // gender, age
}
普通对象属性赋值 vs Object.defineProperty

经过上面的了解,你可能发现了一个现象
Person.gender = 'male'通过赋值得到的属性,可删除,可枚举,可修改。
也就是说 等价于
Object.defineProperty(Person,'gender',{ value: 'male', writable:true, configurable:true, enumerable:true })

Object.defineProperty(Person,'gender',{
	value: 'male'
})
等价于
Object.defineProperty(Person,'gender',{
	value: 'male',
	writable:false,
	configurable:false,
	enumerable:false
})
不变性
  • 对象常量
  • 禁止扩展
  • 密封
  • 冻结

对象常量

let Person = {}
Object.defineProperty(Person,'name',{
	value: 'jack',
	writable: false,  //不可重新赋值
	configurable: false //不可删除
})

禁止扩展
使用Object.preventExtensions(…) 禁止对象再添加其他属性
(虽然不能扩展,但是能够配置)

var Person = {
	name: 'jack'
}
Object.preventExtensions(Person)
Person.gender = 'male' //error Can't add property gender, 
object is not extensible

密封
密封比禁止扩展更猛,不仅不能扩展,还不能配置!
使用Object.seal()
(但是它能直接修改Person.name哦~ )

var Person = {
	name: 'jack'
}
Object.seal(Person)

冻结
这个是终极boss了吧,不能扩展,不能配置,连原有属性都不给修改了!!
Object.freeze()

var Person = {
	name: 'jack'
}
Object.freeze(Person)
赋值的作用和影响

赋值可能会调用原型上的setter

let proto = {
	get bar(){
		console.log('Getter!')
		return 'a'
	}
}
let obj = Object.create(proto)
obj.bar = 'hello'// Cannot set property bar of #<Object> which has only a getter
console.log(obj.bar)// a
let proto = {
	get bar(){
		console.log('Getter!')
		return 'a'
	}
}
let obj = Object.create(proto)
obj.bar = 'hello'// Cannot set property bar of #<Object> which has only a getter
console.log(obj.bar)// a

//但是我可以通过定义操作呀!
Object.defineProperty(obj, 'bar', {
	value: 'hello'
})
console.log(obj.bar) //hello

附参考链接
深入浅出Object.defineProperty

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值