Создание объектов в виде массива в JavaScript

В JavaScript есть объекты, которые притворяются массивами (или похожими на массивы). Такие объекты arguments, NodeList (возвращаются из 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, а не массив.

Ответы

Ответ 1

Зависит конкретно от консоли. Для пользовательских объектов в консоли разработчика 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;
}

Обратите внимание, что возможно наличие объекта, который появляется в консоли как массив ([]), но который перебирается с помощью цикла for..in в jQuery или объекта, который отображается как объект в консоли ({}), но он перебирается с помощью цикла for в jQuery.

Ответ 2

Используется ли это: прототип расширенного массива, похоже, что он делает то, что вы делали, и создавая прототип в виде массива, но включая дополнительный метод (который может работать или не работать, я не тестировал это):

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

Надеюсь, что это поможет.

Ответ 3

Я думаю, этот - это то, что вы ищете. Переопределите функцию toString.

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

Ответ 4

Посмотрите на это:

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]