javascript 你什么时候使用 Object.defineProperty()
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10105824/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
when do you use Object.defineProperty()
提问by Andre Meinhold
I'm wondering when I should use
我想知道我什么时候应该使用
Object.defineProperty
to create new properties for an object. I'm aware that I'm able to set things like
为对象创建新属性。我知道我可以设置类似的东西
enumerable: false
but when do you need this really? If you just set a property like
但你什么时候真的需要这个?如果你只是设置一个属性
myObject.myprop = 5;
its descriptors are all set to true, right? I'm actually more curious when you guys use that rather verbose call to .defineProperty() and for what reasons.
它的描述符都设置为true,对吗?当你们使用对 .defineProperty() 的相当冗长的调用以及出于什么原因时,我实际上更加好奇。
采纳答案by Rob W
Object.defineProperty
is mainly used to set properties with specific property descriptors (e.g. read-only (constants), enumerability (to not show a property in a for (.. in ..)
loop, getters, setters).
Object.defineProperty
主要用于设置具有特定属性描述符的属性(例如只读(常量)、可枚举性(在for (.. in ..)
循环中不显示属性、getter、setter)。
"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
Example
例子
This method extends the Object
prototype with a property. Only the getter is defined, and the enumerability is set to false
.
此方法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]"
回答by Pascalius
Features like 'enumerable' are rarely used in my experience. The major use case is computed properties:
在我的经验中很少使用像“可枚举”这样的功能。主要用例是计算属性:
var myObj = {};
myObj.width = 20;
myObj.height = 20;
Object.defineProperty(myObj, 'area', {
get: function() {
return this.width*this.height;
}
});
console.log(myObj.area);
回答by Gerard Simpson
A really good reason for using Object.defineProperty is that it lets you loop through a function in an object as a computed property, which executes the function instead of returning the function's body.
使用 Object.defineProperty 的一个很好的理由是,它允许您将对象中的函数作为计算属性进行循环,从而执行函数而不是返回函数的主体。
For example:
例如:
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
Versus adding the function as a property to an object literal:
与将函数作为属性添加到对象字面量相比:
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;}
Make sure you set the enumerable property to true in order to loop through it.
确保将 enumerable 属性设置为 true 以便循环遍历它。
回答by Danziger
For example, that's how Vue.js keeps track of changes in the data
object:
When you pass a plain JavaScript object to a Vue instance as its
data
option, Vue will walk through all of its properties and convert them togetter/setters
usingObject.defineProperty
. This is an ES5-only and un-shimmable feature, which is why Vue doesn't support IE8 and below.The getter/setters are invisible to the user, but under the hood they enable Vue to perform dependency-tracking and change-notification when properties are accessed or modified.
[...]
当您将普通 JavaScript 对象作为其
data
选项传递给 Vue 实例时,Vue 将遍历其所有属性并将它们转换为getter/setters
usingObject.defineProperty
。这是一个仅限 ES5 且不可调整的功能,这就是 Vue 不支持 IE8 及更低版本的原因。getter/setter 对用户是不可见的,但在幕后,它们使 Vue 能够在访问或修改属性时执行依赖项跟踪和更改通知。
[...]
Keep in mind that even a super slim and basic version of Vue.js would use something more than just Object.defineProperty
, but the main functionality comes from it:
请记住,即使是 Vue.js 的超薄和基本版本也会使用更多的东西Object.defineProperty
,但主要功能来自它:
Here you can see an article where the author implements a minimal PoC version of something like Vue.js: https://medium.com/js-dojo/understand-vue-reactivity-implementation-step-by-step-599c3d51cd6c
在这里你可以看到一篇文章,其中作者实现了 Vue.js 之类的最小 PoC 版本:https://medium.com/js-dojo/understand-vue-reactivity-implementation-step-by-step-599c3d51cd6c
And here a talk (in Spanish) where the speaker builds something similar while explaining reactivity in Vue.js: https://www.youtube.com/watch?v=axXwWU-L7RM
这里有一个演讲(西班牙语),演讲者在解释 Vue.js 中的反应性时构建了类似的东西:https: //www.youtube.com/watch?v =axXwWU-L7RM
回答by Alfonso Pérez
One neat use case I have seen for defineProperty
is for libraries to provide an error property to the user which, if it's not accessed within a certain interval you would throw yourself. For example:
我见过的一个巧妙的用例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;
},
});
Source for this code: https://github.com/apollographql/react-apollo/blob/ddd3d8faabf135dca691d20ce8ab0bc24ccc414e/src/graphql.tsx#L510
此代码的来源:https: //github.com/apollographql/react-apollo/blob/ddd3d8faabf135dca691d20ce8ab0bc24ccc414e/src/graphql.tsx#L510
回答by Willem van der Veen
Summary:
概括:
In Javascript Objects are collections of key-value pairs.
Object.defineProperty()
is a function which can define a new property on an object and can set the following attributes of a property:
在 Javascript 中,对象是键值对的集合。
Object.defineProperty()
是一个函数,它可以在对象上定义新属性,并可以设置属性的以下属性:
- value
<any>
:The value associated with the key - writable
<boolean>
:if writable is set totrue
The property can be updated by assigning a new value to it. If set tofalse
you can't change the value. - enumerable
<boolean>
:if enumerable is set totrue
Property can be accessed via afor..in
loop. Furthermore are the only the enumerable property keys returned withObject.keys()
- configurable
<boolean>
:If configurable is set tofalse
you cannot change change the property attributes (value/writable/enumerable/configurable), also since you cannot change the value you cannot delete it using thedelete
operator.
- value
<any>
:与键关联的值 - writable
<boolean>
:如果 writable 设置为true
可以通过为其分配新值来更新该属性。如果设置为false
您不能更改该值。 - enumerable
<boolean>
:如果 enumerable 设置为true
Property 可以通过for..in
循环访问。此外是唯一返回的可枚举属性键Object.keys()
- 可配置
<boolean>
:如果可配置设置为false
您不能更改更改属性属性(值/可写/可枚举/可配置),同样由于您无法更改值,因此您无法使用delete
运算符删除它。
Example:
例子:
let obj = {};
Object.defineProperty(obj, 'prop1', {
value: 1,
writable: false,
enumerable: false,
configurable: false
}); // create a new property (key=prop1, value=1)
Object.defineProperty(obj, 'prop2', {
value: 2,
writable: true,
enumerable: true,
configurable: true
}); // create a new property (key=prop2, value=2)
console.log(obj.prop1, obj.prop2); // both props exists
for(const props in obj) {
console.log(props);
// only logs prop2 because writable is true in prop2 and false in prop1
}
obj.prop1 = 100;
obj.prop2 = 100;
console.log(obj.prop1, obj.prop2);
// only prop2 is changed because prop2 is writable, prop1 is not
delete obj.prop1;
delete obj.prop2;
console.log(obj.prop1, obj.prop2);
// only prop2 is deleted because prop2 is configurable and prop1 is not
回答by Anish Choudhary
Object.defineProperty
prevents you from accidentally assigning values to some key in its prototype chain. With this method you assign only to that particular object level(not to any key in prototype chain).
Object.defineProperty
防止您意外地为其原型链中的某个键分配值。使用此方法,您只分配给特定的对象级别(而不是原型链中的任何键)。
For example:
There is an object like {key1: value1, key2: value2}
and you don't know exactly its prototype chain or by mistake you miss it and there is some property 'color' somewhere in prototype chain then-
例如:有一个像这样的对象{key1: value1, key2: value2}
,但你并不确切知道它的原型链,或者你错误地错过了它,并且在原型链的某处有一些属性“颜色”然后-
using dot(.) assignment-
使用 dot(.) 赋值-
this operation will assign value to key 'color' in prototype chain(if key exist somewhere) and you will find the object with no change as . obj.color= 'blue'; // obj remain same as {key1: value1, key2: value2}
此操作将为原型链中的键 'color' 赋值(如果键存在于某处),您将找到没有更改的对象为 。obj.color = '蓝色'; // obj 与 {key1: value1, key2: value2} 相同
using Object.defineProperty method-
使用 Object.defineProperty 方法-
Object.defineProperty(obj, 'color', {
value: 'blue'
});
// now obj looks like {key1: value1, key2: value2, color: 'blue'}
. it adds property to the same level.Then you can iterate safely with method Object.hasOwnProperty()
.
// 现在 obj 看起来像{key1: value1, key2: value2, color: 'blue'}
. 它将属性添加到同一级别。然后您可以使用 method 安全地迭代Object.hasOwnProperty()
。
回答by David
A good use is when you need to do some interception or apply a classical Observer/Observable pattern in a elegant way:
一个很好的用途是当你需要做一些拦截或以优雅的方式应用经典的 Observer/Observable 模式时:
回答by AFOC
A very useful case is to monitor changes to something and act on them. It's easy because you can have callback functions fire whenever the value gets set. Here's a basic example.
一个非常有用的案例是监控某事的变化并对其采取行动。这很容易,因为您可以在设置值时触发回调函数。这是一个基本的例子。
You have an object Player
that can be playing or not playing. You want something to happen right when it starts playing, and right when it stops playing.
您有一个Player
可以播放或不播放的对象。您希望在开始播放时立即发生某些事情,并在停止播放时立即发生。
function Player(){}
Object.defineProperty(Player.prototype, 'is_playing', {
get(){
return this.stored_is_playing; // note: this.is_playing would result in an endless loop
},
set(newVal){
this.stored_is_playing = newVal;
if (newVal === true) {
showPauseButton();
} else {
showPlayButton();
}
}
});
const cdplayer = new Player();
cdplayer.is_playing = true; // showPauseButton fires
This answer is related to a couple other answers here, which are good stepping points for more information, but with no need to follow external links to read about libraries or programming paradigms.
此答案与此处的其他几个答案有关,它们是了解更多信息的良好起点,但无需遵循外部链接来阅读有关库或编程范式的信息。
回答by SammieFox
@Gerard Simpson
@杰拉德·辛普森
If 'area' should be enumerable it can be written without Object.defineProperty, too.
如果 'area' 应该是可枚举的,它也可以在没有 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