Javascript:检索对象属性名称 [英] Javascript: Retrieve Object Property Names
问题描述
我正在尝试编写一个需要知道传入对象的属性名称的函数,如下所示:
I'm trying to write a function that needs to know the property names of an object being passed in, like so:
var data = { "key1":"value1", "key2":"value2", etc}
^ i want the string value "key1"
如何从数据
中检索字符串key1?我知道我可以动态设置属性,如 data [prop] = value
但我想知道 prop
来自哪个传入的对象。
How do I retrieve the string "key1" from data
? I know I can set a property dynamically like data[prop]=value
but i want to know what prop
is from an object passed in.
如果这没有意义,我想我可以尝试解释更多。谢谢!
If that doesn't make sense I suppose I could try to explain more. Thanks!
我最终想做的事情如下:
I eventually want to do something like:
for (var i = 0; i<data.length; i++)
{
var name = data[i].getPropertyName() <--- not a real function
// do stuff
}
推荐答案
在我们看看之前选项,快速了解JavaScript中属性的四个关键内容:
Before we look at our options, a quick note of the four key things about properties in JavaScript:
- 对象可以拥有自己的属性,以及它们继承的属性他们的原型对象。
- 属性可以是可枚举或不可枚举。
- 属性可以具有字符串或(从ES2015 / ES6开始)名称
符号
s。 - 属性不能有数字的名称,例如1.有时候我们会像他们那样行事,就像我们处理数组时一样,但事实并非如此。标准数组根本不是真正的数组(根据规范) ;允许JavaScript实现在可以的情况下进行优化),并且数组中的条目是名称为字符串的对象属性。所以
a = ['x','y','z']
定义一个包含三个属性的数组,其名称为0
,1
,2
。当我们a [0]
访问第一个时,数字0
将转换为字符串。 (理论上;再次允许JavaScript实现进行优化。)
- Objects can have properties of their own, and properties they inherit from their prototype object.
- Properties can be enumerable or non-enumerable.
- Properties can have names that are strings, or (as of ES2015/ES6) names that are
Symbol
s. - Properties cannot have names that are numbers, like 1. Sometimes we act like they do, as when we're dealing with arrays, but they don't. Standard arrays aren't really arrays at all (per the spec; JavaScript implementations are allowed to optimize when they can), and the entries in arrays are object properties whose names are strings. So
a = ['x', 'y', 'z']
defines an array with three properties whose names are"0"
,"1"
, and"2"
. When we doa[0]
to access the first one, the number0
is converted to a string. (In theory; again, the JavaScript implementation is allowed to optimize.)
所有这些属性都可以被发现和枚举(甚至是不可数的)。
您有以下几种选择:
All of these properties can be discovered and enumerated (even the non-enumerable ones). You have several options for doing so:
-
for-in
loop ( spec | MDN ),有或没有hasOwnProperty
保护循环内部以区分自己的和继承的属性。 (不包括以符号
s命名的属性。)循环显示属性的名称。 -
Object.keys
( spec | MDN )(ES5 +),它返回一个对象自己的可枚举属性名称的数组。 (不包括以符号
s命名的属性。) -
Object.getOwnPropertyNames
( spec | MDN )( ES5 +),它返回一个对象自己的属性名称数组,无论它们是否可枚举。 (不包括以符号
s命名的属性。) -
Reflect.enumerate
(规范 | MDN )(ES2015 +),它返回一个对象的可枚举属性名称的迭代器,包括它继承的属性。 (不包括以符号
s命名的属性。) -
Object.getOwnPropertySymbols
( spec | MDN )(ES2015 +),返回一个对象自己的属性名称数组,以Symbol
命名,无论它们是否可枚举。 (不包括用字符串命名的。) -
Reflect.ownKeys
( spec | MDN )(ES2015 +),它返回一个对象自己属性名称的数组无论它们如何命名(Symbol
或字符串),以及它们是否可枚举。
- A
for-in
loop (spec | MDN), with or without ahasOwnProperty
guard inside the loop to differentiate between "own" and inherited properties. (Does not include properties named withSymbol
s.) Loops through the names of the properties. Object.keys
(spec | MDN) (ES5+), which returns an array of the names of an object's own, enumerable properties. (Does not include properties named withSymbol
s.)Object.getOwnPropertyNames
(spec | MDN) (ES5+), which returns an array of the names of an object's own properties, regardless of whether they're enumerable. (Does not include properties named withSymbol
s.)It was removed in ES2016.Reflect.enumerate
(spec | MDN) (ES2015+), which returns an iterator for the names of the enumerable properties of an object, including ones it inherits. (Does not include properties named withSymbol
s.)Object.getOwnPropertySymbols
(spec | MDN) (ES2015+), which returns an array of the names of an object's own properties named withSymbol
s, regardless of whether they're enumerable. (Leaves out ones named with strings.)Reflect.ownKeys
(spec | MDN) (ES2015+), which returns an array of the names of an object's own properties no matter how they're named (Symbol
or string), and whether they're enumerable or not.
如您所见,大多数操作只包括名称为字符串的属性,只有 Object.getOwnPropertySymbols
和 Reflect.ownKeys
给我们以符号
s命名的那些。
As you can see, most of the operations only include properties whose names are strings, with only Object.getOwnPropertySymbols
and Reflect.ownKeys
giving us the ones named with Symbol
s.
顺序对于 for-in
或 Object.keys
,未定义键(甚至在ES2015中)。在ES2015及以上版本中,通过 为其他四个定义 -ordinary-object-internal-methods-and-internal-slots-ownpropertykeysrel =noreferrer> [[OwnPropertyKeys]]
和(如适用) [[Enumerate]]
操作。 (由于ES2015仍然[在撰写本文时]相对知道,可能并非所有JavaScript引擎都能正确实现订单。)
The order of the keys is not defined (not even in ES2015) for for-in
or Object.keys
. In ES2015 and above, it is defined for the other four, by the [[OwnPropertyKeys]]
and (where applicable) [[Enumerate]]
operations. (Since ES2015 is still [as of this writing] relatively knew, it's possible not all JavaScript engines correctly implement the order yet.)
让我们看一些例子。首先,一些设置:
Let's look at examples. First, some setup:
// Create an object with one "own" property (plus the ones it
// inherits from Object.prototype):
var proto = {
one: 1
}
// Create an object that uses the above as its prototype
var obj = Object.create(proto);
// Add a couple of enumerable properties
obj.two = 2;
obj.three = 3;
// Add a non-enumerable property (by default, properties created
// with Object.defineProperty are non-enumerable)
Object.defineProperty(obj, "four", {
value: 4,
configurable: true,
writable: true
});
( Object.create
是在ES5中添加,但它只带一个参数[如上所述]的版本可以很容易地为过时的JavaScript引擎(如IE8中的那个)进行填充/填充。 Object.defineProperty
也被添加到ES5中,无法正确填充/填充。)
(Object.create
was added in ES5, but the version of it taking just one argument [as above] can easily be shimmed/polyfilled for obsolete JavaScript engines, like the one in IE8. Object.defineProperty
was also added in ES5, and cannot be correctly shimmed/polyfilled.)
由于大多数操作只涉及字符串命名的属性,我们忽略了现在符号
。
Since most of the operations only involve properties named by strings, we're ignoring Symbol
s for now.
上面的代码运行后,我们在内存中有这个( *
名称旁边表示它是一个不可枚举的属性):
Once the code above runs, we have this in memory (the *
next to a name indicates it's a non-enumerable property):
+−−−−−−−−−−−−−−−−−+
Object.prototype−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+−−>| toString* |−−>(...a function...)
| | valueOf* |−−>(...a function...)
| | hasOwnProperty* |−−>(...a function...)
| | ... |
| +−−−−−−−−−−−−−−−−−+
|
+−−−−−−−−−−−−−−−+ |
proto−−−−−−−−−−−−−−−−−−−−+−−>| [[Prototype]] |−−+
| | one: 1 |
| +−−−−−−−−−−−−−−−+
|
+−−−−−−−−−−−−−−−+ |
obj−−>| [[Prototype]] |−−+
| two: 2 |
| three: 3 |
| four*: 4 |
+−−−−−−−−−−−−−−−+
有了这个设置,让我们来看看我们的选择:
With that setup, let's look at our options:
for-in
循环遍历所有对象属性的名称(包括它从其原型继承的属性),其名称为字符串(省略任何名称为符号
s)。
for-in
loops through the names of all of an object's properties (including ones it inherits from its prototype) whose names are strings (leaving out any whose names are Symbol
s).
for (var name in obj) {
// name is the name of each property, so:
console.log(name + " = " + obj[name]);
}
// Create an object with one "own" property (plus the ones it
// inherits from Object.prototype):
var proto = {
one: 1
}
// Create an object that uses the above as its prototype
var obj = Object.create(proto);
// Add a couple of enumerable properties
obj.two = 2;
obj.three = 3;
// Add a non-enumerable property (by default, properties created
// with Object.defineProperty are non-enumerable)
Object.defineProperty(obj, "four", {
value: 4,
configurable: true,
writable: true
});
for (var name in obj) {
// name is the name of each property, so:
console.log(name + " = " + obj[name]);
}
有了这个,我们看到
two = 2
three = 3
one = 1
...或者simila河您看到属性的顺序未定义,即使在ES2015中也没有定义。
...or similar. The order you see the properties in is not defined, not even in ES2015.
如果我们想要循环但忽略继承属性,我们可以添加 hasOwnProperty
check:
If we wanted the loop, but ignoring inherited properties, we can add a hasOwnProperty
check:
for (var name in obj) {
if (obj.hasOwnProperty(name)) {
console.log(name + " = " + obj[name]);
}
}
// Create an object with one "own" property (plus the ones it
// inherits from Object.prototype):
var proto = {
one: 1
}
// Create an object that uses the above as its prototype
var obj = Object.create(proto);
// Add a couple of enumerable properties
obj.two = 2;
obj.three = 3;
// Add a non-enumerable property (by default, properties created
// with Object.defineProperty are non-enumerable)
Object.defineProperty(obj, "four", {
value: 4,
configurable: true,
writable: true
});
for (var name in obj) {
if (obj.hasOwnProperty(name)) {
console.log(name + " = " + obj[name]);
}
}
有了这个,我们看到了
two = 2
three = 3
我们不喜欢看不到一个
因为它是继承的。
We don't see one
because it's inherited.
因为 hasOwnProperty
是对象的一个方法,理论上它可以用一个没有返回我们期望的版本来覆盖:
Since hasOwnProperty
is a method on the object, in theory it could be overridden with a version that didn't return what we expect:
obj.hasOwnProperty = function() {
return true;
};
...这会欺骗我们的循环。这通常不是问题,但如果你想防范它,请使用 Object.prototype
中的那个:
...which would fool our loop above. That's not usually an issue, but if you want to guard against it, use the one from Object.prototype
instead:
var hasOwn = Object.prototype.hasOwnProperty;
for (var name in obj) {
if (hasOwn.call(obj, name)) {
console.log(name + " = " + obj[name]);
}
}
当然,有人可以分配给 Object.prototype.hasOwnProperty
属性,但如果他们这样做,相当多的事情可能会破坏。
Of course, someone can assign to the Object.prototype.hasOwnProperty
property as well, but if they do, a fair number of things are likely to break.
Object.keys
为我们提供了一个对象的拥有的,可枚举的属性的名称数组,这些属性用字符串命名。因此它不包括继承的属性,标记为非可枚举的属性,或以符号
s命名的属性。
Object.keys
gives us an array of the names of the object's own, enumerable properties named with strings. So it doesn't include inherited properties, properties marked non-enumerable, or properties named with Symbol
s.
var propNames = Object.keys(obj);
然后,我们可以通过多种方式循环遍历该数组中的条目,例如 forEach
:
We can then loop over the entries in that array in any of several ways, such as forEach
:
propNames.forEach(function(name) {
console.log(name + " = " + obj[name]);
});
// Create an object with one "own" property (plus the ones it
// inherits from Object.prototype):
var proto = {
one: 1
}
// Create an object that uses the above as its prototype
var obj = Object.create(proto);
// Add a couple of enumerable properties
obj.two = 2;
obj.three = 3;
// Add a non-enumerable property (by default, properties created
// with Object.defineProperty are non-enumerable)
Object.defineProperty(obj, "four", {
value: 4,
configurable: true,
writable: true
});
var propNames = Object.keys(obj);
propNames.forEach(function(name) {
console.log(name + " = " + obj[name]);
});
通过我们的样本设置,它给了我们:
With our sample setup, that gives us:
two = 2
three = 3
订单o f数组中的名称未由规范定义,即使在ES2015中也没有定义。
The order of the names in the array is not defined by the specification, not even in ES2015.
Object.getOwnPropertyNames
返回以字符串命名的对象自己的属性名称数组,无论是否可枚举或不。它省略了以 Symbol
s命名的属性。
Object.getOwnPropertyNames
returns an array of the names of the object's own properties named with strings, whether enumerable or not. It leaves out properties named with Symbol
s.
var propNames = Object.getOwnPropertyNames(obj);
propNames.forEach(function(name) {
console.log(name + " = " + obj[name]);
});
// Create an object with one "own" property (plus the ones it
// inherits from Object.prototype):
var proto = {
one: 1
}
// Create an object that uses the above as its prototype
var obj = Object.create(proto);
// Add a couple of enumerable properties
obj.two = 2;
obj.three = 3;
// Add a non-enumerable property (by default, properties created
// with Object.defineProperty are non-enumerable)
Object.defineProperty(obj, "four", {
value: 4,
configurable: true,
writable: true
});
var propNames = Object.getOwnPropertyNames(obj);
propNames.forEach(function(name) {
console.log(name + " = " + obj[name]);
});
通过我们的样本设置,它给了我们:
With our sample setup, that gives us:
two = 2
three = 3
four = 4
数组中名称的顺序由 [[OwnPropertyKeys]]
操作在规范中,该订单是:
The order of the names in the array is defined by the [[OwnPropertyKeys]]
operation in the specification, which says the order is:
- 符合整数索引,按数字顺序排列。
- 其他属性的名称,按照创建属性的顺序。
- The property names that qualify as integer indexes, in numeric order.
- The names for other properties, in the order the property was created.
所以我们得到两个
,三个
,四个
因为这些都不符合规范对整数索引的定义,这就是订单我们在其中添加了属性。如果我们以不同的顺序添加它们,或者包含那些符合索引的顺序,我们会得到不同的结果:
So we get two
, three
, four
because none of those fits the spec's definition of an integer index, and that's the order in which we added the properties. If we added them in a different order, or included ones that qualified as indexes, we'd get different results:
var obj2 = {};
obj2.four = 4;
obj2[0] = "zero";
obj2.two = 2;
obj2.three = 3;
Object.getOwnPropertyNames(obj2).forEach(function(name) {
console.log(name + " = " + obj2[name]);
});
var obj2 = {};
obj2.four = 4;
obj2[0] = "zero";
obj2.two = 2;
obj2.three = 3;
Object.getOwnPropertyNames(obj2).forEach(function(name) {
console.log(name + " = " + obj2[name]);
});
给我们:
0 = zero
four = 4
two = 2
three = 3
0
首先是因为虽然它是一个字符串,它符合整数索引的标准。然后我们得到四
,因为它是先创建的,然后两个
,然后三
。
0
was first because although it's a string, it fits the criteria for an integer index. Then we get four
because it was created first, then two
, then three
.
Reflect.enumerate
已在ES2016中删除。
Reflect.enumerate
was removed in ES2016.
Reflect.enumerate
使用新的迭代器功能ES2015。它返回一个迭代器,它将遍历对象的字符串命名的可枚举属性的名称,包括继承的属性,跳过以 Symbol
命名的或不可枚举的。首先,它访问自己的属性(按照 [[OwnPropertyKeys]]
定义的顺序,然后继承属性(除非它们被自己的属性隐藏) 。
Reflect.enumerate
uses the new iterator feature of ES2015. It returns an iterator that will iterate over the names of the string-named enumerable properties of the object, including inherited ones, skipping ones named with Symbol
or that aren't enumerable. First it visits the "own" properties (in the order defined by [[OwnPropertyKeys]]
, and then inherited properties (unless they've been hidden by "own" properties).
我们可以使用新的 for-of
循环来循环它们:
We can use the new for-of
loop to loop over them:
for (let name of Reflect.enumerate(obj)) {
console.log(name + " = " + obj[name]);
}
通过我们的设置,我们可以:
With our setup, that gives us:
two = 2
three = 3
one = 1
一个
在最后,因为它是继承的,而自己的属性是第一个。
one
is at the end because it's inherited, and "own" properties come first.
注意:同样,由于ES2015在撰写本文时相对较新,因此一些JavaScript引擎可能尚未实现 Reflect
对象。
Note: Again, since ES2015 is relatively new as of this writing, some JavaScript engines may not implement the Reflect
object yet.
Object.getOwnPropertySymbols
返回一个对象自己的属性数组使用符号
s,无论它们是否可枚举。 (不包括用字符串命名的。)我们需要一个不同的设置来尝试这个,因为我们在主设置中没有包含 Symbol
-named属性。由于忽略了继承的属性,我们将保持简单:
Object.getOwnPropertySymbols
returns an array of an object's own properties named with Symbol
s, regardless of whether they're enumerable. (Leaves out ones named with strings.) We'll need a different setup to try this, since we didn't include Symbol
-named properties in our main setup. Since inherited properties are ignored, we'll keep it simple:
var obj3 = {};
obj3[Symbol("x")] = "ecks";
obj3[1] = "one";
obj3[Symbol("y")] = "why";
obj3.z = "zee";
Object.getOwnPropertySymbols(obj3).forEach(function(symbol) {
console.log(symbol.toString() + " = " + obj3[symbol]);
});
var obj3 = {};
obj3[Symbol("x")] = "ecks";
obj3[1] = "one";
obj3[Symbol("y")] = "why";
obj3.z = "zee";
Object.getOwnPropertySymbols(obj3).forEach(function(symbol) {
console.log(symbol.toString() + " = " + obj3[symbol]);
});
输出:
Symbol(x) = ecks
Symbol(y) = why
z
未列出,因为它有一个字符串名称,而不是符号
名称。 符号(x)
是第一个,因为它是先创建的。
z
wasn't listed because it has a string name, not a Symbol
name. Symbol(x)
was first because it was created first.
符号
比此处所示,但正如您所看到的,如果我们给一个符号命名,我们可以使用 toString
来取回符号(此处的名称)
作为字符串。有趣的是,我们必须调用 toString
显式( thesymbol.toString()
)或使用字符串(theSymbol
);将符号附加到字符串时, +
运算符不会为我们执行此操作。
There's a lot more to Symbols
than shown here, but as you can see, if we give a symbol a name, we can use toString
to get back Symbol(the name here)
as a string. Interesting, we have to call toString
explicitly (thesymbol.toString()
) or use String(theSymbol
); the +
operator will not do it for us when appending a symbol to a string.
Reflect.ownKeys
返回一个数组对象自己的属性,无论它们如何命名( Symbol
或字符串),以及它们是否可枚举。它忽略了继承的属性:
Reflect.ownKeys
returns an array of an object's own properties no matter how they're named (Symbol
or string), and whether they're enumerable or not. It ignores inherited properties:
var obj3 = {};
obj3[Symbol("x")] = "ecks";
obj3[1] = "one"
obj3[Symbol("y")] = "why";
obj3.z = "zee";
Reflect.ownKeys(obj3).forEach(function(key) {
console.log(key.toString() + " = " + obj3[key]);
});
var obj3 = {};
obj3[Symbol("x")] = "ecks";
obj3[1] = "one"
obj3[Symbol("y")] = "why";
obj3.z = "zee";
Reflect.ownKeys(obj3).forEach(function(key) {
console.log(key.toString() + " = " + obj3[key]);
});
输出:
1 = one
z = zee
Symbol(x) = ecks
Symbol(y) = why
注意订单,由 [[OwnPropertyKeys]]
定义: 1
是第一个,因为它是一个字符串这符合整数索引。接下来是 z
,因为它是一个以字符串命名的属性。然后我们按照它们的创建顺序获得 Symbol
-named属性。
Note the order, which is defined by [[OwnPropertyKeys]]
: 1
was first because it's a string that qualifies as an integer index. z
was next because it's a string-named property. Then we have the Symbol
-named properties, in the order in which they were created.
这篇关于Javascript:检索对象属性名称的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!