У меня есть некоторый код JavaScript, который я пытаюсь очистить ... Я изначально написал определение массива объектов (называемых myData) в стиле "грубой силы". Стиль грубой силы определяет массив из 4 объектов (массив всегда имеет размер 4). Мое приложение работает нормально, когда определяется таким образом. Позже код в программе читает JSON и обновляет различные элементы в синтаксисе, похожем на:

myData[2].Quarter = "Q2";

Когда я пытаюсь очистить / консолидировать определение myData, мой код выполняется без синтаксической ошибки, но все 4 элемента массива заканчиваются одинаковыми значениями, где в стиле грубой силы каждый объект в массиве заканчивается разными значениями. , Единственное, что отличается, это два определения. Это то, что я называю "грубой силой", и весь мой кодовый набор работает нормально ... Это буквально один и тот же объект, скопированный 4 раза.

var myData = [
     {
        Quarter: 'EMPTY',
        Field_Cloud:0,
        Field_Cloud_Renew:0,
        Field_On_Premise:0,
        Field_Total:0,
        OD_Cloud:0,
        OD_Cloud_Renew:0,
        OD_On_Premise:0,
        OD_Total:0,
        Field_OD_Total:0
    },
        {
        Quarter: 'EMPTY',
        Field_Cloud:0,
        Field_Cloud_Renew:0,
        Field_On_Premise:0,
        Field_Total:0,
        OD_Cloud:0,
        OD_Cloud_Renew:0,
        OD_On_Premise:0,
        OD_Total:0,
        Field_OD_Total:0
    },
        {
        Quarter: 'EMPTY',
        Field_Cloud:0,
        Field_Cloud_Renew:0,
        Field_On_Premise:0,
        Field_Total:0,
        OD_Cloud:0,
        OD_Cloud_Renew:0,
        OD_On_Premise:0,
        OD_Total:0,
        Field_OD_Total:0
    },
        {
        Quarter: 'EMPTY',
        Field_Cloud:0,
        Field_Cloud_Renew:0,
        Field_On_Premise:0,
        Field_Total:0,
        OD_Cloud:0,
        OD_Cloud_Renew:0,
        OD_On_Premise:0,
        OD_Total:0,
        Field_OD_Total:0
    }   
    ];

Я пытаюсь закрепить это до того, что, по моему мнению, должно быть идентичным кодом, но тогда мое приложение больше не работает. Симптом состоит в том, что все 4 объекта массива заканчиваются одинаковыми значениями.

Сводный (но неработающий) код:

 var myDataStruct= {
        Quarter: 'EMPTY',
        Field_Cloud:0,
        Field_Cloud_Renew:0,
        Field_On_Premise:0,
        Field_Total:0,
        OD_Cloud:0,
        OD_Cloud_Renew:0,
        OD_On_Premise:0,
        OD_Total:0,
        Field_OD_Total:0
    };

    var myData = [];
    myData.push(myDataStruct);
    myData.push(myDataStruct);
    myData.push(myDataStruct);
    myData.push(myDataStruct);

Что я делаю не так, и как я могу определить, что myData является надлежащим консолидированным способом?

2
user1009073 28 Авг 2017 в 18:57

3 ответа

Лучший ответ

Вы можете использовать объектно-ориентированное программирование и наследование:

var myDataStruct = {
    Quarter: 'EMPTY',
    Field_Cloud:0,
    Field_Cloud_Renew:0,
    Field_On_Premise:0,
    Field_Total:0,
    OD_Cloud:0,
    OD_Cloud_Renew:0,
    OD_On_Premise:0,
    OD_Total:0,
    Field_OD_Total:0
};

var myData = Array.from({length:4}, ()=>Object.create(myDataStruct));

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

var myData = Array.from({length:4}, ()=>Object.assign({},myDataStruct));

Как они выглядят в памяти:

1) ваш подход, запихивая тот же объект в массив:

//the object
123:
  {Quarter:"Empty",...}
//the array
124: 123
125: 123
126: 123
127: 123
128: null

