前言:
JavaScript 对象与其他面向对象的语言( 如Java )不太一样,因为ES6 之前没有类的概念。幸运的是,ES6 和 TypeScript 都引入了类的概念,这就使我们理解和使用起来更为方便。 在学习js对象之前,先把一些重要概念走一遍,有助于我们更好地理解对象,第一个要掌握的就是 Object.defineProperty()
【属性特性】 是用来描述js对象的属性的一些内在特征,如这些属性是否可写,是否可枚举,是否可配置等。属性特性分为两类,分别为数据属性 和 访问器属性(也叫存取器属性)。
configurable [Boolean]表示能否通过delete删除属性,能否修改属性的特性,能否把属性修改为访问器属性
enumerable [Boolean]表示是否能通过 for-in 枚举该属性
writable [Boolean]表示能否修改属性的值
value [any]表示这个属性的值
要想设置属性的特性,或者想让新建属性具有某种特性,则必须使用ES5中定义的Object.defineProperty(obj,property,descriptor)
obj [Object]表示传入的要修改的对象
property [String]表示该对象需要修改或新建的属性
descriptor [Object]表示该属性对应的属性特性
举例:
var person = { name: "Tom" , age: 24 }
Object.defineProperty(person,"name",{ //修改name的属性特性
enumerable:false, //设置为不可枚举
writable: false, //设置为只读属性
configurable: false, //设置为不可配置
value: "Jerry" //设置属性值
})
// 1.验证enumerable
for(var property in person){
console.log(property) // age
}
// 2.验证writable
console.log(person.name) //Jerry
person.name = "Helen"
console.log(person.name) //Jerry,(严格模式:throw Error)
// 3.验证configurable
delete person.name // 属性还在,什么也不发生 (严格模式:throw Error)
划重点:
(1)关于configurable,一旦将属性定义为不可配置的,就不能再把它变为可配置了
举例:
var person = { name: "Tom" , age: 24 }
Object.defineProperty(person,"name",{
configurable: false, //设置为不可配置
})
// throw Error
Object.defineProperty(person,"name",{
configurable: true, //设置为可配置,报错
})
划重点
(2)在调用Object.defineProperty()方法创建一个新的属性时,如果不指定属性特性,则enumerable,writable,configurable均默认为false。如果调用Object.defineProperty()方法只是修改已定义的属性时,则以上三个特性默认为true。
举例:
//通过Object.getOwnPropertyDescriptor()方法可以拿到属性a的属性描述符
var obj1 = {}
Object.defineProperty(obj1 ,"num",{})
Object.getOwnPropertyDescriptor(obj1,"num") // {value: undefined, writable: false, enumerable: false, configurable: false}
var obj2 = { num :10 }
Object.defineProperty(obj2 ,"num",{})
Object.getOwnPropertyDescriptor(obj2,"num") // {value: 10, writable: true, enumerable: true, configurable: true}
configurable [Boolean]同数据属性,不同之处:能否把属性修改为数据属性
enumerable [Boolean]同数据属性
get [Function]读取属性值的时候触发这个方法
set [Function]写入属性值的时候触发这个方法
不同于数据属性,访问器属性不能直接定义,必须通过Object.defineProperty()来定义
举例:
// 通过访问器属性改变总冠军队伍
var winner = { team : 'unknown' }
Object.defineProperty(winner,'num',{
get: function(){
return this.team
},
set:function(num){
if(num === 1){
this.team = 'Warriors'
}else{
this.team = 'Rockets'
}
}
})
//以下是使用访问器属性的常见方式,即设置一个属性的值会导致其他属性发生变化
console.log(winner.team) //unknown
winner.num = 1
console.log(winner.team) //Warriors
winner.num = 2
console.log(winner.team) //Rockets
对比以上两种属性特性,访问器属性的用途会更广一些。例如现在最流行的前端框架Vue,其源码中使用了Object.defineProperty()来定义访问器属性,通过观察者模式监听数据变化,从而实现双向数据绑定。
Object.defineProperty()我们使用的机会并不多,很多框架源码中,或者ES6中的修饰器(Decorator)原理都是通过以上方法改造的
如有不恰当的地方,欢迎多多批评指正 ^ _ ^