#javascript #arrays #javascript-objects #conventions
Вопрос:
Это консольный вывод двух разных «массивов», состоящих из одних и тех же строк. Я не знаю, как они возникли (есть много кода, который я не писал), но я считаю, что только Object2 является истинным массивом, поскольку он имеет функцию длины. Вызов Object1.длина дает 0.
Несмотря на то, что объект 1 в консоли называется массивом, на самом деле он выглядит как объект с числовыми атрибутами. Как я могу гарантировать, что массив типа Object1 никогда не используется и все массивы выглядят как 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: 3
Правка 1:
Object1 и Object2-это просто имена переменных, которые я использовал для этого примера.
Вызов Array.isArray(Объект 1) = false, в то время как Array.isArray(Объект 2) = True. Как бы вообще можно было создать объект, называемый массивом? [На это ответил КРайс в комментариях. См. Правку 3]
Правка 2: Код находится в чудовищном угловом положении, но вот некоторый код, показывающий, как возникают данные. Object1-это переменная, содержащая то, что должно быть массивом под названием «someArray» в приведенной ниже модели, и она инициализируется с помощью адаптера. Object2 был сделан как традиционный встроенный массив: Object2 = [];
Модель
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;
},
];
});
Адаптер
var serializedSomeObject = someObjectInstance.serialize();
return $http({
method: 'PUT',
url: 'someUrl.com/api',
data: serializedSomeObject,
}).then(function (response) {
return SomeObjectModel.build(response.data);
});
Изменить 3:
@CRice указал, что этот код может воспроизвести экземпляр Object1, который называет себя массивом, но не ведет себя как таковой:
var o = { 0: 'ABC', 1: 'IJK', 2: 'XYZ' };
Object.setPrototypeOf(o, Array.prototype);
console.log(o);
Изменить 4:
Я не знаю, почему сериализация, а затем десериализация вызвали это, но мое решение состоит в том, чтобы повторить атрибуты Object1, просто поместить их в новый массив и закрыть его. Вот мое решение для преобразования объекта 1 в объект 2:
var Object2 = [];
var attr = Object.getOwnPropertyNames(Object1);
for(var i=0; i<attr.length; i ){
Object2.push(Object1[attr[i]]);
}
console.log(Object2);
Спасибо Крайсу за то, что помог мне воспроизвести его в консоли!
Комментарии:
1. Это … действительно странно. Пожалуйста, опубликуйте минимальный воспроизводимый пример
2. Хорошо, я сделаю все возможное, чтобы найти способ воспроизвести его для вас. Информация сериализуется, а затем десериализуется, поэтому я думаю, что это приводит к неправильному чтению одного и того же массива.
3. Как именно были созданы и заселены объекты 1 и 2? Это то, что нам действительно нужно знать. Покажите этот код, пожалуйста.
4. Возможное воспроизведение:
o = {0: "ABC", 1: "IJK", 2: "XYZ"}; Object.setPrototypeOf(o, Array.prototype); console.log(o);
дает почти идентичный результат при запуске в Chrome devtools.5. Интересно, @CRice. Интересно, был ли метод serialize (), добавленный в прототип, перегружен массивом?
Ответ №1:
Я нашел причину. Существует модуль, который глубоко клонирует сложные объекты, чтобы их можно было восстановить в будущем. Можете ли вы определить ошибку в этом рекурсивном цикле?
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;
}
Когда someArray проходит через функцию cloneObject (), он создает новый объект под названием Array, который не сохраняет истинные свойства массива, а вместо этого преобразует его в объект с прото= «Массив» (как указал @КРайс) и ничего больше. Чтобы исправить это, нам действительно нужно переработать функцию cloneObject для сохранения массивов. Это исправленная функция глубокого копирования cloneObject, которую я сейчас использую:
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;
}