当前位置: 首页 > 科技观察

JS属性特性(propertydescriptor)

时间:2023-03-14 08:17:37 科技观察

概念ECMAScript5定义了一个对象叫做“propertydescriptor”,它用来描述JS的各种特性。属性描述符对象有4个属性:configurable:可配置,控制对其描述的属性的修改,表示属性的特性是否可以修改,属性是否可以作为访问器属性修改,属性是否可以删除通过删除从而重新定义属性。默认值是true。enumerable:可枚举性,表示是否可以通过for-in遍历获取属性。默认值是true。writable:可写性,表示属性的值是否可以修改。默认值是true。value:数据属性,表示属性的值。默认值未定义。除了上述属性外,还有两个访问器属性,分别是get和set,可以代替value和writable。get:读取属性时调用的函数。仅指定get表示该属性是只读属性。默认值未定义。set:写入属性时调用的函数。仅指定set表示该属性是只写属性。默认值未定义。使用“属性描述符”对象只能在Object.defineProperty或Object.defineProperties中使用。API用法:false,enumberable:false,writable:true,value:'sexy'})//accessorObject.defineProperty(hello,'woman',{configurable:false,enumberable:false,get:function(){returnthis.girl},set:function(val){this.girl=val}})//定义多个属性Object.defineProperties(hello,{boy:{configurable:false,enumberable:false,writable:false,value:'handsome'},man:{configurable:false,enumberable:false,writable:true,get:function(){returnthis.boy}}})当使用Object.defineProperty或Object.defineProperties操作(新的或修改的)时,不允许创建或修改属性,抛出TypeError异常。//本例在上一个例子的基础上运行Object.defineProperty(hello,'boy',{writable:true})//UncaughtTypeError:Cannotredefineproperty:boy因为之前的boy属性已经设置为不可配置,所以修改为writable这里会抛出TypeError异常。可以通过Object.getOwnPropertyDescriptor或Object.getOwnPropertyDescriptors获取属性描述符。API使用Object.getOwnPropertyDscriptor:https://developer.mozilla.org...Object.getOwnPropertyDescriptors:https://developer.mozilla.org...规则varrules={common:'test'}如果属性不可配置,它的可配置性和可枚举性不能被修改。Object.defineProperty(rules,'rule1',{configurable:false,enumberable:false})//修改configurable会抛出类型错误异常Object.defineProperty(rules,'rule1',{configurable:true})//UncaughtTypeError:Cannotredefineproperty:rule1//修改ennumberable不会抛出异常,但是enmuberable没有被修改undefined,writable:false,enumerable:false,configurable:false}如果accessor属性是不可配置的,get和set方法不能已修改,也不能将其转换为数据属性。Object.defineProperty(rules,'rule2',{configurable:false,enumberable:false,get:function(){returnthis.common},set:function(val){this.common=val}})//修改get或set方法会抛出类型错误异常Object.defineProperty(rules,'rule2',{get:function(){returnthis.common+'rule2'}})//UncaughtTypeError:Cannotredefineproperty:rule2Object.defineProperty(rules,'rule2',{set:function(val){this.common='rule2'}})//UncaughtTypeError:Cannotredefineproperty:rule2//转换为数据属性也会抛出类型错误异常Object.defineProperty(rules,'rule2',{value:'rule2'})//UncaughtTypeError:Cannotredefineproperty:rule2如果数据属性不可配置,则不能转换为访问器属性;同时,它的可写性不能由false变为true,但可以由true变为false。Object.defineProperty(rules,'rule3',{configurable:false,writable:false,value:'rule3'})//修改writable为true会抛出类型错误异常Object.defineProperty(rules,'rule3',{writable:true})Object.defineProperty(rules,'rule4',{configurable:false,writable:true,value:'rule4'})//可以修改writable为falseObject.defineProperty(rules,'rule4',{writable:false})Object.getOwnPropertyDescriptor(rules,'rule4')//Object{value:"rule4",writable:false,enumerable:false,configurable:false}如果数据属性不可配置不可写,则不能修改值;如果是可配置但不可写的,可以修改它的值(其实就是先标记为可写,再修改它的值,最后再标记回不可写)。其实这里说的修改值就是通过Object.defineProperty或者Object.defineProperties方法修改的。当数据属性不可配置时,不能通过直接赋值修改属性值。Object.defineProperty(rules,'rule5',{configurable:false,writable:false,value:'rule5'})//修改属性值会抛出类型错误异常Object.defineProperty(rules,'rule5',{value:'rule55'})//UncaughtTypeError:Cannotredefineproperty:rule5rules.rule5='rule55'//该值没有被修改,不会抛出异常rules.rule5//'rule5'Object.defineProperty(rules,'rule6',{configurable:true,writable:false,value:'rule6'})//修改属性值Object.defineProperty(rules,'rule6',{value:'rule66'})rules.rule6//'rule66'rules.rule6='rule6'//这个值没有被修改,以后不会修改。rules.rule6//'rule6'只指定集合不可读。如果您尝试读取属性值,它将返回undefined。(红皮书说只有严格模式才会抛出异常,其实没有)Object.defineProperty(rules,'rule7',{get:function(){returnthis.common}})rules.rule7='rule7'//UncaughtTypeError:Cannotredefineproperty:rule7如果对象是不可扩展的,你可以编辑现有的自己的属性,但不能向它添加新的属性。操作对象扩展性的API有3个:Object.preventExtensions、Object.seal和Object.freeze。API使用Object.preventExtensions:https://developer.mozilla.org...Object.seal:https://developer.mozilla.org...Object.freeze:https://developer.mozilla.org...Object.isExtensions:https://developer.mozilla.org...Object.isSealed:https://developer.mozilla.org...Object.isFrozen:https://developer.mozilla.org...使用对象.preventExtensions可以将对象转换为不可扩展的。使用Object.isExtensions确定对象是否可扩展。varex={}Object.defineProperty(ex,'ex1',{configurable:true,writable:true,value:'ex1'})Object.isExtensible(ex)//trueObject.preventExtensions(ex)Object.isExtensible(ex)//false//可以修改已有的属性Object.defineProperty(ex,'ex1',{writable:false,value:'ex11'})Object.getOwnPropertyDescriptor(ex,'ex1')//Object{value:"ex11",writable:false,enumerable:false,configurable:true}//添加属性会抛出类型错误异常Object.defineProperty(ex,'ex2',{value:'ex2'})//UncaughtTypeError:Cannotdefineproperty:ex2,对象不可扩展。使用Object.seal不仅可以将对象转换为不可扩展的,还可以将对象自身的所有属性转换为不可配置的。即不能给对象增加新的属性,也不能删除或配置它已有的属性(这里也会遵循之前的规则)。使用Object.isSealed确定对象是否密封。varse={}Object.defineProperty(se,'se1',{configurable:true,writable:false,value:'se1'})Object.isSealed(se)//falseObject.seal(se)Object.isSealed(se)//true//修改已有属性会抛出类型错误异常Object.defineProperty(se,'se1',{writable:true,value:'se11'})//UncaughtTypeError:Cannotredefineproperty:se1//添加属性会抛出类型错误异常Object.defineProperty(se,'se2',{value:'se2'})//UncaughtTypeError:Cannotdefineproperty:se2,objectisnotextensible。使用Object.freeze除了将对象转换为不可扩展并转换其属性之外,除了不可配置之外,还可以将自身属性转换为只读。(如果对象用set设置,accessor属性不受影响,set方法仍然可以调用,不会抛出异常,但是如果set方法是改变对象的属性,则不能修改successful)使用Object.isFrozen检测对象是否被冻结(frozen)。varfr={}Object.defineProperty(fr,'fr1',{configurable:true,writable:false,value:'fr1'})Object.isFrozen(fr)//falseObject.freeze(fr)Object.isFrozen(fr)//true//修改一个已经存在的属性会抛出类型错误异常抛出类型错误异常Object.defineProperty(fr,'fr2',{value:'fr2'})//UncaughtTypeError:Cannotdefineproperty:fr2,objectisnotextensible.fr.fr1='fr11'//不能修改fr1属性fr.fr1//'fr1'varset={}Object.defineProperty(set,'set1',{configurable:true,value:'set1'})Object.defineProperty(set,'set2',{configurable:true,set:function(val){this.set1=val}})Object.isFrozen(set)//falseObject.freeze(set)Object.isFrozen(set)//trueset.set2='set2'set.set1//'set1'我是对的属性描述符非常陌生,主要是因为它们很少被使用。不过最近开始学写一些小库(虽然很折腾),感觉属性描述符是有使用场景的。暂时能想到的就是将库对象的一些属性设置为只读,防止对象的一些属性被用户覆盖。还有一个用法是我在认识和学习vue的时候才知道的,就是通过getters和setters来实现“监控”对象属性的数据更新(这里挖个坑,以后学习这个方法,以后再写一篇“监控”的文章)“对象属性的数据更新文章)。***,如果你知道更多属性描述符的后期使用场景,希望大家在评论区留下你的意见。