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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11886578/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-26 14:40:02  来源:igfitidea点击:

Creating array-like objects in JavaScript

javascriptarraysobject

提问by Rocket Hazmat

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 中,有些对象伪装成数组(或“类数组”)。此类对象是argumentsNodeLists(从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 lengthproperty.

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 fooobject. I can "convert" it to an array using

当 I 时console log(test),我得到(如预期的)一个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.log,它显示为一个数组?

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

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

回答by zzzzBov

Depends specifically on the console. For custom objects in Chrome's developer console, and Firebug you'll need both the lengthand spliceproperties. splicewill also have to be a function.

具体取决于控制台。对于 Chrome 开发者控制台和 Firebug 中的自定义对象,您将需要lengthsplice属性。splice也必须是一个函数。

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 forloop or a for..inloop:

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..inloop in jQuery, or an object that appears as an object in the console ({}) but that gets iterated over with a forloop in jQuery.

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

回答by Paul Aldred-Bann

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.

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

回答by Bhojendra Rauniyar

The same question got into my mind as while we can use array like argumentsparameter:

我想到了同样的问题,因为我们可以使用类似arguments参数的数组:

function arrayLike() {
  console.log(typeof arguments)
  console.log(arguments)
  console.log(Array.from(arguments))
}
arrayLike(1,2,3)

So, let's try creating our own array-like object:

所以,让我们尝试创建我们自己的类数组对象:

let arrayLikeObject = {
  0: 1,
  1: 2
 }
 
 console.log(Array.from(arrayLikeObject))

Obviously, there's no length property defined so our arrayLikeObjectwill only return an empty array. Now, let's try defining a length property:

显然,没有定义长度属性,所以我们arrayLikeObject只会返回一个空数组。现在,让我们尝试定义一个长度属性:

let arrayLikeObject = {
  length: 2,
  0: 1,
  1: 2
 }
 
 console.log(Array.from(arrayLikeObject))

What if length is set different?

如果长度设置不同怎么办?

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



But, I don't want to convert it...

但是,我不想转换它...

You actually wanted to create an array, not array-like object. The array-like object must be converted like you said:

您实际上想要创建一个数组,而不是类似数组的对象。必须像您说的那样转换类数组对象:

Array.prototype.slice.call(arrayLikeObject)
// Or,
[].slice.call(arrayLikeObject)

If you do try to use array methods on array-like object, then you'll get type error:

如果您确实尝试在类数组对象上使用数组方法,那么您将收到类型错误:

let arrayLikeObject = {
  length: 5,
  0: 1,
  1: 2
 }

 console.log(arrayLikeObject.sort())

Thus, to use the array methods on arrayLikeObject, we need to convert it into array as we did in preceding examples using Array.from.

因此,要在 arrayLikeObject 上使用数组方法,我们需要像在前面的示例中使用Array.from.

Otherwise, you simply need to create an array:

否则,您只需要创建一个数组:

let arr = [1,2] // I don't mean, you don't know


Other consideration:

其他考虑:

You can't use it as constructor:

您不能将其用作构造函数:

let arrayLikeObject = {
    length: 1,
    slice: function () {
      return 1
    }
}

console.log(new arrayLikeObject) // Type error

In the following snippet, the result will be [undefined]as the length property is set to 1 but there's no 0indexed property:

在以下代码段中,结果将是[undefined]length 属性设置为 1 但没有0索引属性:

let arrayLikeObject = {
  length: 1,
  slice: function () {
    return 1
  }
}
console.log(Array.from(arrayLikeObject))

But if you set the length to 0, then the result will be an empty array []because we're telling that we don't have any values in this array-like object.

但是如果你将长度设置为 0,那么结果将是一个空数组,[]因为我们告诉我们在这个类似数组的对象中没有任何值。

回答by Pawel Kwiecien

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]

回答by kothvandir

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

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

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