在JavaScript中创建类似数组的对象

时间:2022-06-19 16:26:19

In JavaScript, there are objects that pretend to be arrays (or are "array-like"). Such objects are arguments, NodeLists (returned from getElementsByClassName, etc.), and jQuery objects.

在JavaScript中,有些对象假装是数组(或者是“类数组”)。这些对象是参数,NodeLists(从getElementsByClassName返回等)和jQuery对象。

When console.logged, they appear as arrays, but they are not. I know that in order to be array-like, an object must have a length property.

在console.logged中,它们显示为数组,但它们不是。我知道,为了像数组一样,对象必须具有length属性。

So I made an "object" like this:

所以我做了一个像这样的“对象”:

function foo(){
    this.length = 1;
    this[0] = "bar";
}

var test = new foo;

When I console log(test), I get (as expected) a foo object. I can "convert" it to an array using

当我控制日志(测试)时,我得到(如预期的)一个foo对象。我可以使用“转换”它到一个数组

Array.prototype.slice.call(test)

But, I don't want to convert it, I want it to be array-like. How do I make an array-like object, so that when it's console.logged, it appears as an array?

但是,我不想转换它,我希望它像数组一样。我如何制作一个类似数组的对象,这样当它是console.logged时,它会显示为一个数组?

I tried setting foo.prototype = Array.prototype, but console.log(new foo) still shows a foo object, and not an array.

我尝试设置foo.prototype = Array.prototype,但是console.log(new foo)仍​​然显示foo对象,而不是数组。

4 个解决方案

#1


26  

Depends specifically on the console. For custom objects in Chrome's developer console, and Firebug you'll need both the length and splice properties. splice will also have to be a function.

具体取决于控制台。对于Chrome开发人员控制台和Firebug中的自定义对象,您需要长度和拼接属性。拼接也必须是一个功能。

a = {
    length: 0,
    splice: function () {}
}
console.log(a); //[]

It's important to note, however, that there is no official standard.

然而,重要的是要注意,没有官方标准。

The following code is used by jQuery (v1.11.1) internally to determine if an object should use a for loop or a for..in loop:

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;
}

Note that it's possible to have an object that appears in the console as an array ([]) but that gets iterated over with a for..in loop in jQuery, or an object that appears as an object in the console ({}) but that gets iterated over with a for loop in jQuery.

请注意,可以将一个对象作为数组([])显示在控制台中,但是可以在jQuery中使用for..in循环或在控制台中显示为对象的对象({})进行迭代但是在jQuery中使用for循环迭代了。

#2


4  

Is this any use: extended array prototype, seems like he's doing what you did and creating the prototype as an array, but including an extra method (that may or may not work, I've not tested this):

这是否有用:扩展阵列原型,看起来他正在做你做的事情并将原型创建为数组,但包括一个额外的方法(可能或可能不起作用,我没有测试过这个):

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]);
    }
};

Hope it helps in some way.

希望它在某种程度上有所帮助。

#3


0  

I think this is what you are looking for. Override the toString function.

我想这就是你要找的东西。覆盖toString函数。

foo.prototype.toString = function()
{
    return "[object Foo <" + this[0] +">]";
}

#4


0  

Look at this :

看这个 :

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); 

This will display in Chrome : 5 120 [1, 2, 3, 4, 5]

这将在Chrome中显示:5 120 [1,2,3,4,5]

#1


26  

Depends specifically on the console. For custom objects in Chrome's developer console, and Firebug you'll need both the length and splice properties. splice will also have to be a function.

具体取决于控制台。对于Chrome开发人员控制台和Firebug中的自定义对象,您需要长度和拼接属性。拼接也必须是一个功能。

a = {
    length: 0,
    splice: function () {}
}
console.log(a); //[]

It's important to note, however, that there is no official standard.

然而,重要的是要注意,没有官方标准。

The following code is used by jQuery (v1.11.1) internally to determine if an object should use a for loop or a for..in loop:

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;
}

Note that it's possible to have an object that appears in the console as an array ([]) but that gets iterated over with a for..in loop in jQuery, or an object that appears as an object in the console ({}) but that gets iterated over with a for loop in jQuery.

请注意,可以将一个对象作为数组([])显示在控制台中,但是可以在jQuery中使用for..in循环或在控制台中显示为对象的对象({})进行迭代但是在jQuery中使用for循环迭代了。

#2


4  

Is this any use: extended array prototype, seems like he's doing what you did and creating the prototype as an array, but including an extra method (that may or may not work, I've not tested this):

这是否有用:扩展阵列原型,看起来他正在做你做的事情并将原型创建为数组,但包括一个额外的方法(可能或可能不起作用,我没有测试过这个):

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]);
    }
};

Hope it helps in some way.

希望它在某种程度上有所帮助。

#3


0  

I think this is what you are looking for. Override the toString function.

我想这就是你要找的东西。覆盖toString函数。

foo.prototype.toString = function()
{
    return "[object Foo <" + this[0] +">]";
}

#4


0  

Look at this :

看这个 :

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); 

This will display in Chrome : 5 120 [1, 2, 3, 4, 5]

这将在Chrome中显示:5 120 [1,2,3,4,5]