Автор оригинала: FreeCodeCamp Community Member.
Лукас Гисдер-Дуб
Новый всегда лучше!
Вы наверняка решили копии в JavaScript раньше, даже если вы этого не знали. Может быть, вы также слышали о парадигме в функциональном программировании, которые вы не должны изменять какие-либо существующие данные. Чтобы сделать это, вы должны знать, как безопасно копировать значения в JavaScript. Сегодня мы посмотрим, как это сделать, избегая подводных камней!
Прежде всего, какова копия?
Копия просто выглядит как старая вещь, но нет. Когда вы меняете копию, вы ожидаете, что первоначальная вещь остается прежней, в то время как копия меняется.
В программировании мы храним значения в переменных. Создание копии означает, что вы инициируете новую переменную с одинаковым значением (ами). Тем не менее, есть большая потенциальная ловушка для рассмотрения: Глубокое копирование против Неглубокое копирование Отказ Глубокая копия означает, что все значения новой переменной копируются и Отключен от оригинала Переменная. Неглубокая копия означает, что определенные (под) значения являются все еще связано к исходной переменной.
Примитивные типы данных
Примитивные типы данных включают следующее:
- Номер – например
1.
- Строка – например
'Привет'
- Boolean – E.g.
правда
неопределенный
ноль
Когда вы создаете эти значения, они плотно соединяются с переменными, к которой они назначены. Они существуют только один раз. Это означает, что вам не нужно беспокоиться о копировании примитивных типов данных в JavaScript. Когда вы делаете копию, это будет настоящая копия. Давайте посмотрим пример:
const a = 5
let b = a // this is the copy
b = 6
console.log(b) // 6
console.log(a) // 5
Выполняя B
Вы делаете копию. Теперь, когда вы переназнаете новое значение для B
ценность B
изменения, но не А
Отказ
Композитные типы данных – объекты и массивы
Технически, массивы также являются объектами, поэтому они ведут себя так же. Я буду подробно проходить через них обоих позже.
Здесь становится интереснее. Эти значения фактически хранятся только один раз, когда создаются, и присвоение переменной просто создает указатель (ссылка) к этому значению Отказ
Теперь, если мы сделаем копию B
и измените некоторое вложенное значение в B
это на самом деле меняет А
вложенное значение, так как А
и B
на самом деле указать на то же самое. Пример:
const a = {
en: 'Hello',
de: 'Hallo',
es: 'Hola',
pt: 'Olà'
}
let b = a
b.pt = 'Oi'
console.log(b.pt) // Oi
console.log(a.pt) // Oi
В приведенном выше примере мы на самом деле сделали Малая копия Отказ Это часто проблематично, поскольку мы ожидаем, что старая переменная имеет исходные значения, а не измененные. Когда мы к ней доступаем, мы иногда получаем ошибку. Возможно, вы попытаетесь сделать его некоторое время, прежде чем найти ошибку, поскольку многие разработчики действительно не понимают концепцию и не ожидают, что это будет ошибка.
Давайте посмотрим, как мы можем сделать копии объектов и массивов.
Объекты
Есть несколько способов сделать копии объектов, особенно с новым расширением и улучшением спецификации JavaScript.
Распространение оператора
Введен с ES2015, этот оператор просто отлично, потому что он такой короткий и простой. Он «распространяется» все значения в новый объект. Вы можете использовать его следующим образом:
const a = {
en: 'Bye',
de: 'Tschüss'
}
let b = {...a}
b.de = 'Ciao'
console.log(b.de) // Ciao
console.log(a.de) // Tschüss
Вы также можете использовать его, чтобы объединить два объекта вместе, например const c = {... a, ... b}
Отказ
Объект.assign
Это было в основном использовалось до того, как оператор спреда был рядом, и он в основном делает то же самое. Вы должны быть осторожны, хотя, как первый аргумент в Объект.assign ()
Метод на самом деле становится измененным и возвращенным. Поэтому убедитесь, что вы передаете объект, чтобы скопировать, по крайней мере, как второй аргумент. Обычно вы просто передали пустой объект в качестве первого аргумента, чтобы предотвратить изменение существующих данных.
const a = {
en: 'Bye',
de: 'Tschüss'
}
let b = Object.assign({}, a)
b.de = 'Ciao'
console.log(b.de) // Ciao
console.log(a.de) // Tschüss
Ловушка: вложенные предметы
Как уже упоминалось ранее, есть одно большое предупреждение при работе с копированием объектов, которые применяются к обоим способам, перечисленным выше. Когда у вас есть вложенный объект (или массив), и вы копируете его, вложенные объекты внутри этого объекта не будут скопированы, поскольку они являются только указателями/ссылками. Следовательно, если вы измените вложенный объект, вы измените его для обоих экземпляров, что означает, что вы получите работу Малая копия снова Отказ Пример://плохой пример
const a = {
foods: {
dinner: 'Pasta'
}
}
let b = {...a}
b.foods.dinner = 'Soup' // changes for both objects
console.log(b.foods.dinner) // Soup
console.log(a.foods.dinner) // Soup
Сделать Глубокая копия вложенных объектов , вам придется рассмотреть это. Один из способов предотвратить, что это вручную копировать все вложенные объекты:
const a = {
foods: {
dinner: 'Pasta'
}
}
let b = {foods: {...a.foods}}
b.foods.dinner = 'Soup'
console.log(b.foods.dinner) // Soup
console.log(a.foods.dinner) // Pasta
Если вам интересно, что делать, когда объект имеет больше ключей, чем только еда
Вы можете использовать полный потенциал оператора распространения. При прохождении больше свойств после ... распространяться
они перезаписывают оригинальные значения, например const b = {... A, продукты питания: {... A.foods}}
Отказ
Делать глубокие копии без мышления
Что если вы не знаете, насколько глубоко вложенные структуры? Можно очень утомительно вручную пройти через большие объекты и копировать каждый вложенный объект вручную. Есть способ скопировать все, не думая. Вы просто Stringify
Ваш объект и Разбор
Это сразу после:
const a = {
foods: {
dinner: 'Pasta'
}
}
let b = JSON.parse(JSON.stringify(a))
b.foods.dinner = 'Soup'
console.log(b.foods.dinner) // Soup
console.log(a.foods.dinner) // Pasta
Здесь вы должны учитывать, что вы не сможете копировать экземпляры пользовательских классов, поэтому вы можете использовать его только при копировании объектов с родные значения JavaScript внутри.
Массива
Копирование массивов так же распространено, как копирование объектов. Много логики позади этого похожа, поскольку массивы также просто объекты под капотом.
Распространение оператора
Как и в случае с объектами, вы можете использовать оператор распространения для копирования массива:
const a = [1,2,3]
let b = [...a]
b[1] = 4
console.log(b[1]) // 4
console.log(a[1]) // 2
Функции массива – Карта, фильтр, уменьшить
Эти методы вернут новый массив со всеми (или некоторыми) значениями оригинала. При этом вы также можете изменить значения, которые поставляются очень удобны:
const a = [1,2,3]
let b = a.map(el => el)
b[1] = 4
console.log(b[1]) // 4
console.log(a[1]) // 2
В качестве альтернативы вы можете изменить нужный элемент во время копирования:
const a = [1,2,3]
const b = a.map((el, index) => index === 1 ? 4 : el)
console.log(b[1]) // 4
console.log(a[1]) // 2
Array.slice
Этот метод обычно используется для возврата подмножества элементов, начиная с конкретного индекса и, необязательно, заканчивая определенным индексом исходного массива. При использовании array.slice ()
или array.slice (0)
Вы получите копию оригинального массива.
const a = [1,2,3]
let b = a.slice(0)
b[1] = 4
console.log(b[1]) // 4
console.log(a[1]) // 2
Вложенные массивы
Подобно объектам, используя методы выше, чтобы скопировать массив с другим массивом или объектом внутри, будет генерировать Малая копия Отказ Чтобы предотвратить это, также использовать Json.parse (json.stringify (Сомэррай))
Отказ
Бонус: копирование экземпляра пользовательских классов
Когда вы уже являетесь Pro в JavaScript, и вы имеете дело с функциями или классами пользовательских конструкторов, возможно, вы хотите скопировать экземпляры из них.
Как уже упоминалось ранее, вы не можете просто затрагивать + те, как вы потеряете методы класса. Вместо этого вы бы хотели добавить пользовательский Скопировать
Способ создания нового экземпляра со всеми старыми значениями. Давайте посмотрим, как это работает:
class Counter {
constructor() {
this.count = 5
}
copy() {
const copy = new Counter()
copy.count = this.count
return copy
}
}
const originalCounter = new Counter()
const copiedCounter = originalCounter.copy()
console.log(originalCounter.count) // 5
console.log(copiedCounter.count) // 5
copiedCounter.count = 7
console.log(originalCounter.count) // 5
console.log(copiedCounter.count) // 7
Чтобы справиться с объектами и массивами, которые ссылаются внутри вашего экземпляра, вам придется применить ваши недавно выученные навыки о Глубокое копирование ! Я просто добавлю окончательное решение для пользовательского конструктора Скопировать
Способ сделать его более динамичным:
С помощью этого метода копирования вы можете поставить столько ценностей, сколько вы хотите в своем конструкторе, без необходимости вручную копировать все!
Об авторе: Лукас Гисдер-Дубко соучредин и руководил стартапом в качестве CTO в течение 1 1/2 лет, построение технологической команды и архитектуры. Выйдя из запуска, он преподавал кодировку в качестве инструктора свинца в Ironhack И сейчас строит стартап агентства и консультации в Берлине. Проверить dube.io Узнать больше.