JavaScript метод assign()
JavaScript ObjectОпределение и применение
JavaScript метод assign() позволяет произвести поверхностное копирование значений всех перечислимых собственных свойств и методов из одного или нескольких исходных объектов в целевой объект. Метод также копирует свойства, ключом которых является символ (Symbol).
Обращаю Ваше внимание, что метод .assign() перезаписывает значение свойства или метода в целевом объекте, если они имеют один и тот же ключ, что и в переданном источнике. Если источники имеют один и тот же ключ (свойство), то более поздние источники будут перезаписывать более ранние.
Под перечислимыми свойствами стоит понимать те, атрибут enumerable которых имеет значение true, вследствие чего они будут перечислимы в циклах, например в цикле for...in. Атрибуты в свою очередь описываются дескрипторами свойств – это обычные объекты JavaScript, которые описывают атрибуты и значение свойства. Подробную информацию о дескрипторах свойств и атрибутах вы можете получить в описании метода defineProperty(), который позволяет определить новое или изменить существующее свойство объекта, описывая его дескрипторами.
Поддержка браузерами
Метод | Chrome | Firefox | Opera | Safari | IExplorer | Edge |
---|---|---|---|---|---|---|
assign() | 45.0 | 34.0 | 32.0 | 9.0 | Нет | Да |
JavaScript синтаксис:
// копирование из одного исходного объекта Object.assign( target, source ); // копирование из нескольких исходных объектов Object.assign( target, ...sources );
Версия JavaScript
ECMAScript 2015 (6th Edition, ECMA-262)Значения параметров
Параметр | Описание |
---|---|
target | Целевой объект в который будут скопированы значения всех перечислимых собственных свойств и методов объекта, или объектов, перечисленных в параметре метода. Обязательное значение. |
source / sources | Исходный объект или объекты из которых производиться копирование значений всех перечислимых собственных свойств и методов. Обязательное значение. Такие источники как null или undefined обрабатываются как пустые объекты и не добавляют ничего к целевому объекту. Если источник не имеет перечислимых свойств или методов, то он также не будет добавлен к целевому объекту. |
Исключения
Тип исключения | Описание |
---|---|
TypeError | Возникает в том случае, если целевое свойство или метод перезаписывается, а оно доступно только для чтения, целевой объект при этом может быть изменен, если какие-либо свойства или методы были добавлены до возникновения подобной ошибки (пример рассмотрен ниже). |
Пример использования
Слияние объектов
В этом примере мы рассмотрим как с помощью метода assign() поверхностно скопировать собственные свойства трех объектов в один объект:
// инициализируем переменные, содержащие объект let a = {a: 1}, b = {b: 2}, c = {c: 3}; let mergeObjects = Object.assign( a, b, c ); // переменная "a" является целевым объектом, а переменные "b" и "c" служат источниками console.log( mergeObjects ); // переменная содержит значение { a: 1, b: 2, c: 3 } console.log( a ); // переменная содержит значение { a: 1, b: 2, c: 3 }
Слияние объектов с одинаковыми свойствами
В этом примере мы рассмотрим с Вами как происходт поверхностное копирование объектов, которые имеют одинаковые свойства:
// инициализируем переменные, содержащие объект с одноименными свойствами let a = {x: 1}, b = {x: 2}, c = {x: 3}; Object.assign( a, b, c ); // переменная "a" является целевым объектом, а переменные "b" и "c" служат источниками console.log( a ); // переменная содержит значение { x: 3 }
Обратите внимание, что метод .assign() перезаписывает значение свойства в целевом объекте, если они имеют один и тот же ключ, что и в переданном источнике. Если источники имеют один и тот же ключ (свойство), то более поздние источники будут перезаписывать более ранние, как в этом примере, сначала переменная "b" перезаписала значение свойства x переменной "a", а потом переменная "c" перезаписала начение свойства x переменной "a".
Поверхностное копирование объекта
В следующем примере мы рассмотрим как произвести поверхностное копирование объекта в новый объект:
let student = {name: "Ivan", family: "Susanin"}; let shallowClone = Object.assign( {}, student ); console.log( shallowClone ); // переменная содержит значение {name: "Ivan", family: "Susanin"}
Проблемы при поверхностном копировании
В этом примере мы с Вами детально рассмотрим как происходит поверхностное копирование элементов объекта, значением которых является объект:
// инициализируем переменную, содержащую объект let obj = { a: 1, b: { c: 2 } }; // осуществляем поверхностное копирование объекта и инициализируем переменную let newObj = Object.assign( {}, obj ); console.log( newObj ); // переменная содержит значение { a: 1, b: { c: 2} } obj.a = 100; // изменяем значение свойства объекта obj newObj.a = 150; // изменяем значение свойства объекта newObj console.log( obj ); // переменная содержит значение { a: 100, b: { c: 2} } console.log( newObj ); // переменная содержит значение { a: 150, b: { c: 2} } obj.b.c = 200; // изменяем значение свойства объекта obj console.log( obj ); // переменная содержит значение { a: 100, b: { c: 200} } console.log( newObj ); // переменная содержит значение { a: 150, b: { c: 200} }
Важным в понимании работы метода assign() и поверхностного копирования в частности является то, что если исходное значение свойство является ссылкой на объект, то оно копирует только ссылку на это значение, а не создает новое значение. Независимо от того где мы изменяем это значение - в новом объекте, или в первоначальном, значение будет изменено везде. Для осуществления глубокого клонирования нам необходимо использовать другие альтернативы.
Глубокое копирование объекта
Глубокое копирование объекта в отличии от поверхностного дублирует каждый встреченный ею объект, то есть копия и исходный объект не будут разделять общие элементы, поэтому она в действительности будет являться полноценной копией оригинала.
Давайте рассмотрим одно из решений проблемы, с которой мы столкнулись с помощью метода assign() и сделаем глубокую копию нашего объекта:
// инициализируем переменную, содержащую объект let obj = { a: 1, b: { c: 2 } }; // осуществляем глубокое копирование объекта и инициализируем переменную let newObj = JSON.parse( JSON.stringify( obj ) ); console.log( newObj ); // переменная содержит значение { a: 1, b: { c: 2} } obj.b.c = 200; // изменяем значение свойства объекта obj console.log( obj ); // переменная содержит значение { a: 1, b: { c: 200} } console.log( newObj ); // переменная содержит значение { a: 1, b: { c: 2} }
В этом примере с использованием метода JSON.stringify мы преобразовали значение переменной obj в строку JSON, а с помощью метода JSON.parse парсим (разбираем) эту строку и возвращаем новый объект, соответствующий переданной строке. В результате чего, свойства, значением которых является объект имеют собственные значения, а не ссылаются на первоначальный объект. Благодаря этим преобразованиям мы получаем новый объект, который является действительно полноценной копией оригинала.
Копирование символов
Метод assign() позволяет скопировать свойства, ключом которых является символ (Symbol):
// инициализируем переменную, содержащую объект let obj = { [Symbol( "test" )]: "test", "name": "Vasya" }; let newObj = Object.assign( {}, obj ) ; console.log( obj ); // переменная содержит значение {name: "Vasya", Symbol(test): "test"}
Нюансы поверхностного копирования
В этом примере мы с Вами рассмотрим некоторые нюансы при поверхностном копировании:
let v1 = null, v2 = true, v3 = undefined, v4 = NaN, v5 = "", v6 = Symbol( "test" ), v7 = [], v8 = {}, v9 = Infinity, v10 = 100, v11 = "ok?"; let obj = Object.assign( {}, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11); console.log( obj ); // переменная содержит значение {0: "o", 1: "k", 2: "?"}
Обратите внимание, что только строки могут иметь собственные перечислимые свойства, остальные переменные просто были проигнорированы.
Возникновение исключения
Давайте рассмотрим пример в котором рассмотрим при каких условиях вызыается исключение при работе со свойством assign():
// задаем пустому объекту новое свойство и инициализируем переменную let target = Object.defineProperty( {}, "a", { value: 1, // значение свойства writable: false // свойство только для чтения }); console.log( target ); // переменная содержит значение {a: 1} Object.assign( target, { b: 2 }, { c: 3, a: 4, d: 5 }); // TypeError свойство "a" только для чтения console.log( target ); // переменная содержит значение {b: 2, c: 3, a: 1}
В этом примере с использованием метода defineProperty() мы задаем пустому объекту новое свойство только для чтения и инициализируем этим объектом переменную. После этого мы копируем в целевой объект два объекта, что приводит к возникновению исключения по той причине, что происходит попытка перезаписать свойство доступное только для чтения.
Обратите внимание, что те свойства, которые были добавлены до ошибки, которая прервала копирование, были успешно скопированы в целевой объект.
JavaScript Object