[解決済み] javascriptでディープクローンを作る方法
質問
JavaScriptのオブジェクトをディープクローンする方法は?
のようなフレームワークをベースにした様々な関数があることは知っています。
JSON.parse(JSON.stringify(o))
と
$.extend(true, {}, o)
が、そんなフレームワークは使いたくありません。
ディープクローンを作成するための最もエレガントで効率的な方法は何ですか。
配列のクローンのようなエッジケースを気にしています。プロトタイプの連鎖を断ち切らないこと、自己参照を扱うこと。
DOMオブジェクトのコピーなどのサポートについては、以下の理由から気にしないことにしています。
.cloneNode
はそのために存在するのです。
主にディープクローンを使いたいので
node.js
V8エンジンのES5の機能を使うのは許容範囲内です。
[編集]をクリックします。
オブジェクトをプロトタイプで継承してコピーを作成するのと クローン です。前者はプロトタイプの連鎖を混乱させます。
[さらに編集]。
回答を読んで、オブジェクト全体のクローン作成は非常に危険で難しいゲームであるという、腹立たしい発見に至りました。例えば、次のようなクロージャベースのオブジェクトを考えてみましょう。
var o = (function() {
var magic = 42;
var magicContainer = function() {
this.get = function() { return magic; };
this.set = function(i) { magic = i; };
}
return new magicContainer;
}());
var n = clone(o); // how to implement clone to support closures
オブジェクトのクローンを作成し、クローン作成時に同じ状態を持ち、かつ
o
JSパーサーをJSで書かずに。
このような機能は、もう実世界では必要ないはずです。これは単なる学術的な興味に過ぎない。
どのように解決するのか?
何をクローン化したいかは、本当に人それぞれです。これは本当にJSONオブジェクトなのか、それともJavaScriptの任意のオブジェクトなのか。もし、どんなものでもいいからクローンを作りたいのであれば、ちょっと困ったことになるかもしれません。どのようなトラブルですか?以下に説明しますが、まず、オブジェクト リテラル、任意のプリミティブ、配列、DOM ノードのクローンを作成するコード例を示します。
function clone(item) {
if (!item) { return item; } // null, undefined values check
var types = [ Number, String, Boolean ],
result;
// normalizing primitives if someone did new String('aaa'), or new Number('444');
types.forEach(function(type) {
if (item instanceof type) {
result = type( item );
}
});
if (typeof result == "undefined") {
if (Object.prototype.toString.call( item ) === "[object Array]") {
result = [];
item.forEach(function(child, index, array) {
result[index] = clone( child );
});
} else if (typeof item == "object") {
// testing that this is DOM
if (item.nodeType && typeof item.cloneNode == "function") {
result = item.cloneNode( true );
} else if (!item.prototype) { // check that this is a literal
if (item instanceof Date) {
result = new Date(item);
} else {
// it is an object literal
result = {};
for (var i in item) {
result[i] = clone( item[i] );
}
}
} else {
// depending what you would like here,
// just keep the reference, or create new object
if (false && item.constructor) {
// would not advice to do that, reason? Read below
result = new item.constructor();
} else {
result = item;
}
}
} else {
result = item;
}
}
return result;
}
var copy = clone({
one : {
'one-one' : new String("hello"),
'one-two' : [
"one", "two", true, "four"
]
},
two : document.createElement("div"),
three : [
{
name : "three-one",
number : new Number("100"),
obj : new function() {
this.name = "Object test";
}
}
]
})
それでは、リアルなオブジェクトのクローンを作成する際に起こりうる問題について説明します。今話しているのは、次のような方法で作成したオブジェクトのことです。
var User = function(){}
var newuser = new User();
もちろん、オブジェクトのクローンを作ることはできます。すべてのオブジェクトはコンストラクタのプロパティを公開しており、それを使ってオブジェクトのクローンを作ることができますが、常にうまくいくとは限りません。また、単純に
for in
しかし、それは同じ方向に進みます - トラブルです。コードの中にもクローン機能は含まれているのですが、それは
if( false )
ステートメントを使用します。
では、なぜクローンを作るのが面倒なのでしょうか?まず第一に、すべてのオブジェクトやインスタンスは、何らかの状態を持っている可能性があります。例えば、オブジェクトがプライベート変数を持っていないとは限りません。
状態がないと仮定すると、それはそれでいいんです。そうすると、まだ別の問題があります。コンストラクタ経由でクローンを作成すると、別の問題が発生します。それは、引数依存性です。このオブジェクトを作成した人が、ある種のオブジェクトを作成しなかったかどうかを確認することはできません。
new User({
bike : someBikeInstance
});
someBikeInstance はおそらく何らかのコンテキストで作成されたもので、そのコンテキストは clone メソッドでは未知です。
では、どうすればいいのか?まだ、次のことができます。
for in
しかし、そのようなオブジェクトのクローンを作らず、このオブジェクトの参照だけを渡すというのはどうでしょう?
もうひとつの解決策は、クローンする必要のあるすべてのオブジェクトは、この部分を自分で実装し、適切なAPIメソッド(cloneObjectなど)を提供しなければならないという規約を設定することです。例えば
cloneNode
はDOMのためにやっています。
あなたが決めてください。
関連
-
[解決済み】Uncaught ReferenceError。Reactが定義されていない
-
[解決済み】Vueが定義されていない
-
[解決済み] 配列から特定の項目を削除するにはどうすればよいですか?
-
[解決済み] JavaScriptで "use strict "は何をするのか、その根拠は?
-
[解決済み] JavaScriptで文字列が部分文字列を含むかどうかを確認する方法は?
-
[解決済み] あるJavaScriptファイルを他のJavaScriptファイルにインクルードするにはどうすればよいですか?
-
[解決済み] JavaScriptでオブジェクトをディープクローンする最も効率的な方法は何ですか?
-
[解決済み】別のウェブページにリダイレクトするにはどうすればいいですか?
-
[解決済み】JavaScriptで文字列の出現箇所をすべて置換する方法
-
[解決済み】オブジェクトからプロパティを削除する(JavaScript)
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] Uncaught TypeError: 未定義のプロパティ 'top' を読み込めない
-
[解決済み】webpack: モジュールが見つかりません。Error: 解決できない(相対パスで)
-
[解決済み】JavaScriptのgetElementByNameが機能しない
-
[解決済み] テスト
-
[解決済み】このオブジェクトの "forEach "はなぜ関数でないのですか?
-
[解決済み】Babel NodeJS ES6: SyntaxError: 予期しないトークンのエクスポート
-
[解決済み】 Uncaught Reference Error: stLight is not defined (in Chrome only)
-
[解決済み】SyntaxError: 期待された式が、'<'を得た。
-
[解決済み】JavaScriptで関数が存在するかどうかを確認する方法は?
-
[解決済み】中央値の計算 - javascript