Esta es la salida de la consola de dos "matrices" diferentes formadas por las mismas cadenas. No sé cómo se originaron (hay mucho código que no escribí), pero creo que solo Object2 es un verdadero Array, ya que tiene una función de longitud. Llamar a Object1.length da 0.
Aunque Object1 se denomina Array en la consola, en realidad parece ser un Object con atributos numéricos. ¿Cómo me aseguro de que el tipo de matriz Object1 nunca se use y que todas las matrices se vean como Object2?
Object1 Array {0: 'ABC', 1: 'IJK', 2: 'XYZ'} 0: "ABC" 1: "IJK" 2: "XYZ" [[Prototype]]: Array(0) Object2 (3) ['ABC', 'IJK', 'XYZ'] 0: "ABC" 1: "IJK" 2: "XYZ" length: 3Edición 1: Object1 y Object2 son solo nombres de variables que usé para este ejemplo.
Llamar a Array.isArray(Object1) = false mientras que Array.isArray(Object2) = True. ¿Cómo se podría incluso hacer un Objeto llamado Array? [Esto fue respondido por CRice en los comentarios. Ver Edición 3]
Edición 2: el código está en una monstruosidad de AngularJS, pero aquí hay un código que muestra cómo se originan los datos. Object1 es una variable que contiene lo que debería ser una matriz llamada "someArray" en el modelo a continuación y se inicializa con el adaptador. Object2 se hizo como una matriz en línea tradicional: Object2 = [];
Modelo
define([], function () { return [ function () { function SomeObjectModel(someArray) { this.someArray = someArray; } SomeObjectModel.prototype.serialize = function () { return { someArray: this.someArray, }; }; SomeObjectModel.build = function (data) { return new SomeObjectModel(data.someArray); }; return SomeObjectModel; }, ]; });Adaptador
var serializedSomeObject = someObjectInstance.serialize(); return $http({ method: 'PUT', url: 'someUrl.com/api', data: serializedSomeObject, }).then(function (response) { return SomeObjectModel.build(response.data); });Edición 3: @CRice señaló que este código puede reproducir la instancia de Object1 que se llama a sí misma Array pero no se comporta como tal:
var o = { 0: 'ABC', 1: 'IJK', 2: 'XYZ' }; Object.setPrototypeOf(o, Array.prototype); console.log(o);Edición 4: no sé por qué serializar y luego deserializar causó esto, pero mi solución es iterar sobre los atributos de Object1 y simplemente insertarlos en una nueva matriz y llamarlo un día. Aquí está mi solución para convertir Object1 a Object2:
var Object2 = []; var attr = Object.getOwnPropertyNames(Object1); for(var i=0; i<attr.length; i++){ Object2.push(Object1[attr[i]]); } console.log(Object2);¡Gracias CRice por ayudarme a reproducirlo en la consola!
Encontré la causa. Hay un módulo que realiza clonaciones profundas de objetos complejos para que puedan restaurarse en el futuro. ¿Puedes detectar el error en este bucle recursivo?
function cloneObject(src) { let target = {}; target.__proto__ = src.__proto__; for (let prop in src) { if (src.hasOwnProperty(prop)) { // if the value is a nested object, recursively copy all it's properties if (isObject(src[prop])) { target[prop] = cloneObject(src[prop]); } else { target[prop] = src[prop]; } } } return target; }Cuando someArray pasa por la función cloneObject(), crea un nuevo objeto llamado Array que no retiene las verdaderas propiedades de la matriz, sino que lo convierte en un objeto con proto='Array' (como señaló @CRice) y nada más. Para solucionar esto, realmente necesitamos volver a trabajar en la función cloneObject para preservar las matrices. Esta es la función cloneObject de copia profunda corregida que ahora estoy usando:
function cloneObject(src) { let target = {}; var isArray = Array.isArray(src); if(isArray){ target = []; } else { target.__proto__ = src.__proto__; } for (let prop in src) { if (src.hasOwnProperty(prop)) { // if the value is a nested object, recursively copy all it's properties if (isObject(src[prop])) { var propertyValue = cloneObject(src[prop]); } else { var propertyValue = src[prop]; } // if src was an array if(isArray){ target.splice(prop, 0, propertyValue); } else { target[prop] = propertyValue; } } } return target; }