方法が正しくクローンをJavaScriptのオブジェクト?
-
05-09-2019 - |
質問
私は、オブジェクト x
.思をコピーすることとしてオブジェクト y
, ように変更 y
しないように注意してください x
.その複写物由来のものから内蔵のJavaScriptオブジェクトの結果、不要な物件です。なのがこの問題はいっても、私の複製の一つが、自分のリテラル構築されたオブジェクト。
方法が正しくクローンをJavaScriptのオブジェクト?
解決
このanyオブジェクトにJavaScriptのないシンプル"または簡単です。での問題を誤って持ち直しの属性からオブジェクトの試作ときの試作およびコピーされませんの新しいインスタンス.たとえば、追加 clone
方法 Object.prototype
, として、その答えを描く、明示的にスキップする属性。がある場合はその他の追加方法を追加 Object.prototype
, その他の中間試作るんですか?その場合は、コピーなんか、する必要がありますが不測の事態、地域の属性を hasOwnProperty
方法。
のほか、非enumerable属性ごとの出会いは、より厳しい問題になったとき、コピーオブジェクトが隠れていた。例えば、 prototype
隠れ家の機能です。また、オブジェクトのプロトタイプは参照される属性 __proto__
, でもある隠れするのではないコピーによるグループで繰り返し処理のソースオブジェクトの属性です。と思い __proto__
が特FirefoxのJavaScriptインタプリタでも他のブラウザでご利用いただけます。画像になります。すべてまかなえるわけではないがenumerable.コピーすることができ、隠れた属性まっている場合、その名前がわからないの道を発見します。
他のスナッグのセグメントのパネルデータを用ガソリューションには、問題設定の試作相続ます。場合はソースオブジェクトの試作 Object
, し、単に新しい一般オブジェクト {}
する場合があ源の試作はその子孫の Object
, しかなか出会えないおいしさのメンバーの追加から試作するスキップを使用 hasOwnProperty
フィルター、または試作なenumerable。Oneソリューションが呼び出元のオブジェクトの constructor
得するプロパティの初期のコピーオブジェクトをコピー以上の属性は、その場合も取得しません非enumerable属性です。例えば、 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
.していただくための一 Date
と同じもの呼び出しによる setTime
方法が、固有の Date
クラスです。はないと思いますので防弾総合こうした問題をクリアできるものをやらせていただきたいと思いる。
私ため一般に深くコピーした結果を損なうことを想定している必要コピー無地 Object
, Array
, Date
, String
, Number
, や 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単純な種類の、どのデータのオブジェクトの配列を形成ツリー構造です。ることはありません以上の参照と同じデータをオブジェクトです。例えば:
// 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のオブジェクトを引き起こす場合もあるのに十分な用途に応じて様々などをまったく想定していないことを仕事だけでものを投げます。
他のヒント
を使用しない場合 Date
s,機能、定義されていません、または無限内のオブジェクトは、ほとんど変わりません。ライナー 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()
この作品はすべての種類の物を含む物体の配列、文字列、boolean値を代入する必要がある。
参照 この条約は、ストラクチャードクローンのアルゴリズムのブラウザ 使用される掲載する際には、メッセージから行っています.また機能のための深いクローン
のECMAScript 6で Object.assign の方法があります、これは別のオブジェクトからすべての列挙可能な独自のプロパティのコピー値。たとえばます:
var x = {myProp: "value"};
var y = Object.assign({}, x);
しかし、ネストされたオブジェクトがまだ参照としてコピーされていることに注意してください。
多くの回答がなしに言及している オブジェクトです。の作成 からECMAScript5、確かにさせない正確なコピーがセットのソースとして試作品の新しいオブジェクトです。
したがって、これは正確な答え、それは一線溶液とします。でも最高の2例:
- な継承に役立つ(duh!)
- のソースオブジェクトな変性との関係、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
なぜ私はこのソリューションする優位性があるか。このネイティブ、このようなループ、再帰.しかし、古いブラウザが必要polyfill.
これまでにないクローンをJavascriptのオブジェクトの一行のコード
An Object.assign
方法は、ECMAScript2015年ES6の標準となどあります。
var clone = Object.assign({}, obj);
のオブジェクトです。assign()メソッドを使用するコピーの値は全てenumerable自身の特性から以上のソースオブジェクト対象オブジェクトです。
の polyfill 応ブラウザ:
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;
}
});
}
については幾つかのポイントがあほとんどのソリューションのインターネット。ですから守るのに、なぜこのような受け答えになります。
出発状況
したい deepコピー Javascript Object
すべての子どもたちや子どもなどです。もの造形、野暮ったすぎやしませんかのような通常の開発、 Object
は 通常の properties
, circular structures
も nested objects
.
いましょう circular structure
や nested 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
ネイティブの解
後の繰り返しで遠距離職が巧私の同僚、上司から"何が起きたのか、みんなが簡単 液 その後googling.それ 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"
}
}
...ていますので、動作しなかったの入れ子構造です。
polyfillのためのネイティブの解決
あpolyfill用 Object.create
古いブラウザでのIE8.このようなものが推奨する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
要件に合わせたものの、まだまだ小規模の課題などを変更する instance
の nested
や circ
へ Object
.
構造の樹木を共有する葉んのでコピーされ、その二つの独立した葉:
[Object] [Object]
/ \ / \
/ \ / \
|/_ _\| |/_ _\|
[Object] [Object] ===> [Object] [Object]
\ / | |
\ / | |
_\| |/_ \|/ \|/
[Object] [Object] [Object]
結論
最後のソリューション再帰るキャッシュからアクセスが可能なのですが、 実 深いコピーのオブジェクトです。取扱い簡単 properties
, circular structures
や nested object
, ですが、すべての空港を表示一部の空港を表をインスタンスがクローニング.
、underscore.jsライブラリはクローンの方法があります。
y = _.clone(x);
か、
のようにそれを拡張することができますcopiedObject = _.extend({},originalObject);
の 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
、ちょうどあなたがコピーするデータの大きな塊のために使用していないことを確認しますが、それは多くの場合、1行の便利な方法かもしれない、このような何か:
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
一つの特に無粋ソリューションは、メンバー・メソッドを持たないオブジェクトの深いコピーを作成するJSONエンコーディングを使用することです。方法論は、それをデコードすることにより、あなたが探しているのコピーを取得し、あなたのターゲットオブジェクトをエンコードJSONにあります。あなたが必要なだけのコピーを作成するために必要な数だけ倍をデコードすることができます。
もちろん、機能はJSONに属していないので、これが唯一のメンバー・メソッドなしでオブジェクトのために働くます。
私は、キーと値のストアでJSONのブロブを格納していますので、この方法論は、私のユースケースのために完璧だった、と彼らはJavaScriptのAPI内のオブジェクトとして公開されている場合、各オブジェクトは、実際の元の状態のコピーが含まれていますオブジェクト呼び出し側が露出したオブジェクトを変異させた後、私たちは、デルタを計算することができます。
var object1 = {key:"value"};
var object2 = object1;
object2 = JSON.stringify(object1);
object2 = JSON.parse(object2);
object2.key = "a change";
console.log(object1);// returns value
利用できる 広め物件 コピーしないオブジェクト参照です。に注意してください(コメント)をコピーするだけでな最低のオブジェクトまたは配列です。入れ子の物性はいまだ参照!
完全クローン:
let x = {a: 'value1'}
let x2 = {...x}
// => mutate without references:
x2.a = 'value2'
console.log(x.a) // => 'value1'
クローンが書かれた第二レベル:
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なのかをサポートしない深いクローンネイティブ.使用機能です。例えばRamda:
はAngularJSを使用するものについては、クローニングまたはこのライブラリ内のオブジェクトの拡張するための直接的な方法もある。
var destination = angular.copy(source);
または
angular.copy(source, destination);
もっとangular.copyのドキュメントのに...
A.Levyの答えはここで、ほぼ完全である私の小さな貢献である:を再帰的な参照を処理する方法方法があるの、
この行を参照してください if(this[attr]==this) copy[attr] = copy;
、我々は代わりに
cloneNodeをのを使用する必要があります。 if(this.cloneNode) return this.cloneNode(true);
A.Levyの徹底的な調査とカルバンのプロトタイピングのアプローチに触発され、私は、このソリューションを提供します:
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;
}
答えでも、アンディ・バークの注を参照してください。
ここでは、使用できる機能です。
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;
}
この記事から: Javascriptをの中に配列やオブジェクトをコピーする方法ブライアンHuismanによるます:
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;
};
ES-6では、あなたは、単にObject.assign(...)を使用することができます。 例:
let obj = {person: 'Thor Odinson'};
let clone = Object.assign({}, obj);
良いの参照はここにあります: https://googlechrome.github.io/samples/object-assign-es6/
にECMAScript2018年
let objClone = { ...obj };
ご注意 入れ物 まだコピー を参考にしています。
あなたがオブジェクトを複製し、コードの単一の行を使用して、以前のものから任意の参照を削除することができます。単純に実行します。
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();
};
}
新しい答えは古い問題です!場合に有用ECMAScript2016年ES6) 広めの構文, です。
keepMeTheSame = {first: "Me!", second: "You!"};
cloned = {...keepMeTheSame}
このスクリーン法の浅いコピーオブジェクトです。作りディープコピー、makign新しいコピーの値毎に再帰的にネストしたオブジェクトを必要とするのに重解する。
JavaScriptは常に進化を続けております。
let clone = Object.assign( Object.create( Object.getPrototypeOf(obj)), obj)
ES6解決したい場合(浅)クローンa クラスのインスタンス だけではなく物件のオブジェクトです。
クローニング単純なオブジェクトに興味があります:
JSON.parse(JSON.stringify(json_original));
ソース:<のhref = "https://stackoverflow.com/questions/18359093/how-to-copy-javascript-object-to-new-variable-not-by-reference?answertab=votes#tab-トップ ">どのようにしないで参照することにより、新たな変数にJavaScriptオブジェクトをコピーするには?の
Lodashを使用します:
var y = _.clone(x, true);
もあると思いますが、作業の答えです。深いコピーが懸念:
- 保物件の独立。
- とくに生きているクローニングオブジェクトです。
と思うのですが最初にserializeおよび直列化復元しい割り当てに関するコピー機能です。
let deepCloned = JSON.parse(JSON.stringify(source));
let merged = Object.assign({}, source);
Object.assign(merged, deepCloned);
この問題は、多くの答えが、今この手に入れやすいのも良いですね。
ディープコピーやクローンについて、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}}
私は、これはnodejsと所望の方法で動作しないことを、この記事では、すべてのObject.create
ソリューションに追加したいです。
のFirefoxでの結果
var a = {"test":"test"};
var b = Object.create(a);
console.log(b);´
である
{test:"test"}
ます。
はnodejsではそれがある。
{}
これも機能し、複数の/循環参照のクローニングを処理するためA.レヴィのコードの適応である - これが意味することはクローン化されたツリー内の場合、2つのプロパティは、同じオブジェクトの参照、クローン化されたオブジェクト・ツリーであることですこれらのプロパティは1と参照されたオブジェクトの同じクローンを指しています。これはまた、未処理のままの場合、環状依存性のケースを解決する無限ループにつながります。アルゴリズムの複雑さは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));
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;
};
私は自分の実装を書いています。わからないことは、より良い解決策としてカウントされている場合:
/*
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;
}
上記ヤンTuroňの答えは非常に近く、互換性の問題のために、ブラウザで使用するのがベストかもしれないが、それは潜在的にいくつかの奇妙な列挙の問題が発生します。例えば、実行
for ( var i in someArray ) { ... }
は、配列の要素を反復した後、私にclone()メソッドを割り当てます。ここで列挙を避け、Node.jsのと連携適応があります:
Object.defineProperty( Object.prototype, "clone", {
value: 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;
}
});
Object.defineProperty( Date.prototype, "clone", {
value: function() {
var copy = new Date();
copy.setTime( this.getTime() );
return copy;
}
});
Object.defineProperty( Number.prototype, "clone", { value: function() { return this; } } );
Object.defineProperty( Boolean.prototype, "clone", { value: function() { return this; } } );
Object.defineProperty( String.prototype, "clone", { value: function() { return this; } } );
これは、列挙クローン()メソッドを作る避けるためfalseに列挙のDefineProperty()デフォルトます。