Object.defineProperty ,顾名思义,为对象定义属性。在js中我们可以通过下面这几种方法定义属性
1 2 3 4 5 6 7 8 9 10
| // (1) define someOne property name someOne.name = 'cover';
//or use (2) someOne['name'] = 'cover'; d // or use (3) defineProperty Object.defineProperty(someOne, 'name', { value : 'cover' })
|
我们可以通过Object.defineProperty这个方法,直接在一个对象上定义一个新的属性,或者是修改已存在的属性。最终这个方法会返回该对象。
语法
Object.defineProperty(object, propertyname, descriptor)
参数
object
必需。 要在其上添加或修改属性的对象。 这可能是一个本机 JavaScript对象(即用户定义的对象或内置对象)或 DOM 对象。
propertyname
必需。 一个包含属性名称的字符串。
descriptor
必需。 属性描述符。 它可以针对数据属性或访问器属性。
属性的状态设置
1.descriptor的参数值得我们关注下,该属性可设置的值有:
【value】 属性的值,默认为 undefined。
【writable】 该属性是否可写,如果设置成 false,则任何对该属性改写的操作都无效(但不会报错),对于像前面例子中直接在对象上定义的属性,这个属性该特性默认值为为 true。
1 2 3 4 5 6 7 8
| var someOne = { }; Object.defineProperty(someOne, "name", { value:"coverguo" , //由于设定了writable属性为false 导致这个量不可以修改 writable: false }); console.log(someOne.name); // 输出 coverguo someOne.name = "linkzhu"; console.log(someOne.name); // 输出coverguo
|
2.
configurable如果为false,则任何尝试删除目标属性或修改属性以下特性(writable, configurable, enumerable)的行为将被无效化,对于像前面例子中直接在对象上定义的属性,这个属性该特性默认值为为 true。
1 2 3 4 5 6 7 8 9
| var someOne = { }; Object.defineProperty(someOne, "name", { value:"coverguo" , configurable: false }); delete someOne.name; //删除属性---然并卵 console.log(someOne.name);// 输出 coverguo someOne.name = "linkzhu"; console.log(someOne.name); // 输出coverguo
|
3.enumerable 是否能在for-in循环中遍历出来或在Object.keys中列举出来。对于像前面例子中直接在对象上定义的属性,这个属性该特性默认值为为 true
注意 在调用Object.defineProperty()方法时,如果不指定, configurable, enumerable, writable特性的默认值都是false,这跟之前所 说的对于像前面例子中直接在对象上定义的属性,这个特性默认值为为 true。并不冲突
,如下代码所示:
1 2 3 4 5 6 7 8 9 10 11 12 13
| //调用Object.defineProperty()方法时,如果不指定 var someOne = { }; someOne.name = 'coverguo'; console.log(Object.getOwnPropertyDescriptor(someOne, 'name')); //输出 Object {value: "coverguo", writable: true, enumerable: true, configurable: true}
//直接在对象上定义的属性,这个特性默认值为为 true var otherOne = {}; Object.defineProperty(otherOne, "name", { value:"coverguo" }); console.log(Object.getOwnPropertyDescriptor(otherOne, 'name')); //输出 Object {value: "coverguo", writable: false, enumerable: false, configurable: false}
|
【get】一旦目标对象访问该属性,就会调用这个方法,并返回结果。默认为 undefined。
【set】 一旦目标对象设置该属性,就会调用这个方法。默认为 undefined。
从上面,可以得知,我们可以通过使用Object.defineProperty,来定义和控制一些特殊的属性,如属性是否可读,属性是否可枚举,甚至修改属性的修改器(setter)和获取器(getter)
那什么场景和地方适合使用到特殊的属性呢?
优化对象获取和修改属性方式
这个优化对象获取和修改属性方式,是什么意思呢? 过去我们在设置dom节点transform时是这样的。
1 2 3 4 5
| //加入有一个目标节点, 我们想设置其位移时是这样的 var targetDom = document.getElementById('target'); var transformText = 'translateX(' + 10 + 'px)'; targetDom.style.webkitTransform = transformText; targetDom.style.transform = transformText;
|
通过上面,可以看到如果页面是需要许多动画时,我们这样编写transform属性是十分蛋疼的。(┬_┬)
但如果通过Object.defineProperty, 我们则可以
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| //这里只是简单设置下translateX的属性,其他如scale等属性可自己去尝试
Object.defineProperty(dom, 'translateX', { set: function(value) { var transformText = 'translateX(' + value + 'px)'; dom.style.webkitTransform = transformText; dom.style.transform = transformText; } //这样再后面调用的时候, 十分简单 dom.translateX = 10; dom.translateX = -10; //甚至可以拓展设置如scale, originX, translateZ,等各个属性,达到下面的效果 dom.scale = 1.5; //放大1.5倍 dom.originX = 5; //设置中心点X }
|
上面只是个简单的版本,并不是最合理的写法,但主要是为了说明具体的意图和方法
有兴趣了解更多可以看下面这个库:
点我,老铁