属性描述符
属性描述符表达了一个属性的相关信息(元数据),本质上是一个对象。
数据属性
在我们使用对象的过程中,对一个对象进行取值和赋值的时候,该属性称之为 数据属性
存取器属性
存取器属性是当给属性赋值或者取值的时候,会自动的运行一个函数。
语法
Object.defineProperty(obj, prop, descriptor) // 参数 obj:要定义属性的对象。 prop: 要定义或修改的属性的名称或 Symbol 。 descriptor:要定义或修改的属性描述符。 在descriptor里面有一个get和set的函数就是存取器属性
例如:
var obj = {}; Object.defineProperty(obj, 'x', { get:function(){ // 这里的返回值就是读取obj的属性x的值,默认返回undefined }, set:function(val){ // 这里的val参数是设置obj.x的值 }, }) // 进行设置和取值需要注意,定义一个额外的变量,不然会造成无限调用set方法而内存溢出
存取器修饰符的作用
- 我们会发现,当我们去改变属性赋值的时候,会自动执行set函数,相当于是通知了set函数。属性取值的时候会自动的执行get函数,自动通知get函数。正是因为有这个自动通知的功能,vue2中的响应式系统就是基于Object.defineProperty()来实现对象的响应的。
- 我们还可以基于存取器来 实现对单一属性的控制,在函数里面实现对某一属性的类型判断或者是做限定。
例如: 有一个用户的对象,年龄只能是正数,并且是有一定范围的。
var User = function(name, age){ this.name = name; var _age; Object.defineProperty(this, 'age', { get:function(){ return _age; }, set:function(val){ // 年龄小于0赋值给0,大于200赋值200 if(val < 0){ _age = 0; }else if(val > 200){ _age = 200; } _age = val; }, }) // 赋值age,然后通过set来进行校验 this.age = age; } var u = new User('twinkle', 10); console.log(u.age); u.age = -1; console.log(u.age); u.age = 1000; console.log(u.age)
结果:
其他属性描述符号
configurable
当且仅当该属性的 configurable 键值为 true 时,该属性的描述符才能够被改变,同时该属性也能从对应的对象上被删除。
默认为 false。
enumerable
当且仅当该属性的 enumerable 键值为 true 时,该属性才会出现在对象的枚举属性中。
默认为 false。
数据描述符还具有以下可选键值:
value
该属性对应的值。可以是任何有效的 JavaScript 值(数值,对象,函数等)。
默认为 undefined。
writable
当且仅当该属性的 writable 键值为 true 时,属性的值,也就是上面的 value,才能被赋值运算符 (en-US)改变。
默认为 false。
写出来的代码是这样的:
var obj = {}; Object.defineProperty(obj, "x", { enumerable: false, // 是否可枚举的 configurable: false, // 是否可以可以被操作 writable: false, // 是否可写,默认是只读 value: "1" });
结果:
这里可能有人会问,存取器属性符和其他属性符里面有相斥的地方,比如: 我设置了value: 1 然后我有设置了get方法并且返回2,那我读取的结果是啥?
var obj = {}; Object.defineProperty(obj, "x", { enumerable: false, // 是否可枚举的 configurable: false, // 是否可以可以被操作 writable: false, // 是否可写,默认是只读 value: "1", get:function(){ return 2 } });
如果代码如上的话,代码手写在运行时候就会报错。
描述符可拥有的键值
|
enumerable |
value |
writable |
get |
set |
|
数据描述符 | 可以 | 可以 | 可以 | 可以 | 不可以 | 不可以 |
存取描述符 | 可以 | 可以 | 不可以 | 不可以 | 可以 | 可以 |
如果一个描述符不具有 value、writable、get 和 set 中的任意一个键,那么它将被认为是一个数据描述符。如果一个描述符同时拥有 value 或 writable 和 get 或 set 键,则会产生一个异常。
更多请查看