理解Object.defineProperty
Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或在修改一个对象的现有属性,并返回这个对象(即第一个参数obj)
语法:
Object.defineProperty(obj , prop , descriptor)
//obj:要在其上定义属性的对象 //prop:要定义或修改的属性的名称 //descriptor:将被定义或修改的属性描述符
vue.js就是通过Object.defineProperty实现双向绑定
给对象的属性添加特性描述,目前提供两种形式:数据描述和存取器描述
数据描述
当修改或定义对象的某个属性的时候,给这个属性添加一些特性
value: 设置属性的值
writable: 值是否可以重写。true | false
enumerable: 目标属性是否可以被枚举。true | false
configurable: 目标属性是否可以被删除或是否可以再次修改特性 true | false
value:属性对应的值,可以是任意类型的值,默认为undefined
let obj = {} //第一种情况:不设置value属性 Object.defineProperty(obj,"newKey",{ }); console.log( obj.newKey ); //undefined ------------------------------ //第二种情况:设置value属性 Object.defineProperty(obj,"newKey",{ value:"hello" }); console.log( obj.newKey ); //hello
writable:属性的值是否可以被重写,默认为false,设置为true可以被重写
let Person = {}; Object.defineProperty(Person,'city',{ city:'伦敦' //writable默认为false,不能改变属性值 }) Person.city = '巴黎'; console.log(Person.city);//undefined
let Person = {}; Object.defineProperty(Person,'city',{ city:'伦敦', writable:true }) Person.city = '巴黎'; console.log(Person.city);//巴黎
enumerable:此属性是否可以被枚举
设置为true可以被枚举;设置为false,不能被枚举(默认false)
var obj = {} //第一种情况:enumerable设置为false,不能被枚举。 Object.defineProperty(obj,"newKey",{ value:"hello", writable:false, enumerable:false }); //枚举对象的属性 for( var attr in obj ){ console.log( attr ); } //第二种情况:enumerable设置为true,可以被枚举。 Object.defineProperty(obj,"newKey",{ value:"hello", writable:false, enumerable:true }); //枚举对象的属性 for( var attr in obj ){ console.log( attr ); //newKey }
configurable:是否可以删除目标属性或是否可以再次修改属性的特性
设置true可以被删除或可以重新设置特性,false不能设置
这个属性起到的作用
-
目标属性是否可以使用delete删除
-
目标属性是否可以再次设置特性
//-----------------测试目标属性是否能被删除------------------------ var obj = {} //第一种情况:configurable设置为false,不能被删除。 Object.defineProperty(obj,"newKey",{ value:"hello", writable:false, enumerable:false, configurable:false }); //删除属性 delete obj.newKey; console.log( obj.newKey ); //hello //第二种情况:configurable设置为true,可以被删除。 Object.defineProperty(obj,"newKey",{ value:"hello", writable:false, enumerable:false, configurable:true }); //删除属性 delete obj.newKey; console.log( obj.newKey ); //undefined
//-----------------测试是否可以再次修改特性------------------------ var obj = {} //第一种情况:configurable设置为false,不能再次修改特性。 Object.defineProperty(obj,"newKey",{ value:"hello", writable:false, enumerable:false, configurable:false }); //重新修改特性 Object.defineProperty(obj,"newKey",{ value:"hello", writable:true, enumerable:true, configurable:true }); console.log( obj.newKey ); //报错:Uncaught TypeError: Cannot redefine property: newKey //第二种情况:configurable设置为true,可以再次修改特性。 Object.defineProperty(obj,"newKey",{ value:"hello", writable:false, enumerable:false, configurable:true }); //重新修改特性 Object.defineProperty(obj,"newKey",{ value:"hello", writable:true, enumerable:true, configurable:true }); console.log( obj.newKey ); //hello
一旦使用Object.defineProperty给对象添加属性,那么如果不设置属性的特性,那么configurable、enumerable、writable这些值都为默认的false
存取器描述
当使用存取器描述属性的特性的时候,允许设置以下特性属性
当设置或获取对象的某个属性的值的时候,可以提供getter/setter方法,没有的话则为undefined
-
getter 是一种获得属性值的方法
-
setter是一种设置属性值的方法
注意:当使用了getter或setter方法,不允许使用writable和value这两个属性
var obj = {}; var initValue = 'hello'; Object.defineProperty(obj,"newKey",{ get:function (){ //当获取值的时候触发的函数 return initValue; }, set:function (value){ //当设置值的时候触发的函数,设置的新值通过参数value拿到 initValue = value; } }); //获取值 console.log( obj.newKey ); //hello //设置值 obj.newKey = 'change value'; console.log( obj.newKey ); //change value
get或set不是必须成对出现,任写其一就可以。如果不设置方法,则get和set的默认值为undefined
let obj = { num:4 }; let n = 2; Object.defineProperty(obj,'num',{ get:function(){ //取 obj.num 属性时会触发 get 方法 /*数据劫持*/ //当你获取这个属性的时候,会调用 n += 2; return n; }, set(val){ //给 obj.num 赋值时会触发 set 方法 //val 是给 obj.num 赋值时的那个值 } }); console.log(obj.num < 5 && obj.num > 5);//true /*num即小于5,又大于,就是应为,第一次判断obj.num时num=(n+=2)=4,符合了第一个条件,此时的n=4。 读到第二个判断的时候,再次触发函数,此时n+=之后为6,又符合了第二个判断条件,所以出现了true*/