Автор оригинала: Scott Robinson.
Вступление
Очень распространенная задача в программировании, независимо от языка, является копирование (или клон) объектом по значению, в отличие от копирования посредством ссылки. Разница в том, что при копировании по значению у вас есть два не связанный объекты с одинаковым значением или данными. Копирование посредством ссылки означает, что у вас есть два объекта, которые указывают на те же данные в памяти. Это означает, что если вы манипулируете объектом A, например, он также будет манипулировать объектом B, поскольку они оба ссылаются на одни и те же основные данные.
В этой статье я пройду несколько способов скопировать объекты по значению в JavaScript. Я покажу, как вы можете сделать это, используя обе сторонние библиотеки, так и путем написания собственной функции копирования.
Примечание : Поскольку Node.js – это просто время выполнения, построенной на двигателе V8 JavaScript, все методы клонов, которые я показываю в этой статье, также будет работать для узла.
Сторонние библиотеки
Существует ряд популярных сторонних библиотек, которые имеют встроенный встроенную функциональность, которую мы перейдем в следующие несколько разделов. На мой взгляд, это лучшее решение для самых простых случаев использования, поскольку они были сильно проверены и постоянно обновлены. Написание этого типа кода самостоятельно нелегко, поэтому очень полезно использовать код, который имеет на нем много глаз.
Лоташ
Лоташ Библиотека предоставляет несколько различных методов копирования или клонирования, объектов в зависимости от вашего использования.
Самый общий метод является клон ()
Метод, который обеспечивает неглубокий Копии объектов. Он работает, просто передавая объект как первый аргумент, и копия будет возвращена:
const _ = require('lodash'); let arrays = {first: [1, 2, 3], second: [4, 5, 6]}; let copy = _.clone(arrays); console.log(copy);
{ first: [ 1, 2, 3 ], second: [ 4, 5, 6 ] }
Это означает, что объект «верхнего уровня» (или массив, буфер, карта и т. Д.) Клонируется, но любые более глубокие объекты будут скопированы посредством ссылки. Подведенный ниже код демонстрирует, что Первый
Массив в оригинале Массивы
Объект – это тот же объект, что и Первый
Массив в Скопировать
объект:
const _ = require('lodash'); let arrays = {first: [1, 2, 3], second: [4, 5, 6]}; let copy = _.clone(arrays); console.log(copy.first === arrays.first);
true
Если вы предпочитаете, что Все Объекты, как мелкие, так и глубокие объекты, скопированы, то вы захотите использовать CLONDEEP ()
Метод вместо этого:
const _ = require('lodash'); let arrays = {first: [1, 2, 3], second: [4, 5, 6]}; let copy = _.cloneDeep(arrays); console.log(copy);
{ first: [ 1, 2, 3 ], second: [ 4, 5, 6 ] }
Этот метод работает рекурсивно клонированием всех значений на любом уровне глубины.
На проведении одинакового чека на равенство сверху, мы видим, что оригинальные и скопированные массивы больше не равны, так как они являются уникальными копиями:
const _ = require('lodash'); let arrays = {first: [1, 2, 3], second: [4, 5, 6]}; let copy = _.cloneDeep(arrays); console.log(copy.first === arrays.first);
false
Лоташ предлагает еще несколько методов клонов, в том числе клоневит ()
и CLONDEEPWITH ()
Отказ Оба эти методы принимают другой параметр под названием Customizer
, который является функцией, используемой для создания скопированного значения.
Поэтому, если вы хотите использовать какую-либо пользовательскую логику копирования, вы можете передавать функцию для обработки его в методе Lodyash. Например, скажем, у вас есть объект, который содержит некоторые Дата
Объекты, но вы хотите, чтобы те, которые были преобразованы в Timestamps после копирования, вы можете сделать это так:
const _ = require('lodash'); let tweet = { username: '@ScottWRobinson', text: 'I didn\'t actually tweet this', created_at: new Date('December 21, 2018'), updated_at: new Date('January 01, 2019'), deleted_at: new Date('February 28, 2019'), }; let tweetCopy = l.cloneDeepWith(tweet, (val) => { if (l.isDate(val)) { return val.getTime(); } }); console.log(tweetCopy);
{ username: '@ScottWRobinson', text: 'I didn\'t actually tweet this', created_at: 1545372000000, updated_at: 1546322400000, deleted_at: 1551333600000 }
Как вы можете видеть, единственные данные, которые были изменены нашим методом, были теми, что были Дата
Объекты, которые сейчас были включены в метки Unix.
Нижнее подчеркивание
Подчеркивание клон ()
Способ работает так же, как и Лодаш клон ()
метод. Он предоставляет только неглубокую копию данного объекта, причем какие-либо вложенные объекты копируются посредством ссылки.
Тот же пример, что и прежде чем демонстрирует это:
const _ = require('underscore'); let arrays = {first: [1, 2, 3], second: [4, 5, 6]}; let copy = _.clone(arrays); console.log(copy.first === arrays.first);
true
К сожалению, библиотека подчеркивания, похоже, не имеет никакого метода для обработки глубокого копирования. Вы можете реализовать эту логику самостоятельно (используя некоторые из логики, показанной ниже) и все еще используйте подчеркивание клон
Способ для мелкой копии, или вы можете попробовать одно из других решений в этой статье.
Пользовательские решения
Как я уже упоминал ранее, взяв на себя эту проблему самостоятельно, – это сложный, поскольку есть много случаев (и сложных краевых случаев) для обработки при клонировании объекта в JavaScript. Хотя, если сделано правильно, вы сможете добавить немного хорошей настройки в вашем методе, который может быть невозможен иначе.
Используя JSON методы
Одно часто цитируемое решение – просто использовать Json.stringify
и Json.parse
Методы для вашего преимущества, как это:
let arrays = {first: [1, 2, 3], second: [4, 5, 6]}; let copy = JSON.parse(JSON.stringify(arrays)); console.log(copy);
{ first: [ 1, 2, 3 ], second: [ 4, 5, 6 ] }
Это оставит вас с глубоко скопированным объектом, и он работает очень хорошо для простых объектов, которые легко преобразуются в JSON.
Мы можем снова проверить это, используя тот же чек, как свыше:
console.log(copy.first === arrays.first);
false
Если вы знаете, что ваш объект легко сериализуется, то это может быть хорошим решением для вас.
Написание собственного с нуля
Если по какой-то причине ни одно из других решений не работают для вас, то вам придется написать свой собственный метод клона.
Поскольку я не доверяю себе правильно реализовать полный метод клона (и рисковать читателями, копируя мои ошибки в своем производстве), я скопировал следующую функцию клона из этот гид , который копирует объекты рекурсивно и кажется, работают над многими общими типами данных, которые вы получите в JavaScript.
function clone(thing, opts) { var newObject = {}; if (thing instanceof Array) { return thing.map(function (i) { return clone(i, opts); }); } else if (thing instanceof Date) { return new Date(thing); } else if (thing instanceof RegExp) { return new RegExp(thing); } else if (thing instanceof Function) { return opts && opts.newFns ? new Function('return ' + thing.toString())() : thing; } else if (thing instanceof Object) { Object.keys(thing).forEach(function (key) { newObject[key] = clone(thing[key], opts); }); return newObject; } else if ([ undefined, null ].indexOf(thing) > -1) { return thing; } else { if (thing.constructor.name === 'Symbol') { return Symbol(thing.toString().replace(/^Symbol\(/, '').slice(0, -1)); } return thing.__proto__.constructor(thing); } }
Эта функция работает путем обработки конкретных случаев при необходимости (например, массивы, регулярные выражения, функции и т. Д.), а затем для всех других типов данных (например, цифры, строки, логические значения и т. Д.) Это по умолчанию для вещь
Собственный конструктор для копирования значения. Если вещь
это сам объект, то он просто рекурсивно называет себя на детских атрибутах вещь
Отказ
Ознакомьтесь с полным циклом в ссылке выше для всех типов данных и кромки, которые оно было проверено.
Заключение
Хотя в теории простой, на практике копирование объекта в JavaScript – это что-то, кроме простых. К счастью, там есть довольно много решений для вас, например Cloneeep
в Лоташ или даже встроенном JSON
методы. И если по какой-либо причине никто из них подходит, тогда это это Можно написать свой собственный метод клона, пока вы тщательно проверяете его.
Удачи, и мы знаем, если у вас есть какие-либо мысли, идеи или советы в комментариях.