JavaScriptオブジェクトを正しく複製するにはどうすればよいですか?


3078

私はオブジェクトを持っていますxy変更が変更されyないように、それをオブジェクトとしてコピーしたいと思いますx。組み込みのJavaScriptオブジェクトから派生したオブジェクトをコピーすると、余分な不要なプロパティが発生することに気付きました。私は自分のリテラル構成オブジェクトの1つをコピーしているので、これは問題ではありません。

JavaScriptオブジェクトを正しく複製するにはどうすればよいですか?


30
:この質問を参照してくださいstackoverflow.com/questions/122102/...
Niyaz

256
JSONのために、私が使うmObj=JSON.parse(JSON.stringify(jsonObject));
主楼を。

67
私は本当に誰も提案しない理由を本当に得ませんObject.create(o)、それは著者が尋ねるすべてをしますか?
froginvasion 2014

44
var x = { deep: { key: 1 } }; var y = Object.create(x); x.deep.key = 2; これを行った後y.deep.keyも2になるため、Object.createは複製に使用できません...
Ruben Stolk

17
@ r3wtその仕事... ..唯一の解決策の基本的なテストを行った後に投稿してくださいません
akshay

回答:


1561

JavaScriptのオブジェクトに対してこれを行うのは簡単でも簡単でもありません。プロトタイプに残しておき、新しいインスタンスにコピーしてはならないオブジェクトのプロトタイプから誤って属性を取得する問題に遭遇します。たとえば、cloneメソッドをObject.prototypeに追加する場合、一部の回答が示すように、その属性を明示的にスキップする必要があります。しかしObject.prototype、あなたが知らない他の追加のメソッド、または他の中間プロトタイプがある場合はどうなりますか?その場合、コピーしてはならない属性をコピーするので、hasOwnPropertyメソッドで予期しないローカルでない属性を検出する必要があります。

列挙できない属性に加えて、非表示のプロパティを持つオブジェクトをコピーしようとすると、より困難な問題が発生します。たとえば、prototypeは関数の非表示プロパティです。また、オブジェクトのプロトタイプは属性__proto__で参照されますが、これも非表示であり、ソースオブジェクトの属性を反復するfor / inループによってコピーされません。私が思うに__proto__、FirefoxのJavaScriptインタープリタに固有のかもしれないし、それが他のブラウザで別の何かかもしれないが、あなたは画像を取得します。すべてが列挙可能というわけではありません。非表示の属性は、名前がわかっていればコピーできますが、自動的に検出する方法はわかりません。

エレガントなソリューションを求めるもう1つの問題は、プロトタイプ継承を正しく設定する問題です。ソースオブジェクトのプロトタイプがObjectである場合、で新しい一般オブジェクトを作成するだけで機能します{}が、ソースのプロトタイプがの子孫でObjectある場合、そのプロトタイプから、hasOwnPropertyフィルターを使用してスキップした、またはプロトタイプにありましたが、そもそも列挙できませんでした。1つの解決策は、ソースオブジェクトのconstructorプロパティを呼び出して初期コピーオブジェクトを取得してから属性をコピーすることですが、それでも列挙できない属性は取得されません。たとえば、Dateオブジェクトはそのデータを非表示のメンバーとして保存します。

function clone(obj) {
    if (null == obj || "object" != typeof obj) return obj;
    var copy = obj.constructor();
    for (var attr in obj) {
        if (obj.hasOwnProperty(attr)) copy[attr] = obj[attr];
    }
    return copy;
}

var d1 = new Date();

/* Executes function after 5 seconds. */
setTimeout(function(){
    var d2 = clone(d1);
    alert("d1 = " + d1.toString() + "\nd2 = " + d2.toString());
}, 5000);

の日付文字列はの日付文字列d1より5秒遅れd2ます。1つDateを別のものと同じにするsetTime方法は、メソッドを呼び出すことですが、これはDateクラスに固有です。私は間違っていても大丈夫ですが、この問題に対する防弾総合的な解決策はないと思います!

私は私が唯一の平野コピーする必要があるだろうと仮定することにより犠牲になってしまったコピー一般的な深いを実装しなければならなかったときはObjectArrayDateStringNumber、またはBoolean。最後の3つのタイプは不変なので、浅いコピーを実行でき、変更が心配されません。さらに、そのリストに含まれる、ObjectまたはArrayリストに含まれる6つの単純なタイプのいずれかに含まれるすべての要素を想定しました。これは、次のようなコードで実現できます。

function clone(obj) {
    var copy;

    // Handle the 3 simple types, and null or undefined
    if (null == obj || "object" != typeof obj) return obj;

    // Handle Date
    if (obj instanceof Date) {
        copy = new Date();
        copy.setTime(obj.getTime());
        return copy;
    }

    // Handle Array
    if (obj instanceof Array) {
        copy = [];
        for (var i = 0, len = obj.length; i < len; i++) {
            copy[i] = clone(obj[i]);
        }
        return copy;
    }

    // Handle Object
    if (obj instanceof Object) {
        copy = {};
        for (var attr in obj) {
            if (obj.hasOwnProperty(attr)) copy[attr] = clone(obj[attr]);
        }
        return copy;
    }

    throw new Error("Unable to copy obj! Its type isn't supported.");
}

上記の関数は、オブジェクトと配列のデータがツリー構造を形成している限り、私が言及した6つの単純な型に対して適切に機能します。つまり、オブジェクト内の同じデータへの参照は1つだけです。例えば:

// This would be cloneable:
var tree = {
    "left"  : { "left" : null, "right" : null, "data" : 3 },
    "right" : null,
    "data"  : 8
};

// This would kind-of work, but you would get 2 copies of the 
// inner node instead of 2 references to the same copy
var directedAcylicGraph = {
    "left"  : { "left" : null, "right" : null, "data" : 3 },
    "data"  : 8
};
directedAcyclicGraph["right"] = directedAcyclicGraph["left"];

// Cloning this would cause a stack overflow due to infinite recursion:
var cyclicGraph = {
    "left"  : { "left" : null, "right" : null, "data" : 3 },
    "data"  : 8
};
cyclicGraph["right"] = cyclicGraph;

JavaScriptオブジェクトを処理することはできませんが、投げたものに対してのみ機能することを想定していなければ、多くの目的には十分です。


