当前位置: 首页 > 后端技术 > Node.js

Object.defineProperty在JavaScript中的用法

时间:2023-04-03 23:13:27 Node.js

在JavaScript中,对象的属性的添加或修改往往有如下方式:obj.name='John'此外,还可以在Object.defineProperty()方法中添加或修改modified修改对象的属性。更重要的是,方法除了目标对象obj和属性名prop之外,还可以传入属性描述符来实现更复杂的属性。属性描述符是一个对象,有两种形式:一种是数据描述符,另一种是访问描述符。Object.defineProperty(obj,prop,descriptor)数据描述符数据描述符支持以下特性:enumerable:表示对象是否可以被枚举。默认为false,表示不能枚举。for...in和Object.keys()中无法枚举该属性,同时也会影响JSON.stringify()。configurable:表示对象属性是否可以删除,除value和writable属性外的其他属性是否可以修改。默认为false,表示属性不可删除,属性不可修改。value:属性对应的值,默认未定义。writable:默认为false,表示只读,不能给该属性赋值。在严格模式下,为只读属性赋值会引发错误。在松散模式下,给只读属性赋值是不会生效的。//示例1,等同于obj.name='John'varobj={}Object.defineProperty(obj,'name',{value:'John',writable:true,configerable:true,enumerable:true})//例2,设置name属性为只读'usestrict'varobj={}Object.defineProperty(obj,'name',{value:'John',writable:false,configerable:true,enumerable:true})obj.name='Joy'//TypeError//例3,设置name属性为不可枚举varobj={}Object.defineProperty(obj,'name',{value:'John',writable:true,configerable:true,enumerable:false})console.log(obj.name)//Johnconsole.log(Object.keys(obj))//[]//示例4,将name属性设置为不可配置(undeletable,exceptvalue其他属性不可修改)varobj={}Object.defineProperty(obj,'name',{value:'John',writable:true,configerable:false,enumerable:true})deleteobj.name//falseObject.defineProperty(obj,'name',{enumerable:false})//TypeError存储描述符存储描述符支持以下特性:enumerable:同上。可配置:同上。set:设置setter方法,当属性被修改时会执行,以新的属性值作为参数。默认值未定义。get:设置getter方法,当属性被访问时会执行。默认值未定义。//例5,使用get和set统计读写属性的个数varobj={},name='',count1=0,count2=0Object.defineProperty(obj,'name',{get:function(){console.log('Read'+(++count1)+'times')returnname},set:function(newVal){console.log('Write'+(++count2)+'times')名称=newVal}})obj.name//读取1次obj['name']//读取2次obj.name='Joy'//写入1次obj.name='Jack'//写入2次Notes还有其他三个需要注意的地方,一个是不同描述符的属性不能共享;二是添加属性时,未引入的属性会设置为默认值,修改属性时,未引入的属性保持原样;第三个是:对象。defineProperty(obj,'name',{value:'John'})//该属性是只读的,不可配置的,不可枚举的。等价于Object.defineProperty(obj,'name',{value:'John',writable:false,configerable:false,enumerable:false})obj.name='John'//属性可写,可配置,可枚举。等价于Object.defineProperty(obj,'name',{value:'John',writable:true,configerable:true,enumerable:true})实际应用比如有一个对象Student,它有两个属性name和age,ifnot想把年龄设置的太大或者太小,怎么办?我们可以添加setter和getter方法。每次我们要修改年龄,通过setter方法修改属性,通过getter方法读取属性:functionStudent(name,age){this.name=namethis.setAge=function(val){age=valif(age<0)age=0if(age>100)age=100}this.getAge=function(){returnage}}vars=newStudent('John',16)s.setAge(25)console.log(s.getAge())//25s.setAge(-5)console.log(s.getAge())//0s.setAge(500)console.log(s.getAge()))//100看起来很好,但是每次读取或修改属性时,都会调用setter或getter方法,这会增加很多代码。使用Object.defineProperty方法直接以最原始的方式读取和修改属性,无需额外代码::function(){return_age},set:function(val){_age=valif(_age<0)_age=0if(_age>100)_age=100}})}vars=newStudent('John',16)s.age=25console.log(s.age)//25s.age=-5console.log(s.age)//0s.age=500console.log(s.age)//100个批处理Object.defineProperties()方法可以批量添加或修改属性:varobj={}Object.defineProperties(obj,{name:{value:'John',emunerable:true},age:{value:20,emunerable:true}})Object.create()方法可以在创建对象时批量添加属性:varobj=Object.create(Object.prototype,{name:{value:'John',emunerable:true},age:{value:20、emunerable:true}})也可以通过字面量创建包含setter和getter属性的对象:varobj={getname(){return'John'},setname(val){console.log(val)},getage(){return18}}参考MDNObject.defineProperty()《深入理解 JavaScript》