web-dev-qa-db-ja.com

これはES6でオブジェクトを複製するための良い方法ですか?

"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);
}

シモンズ:これを行うための組み込み関数が見つからなかったことに不満を感じています。

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