5
nodejsでほぼ正常に機能しました-(var i = 0、var len = obj.length; i <len; ++ i){の行を(var i = 0; i <obj.length; ++ i){
Trindaz 2012年

5
今後のGoogle社員向け:同じディープコピー、gist.github.com
2234277

8
今日JSON.parse(JSON.stringify([some object]),[some revirer function])は解決策でしょうか?
KooiInc

5
最初のスニペットでは、それはいけないのvar cpy = new obj.constructor()ですか?
cyon 2014年

8
オブジェクトの割り当てはChromeで真のコピーを作成していないようで、元のオブジェクトへの参照を維持します-最終的にJSON.stringifyとJSON.parseを使用してクローンを作成しました-完全に機能しました
1owk3y

974

Dateオブジェクト内でs、functions、undefined、regExp、またはInfinityを使用しない場合、非常に単純な1つのライナーはJSON.parse(JSON.stringify(object))次のとおりです。

const a = {
  string: 'string',
  number: 123,
  bool: false,
  nul: null,
  date: new Date(),  // stringified
  undef: undefined,  // lost
  inf: Infinity,  // forced to 'null'
}
console.log(a);
console.log(typeof a.date);  // Date object
const clone = JSON.parse(JSON.stringify(a));
console.log(clone);
console.log(typeof clone.date);  // result of .toISOString()

これは、オブジェクト、配列、文​​字列、ブール値、数値を含むあらゆる種類のオブジェクトで機能します。

ワーカーとの間でメッセージを投稿するときに使用されるブラウザーの構造化クローンアルゴリズムに関するこの記事も参照してください。また、ディープクローニング用の関数も含まれています。


42
これはテストにのみ使用できることに注意してください。まず、時間とメモリ消費の点で最適とはほど遠いです。次に、すべてのブラウザにこのメソッドがあるわけではありません。
Nux 2013

2
JSON2.jsまたはJSON3.jsを常に含めることができます。とにかくあなたはあなたのアプリのためにそれらを必要とするでしょう。しかし、JSON.stringifyには継承されたプロパティが含まれていないため、これが最善の解決策ではない可能性があることに同意します。
ティム香港

78
@Nux、なぜ時間とメモリの点で最適ではないのですか?MiJynは次のように述べています。「このメソッドが(ディープオブジェクトでの)浅いコピーよりも遅いのは、このメソッドが定義上、ディープコピーだからです。しかし、JSONはネイティブコードで実装されているため(ほとんどのブラウザー)、これはかなり高速になります。他のJavaScriptベースのディープコピーソリューションを使用するよりも、JavaScriptベースの浅いコピーテクニックよりも高速な場合があります(jsperf.com/cloning-an-object/79を参照)。stackoverflow.com/questions/122102/...
BeauCielBleu

16
2014年10月の更新をこれに追加したいだけです。JSON.parse(JSON.stringify(oldObject));を使用すると、Chrome 37以降が高速になります。これを使用する利点は、JavaScriptエンジンが必要に応じて、より良いものを表示して最適化することが非常に簡単になることです。
mirhagk 2014年

17
2016年の更新:これは、広く使用されているほとんどすべてのブラウザーで動作するはずです。(「使用できますか...」を参照)現在の主な問題は、十分なパフォーマンスがあるかどうかです。
James Foster

783

jQueryでは、extendを使用して浅いコピー作成できます。

var copiedObject = jQuery.extend({}, originalObject)

以降のへの変更はcopiedObjectには影響せずoriginalObject、その逆も同様です。

または、深いコピーを作成するには

var copiedObject = jQuery.extend(true, {}, originalObject)

164
または:var copiedObject = jQuery.extend({},originalObject);
Grant McLean

82
ディープコピーのための最初のパラメータとしてtrueを指定することも有用である:jQuery.extend(true, {}, originalObject);
ウィルシェーバー

6
はい、私は、このリンクは役に立ち(パスカルと同じ解決策)が見つかりstackoverflow.com/questions/122102/...
ギャリー英語

3
ただのメモ、これは元のオブジェクトのプロトコンストラクタをコピーしません
Sam Jones

1
stackoverflow.com/questions/184710/…によれば、「浅いコピー」はoriginalObjectの参照をコピーするだけのようです...subsequent changes to the copiedObject will not affect the originalObject, and vice versa...。私は本当に混乱していました。
Carr

687

ECMAScript 6には、列挙可能なすべての独自のプロパティの値を1つのオブジェクトから別のオブジェクトにコピーするObject.assignメソッドがあります。例えば:

var x = {myProp: "value"};
var y = Object.assign({}, x); 

ただし、ネストされたオブジェクトは参照としてコピーされることに注意してください。


ええ、私はそれObject.assignが行く方法だと信じています。ポリフィルも簡単です:gist.github.com/rafaelrinaldi/43813e707970bd2d77fa

22
(これらは以降も、これはオブジェクトリテラルを経由して定義された「メソッド」を上書きコピーすることに注意しているが、可算)ではない「クラス」機構を介して反抗する方法(これらは、以降ではありません列挙)。
Marcus Junius Brutus

16
Edge以外のIEではサポートされていません。一部の人々はまだこれを使用しています。
Saulius、

1
これは@EugeneTiurinの回答と同じです。
Wilt

5
ここでの経験から言えば、これを使用しないでください。オブジェクトは階層的になるように設計されており、最初のレベルのみをコピーするので、コピーしたオブジェクト全体を割り当てることができます。私を信じて、それはあなたの頭のスクラッチの日を節約するかもしれません。
ow3n

232

MDNごと:

  • 浅いコピーが必要な場合は、 Object.assign({}, a)
  • 「ディープ」コピーの場合は、 JSON.parse(JSON.stringify(a))

外部ライブラリは必要ありませんが、最初にブラウザの互換性を確認する必要があります。


8
JSON.parse(JSON.stringify(a))は美しく見えますが、使用する前に、目的のコレクションにかかる時間をベンチマークすることをお勧めします。オブジェクトのサイズによっては、これが最も速いオプションではない場合があります。
Edza

3
私が気付いたJSONメソッドは、日付オブジェクトを文字列に変換しますが、日付には変換しません。Javascriptのタイムゾーンの面白さに対処し、手動で日付を修正する必要があります。日付以外の他のタイプについても同様のケースになる可能性があります
Steve Seeger

Dateにはclone機能があるので、moment.jsを使用します。詳細はこちらをご覧くださいmomentjs.com/docs/#/parsing/moment-clone
Tareq

これは良いことですが、オブジェクトが内部に関数を持っている場合は注意してください
lesolorzanov

json解析のもう1つの問題は、循環参照です。オブジェクト内に循環参照がある場合、これは壊れます
philoj

133

多くの答えがありますが、ECMAScript 5のObject.createについて言及しているものはありません。確かに正確なコピーは提供されませんが、新しいオブジェクトのプロトタイプとしてソースが設定されます。

したがって、これは質問に対する正確な答えではありませんが、1行のソリューションであり、エレガントです。そしてそれは2つのケースに最適です:

  1. そのような継承が役立つところ(そうです!)
  2. ソースオブジェクトは変更されないため、2つのオブジェクト間の関係は問題になりません。

例:

var foo = { a : 1 };
var bar = Object.create(foo);
foo.a; // 1
bar.a; // 1
foo.a = 2;
bar.a; // 2 - prototype changed
bar.a = 3;
foo.a; // Still 2, since setting bar.a makes it an "own" property

このソリューションが優れていると思うのはなぜですか?これはネイティブなので、ループも再帰もありません。ただし、古いブラウザにはポリフィルが必要です。


注:Object.createはディープコピーではありません(itpastornは再帰がないと述べています)。証明:var a = {b:'hello',c:{d:'world'}}, b = Object.create(a); a == b /* false */; a.c == b.c /* true */;
zamnuts 2013

103
これはプロトタイプの継承であり、クローンではありません。これらは完全に異なるものです。新しいオブジェクトには独自のプロパティはなく、プロトタイプのプロパティをポイントするだけです。クローン作成のポイントは、別のオブジェクトのプロパティを参照しない新しいオブジェクトを作成することです。
d13 2014年

7
私はあなたに完全に同意します。これは「意図された」かもしれないようなクローンではないことにも同意します。しかし、人々に来て、標準化されていないあいまいなソリューションを見つけるのではなく、JavaScriptの性質を採用してください。確かに、あなたはプロトタイプが好きではなく、それらはすべてあなたにとって「大げさ」ですが、あなたが何をしているのかを知っているなら、それらは実際には非常に役に立ちます。
froginvasion 2014

4
@RobG:この記事では、参照と複製の違いについて説明しています:en.wikipedia.org/wiki/Cloning_(programming)Object.create参照を通じて親のプロパティを指します。つまり、親のプロパティ値が変更されると、子のプロパティも変更されます。jsbin.com/EKivInO/2のように、ネストされた配列とオブジェクトに意外な副作用があり、コードに気づかないと見つけにくいバグが発生する可能性があります。複製されたオブジェクトは、親と同じプロパティと値を持つ完全に新しい独立したオブジェクトですが、親には接続されていません。
d13 14

1
これは人々を誤解させます... Object.create()は継承の手段として使用できますが、クローンはそれに近いものではありません。
prajnavantha 2017年

128

1行のコードでJavascriptオブジェクトを複製するエレガントな方法

Object.assignこの方法は、ECMAScriptの2015(ES6)規格の一部であり、あなたが必要な正確に何を行います。

var clone = Object.assign({}, obj);

Object.assign()メソッドは、列挙可能なすべての独自プロパティの値を1つ以上のソースオブジェクトからターゲットオブジェクトにコピーするために使用されます。

続きを読む...

古いブラウザをサポートするためのポリフィル

if (!Object.assign) {
  Object.defineProperty(Object, 'assign', {
    enumerable: false,
    configurable: true,
    writable: true,
    value: function(target) {
      'use strict';
      if (target === undefined || target === null) {
        throw new TypeError('Cannot convert first argument to object');
      }

      var to = Object(target);
      for (var i = 1; i < arguments.length; i++) {
        var nextSource = arguments[i];
        if (nextSource === undefined || nextSource === null) {
          continue;
        }
        nextSource = Object(nextSource);

        var keysArray = Object.keys(nextSource);
        for (var nextIndex = 0, len = keysArray.length; nextIndex < len; nextIndex++) {
          var nextKey = keysArray[nextIndex];
          var desc = Object.getOwnPropertyDescriptor(nextSource, nextKey);
          if (desc !== undefined && desc.enumerable) {
            to[nextKey] = nextSource[nextKey];
          }
        }
      }
      return to;
    }
  });
}

ばかげた質問で申し訳ありませんが、ポリフィルObject.assignvalue関数が1つのパラメータしか取らないのに、なぜ2つのパラメータが取られるのでしょうか。
Qwertie、2016年

@Qwertie昨日すべての引数が反復され、最後に渡された引数からのプロパティに優先順位を付けて1つのオブジェクトにマージされます
Eugene Tiurin

ああ、わかりました。ありがとう(arguments以前はオブジェクトに慣れていませんでした。)Object()Google経由で見つけるのに問題があります...型キャストですよね。
Qwertie 2016年

44
これは、浅い「クローニング」のみを実行します
マーカスジュニウスブルータス

1
この答えは、このようにまったく同じです:stackoverflow.com/questions/122102/...私はそれが同じ人である知っていますが、代わりに、単に答えをコピーするので参照する必要があります。
lesolorzanov

87

インターネット上のほとんどのソリューションにはいくつかの問題があります。そこで、私はフォローアップを行うことにしました。これには、受け入れられた回答を受け入れない理由が含まれています。

開始状況

Javascriptのすべての子とその子などをディープコピーしたいObject。しかし、私は普通の開発者ではないので、私Object普通の propertiescircular structuresそしてさえ持っていnested objectsます。

ではcircular structurenested object最初のとを作成しましょう。

function Circ() {
    this.me = this;
}

function Nested(y) {
    this.y = y;
}

Object名前付きですべてをまとめましょうa

var a = {
    x: 'a',
    circ: new Circ(),
    nested: new Nested('a')
};

次に、aという名前の変数にコピーして、bそれを変更します。

var b = a;

b.x = 'b';
b.nested.y = 'b';

あなたはここで何が起こったのか知っています。

console.log(a, b);

a --> Object {
    x: "b",
    circ: Circ {
        me: Circ { ... }
    },
    nested: Nested {
        y: "b"
    }
}

b --> Object {
    x: "b",
    circ: Circ {
        me: Circ { ... }
    },
    nested: Nested {
        y: "b"
    }
}

次に、解決策を見つけましょう。

JSON

私が最初に試みたのはを使用することJSONでした。

var b = JSON.parse( JSON.stringify( a ) );

b.x = 'b';
b.nested.y = 'b';

時間を無駄にしないでくださいTypeError: Converting circular structure to JSON

再帰コピー(受け入れられた「答え」)

受け入れられた答えを見てみましょう。

function cloneSO(obj) {
    // Handle the 3 simple types, and null or undefined
    if (null == obj || "object" != typeof obj) return obj;

    // Handle Date
    if (obj instanceof Date) {
        var copy = new Date();
        copy.setTime(obj.getTime());
        return copy;
    }

    // Handle Array
    if (obj instanceof Array) {
        var copy = [];
        for (var i = 0, len = obj.length; i < len; i++) {
            copy[i] = cloneSO(obj[i]);
        }
        return copy;
    }

    // Handle Object
    if (obj instanceof Object) {
        var copy = {};
        for (var attr in obj) {
            if (obj.hasOwnProperty(attr)) copy[attr] = cloneSO(obj[attr]);
        }
        return copy;
    }

    throw new Error("Unable to copy obj! Its type isn't supported.");
}

いいですね これはオブジェクトの再帰的なコピーであり、などの他のタイプも処理しますDateが、これは必須ではありませんでした。

var b = cloneSO(a);

b.x = 'b';
b.nested.y = 'b';

再帰とcircular structures一緒にうまく動作しません...RangeError: Maximum call stack size exceeded

ネイティブソリューション

同僚と議論した後、上司は何が起こったのか私たちに尋ねました、そして彼はいくつかのグーグルの後で簡単な解決策を見つけました。と呼ばれていObject.createます。

var b = Object.create(a);

b.x = 'b';
b.nested.y = 'b';

このソリューションは少し前にJavaScriptに追加され、処理さえしましたcircular structure

console.log(a, b);

a --> Object {
    x: "a",
    circ: Circ {
        me: Circ { ... }
    },
    nested: Nested {
        y: "b"
    }
}

b --> Object {
    x: "b",
    circ: Circ {
        me: Circ { ... }
    },
    nested: Nested {
        y: "b"
    }
}

...そして、ご覧のとおり、ネストされた構造の内部では機能しませんでした。

ネイティブソリューションのポリフィル

Object.createIE 8と同じように、古いブラウザーにはポリフィルがあります。これは、Mozillaが推奨するようなものです。もちろん、完璧ではなく、ネイティブソリューションと同じ問題が発生します

function F() {};
function clonePF(o) {
    F.prototype = o;
    return new F();
}

var b = clonePF(a);

b.x = 'b';
b.nested.y = 'b';

私はF範囲の外に置いたので、何instanceofが私たちに伝えているかを見ることができます。

console.log(a, b);

a --> Object {
    x: "a",
    circ: Circ {
        me: Circ { ... }
    },
    nested: Nested {
        y: "b"
    }
}

b --> F {
    x: "b",
    circ: Circ {
        me: Circ { ... }
    },
    nested: Nested {
        y: "b"
    }
}

console.log(typeof a, typeof b);

a --> object
b --> object

console.log(a instanceof Object, b instanceof Object);

a --> true
b --> true

console.log(a instanceof F, b instanceof F);

a --> false
b --> true

ネイティブソリューションと同じ問題ですが、出力は少し悪いです。

より良い(しかし完璧ではない)ソリューション

調べてみると、これに似た質問(JavaScriptでは、ディープコピーを実行するときに、プロパティが「これ」であるためにサイクルを回避するにはどうすればよいですか?

function cloneDR(o) {
    const gdcc = "__getDeepCircularCopy__";
    if (o !== Object(o)) {
        return o; // primitive value
    }

    var set = gdcc in o,
        cache = o[gdcc],
        result;
    if (set && typeof cache == "function") {
        return cache();
    }
    // else
    o[gdcc] = function() { return result; }; // overwrite
    if (o instanceof Array) {
        result = [];
        for (var i=0; i<o.length; i++) {
            result[i] = cloneDR(o[i]);
        }
    } else {
        result = {};
        for (var prop in o)
            if (prop != gdcc)
                result[prop] = cloneDR(o[prop]);
            else if (set)
                result[prop] = cloneDR(cache);
    }
    if (set) {
        o[gdcc] = cache; // reset
    } else {
        delete o[gdcc]; // unset again
    }
    return result;
}

var b = cloneDR(a);

b.x = 'b';
b.nested.y = 'b';

そして、出力を見てみましょう...

console.log(a, b);

a --> Object {
    x: "a",
    circ: Object {
        me: Object { ... }
    },
    nested: Object {
        y: "a"
    }
}

b --> Object {
    x: "b",
    circ: Object {
        me: Object { ... }
    },
    nested: Object {
        y: "b"
    }
}

console.log(typeof a, typeof b);

a --> object
b --> object

console.log(a instanceof Object, b instanceof Object);

a --> true
b --> true

console.log(a instanceof F, b instanceof F);

a --> false
b --> false

要件は一致しているが、変更など、いくつかの小さな問題、まだそこにあるinstancenestedcircにはObject

葉を共有する木の構造はコピーされず、2つの独立した葉になります。

        [Object]                     [Object]
         /    \                       /    \
        /      \                     /      \
      |/_      _\|                 |/_      _\|  
  [Object]    [Object]   ===>  [Object]    [Object]
       \        /                 |           |
        \      /                  |           |
        _\|  |/_                 \|/         \|/
        [Object]               [Object]    [Object]

結論

再帰とキャッシュを使用する最後のソリューションは最善ではないかもしれませんが、それはオブジェクトの実際のディープコピーです。これは、単純に処理しpropertiescircular structuresそしてnested objectクローニングながら、それは混乱意志それらのインスタンスをアップ。

jsfiddle


12
つまり、問題はその問題を回避することです:)
mikus 2014年

@mikus は、基本的なユースケースだけではない実際の仕様になるまでです。
Fabio

2
上記で提供されたソリューションの大丈夫な分析ですが、著者が導き出した結論は、この質問に対するソリューションがないことを示しています。
Amir Mog

2
JSにネイティブのクローン機能が含まれていないのは残念です。
l00k 2016年

1
すべての上位の回答の中で、これは正しい回答に近いと感じています。
KTU、

77

浅いコピーで問題ない場合は、underscore.jsライブラリにcloneメソッドがあります。

y = _.clone(x);

またはあなたはそれを次のように拡張することができます

copiedObject = _.extend({},originalObject);

2
ありがとう。この手法をMeteorサーバーで使用する。
ターボ、

lodashをすぐに使い始めるには、ndash、Browserify、およびlodashを学ぶことをお勧めします。「npm i --save lodash.clone」、「var clone = require( 'lodash.clone');」で動作するようにクローンを作成しました requireを機能させるには、browserifyなどが必要です。インストールして動作を確認したら、コードを実行するたびに(直接Chromeにアクセスするのではなく)、「browserify yourfile.js> bundle.js; start chrome index.html」を使用します。これにより、ファイルと必要なすべてのファイルがnpmモジュールからbundle.jsに収集されます。Gulpを使用すれば、おそらく時間を節約し、このステップを自動化できます。
アーロンベル

65

OK、下にこのオブジェクトがあり、それを複製したいとします。

let obj = {a:1, b:2, c:3}; //ES6

または

var obj = {a:1, b:2, c:3}; //ES5

答えは主にどのdepenedsであるECMAScriptのあなたが、使用してES6+、あなたは、単に使用することができますObject.assignクローンを行うには:

let cloned = Object.assign({}, obj); //new {a:1, b:2, c:3};

または次のようなスプレッド演算子を使用します:

let cloned = {...obj}; //new {a:1, b:2, c:3};

ただし、を使用する場合、使用ES5できるメソッドはいくつかありますが、はJSON.stringify、コピーするデータの大きなチャンクを使用しないことを確認してください。

let cloned = JSON.parse(JSON.stringify(obj)); 
//new {a:1, b:2, c:3};, can be handy, but avoid using on big chunk of data over and over

big chunk of dataに相当するかの例を挙げていただけますか?100kb?100MB?ありがとう!
user1063287 2018

はい、@ user1063287、基本的にはより大きなデータ、パフォーマンスの低下...それは実際には、kb、mb、またはgbではなく、それを何回実行したいかということによります...また、機能しません機能やその他のもの...
Alireza

3
Object.assign浅いコピーを作成します(スプレッドと同じように、@ Alizera)
ボグダンD

es5ではletを使用できません:^)@Alireza
SensationSama

40

特に洗練されていないソリューションの1つは、JSONエンコーディングを使用して、メンバーメソッドを持たないオブジェクトのディープコピーを作成することです。方法論は、ターゲットオブジェクトをJSONエンコードし、それをデコードすることで、目的のコピーを取得することです。必要なだけコピーを作成したいだけ何度でもデコードできます。

もちろん、関数はJSONに属していないため、これはメンバーメソッドのないオブジェクトに対してのみ機能します。

JSONブロブをKey-Valueストアに格納しているため、この方法論は私のユースケースに最適でした。JavaScriptAPIでオブジェクトとして公開されると、各オブジェクトには実際にオブジェクトの元の状態のコピーが含まれるため、呼び出し元が公開オブジェクトを変更した後で、デルタを計算できます。

var object1 = {key:"value"};
var object2 = object1;

object2 = JSON.stringify(object1);
object2 = JSON.parse(object2);

object2.key = "a change";
console.log(object1);// returns value

関数がJSONに属さないのはなぜですか?私はそれらがJSONとして何度も転送されるのを見てきました...
the_drow 2009年

5
関数はデータを転送するための安全な(またはスマートな)方法ではないため、JSON仕様の一部ではありません。FirefoxのネイティブJSONエンコーダーはそれに渡された関数を単に無視することを知っていますが、他の人の動作についてはわかりません。
クリスウォーカー

1
@mark:{ 'foo': function() { return 1; } }リテラルで構成されたオブジェクトです。
abarnert 2012

@abarnert関数はデータではありません。「関数リテラル」は誤称です。関数には、割り当てやあらゆる種類の「シリアル化できない」ものなど、任意のコードを含めることができるためです。
vemv 2013

35

単純に、spreadプロパティを使用して、参照なしでオブジェクトをコピーできます。ただし、注意してください(コメントを参照)。「コピー」は、オブジェクト/配列の最下位レベルにあります。ネストされたプロパティはまだ参照です!


完全なクローン:

let x = {a: 'value1'}
let x2 = {...x}

// => mutate without references:

x2.a = 'value2'
console.log(x.a)    // => 'value1'

第2レベルの参照を含むクローン:

const y = {a: {b: 'value3'}}
const y2 = {...y}

// => nested object is still a references:

y2.a.b = 'value4'
console.log(y.a.b)    // => 'value4'

JavaScriptは、実際にはディープクローンをネイティブでサポートしていません。ユーティリティ関数を使用します。たとえばラムダ:

http://ramdajs.com/docs/#clone


1
これは機能しません... xがインスタンスx = ['ab'、 'cd'、...]になる場合はおそらく機能します
KamilKiełczewskiApr

3
これは機能しますが、これは浅いコピーであるため、他のオブジェクトへの深い参照は参照のままです!
Bugs Bunny

部分クローンはまた、このように発生する可能性があります:const first = {a: 'foo', b: 'bar'}; const second = {...{a} = first}
クリスティアントレイニャ

25

AngularJSを使用している人のために、このライブラリのオブジェクトを複製または拡張する直接的な方法もあります。

var destination = angular.copy(source);

または

angular.copy(source, destination);

angular.copyのドキュメントの詳細...


2
これはディープコピーの参考資料です。
zamnuts 2014

22

こちらが利用できる機能です。

function clone(obj) {
    if(obj == null || typeof(obj) != 'object')
        return obj;    
    var temp = new obj.constructor(); 
    for(var key in obj)
        temp[key] = clone(obj[key]);    
    return temp;
}

10
この答えはかなり近いですが、正確ではありません。Dateオブジェクトを複製しようとすると、Dateコンストラクター関数の呼び出しによって新しいDateが現在の日付/時刻で初期化されるため、同じ日付は取得されません。その値は列挙可能ではなく、for / inループによってコピーされません。
A.レビー

完璧ではありませんが、これらの基本的なケースには適しています。たとえば、基本的なオブジェクト、配列、または文字列である可能性がある引数の単純な複製を許可します。
james_womack 2013年

を使用してコンストラクタを正しく呼び出すために賛成new。受け入れられた答えはしません。
GetFree

他のすべてのノードで動作します!まだ参照リンクを残している
user956584 2017

再帰的な思考は素晴らしいです。しかし、値が配列の場合、それは機能しますか?
Q10Viking 2019

22

A.Levyの答えはほぼ完成です。これが私の小さな貢献です。再帰的な参照を処理する方法があります。この行を参照してください

if(this[attr]==this) copy[attr] = copy;

オブジェクトがXML DOM要素の場合、代わりにcloneNodeを使用する必要があります

if(this.cloneNode) return this.cloneNode(true);

A.Levyの徹底的な調査とCalvinのプロトタイピングアプローチに触発されて、私はこのソリューションを提供します。

Object.prototype.clone = function() {
  if(this.cloneNode) return this.cloneNode(true);
  var copy = this instanceof Array ? [] : {};
  for(var attr in this) {
    if(typeof this[attr] == "function" || this[attr]==null || !this[attr].clone)
      copy[attr] = this[attr];
    else if(this[attr]==this) copy[attr] = copy;
    else copy[attr] = this[attr].clone();
  }
  return copy;
}

Date.prototype.clone = function() {
  var copy = new Date();
  copy.setTime(this.getTime());
  return copy;
}

Number.prototype.clone = 
Boolean.prototype.clone =
String.prototype.clone = function() {
  return this;
}

回答にあるAndy Burkeのメモも参照してください。


3
Date.prototype.clone = function() {return new Date(+this)};
RobG 2014

22

この記事から:Brian HuismanによるJavaScriptで配列とオブジェクトをコピーする方法

Object.prototype.clone = function() {
  var newObj = (this instanceof Array) ? [] : {};
  for (var i in this) {
    if (i == 'clone') continue;
    if (this[i] && typeof this[i] == "object") {
      newObj[i] = this[i].clone();
    } else newObj[i] = this[i]
  } return newObj;
};

4
これは近いですが、どのオブジェクトに対しても機能しません。これで日付オブジェクトを複製してみてください。すべてのプロパティが列挙可能ではないため、for / inループにすべてが表示されるわけではありません。
A.レヴィ

このようなオブジェクトプロトタイプに追加すると、jQueryが壊れてしまいました。clone2に名前を変更しても。
iPadDeveloper2011 2012

3
@ iPadDeveloper2011上記のコードには、 '(var i for this)'ではなく、 'i'(for i in this) 'というグローバル変数が作成されるというバグがありました。私は編集して修正するのに十分なカルマを持っているので、そうしました。
mikemaccana 2012

1
@Calvin:これは列挙できないプロパティを作成する必要があります。そうしないと、「クローン」が「for」ループに表示されます。
mikemaccana

2
なぜvar copiedObj = Object.create(obj);同様に良い方法ではないのですか?
Dan P. 14

19

ES-6では、単純にObject.assign(...)を使用できます。例:

let obj = {person: 'Thor Odinson'};
let clone = Object.assign({}, obj);

良いリファレンスはこちらです:https : //googlechrome.github.io/samples/object-assign-es6/


12
オブジェクトのディープクローンは行いません。
8月

これは割り当てであり、コピーではありません。clone.Title = "just a clone"は、obj.Title = "just a clone"を意味します。
HoldOffHunger 2017

@HoldOffHungerあなたは間違っています。ブラウザのJSコンソールで確認してください(let obj = {person: 'Thor Odinson'}; let clone = Object.assign({}, obj); clone.title = "Whazzup";
collapsar

@collapsar:私が確認したとおりです。console.log(person)は、「Thor Odinson」ではなく「Whazzup」になります。8月のコメントを参照してください。
HoldOffHunger 2017

1
@HoldOffHunger Chrome 60.0.3112.113やEdge 14.14393では発生しません。8月のコメントは、objのプロパティのプリミティブ型の値が実際に複製されるため、適用されません。オブジェクトそのものであるプロパティ値は複製されません。
collapsar 2017

18

ECMAScript 2018で

let objClone = { ...obj };

ネストされたオブジェクト参照としてコピーされることに注意してください


1
ネストされたオブジェクトはまだ参照としてコピーされているというヒントをありがとう!「クローン」でネストされたプロパティを変更したので、コードをデバッグするときにほとんど夢中になりましたが、オリジナルは変更されました。
Benny Neugebauer

これは2018年ではなくES2016であり、この回答は2年前に与えられました
Dan Dascalescu

ネストされたプロパティのコピーも必要な場合
Sunil Garg

1
@SunilGargネストされたプロパティをコピーするためにも使用できます const objDeepClone = JSON.parse(JSON.stringify(obj));
Pavan Garre

16

Lodashの使用:

var y = _.clone(x, true);

5
OMGクローニングを再発明するのはおかしいでしょう。これが唯一の正解です。
ダン・ロス

5
私が好む_.cloneDeep(x)、それは本質的に上記と同じものですが、より良い読み込むよう。
garbanzio 14

14

単純なオブジェクトの複製に興味があります:

JSON.parse(JSON.stringify(json_original));

ソース:JavaScriptオブジェクトを新しい変数に参照ではなくコピーする方法は?


とてもいい-シンプル。
Matt H

@MattH:この回答は2012年にすでに提供されています。あなたはそれを見ましたか?モハメッド、あなたはそれらの1つを複製する前に既存の答えをチェックしましたか?
Dan Dascalescu

まあそれは一方向です。tyはそのことをまったく考えていませんでした
1-14x0r

13

1行のコードを使用して、オブジェクトを複製し、以前のオブジェクトからの参照を削除できます。単に行います:

var obj1 = { text: 'moo1' };
var obj2 = Object.create(obj1); // Creates a new clone without references

obj2.text = 'moo2'; // Only updates obj2's text property

console.log(obj1, obj2); // Outputs: obj1: {text:'moo1'}, obj2: {text:'moo2'}

現在Object.createをサポートしていないブラウザー/エンジンの場合、次のポリフィルを使用できます。

// Polyfill Object.create if it does not exist
if (!Object.create) {
    Object.create = function (o) {
        var F = function () {};
        F.prototype = o;
        return new F();
    };
}

1
+1 Object.create(...)は間違いなく進むべき道のようです。
ルネNyffenegger

完璧な答え。多分あなたはの説明を追加できObject.hasOwnPropertyますか?そうすれば、プロトタイプリンクを検索しないようにする方法がわかります。
froginvasion 2014

うまく機能しますが、ポリフィルはどのブラウザで機能しますか?
Ian Lunn 2014年

11
これは、プロトタイプとしてobj1を使用してobj2を作成しています。これはtext、obj2 のメンバーをシャドウしているためにのみ機能します。コピーを作成するのではなく、obj2でメンバーが見つからない場合にプロトタイプチェーンを延期します。
Nick Desaulniers 2014年

2
これはそれを「参照なしで」作成するのではなく、参照をプロトタイプに移動するだけです。それはまだリファレンスです。元のプロパティが変更されると、「クローン」のプロトタイププロパティも変更されます。それはまったくクローンではありません。
神保ジョニー2016年

13

古い質問への新しい答え!ECMAScript 2016(ES6)をSpread Syntaxで使用する喜びがあれば、それは簡単です。

keepMeTheSame = {first: "Me!", second: "You!"};
cloned = {...keepMeTheSame}

これにより、オブジェクトの浅いコピーに対してクリーンなメソッドが提供されます。ディープコピーを作成するには、再帰的にネストされたすべてのオブジェクトのすべての値の新しいコピーを作成します。これには、上記のより重いソリューションが必要です。

JavaScriptは進化を続けています。


2
オブジェクトに関数を定義していると機能しません
Petr Marek

私の知る限り見るように広がり、オペレータが唯一の反復可能オブジェクトで動作します- developer.mozilla.orgは言う: var obj = {'key1': 'value1'}; var array = [...obj]; // TypeError: obj is not iterable
オレグ

@Oleh so [... obj]; `の代わりに` {... obj}を使用してください
マニカントゴータム

@manikantgautam以前はObject.assign()を使用していましたが、実際には最新のChrome、Firefox(まだEdgeおよびSafariではサポートされていません)でオブジェクトスプレッド構文がサポートされています。ECMAScriptの提案...しかし、Babelは私が知る限りそれをサポートしているので、おそらく安全に使用できます。
Oleh

12
let clone = Object.assign( Object.create( Object.getPrototypeOf(obj)), obj)

プロパティオブジェクトだけでなく、クラスインスタンスを(浅く)複製する場合のES6ソリューション。


これはどう違うのlet cloned = Object.assign({}, obj)ですか?
ceztko

10

シンプルで実用的な答えがあると思います。ディープコピーには2つの懸念があります。

  1. プロパティを互いに独立させます。
  2. そして、クローンされたオブジェクトでメソッドを存続させます。

したがって、1つの簡単な解決策は、最初にシリアル化と逆シリアル化を行い、次に関数を割り当てるための割り当てを行うことだと思います。

let deepCloned = JSON.parse(JSON.stringify(source));
let merged = Object.assign({}, source);
Object.assign(merged, deepCloned);

この質問には多くの答えがありますが、これも役立つと思います。


lodashのインポートが許可されている場合は、lodashを使用することをお勧めしcloneDeepます。
ConductedClever

2
私はJSON.parse(JSON.stringify(source))を使用しています。常に働いています。
ミーシャ

2
@Misha、このようにすると、機能を逃してしまいます。「作品」という言葉には多くの意味があります。
ConductedClever

また、前述のとおり、最初のレイヤーの機能のみがコピーされることに注意してください。したがって、相互にいくつかのオブジェクトがある場合、フィールドごとに再帰的にコピーするのが唯一の方法です。
ConductedClever

9

ディープコピーとクローンの場合は、JSON.stringifyに続いてオブジェクトをJSON.parseします。

obj = { a: 0 , b: { c: 0}};
let deepClone = JSON.parse(JSON.stringify(obj));
obj.a = 5;
obj.b.c = 5;
console.log(JSON.stringify(deepClone)); // { a: 0, b: { c: 0}}

かなり賢い...このアプローチの欠点はありますか?
Aleks

8

これはA. Levyのコードの改作であり、関数のクローン作成と複数/循環参照も処理します。つまり、クローン化されたツリー内の2つのプロパティが同じオブジェクトの参照である場合、クローン化されたオブジェクトツリーにはこれらが含まれます。プロパティは、参照されるオブジェクトの同一のクローンを指します。これは、処理されないままにしておくと無限ループにつながる循環依存のケースも解決します。アルゴリズムの複雑さはO(n)です。

function clone(obj){
    var clonedObjectsArray = [];
    var originalObjectsArray = []; //used to remove the unique ids when finished
    var next_objid = 0;

    function objectId(obj) {
        if (obj == null) return null;
        if (obj.__obj_id == undefined){
            obj.__obj_id = next_objid++;
            originalObjectsArray[obj.__obj_id] = obj;
        }
        return obj.__obj_id;
    }

    function cloneRecursive(obj) {
        if (null == obj || typeof obj == "string" || typeof obj == "number" || typeof obj == "boolean") return obj;

        // Handle Date
        if (obj instanceof Date) {
            var copy = new Date();
            copy.setTime(obj.getTime());
            return copy;
        }

        // Handle Array
        if (obj instanceof Array) {
            var copy = [];
            for (var i = 0; i < obj.length; ++i) {
                copy[i] = cloneRecursive(obj[i]);
            }
            return copy;
        }

        // Handle Object
        if (obj instanceof Object) {
            if (clonedObjectsArray[objectId(obj)] != undefined)
                return clonedObjectsArray[objectId(obj)];

            var copy;
            if (obj instanceof Function)//Handle Function
                copy = function(){return obj.apply(this, arguments);};
            else
                copy = {};

            clonedObjectsArray[objectId(obj)] = copy;

            for (var attr in obj)
                if (attr != "__obj_id" && obj.hasOwnProperty(attr))
                    copy[attr] = cloneRecursive(obj[attr]);                 

            return copy;
        }       


        throw new Error("Unable to copy obj! Its type isn't supported.");
    }
    var cloneObj = cloneRecursive(obj);



    //remove the unique ids
    for (var i = 0; i < originalObjectsArray.length; i++)
    {
        delete originalObjectsArray[i].__obj_id;
    };

    return cloneObj;
}

いくつかの簡単なテスト

var auxobj = {
    prop1 : "prop1 aux val", 
    prop2 : ["prop2 item1", "prop2 item2"]
    };

var obj = new Object();
obj.prop1 = "prop1_value";
obj.prop2 = [auxobj, auxobj, "some extra val", undefined];
obj.nr = 3465;
obj.bool = true;

obj.f1 = function (){
    this.prop1 = "prop1 val changed by f1";
};

objclone = clone(obj);

//some tests i've made
console.log("test number, boolean and string cloning: " + (objclone.prop1 == obj.prop1 && objclone.nr == obj.nr && objclone.bool == obj.bool));

objclone.f1();
console.log("test function cloning 1: " + (objclone.prop1 == 'prop1 val changed by f1'));
objclone.f1.prop = 'some prop';
console.log("test function cloning 2: " + (obj.f1.prop == undefined));

objclone.prop2[0].prop1 = "prop1 aux val NEW";
console.log("test multiple references cloning 1: " + (objclone.prop2[1].prop1 == objclone.prop2[0].prop1));
console.log("test multiple references cloning 2: " + (objclone.prop2[1].prop1 != obj.prop2[0].prop1));

1
2016年9月現在、これが質問に対する唯一の正しい解決策です。
DomQ 2016

6

Object.createこの投稿のすべてのソリューションに追加したかったのは、これがnodejsでは希望どおりに機能しないことです。

Firefoxの結果

var a = {"test":"test"};
var b = Object.create(a);
console.log(b);´

です

{test:"test"}

nodejsではそれは

{}

これはプロトタイプの継承であり、クローンではありません。
d13 2014年

1
@ d13引数は有効ですが、JavaScriptでオブジェクトを複製する標準化された方法はないことに注意してください。これは典型的な継承ですが、概念を理解していればクローンとして使用できます。
froginvasion 2014

@froginvasion。Object.createの使用に関する唯一の問題は、ネストされたオブジェクトと配列が、プロトタイプのネストされたオブジェクトと配列への単なるポインタ参照であることです。jsbin.com/EKivInO/2/edit?js,console。技術的には、「クローン」オブジェクトには、他のオブジェクトのプロパティへの共有参照ではない独自の固有のプロパティが必要です。
d13、2014

@ d13大丈夫、私は今あなたの要点を見ます。しかし、私が言いたいのは、プロトタイプ継承の概念に疎外されている人が多すぎて、私にはそれがどのように機能するかを学ぶことができないことです。私が間違っていない場合は、呼び出しObject.hasOwnPropertyて配列を所有しているかどうかを確認するだけで、例を修正できます。はい、これはプロトタイプの継承を処理するための追加の複雑さを追加します。
froginvasion 2014

6
function clone(src, deep) {

    var toString = Object.prototype.toString;
    if(!src && typeof src != "object"){
        //any non-object ( Boolean, String, Number ), null, undefined, NaN
        return src;
    }

    //Honor native/custom clone methods
    if(src.clone && toString.call(src.clone) == "[object Function]"){
        return src.clone(deep);
    }

    //DOM Elements
    if(src.nodeType && toString.call(src.cloneNode) == "[object Function]"){
        return src.cloneNode(deep);
    }

    //Date
    if(toString.call(src) == "[object Date]"){
        return new Date(src.getTime());
    }

    //RegExp
    if(toString.call(src) == "[object RegExp]"){
        return new RegExp(src);
    }

    //Function
    if(toString.call(src) == "[object Function]"){
        //Wrap in another method to make sure == is not true;
        //Note: Huge performance issue due to closures, comment this :)
        return (function(){
            src.apply(this, arguments);
        });

    }

    var ret, index;
    //Array
    if(toString.call(src) == "[object Array]"){
        //[].slice(0) would soft clone
        ret = src.slice();
        if(deep){
            index = ret.length;
            while(index--){
                ret[index] = clone(ret[index], true);
            }
        }
    }
    //Object
    else {
        ret = src.constructor ? new src.constructor() : {};
        for (var prop in src) {
            ret[prop] = deep
                ? clone(src[prop], true)
                : src[prop];
        }
    }

    return ret;
};

2
if(!src && typeof src != "object"){。それはいけ||ないことだと思います&&
MikeM 2013

6

mindeavorは、複製されるオブジェクトは「リテラルで構成された」オブジェクトであると述べたので、解決策は、オブジェクトのインスタンスを複製するのではなく、単にオブジェクトを複数回生成することです。

function createMyObject()
{
    var myObject =
    {
        ...
    };
    return myObject;
}

var myObjectInstance1 = createMyObject();
var myObjectInstance2 = createMyObject();

6

独自の実装を記述しました。それがより良い解決策として数えられるかどうかわかりません:

/*
    a function for deep cloning objects that contains other nested objects and circular structures.
    objects are stored in a 3D array, according to their length (number of properties) and their depth in the original object.
                                    index (z)
                                         |
                                         |
                                         |
                                         |
                                         |
                                         |                      depth (x)
                                         |_ _ _ _ _ _ _ _ _ _ _ _
                                        /_/_/_/_/_/_/_/_/_/
                                       /_/_/_/_/_/_/_/_/_/
                                      /_/_/_/_/_/_/...../
                                     /................./
                                    /.....            /
                                   /                 /
                                  /------------------
            object length (y)    /
*/

以下は実装です。

function deepClone(obj) {
    var depth = -1;
    var arr = [];
    return clone(obj, arr, depth);
}

/**
 *
 * @param obj source object
 * @param arr 3D array to store the references to objects
 * @param depth depth of the current object relative to the passed 'obj'
 * @returns {*}
 */
function clone(obj, arr, depth){
    if (typeof obj !== "object") {
        return obj;
    }

    var length = Object.keys(obj).length; // native method to get the number of properties in 'obj'

    var result = Object.create(Object.getPrototypeOf(obj)); // inherit the prototype of the original object
    if(result instanceof Array){
        result.length = length;
    }

    depth++; // depth is increased because we entered an object here

    arr[depth] = []; // this is the x-axis, each index here is the depth
    arr[depth][length] = []; // this is the y-axis, each index is the length of the object (aka number of props)
    // start the depth at current and go down, cyclic structures won't form on depths more than the current one
    for(var x = depth; x >= 0; x--){
        // loop only if the array at this depth and length already have elements
        if(arr[x][length]){
            for(var index = 0; index < arr[x][length].length; index++){
                if(obj === arr[x][length][index]){
                    return obj;
                }
            }
        }
    }

    arr[depth][length].push(obj); // store the object in the array at the current depth and length
    for (var prop in obj) {
        if (obj.hasOwnProperty(prop)) result[prop] = clone(obj[prop], arr, depth);
    }

    return result;
}

私の場合は少し複雑ですが、私のオブジェクトでは機能しません。
Sajuuk
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.