你什么时候使用Object.defineProperty()

我想知道什么时候该用

Object.defineProperty 

为对象创build新的属性。 我知道,我可以设置的东西

 enumerable: false 

但是你什么时候需要这个呢? 如果你只是设置一个属性

 myObject.myprop = 5; 

其描述符都设置为true,对吗? 实际上,当你们对.defineProperty()进行冗长的调用以及出于什么原因时,我更加好奇。

Object.defineProperty主要用于设置具有特定属性描述符的属性(例如,只读(常量),枚举(不在for (.. in ..)循环中显示属性,getters,setters)。

 "use strict"; var myObj = {}; // Create object // Set property (+descriptor) Object.defineProperty(myObj, 'myprop', { value: 5, writable: false }); console.log(myObj.myprop);// 5 myObj.myprop = 1; // In strict mode: TypeError: myObj.myprop is read-only 

这个方法用一个属性扩展了Object原型。 只有getter被定义,并且可枚举被设置为false

 Object.defineProperty(Object.prototype, '__CLASS__', { get: function() { return Object.prototype.toString.call(this); }, enumerable: false // = Default }); Object.keys({}); // [] console.log([].__CLASS__); // "[object Array]" 

像“enumerable”这样的function很less用于我的经验。 主要的用例是计算属性:

 var myObj = {}; myObj.width = 20; myObj.height = 20; Object.defineProperty(myObj, 'area', { get: function() { return this.width*this.height; } }); console.log(myObj.area); 

使用Object.defineProperty的一个很好的理由是,它可以让你循环一个对象的函数作为一个计算属性,它执行函数而不是返回函数的主体。

例如:

 var myObj = {}; myObj.width = 20; myObj.height = 20; Object.defineProperty(myObj, 'area', { get: function() { return this.width*this.height; }, enumerable: true }); for (var key in myObj) { if (myObj.hasOwnProperty(key)) { console.log(key + " -> " + myObj[key]); } } //width -> 20, height -> 20, area -> 400 

将函数作为属性添加到对象文本中:

 var myObj = {}; myObj.width = 20; myObj.height = 20; myObj.area = function() { return this.width*this.height; }; for (var key in myObj) { if (myObj.hasOwnProperty(key)) { console.log(key + " -> " + myObj[key]); } } // width -> 20, height -> 20, area -> function() { return this.width*this.height;} 

确保将enumerable属性设置为true以便循环。

我已经看到的defineProperty一个整洁的用例是为库提供一个错误属性的用户,如果它没有在一定的时间间隔内访问,你会抛出自己。 例如:

 let logErrorTimeoutId = setTimeout(() => { if (error) { console.error('Unhandled (in <your library>)', error.stack || error); } }, 10); Object.defineProperty(data, 'error', { configurable: true, enumerable: true, get: () => { clearTimeout(logErrorTimeoutId); return error; }, }); 

此代码的来源: https : //github.com/apollographql/react-apollo/blob/ddd3d8faabf135dca691d20ce8ab0bc24ccc414e/src/graphql.tsx#L510

一个很好的用法是当你需要做一些拦截或者以一种优雅的方式应用经典的Observer / Observable模式:

https://www.monterail.com/blog/2016/how-to-build-a-reactive-engine-in-javascript-part-1-observable-objects

@杰拉德·辛普森

如果“区域”应该是可枚举的,那么也可以不用Object.defineProperty来编写。

 var myObj = { get area() { return this.width * this.height } }; myObj.width = 20; myObj.height = 20; for (var key in myObj) { if (myObj.hasOwnProperty(key)) { console.log(key + " -> " + myObj[key]); } } //area -> 400, width -> 20, height -> 20