Дополнительно
Как правильно клонировать объект JavaScript?
У меня есть объект x
. Я'хотел бы скопировать его как объект y
, чтобы изменения y
не изменяли x
. Я понял, что копирование объектов, полученных из встроенных объектов JavaScript, приведет к появлению дополнительных, нежелательных свойств. Это не проблема, так как я копирую один из своих собственных, построенных буквально объектов.
Как правильно скопировать объект JavaScript?
2906
20
Для этого для любого объекта в JavaScript не будет простой и прямолинейной. Вы столкнетесь с проблемой, ошибочно подбирая атрибуты объекта's в опытном образце, который должен быть в прототип и не копируются в новый экземпляр. Если, например, вы добавляете метод
клон
дообъекта.прототипа, а некоторые ответы изобразить, вам необходимо в явном виде отказаться от этого атрибута. Но что, если существуют другие дополнительные методы для объекта.прототип, или прочими промежуточными прототипы, что вы Дон'т знать? В этом случае, вы будете копировать атрибуты, которые вы должны'т, так что вы должны обнаружить непредвиденные, не местные атрибуты [
метод hasOwnProperty`]1 метод.В дополнение к неперечислимый атрибутами, вы'll сталкиваются с более жесткой проблемой, когда при попытке скопировать объекты, которые имеют скрытые свойства. Например, "прототип" - это скрытые свойства функций. Кроме того, объект'ы прототипа есть ссылка с атрибутом свойствоproto`, который также скрыт, и не будет скопирован в/в цикле перебора исходного объекта'с атрибутами. Я думаю, что свойствоproto может быть конкретно в Firefox'JavaScript-интерпретатор с, и это может быть что-то другое в других браузерах, но вы получите картину. Не все перечисли. Вы можете скопировать атрибут "скрытый" если вы знаете его имя, но я не'т знаете, любой способ обнаружить его автоматически.
Еще одна загвоздка в поисках элегантное решение проблемы постановки правильного прототип наследования. Если исходный объект'ы прототипа "объект", а затем просто создать новый общий объект с
{}
будет работать, но если источник'с прототипом является одним из потомковобъект
, то вы собираетесь быть пропущены дополнительных членов от того прототипа, который вы пропустили с помощью метода hasOwnPropertyфильтр, или которые были в прототипе, но там'т перечисляемую в первую очередь. Одним из решений может быть, чтобы назвать объект источник'собственность с
конструктор, чтобы получить исходный объект копирования, а затем скопировать атрибуты, но тогда вы все равно не получите неперечислимый атрибутами. Например, [
дата`]2 объект хранит свои данные как скрытый член:Строки даты для
Д1
будет 5 секунд отстает отД2
. Как сделать одну "дата" совпадает с другим-это по телефонуsetTime
метод, но что является специфическим для класса "дата". Я не'т думаю, что есть пуленепробиваемые общее решение этой проблемы, хотя я бы рад ошибиться!Когда мне нужно было реализовать общие глубокого копирования я закончил ущерба, предполагая, что мне нужно будет лишь скопировать объект равнина`
,
время,
дата,
строка,
число, или
логическое. Последние 3 типы являются неизменными, так что я могу выполнять мелкую копию и не волноваться о ее смене. Я сразу предположил, что какие-либо элементы, содержащиеся в
объектили
время` также будет одним из 6 простые типы в этом списке. Это может быть достигнуто с помощью подобного кода:Выше функция будет адекватно работать на 6 простых я выше типов, поскольку данные в объекты и массивы образуют структуру дерева. То есть, нет'т больше, чем одна ссылка на те же данные в объект. Например:
Он не будет иметь возможность обрабатывать любой объект JavaScript, но это может быть достаточным для многих целей, как долго, как вы Дон'т предположить, что это будет работать для все, что вы бросаете на нее.
Если вы не используете
дата, функции неопределены, или бесконечность внутри объекта, очень простой лайнер
в формате JSON.разобрать(в формате JSON.преобразовать в строки(объекта))`:в
в
Это работает для всех видов объектов, содержащих объекты, массивы, строки, логические значения и числа.
См. Также эта статья о структурированный алгоритм клон браузерах, который используется при отправке сообщений и от работника. Он также содержит функции для глубокого клонирования.
С jQuery, вы можете мелкая копия с продлить:
последующие изменения
copiedObject
не повлияет наoriginalObject
, и наоборот.Или сделать глубокая копия:
В ECMAScript 6 есть объект.назначить метод, который копирует значения всех перечислимых свойств из одного объекта в другой. Например:
Но следует помнить, что вложенные объекты будут скопированы в качестве ссылки.
В уведомление:
Там нет необходимости для внешних библиотек, но вы должны проверить первый браузер.
Есть много ответов, но никто не упоминает объект.создать из ECMAScript 5, который, по общему признанию, не дает вам точную копию, но устанавливает источник в качестве прототипа нового объекта.
Таким образом, это не точный ответ на вопрос, но это решение и, таким образом, элегантно. И это работает лучше для 2 случаев:
Пример:
Почему я считаю это решение выше? Это'родные с таким образом нет циклов, ни рекурсии. Однако, старые браузеры понадобится полифилл.
Элегантный способ, чтобы клонировать объект JavaScript в одну строку кода
Для Себя Объекта.способ назначения является частью спецификации ECMAScript 2015 (ES6 в) стандартные и делает именно то, что вам нужно.
Читать more...
В полифилл для поддержки старых браузеров:
Есть несколько проблем с Большинство решений в интернете. Так что я решил сделать продолжение, которое включает в себя, почему принято отвечать должен'т быть приняты.
отношение
Я хочу глубокий-копия в JavaScript "объект" со всеми своими детьми и их детьми и так далее. Но так как я'м Не вроде нормальный застройщик, мой "объект" нормальный
свойства
, `кольцевые структуры "и даже" вложенных объектов.Так давайте'ы создание кольцевой структуры " и " вложенный объект первым.
Позвольте's и принести все вместе в "объект" по имени "а".
Далее мы хотим скопировать в переменную " B " и мутировать его.
Вы знаете, что происходило здесь, потому что если не вы не'т даже землю, на этот великий вопрос.
Теперь давайте'ы найти решение.
В JSON
В первой попытке я попытался с помощью
формат JSON
.Дон'т тратить слишком много времени на это, вы'll получить
ошибку TypeError: преобразование круговой структуры в JSON
.Рекурсивное копирование (принято на "отвечают")
Позвольте'ы взгляните на принятый ответ.
Выглядит хорошо, хех? Это'ы рекурсивную копию объекта и ручки, а также другие виды, такие как
дата
, но это было'т требование.Рекурсия и
круглых колодцев
не'т хорошо работать вместе...RangeError: максимальный размер стека вызовов превысило
решения #
После ссоры с коллегой, мой босс спросил нас, что случилось, и он нашел простое решение после некоторых погуглить. Это'ы называемого Объекта.создать`.
Этот раствор добавляли некоторое время назад в JavaScript и даже ручки
круглое
.... и вы видите, что ничего'т работать с вложенной структурой внутри.
полифилл для собственного решения
Там'ы полифилла для объекта`.создать в старых браузера, как и в IE 8. Это's что-то вроде рекомендованной Mozilla, и конечно, это's не совершенный и результаты в те же проблемы, как решения.
Я'ве положить
Ф
вне рамок, так что мы можем взглянуть на то, чтоэкземпляром
говорит нам.Такая же проблема, как родной раствора, но немного хуже выход.
лучше (но не идеальным) решением
При рытье вокруг, я нашел похожий вопрос (https://stackoverflow.com/questions/10728412/in-javascript-when-performing-a-deep-copy-how-do-i-avoid-a-cycle-due-to-a-pro) в этом одним, но с лучшим решением.
Если вы'ре хорошо с мелкой копией, библиотекой Underscore.js имеет клон метод.
или вы можете продлить его как
ОК, представьте, что у вас есть этот объект, и вы хотите клонировать его:
или
ответ в основном depeneds, на котором функции вы, используя, в ЕС6+, вы можете просто использовать объект.назначить на клона:
или с помощью операторов такой:
Но если вы используете
в ES5
, вы можете использовать несколько методов, но в JSON.преобразовать в строки, просто убедитесь, что вы не используете для большой кусок данных для копирования, но это может быть одна линия удобный способ во многих случаях, что-то вроде этого:Одним из особо грубое решение-использовать кодировку JSON, чтобы сделать глубокий копий объектов, которые не имеют методов-членов. Методология в JSON закодировать ваш целевой объект, то в результате его расшифровки, вы получаете экземпляр, который вы ищете. Вы можете декодировать столько раз, сколько вы хотите сделать столько копий, сколько вам нужно.
Конечно, функции не принадлежат в JSON, так что это работает только для объектов без методов-членов.
Эта методика идеально подходит для моего использования, так как я'м хранить в JSON BLOB-объектов в хранилище ключ-значение, и, когда они представляются как объекты в JavaScript API, что каждый объект на самом деле содержится копия исходного состояния объекта, поэтому мы можем вычислить дельту после того как абонент мутировал предоставляемый объект.
Вы можете просто использовать спред собственность, чтобы скопировать объект без ссылок. Но будьте внимательны (см. Комментарии), 'скопировать' это просто на самом низком объекта/массива на уровне. Вложенные свойства-это все ссылки!
Полный клон:
Клон со ссылками на втором уровне:
JavaScript на самом деле не поддерживает нативно глубокий клонов. Использование функции полезности. Например Ramda:
Для тех, с помощью AngularJS, существует также прямой метод клонирования или расширения объектов в этой библиотеке.
или
Больше в угловой.копия документации...
А. Леви'ы ответ почти полный, вот мой маленький вклад: есть способ, как справиться с рекурсивными ссылками см. Эта линия
если(это[м]==это) копировать[м] = копия;
Если объект является элементом XML дом, мы должны использовать помощью clonenode вместо
если(это.помощью clonenode) вернуть это.помощью clonenode(true); в`
Вдохновленный А. Леви'исчерпывающего исследования с и Calvin'ы подход прототипирование, я предлагаю такое решение:
См. также Энди Берк's примечание в ответах.
Из этой статьи: Как копировать массивы и объекты в Javascript by Brian Huisman:
Вот функция, которую вы можете использовать.
В ES-6 Вы можете просто использовать объект.назначить(...). Экс:
Хорошая ссылка-это здесь: https://googlechrome.github.io/samples/object-assign-es6/
В ECMAScript 2018
Помните, что вложенные объекты еще копировать в качестве эталона.
Новый ответ на старый вопрос! Если у вас есть удовольствие с помощью ECMAScript 2016 (ЕС6) с распространение синтаксис, Это's легко.
Это обеспечивает чистый способ для мелкую копию объекта. Делает глубокую копию, смысл makign новую копию всех значений для каждого рекурсивно вложенный объект, требует более тяжелых вышеуказанного решения.
Код JavaScript продолжает развиваться.
Вы можете клонировать объект и удалить любые ссылки из предыдущей с помощью одной строки кода. Просто выполните:
Для браузеров / двигатели, которые в настоящее время не поддерживает объект.создать Вы можете использовать этот полифилл: