Как клонировать экземпляр класса Javascript с помощью ES6.
Меня не интересуют решения на основе jquery или $ extend.
Я видел довольно старые дискуссии о клонировании объектов, которые предполагают, что проблема довольно сложная, но с ES6 возникает очень простое решение - я изложу его ниже и посмотрю, считают ли люди его удовлетворительным.
изменить: предполагается, что мой вопрос дублируется; Я видел этот ответ, но ему 7 лет, и он включает очень сложные ответы с использованием pre-ES6 js. Я предполагаю, что мой вопрос, который учитывает ES6, имеет значительно более простое решение.
Object
s, используемых в качестве хранилищ данных. Это о ES6class
и проблеме не потерять информацию о типе класса. Требуется другое решение.Ответы:
Это сложно; Я очень много пробовал! В конце концов, этот однострочник работал для моих пользовательских экземпляров класса ES6:
let clone = Object.assign(Object.create(Object.getPrototypeOf(orig)), orig)
Он избегает установки прототипа, потому что, по их словам, это сильно замедляет код.
Он поддерживает символы, но не идеален для геттеров / сеттеров и не работает с неперечисляемыми свойствами (см. Документацию Object.assign () ). Кроме того, клонирование основных внутренних классов (таких как Array, Date, RegExp, Map и т. Д.), К сожалению, часто требует индивидуальной обработки.
Вывод: это беспорядок. Будем надеяться, что когда-нибудь появится нативная и чистая функциональность клонирования.
источник
const clone = Object.assign( {}, instanceOfBlah ); Object.setPrototypeOf( clone, Blah.prototype );
Обратите внимание на характеристики Object.assign : он выполняет неглубокую копию и не копирует методы класса.
Если вам нужна глубокая копия или больший контроль над копией, есть функции клонирования lodash .
источник
Object.create
создает новый объект с указанным прототипом, почему бы не простоconst clone = Object.assign(Object.create(instanceOfBlah), instanceOfBlah)
. Также будут скопированы методы класса.Blah.prototype != instanceOfBlah
. Вы должны использоватьObject.getPrototypeOf(instanceOfBlah)
Не рекомендуется делать расширения Прототипа, это приведет к проблемам, когда вы будете делать тесты своего кода / компонентов. Фреймворки модульного тестирования не будут автоматически принимать расширения вашего прототипа. Так что это плохая практика. Здесь есть больше объяснений расширений прототипов. Почему расширение собственных объектов - плохая практика?
Для клонирования объектов в JavaScript нет простого и понятного способа. Вот первый пример, использующий «Мелкую копию»:
1 -> Мелкий клон:
class Employee { constructor(first, last, street) { this.firstName = first; this.lastName = last; this.address = { street: street }; } logFullName() { console.log(this.firstName + ' ' + this.lastName); } } let original = new Employee('Cassio', 'Seffrin', 'Street A, 23'); let clone = Object.assign({},original); //object.assing() method let cloneWithPrototype Object.create(Object.getPrototypeOf(original)), original) // the clone will inherit the prototype methods of the original. let clone2 = { ...original }; // the same of object assign but shorter sintax using "spread operator" clone.firstName = 'John'; clone.address.street = 'Street B, 99'; //will not be cloned
Полученные результаты:
Примечание: если у экземпляра есть замыкания как собственные свойства, этот метод не будет его переносить. ( подробнее о замыканиях ) И, кроме того, подобъект «адрес» не будет клонирован.
не будет работать.
будет работать, потому что клон также скопирует свои прототипы.
Чтобы клонировать массивы с помощью Object.assign:
let cloneArr = array.map((a) => Object.assign({}, a));
Клонировать массив с использованием синтаксиса распространения ECMAScript:
let cloneArrSpread = array.map((a) => ({ ...a }));
2 -> Глубокий клон:
Чтобы заархивировать полностью новую ссылку на объект, мы можем использовать JSON.stringify () для синтаксического анализа исходного объекта как строки и после синтаксического анализа обратно в JSON.parse ().
let deepClone = JSON.parse(JSON.stringify(original));
При глубоком клонировании ссылки на адрес будут сохранены. Однако прототипы deepClone будут потеряны, поэтому deepClone.logFullName () не будет работать.
3 -> сторонние библиотеки:
Другой вариант - использовать сторонние библиотеки, такие как loadash или подчеркивание. Они создадут новый объект и скопируют каждое значение из оригинала в новый объект, сохраняя его ссылки в памяти.
Подчеркивание: let cloneUnderscore = _ (оригинал) .clone ();
Клон Loadash: var cloneLodash = _.cloneDeep (оригинал);
Обратной стороной lodash или подчеркивания была необходимость включения в ваш проект дополнительных библиотек. Однако они являются хорошими вариантами и также дают высокие результаты производительности.
источник
{}
клон не унаследует ни один из методов прототипа оригинала.clone.logFullName()
вообще не будет работать. То,Object.assign( Object.create(Object.getPrototypeOf(eOriginal)), eOriginal)
что у вас было раньше, было в порядке, почему вы изменили это?Object.assign({},original)
не работает.Еще один лайнер:
В большинстве случаев ... (работает для Date, RegExp, Map, String, Number, Array), btw, клонирование строки, number немного забавно.
let clone = new obj.constructor(...[obj].flat())
для этого класса без конструктора копирования:
let clone = Object.assign(new obj.constructor(...[obj].flat()), obj)
источник
class A { constructor() { this.x = 1; } y() { return 1; } } const a = new A(); const output = Object.getOwnPropertyNames(Object.getPrototypeOf(a)).concat(Object.getOwnPropertyNames(a)).reduce((accumulator, currentValue, currentIndex, array) => { accumulator[currentValue] = a[currentValue]; return accumulator; }, {});
источник
Вы можете использовать оператор распространения, например, если хотите клонировать объект с именем Obj:
let clone = { ...obj};
И если вы хотите что-то изменить или добавить к клонированному объекту:
let clone = { ...obj, change: "something" };
источник