在JavaScript中,有些对象假装是数组(或者是“类似数组”)。这些对象是arguments
,NodeList
s(从getElementsByClassName
返回等)和jQuery对象。
当console.log
ged时,它们显示为数组,但它们不是。我知道,为了像数组一样,对象必须具有length
属性。
所以我做了一个像这样的“对象”:
function foo(){
this.length = 1;
this[0] = "bar";
}
var test = new foo;
当我console log(test)
时,我得到(正如预期的)foo
个对象。我可以使用
Array.prototype.slice.call(test)
但是,我不想转换它,我希望它像数组一样。如何制作类似于数组的对象,以便在console.log
ged时,它显示为数组?
我尝试设置foo.prototype = Array.prototype
,但console.log(new foo)
仍显示foo
个对象,而不是数组。
答案 0 :(得分:26)
具体取决于控制台。对于Chrome开发者控制台和Firebug中的自定义对象,您需要length
和splice
属性。 splice
也必须是一个功能。
a = {
length: 0,
splice: function () {}
}
console.log(a); //[]
然而,重要的是要注意,没有官方标准。
jQuery(v1.11.1)在内部使用以下代码来确定对象是否应使用for
循环或for..in
循环:
function isArraylike( obj ) {
var length = obj.length,
type = jQuery.type( obj );
if ( type === "function" || jQuery.isWindow( obj ) ) {
return false;
}
if ( obj.nodeType === 1 && length ) {
return true;
}
return type === "array" || length === 0 ||
typeof length === "number" && length > 0 && ( length - 1 ) in obj;
}
请注意,可以将一个对象作为数组([]
)出现在控制台中,但是在jQuery中使用for..in
循环或者作为对象出现的对象进行迭代在控制台({}
)中,但在jQuery中使用for
循环进行迭代。
答案 1 :(得分:4)
这是否有用:extended array prototype,看起来他正在做你做的事情,并将原型创建为数组,但包括一个额外的方法(可能或可能不起作用,我没有测试过这个):
var MyArray = function() {
};
MyArray.prototype = new Array;
MyArray.prototype.forEach = function(action) {
for (var i = 0, l=this.length; i < l, ++i) {
action(this[i]);
}
};
希望它在某种程度上有所帮助。
答案 2 :(得分:1)
与我们可以使用像arguments
这样的数组一样,我想到了同样的问题:
function arrayLike() {
console.log(typeof arguments)
console.log(arguments)
console.log(Array.from(arguments))
}
arrayLike(1,2,3)
因此,让我们尝试创建自己的类似数组的对象:
let arrayLikeObject = {
0: 1,
1: 2
}
console.log(Array.from(arrayLikeObject))
很显然,没有定义length属性,因此我们的arrayLikeObject
仅返回一个空数组。现在,让我们尝试定义一个length属性:
let arrayLikeObject = {
length: 2,
0: 1,
1: 2
}
console.log(Array.from(arrayLikeObject))
如果长度设置不同怎么办?
let arrayLikeObject = {
length: 1,
0: 1,
1: 2
}
console.log(Array.from(arrayLikeObject))
// it will only return the value from first `0: 1`
let arrayLikeObject = {
length: 5,
0: 1,
1: 2
}
console.log(Array.from(arrayLikeObject))
// other 3 values will be printed as undefined
但是,我不想转换它...
您实际上想创建一个数组,而不是类似数组的对象。类似数组的对象必须按照您所说的进行转换:
Array.prototype.slice.call(arrayLikeObject)
// Or,
[].slice.call(arrayLikeObject)
如果您确实尝试在类似数组的对象上使用数组方法,则会出现类型错误:
let arrayLikeObject = {
length: 5,
0: 1,
1: 2
}
console.log(arrayLikeObject.sort())
因此,要在arrayLikeObject上使用数组方法,我们需要像前面示例中那样使用Array.from
将其转换为数组。
否则,您只需要创建一个数组:
let arr = [1,2] // I don't mean, you don't know
其他考虑因素:
您不能将其用作构造函数:
let arrayLikeObject = {
length: 1,
slice: function () {
return 1
}
}
console.log(new arrayLikeObject) // Type error
在以下代码段中,结果是[undefined]
,因为length属性设置为1,但是没有0
索引属性:
let arrayLikeObject = {
length: 1,
slice: function () {
return 1
}
}
console.log(Array.from(arrayLikeObject))
但是,如果将长度设置为0,则结果将是一个空数组[]
,因为我们要告诉我们在此类似数组的对象中没有任何值。
答案 3 :(得分:0)
我认为this正是您所寻找的。 覆盖toString函数。
foo.prototype.toString = function()
{
return "[object Foo <" + this[0] +">]";
}
答案 4 :(得分:0)
看看这个:
var ArrayLike = (function () {
var result;
function ArrayLike(n) {
for (var idx = 0; idx < n; idx++) {
this[idx] = idx + 1;
}
// this.length = Array.prototype.length; THIS WILL NOT WORK !
}
// ArrayLike.prototype.splice = Array.prototype.splice; THIS WILL NOT WORK !
// THIS WILL WORK !
Object.defineProperty(ArrayLike.prototype, 'length', {
get: function() {
var count = 0, idx = 0;
while(this[idx]) {
count++;
idx++;
}
return count;
}
});
ArrayLike.prototype.splice = Array.prototype.splice;
ArrayLike.prototype.multiple = function () {
for (var idx = 0 ; idx < this.length ; idx++) {
if (result) {
result = result * this[idx];
} else {
result = this[idx];
}
}
return result;
};
return ArrayLike
})();
var al = new ArrayLike(5);
al.__proto__ = ArrayLike.prototype;
console.log(al.length, al.multiple(), al);
这将显示在Chrome中:5 120 [1,2,3,4,5]