2) наследственный подход:

//the prototype
123:
  {Quarter:"empty",...}
//the subobjects
124:
  { prototype: 123}
125:
  { prototype: 123}
126:
  { prototype: 123}
127:
  { prototype: 123}
//the array
128:124
129:125
130:126
131:127
132: null

Таким образом, при вашем подходе изменение одного из элементов массива фактически изменяет объект, хранящийся в 123, чтобы они мешали друг другу. С подходом наследования, например изменение первого объекта изменяет объект на 124, на propertylookup он сначала ищет свойство на 124, затем, если его не найдено, он ищет в 123. Так что если вы сделаете

myData[0].Quarter = "Full";

Память изменится на:

//the prototype
123:
  {Quarter:"empty",...}
//the subobjects
124:
  {Quarter: "Full", prototype: 123}

Что приводит к:

myData[0].Quarter // "Full", looked up in 124
myData[1].Quarter // "empty", as not found in 125 and therefore looked up in 123
6
Jonas Wilms 28 Авг 2017 в 16:16

Вы помещаете одну и ту же ссылку на объект в ваш массив, что означает, что когда вы изменяете один объект из вашего массива, все они изменяются.

Чтобы исправить это, вы можете использовать Object.assign() или синтаксис Object Spread, например myData.push(Object.assign({}, myDataStruct));, который создаст пустой объект, объединит его с вашим myDataStruct объектом и затем поместит его в массив.

Полезные ссылки:

0
macbem 28 Авг 2017 в 16:06

Проблема связана с тем, что Javascript обрабатывает объекты по ссылке .

Если вы создаете объект и помещаете его в какой-либо массив четыре раза, то в этом массиве четыре ссылки . Если вы измените объект впоследствии, это изменение повлияет на все объекты в массиве. Но это только из-за массива, содержащего четыре ссылки на один объект, а не четыре копии одного исходного объекта. Если вам нужны копии вашего объекта, вам нужно сначала создать их, что не доступно в Javascript, так же просто, как в других языках.

Просто представьте, что переменные, хранящие объекты (включая функции и массивы в Javascript для каждого, являющегося более специфическим видом объекта), содержат адрес в памяти, где хранится ваш объект. Если вы используете эту переменную для доступа к объекту, она просто указывает на некоторую память. Если вы присваиваете значение переменной какой-либо другой переменной или передаете его в качестве аргумента какой-либо функции, такой как push () массива, то этот адрес копируется и передается, а не свойства вашего объекта.

Когда дело доходит до копирования / клонирования объектов, есть и другие аспекты, которым нужно подчиняться: если у вашего объекта есть свойства типа объекта (или массива или функции), вы можете также захотеть сделать их копии. И они могут иметь такие свойства в свою очередь, тоже. Итак, вам нужна мелкая или глубокая копия вашего объекта? И объекты могут иметь свойства, к которым вы можете получить доступ, но они не обрабатываются некоторыми операциями, но вы все же хотите, чтобы они были скопированы. Этот аспект влияет на перечислимые и не перечислимые свойства. Наконец, каждый объект может иметь свои собственные свойства и «производные» свойства, и некоторые операции обрабатывают их все или только собственные свойства объекта.

Итак, позаботьтесь о подходе, который вам действительно необходим для клонирования вашего объекта.

Вы можете спросить: почему Javascript не создает копии неявно? Я думаю, что это связано с простотой структуры языка. И как только вы позаботитесь об этой «проблеме», вы поймете, насколько быстрым может быть Javascript. Я предпочел бы позаботиться об этом сам, чем страдать от того, что язык тратит время на копирование объектов или реализацию магии копирования при записи.

Примеры

Глубокая Копия, Низкая Производительность, Все Перечислимые Свойства

copy = JSON.parse( JSON.stringify( original ) );

Малая копия, хорошая производительность, собственные перечисляемые свойства

copy = Object.assign( {}, original );

больше об объектах

3
Thomas Urban 28 Авг 2017 в 16:30