it-swarm.com.ru

Это хороший способ клонировать объект в ES6?

Поиск в Google для "javascript clone object" приносит действительно странные результаты, некоторые из них безнадежно устарели, а некоторые слишком сложны, не так ли просто, как просто:

let clone = {...original};

Что-то не так с этим?

115
Dmitry Fadeev

Это хорошо для мелкого клонирования . распространение объекта является стандартной частью ECMAScript 2018 .

Для глубокого клонирования вам понадобится другое решение .

const clone = {...original} для мелкого клона

const newobj = {...original, prop: newOne} для того, чтобы обязательно добавить еще один реквизит к оригиналу и сохранить как новый объект.

183
Mark Shust

Правка: Когда этот ответ был опубликован, синтаксис {...obj} был недоступен в большинстве браузеров. В настоящее время вы можете использовать его (если вам не нужна поддержка IE 11).

Используйте Object.assign.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign

var obj = { a: 1 };
var copy = Object.assign({}, obj);
console.log(copy); // { a: 1 }

Тем не менее, это не сделает глубокий клон. Пока нет родного способа глубокого клонирования.

Правка: Как @Mike 'Pomax' Kamermans упомянул в комментариях, вы можете глубоко клонировать простые объекты (т.е. без прототипов, функций или циклических ссылок), используя JSON.parse(JSON.stringify(input))

54
Alberto Rivera

если вы не хотите использовать json.parse (json.stringify (object)), вы можете создать рекурсивные копии со значением ключа:

function copy(item){
  let result = null;
  if(!item) return result;
  if(Array.isArray(item)){
    result = [];
    item.forEach(element=>{
      result.Push(copy(element));
    });
  }
  else if(item instanceof Object && !(item instanceof Function)){ 
    result = {};
    for(let key in item){
      if(key){
        result[key] = copy(item[key]);
      }
    }
  }
  return result || item;
}

Но лучший способ - создать класс, который может возвращать сам клон

class MyClass{
    data = null;
    constructor(values){ this.data = values }
    toString(){ console.log("MyClass: "+this.data.toString(;) }
    remove(id){ this.data = data.filter(d=>d.id!==id) }
    clone(){ return new MyClass(this.data) }
}
3
marcel

Исходя из ответа @marcel, я обнаружил, что некоторые функции все еще отсутствуют в клонированном объекте. например.

function MyObject() {
  var methodAValue = null,
      methodBValue = null

  Object.defineProperty(this, "methodA", {
    get: function() { return methodAValue; },
    set: function(value) {
      methodAValue = value || {};
    },
    enumerable: true
  });

  Object.defineProperty(this, "methodB", {
    get: function() { return methodAValue; },
    set: function(value) {
      methodAValue = value || {};
    }
  });
}

где на MyObject я мог клонировать methodA, но methodB был исключен. Это произошло потому, что оно отсутствует

enumerable: true

что означало, что он не появился в

for(let key in item)

Вместо этого я переключился на

Object.getOwnPropertyNames(item).forEach((key) => {
    ....
  });

который будет включать не перечисляемые ключи.

Я также обнаружил, что прототип (proto) не был клонирован. Для этого я использовал

if (obj.__proto__) {
  copy.__proto__ = Object.assign(Object.create(Object.getPrototypeOf(obj)), obj);
}

PS: расстраивает, что не смог найти встроенную функцию для этого.

2
Shane Gannon

Если используемые вами методы плохо работают с объектами, включающими такие типы данных, как Date, попробуйте это

Импорт _

import * as _ from 'lodash';

Глубокий клон

myObjCopy = _.cloneDeep(myObj);
1
shaheer shukur

Все описанные выше методы не обрабатывают глубокое клонирование объектов, если оно вложено в n уровней. Я не проверял его производительность по сравнению с другими, но он короткий и простой.

В первом примере ниже показано клонирование объекта с использованием Object.assign, который клонируется только до первого уровня.

var person = {
    name:'saksham',
    age:22,
    skills: {
        lang:'javascript',
        experience:5
    }
}

newPerson = Object.assign({},person);
newPerson.skills.lang = 'angular';
console.log(newPerson.skills.lang); //logs Angular

Используя приведенный ниже подход, глубоко клонируем объект

var person = {
    name:'saksham',
    age:22,
    skills: {
        lang:'javascript',
        experience:5
    }
}

anotherNewPerson = JSON.parse(JSON.stringify(person));
anotherNewPerson.skills.lang = 'angular';
console.log(person.skills.lang); //logs javascript
0
Saksham