对象属性名称作为数字

根据 MDN JavaScript 文档,您可以使用整数定义对象文字属性名:

此外,还可以使用数值或字符串文字作为属性的名称。

像这样:

me = {
name: "Robert Rocha",
123: 26,
origin: "Mexico"
}

我的问题是,如何将具有整数的属性引用为名称?我试了通常的 me.123,但得到了一个错误。我能想到的唯一解决办法是使用 for-in循环。有什么建议吗?

86914 次浏览

你可以使用 me[123]或者 me["123"],两者都可以。

您可以使用 括号符号 me[123]

您可以像引用数组一样引用对象的属性,并使用 me[123]me["123"]

点符号只适用于属性名称,这些属性名称是有效的标识符。标识符必须以字母、 $、 _ 或 Unicode 转义序列开头。对于所有其他属性名,必须使用括号表示法。

在对象文字中,属性名称必须是标识符名称、字符串文字或数值文字(由于属性名称必须是字符串,因此将转换为字符串) :

var obj = {1:1, foo:'foo', '+=+':'+=+'};


alert(obj[1] + ' ' + obj.foo + ' ' + obj['+=+']); // 1 foo +=+

以防其他人对此感到困惑: 当对象中有对象时,使用整数(而不是字符串)属性名可能会产生略微不同的结果(尽管功能相同)(取决于浏览器)。

没有嵌套对象的简单对象具有跨浏览器的一致行为(尽管 正如公认的答案所说,我们需要使用括号而不是点来访问整数属性名) :

var str_simple = {
a: "b", c: "d", e: "f", g: "h",
};
str_simple.a === "b"; // true
str_simple.e === "f"; // true


var int_simple = {
1: 2, 3: 4, 5: 6, 7: 8,
};
int_simple[1] === 2; // true - must use brackets instead of dots
int_simple[5] === 6; // true
// this works b/c int property names are coerced to strings anyway
int_simple[1] === int_simple['1']; // true

这个带字符串键的嵌套对象的工作方式与预期完全一样:

var str_nested = {
a: {b: "c"},
d: {e: "f", g: "h"},
};
str_nested.a; // returns object as expected, no matter the browser - {b: "c"}
str_nested.a.b === "c"; // true
str_nested.d.g === "h"; // true

但是这个等价的带整数键的嵌套对象会根据浏览器返回稍微不同的结果,尽管你仍然可以用相同的方式访问嵌套对象(所以在功能上,它仍然可以工作) :

var int_nested = {
1: {2: 3},
4: {5: 6, 7: 8},
};


// latest Chrome (57)
// Safari 10 (latest for my Mac, 10.10 Yosemite)
int_nested[1]; // returns object as expected - {2: 3}
int_nested[1][2] === 3; // true


// latest Firefox (52)
int_nested[1]; // RETURNS ARRAY-LIKE OBJECT - Object [ <2 empty slots>, 3 ]
int_nested.length; // undefined because it's not technically an array
int_nested[1][2] === 3; // true - works b/c object was padded with empty slots


// and again, in all browsers, we can exchange the integer keys
// for equivalent strings since property names are coerced to strings anyway
int_nested[1][2] === int_nested['1'][2];
int_nested['1'][2] === int_nested[1]['2'];
int_nested[1]['2'] === int_nested['1']['2'];

如果以编程方式构造嵌套对象,这种行为仍然会略有不同,但在功能上是相同的。例如,假设我们想编写一个函数,它接受一个对列表(例如 [[0, 0], [0, 1], [1, 2], [2, 3]]) ,并将其转换为一个嵌套对象,这样我们就可以检查这个对是否在 O (1)时间的对象中(例如 {0: {0: true, 1: true}, 1: {2: true}, 2: {3, true}})。请注意,集合检查 引用相等而不是值相等,所以我们不能将对本身存储在 Set 中并实现相同的结果:

// [[0, 0], [0, 1], [1, 2], [2, 3]] ->
// {
//  0: {0: true, 1: true},
//  1: {2: true},
//  2: {3: true},
// }
function createNestedObject(pairs) {
var obj = {};
for (var pair of pairs) {
var x = pair[0], y = pair[1];
// must create outer object for each unique x or else
// obj[x][y] would fail b/c obj[x] would be undefined
if (!obj.hasOwnProperty(x)) {
obj[x] = {};
}
obj[x][y] = true;
}
return obj;
}


function exists(nested, pair) {
var x = pair[0], y = pair[1];
// uses !! operator so if pair isn't in nested
// we return false instead of undefined
return !!(nested[x] && nested[x][y]);
}

带字符串的对将按预期工作:

var pairs = [["a", "a"], ["a", "b"], ["c", "d"], ["d", "e"]];
var nested = createNestedObject(pairs);
nested; // as expected - {a: {a: true, b: true}, c: {d: true}, d: {e: true}}
exists(nested, ["a", "a"]); // true
exists(nested, ["a", "b"]); // true
exists(nested, ["ZZZ", "ZZZ"]); // false

但在某些浏览器中,整数对不同,但功能相同:

var pairs = [[0, 0], [0, 1], [1, 2], [2, 3]];
var nested = createNestedObject(pairs);
nested; // in Safari 10/Chrome 57 - returns nested objects as expected
nested; // in Firefox 52 - Object [ Object[2], Object[3], Object[4] ]
// BUT still gives correct results no matter the browser
exists(nested, [0, 0]); // true
exists(nested, [0, 1]); // true
exists(nested, ['0', '0']); // true
exists(nested, [999, 999]); // false

数字属性名称的情况似乎比迄今为止的答案所解释的更为复杂。的确,您可以通过 for-in 循环访问这些属性。但是,也许有必要知道 for-in 循环给出的键是字符串,而不是您可能期望的数字:

var obj = {1:2};
for (var key in obj) {
alert(typeof(obj[key])); // you get "number" as expected, however
alert(typeof(key)); // you get "string", not "number"
}

在使用 JSON 进行序列化时也会发生类似的情况:

JSON.stringify( {1:2} ) === '{"1":2}'

因此,如果您的代码依赖于这个小细节,那么您最好注意它。