我想编写一个函数的一个版本,它迭代了Array对象和Objects,只需要很少的重复代码。类似的东西:
function (arr_or_obj) {
arr_or_obj.forEach( function(key,value) {
// do stuff with key and value
});
}
这是在我意识到(至少在Chrome中)之前,Object.keys
返回一个数组键的列表。所以我可以使用它来像对象一样对待数组。像这样:
function (arr_or_obj) {
var keys = Object.keys(arr_or_obj);
keys.forEach( function(key) {
var value = arr_or_obj[key];
// do stuff with key and value
});
}
问题解决了。但这不是在我编写自己的“JavaScript伪数组迭代器”之前。这样做的唯一好处是,不是获取数组的键列表(可能很长),而是通过仅生成我们需要的返回值来节省内存。像这样:
function create_iterator(max) {
var jkeys = {};
jkeys.count_ = 0;
jkeys.length = max;
jkeys.getter_ = function() {
var returnable = jkeys.count_;
jkeys.count_ += 1;
jkeys.__defineGetter__(jkeys.count_,jkeys.getter_);
delete jkeys[jkeys.count_-1];
return returnable;
};
jkeys.__defineGetter__(0, jkeys.getter_);
return jkeys;
}
然后您可以通过以下方式致电:
var z = create_iterator(100);
z[0];
>> 0
z[0];
>> undefined
z[1];
>> 1;
z[2]
>> 2;
...
这是一个问题和答案,但显而易见的问题是,如果不使用Object.keys
有更好的方法吗?
答案 0 :(得分:1)
Object.keys
为您提供了一个对象的拥有的可枚举属性的数组。也就是说,它本身的属性,而不是它的原型,并且是可枚举的(所以不包括数组上的length
之类的东西,这是一个非可枚举的属性)。
如果使用正确的安全措施,您可以使用for-in
执行相同的操作:
var key;
for (key in arr_or_obj) {
if (arr_or_obj.hasOwnProperty(key)) {
// do something with it
}
}
现在你正在做与Object.keys
相同的事情。
但是,请注意,此(和Object.keys
)将包含人们放置在不是数组索引的数组上的属性(这些属性在JavaScript的)。 E.g:
var key;
var a = [1, 2, 3];
a.foo = "bar";
for (key in a) {
if (a.hasOwnProperty(key)) {
console.log(key); // Will show "foo" as well as "0", "1", and "2"
}
}
如果您只想处理数组索引而不是其他属性,则需要知道该东西是否为数组,然后如果是,请使用“这是一个索引”测试:
var key;
var isArray = Array.isArray(arr_or_obj);
// Or (see below):
//var isArray = Object.prototype.toString.call(arr_or_obj) === "[object Array]";
for (key in arr_or_obj) {
if (a.hasOwnProperty(key) &&
(!isArray || isArrayIndex(key))
) {
console.log(key); // Will only show "0", "1", and "2" for `a` above
}
}
...其中Array.isArray
是ES5的新功能,如有必要,可以轻松为旧版浏览器填充:
if (!Array.isArray) {
Array.isArray = (function() {
var toString = Object.prototype.toString;
function isArray(arg) {
return toString.call(arg) === "[object Array]";
}
return isArray;
})();
}
...而isArrayIndex
是:
function isArrayIndex(key) {
return /^0$|^[1-9]\d*$/.test(key) && key <= 4294967294; // 2^32 - 2
}
有关详细信息,请参阅this other answer(幻数来源等)。
上面的循环将遍历对象自己的可枚举属性(所有这些),如果它不是数组,并循环索引(但不是其他属性),如果它是一个数组。
更进一步,如果要包含对象从其原型中获取的属性,该怎么办? Object.keys
省略了(按设计)。如果您想要包含它们,请不要在hasOwnProperty
循环中使用for-in
。
答案 1 :(得分:1)
你可以尝试这样的事情......
Live Demo
function forIn(obj) {
var isArray = Array.isArray(obj),
temp = isArray ? obj : Object.keys(obj);
temp.forEach(function (value, index, array) {
console.log(this[isArray ? index : value]);
}, obj);
}
答案 2 :(得分:0)
你可以写:
for (key in arr_or_obj) {
if (arr_or_obj.hasOwnProperty(key) {
value = arr_or_obj[key];
// do stuff with key and value
}
}