ホームページ >ウェブフロントエンド >jsチュートリアル >jsオブジェクトのシャローコピーとディープコピーについて詳しく解説

jsオブジェクトのシャローコピーとディープコピーについて詳しく解説

高洛峰
高洛峰オリジナル
2017-01-03 15:57:121351ブラウズ

この記事では、JavaScript オブジェクトの浅いコピーと深いコピーのコードを共有します。具体的な内容は次のとおりです

1. 浅いコピー

コピーとは、親オブジェクトのすべての属性を子オブジェクトにコピーすることです。

次の関数はコピーを作成します:

var Chinese = {
  nation:'中国'
}
var Doctor = {
  career:'医生'
}  
function extendCopy(p) {
    var c = {};
    for (var i in p) { 
      c[i] = p[i];
    }
    c.uber = p;
    return c;
 }

使用する場合は次のように記述します:

var Doctor = extendCopy(Chinese);
Doctor.career = '医生';
alert(Doctor.nation); // 中国

ただし、このようなコピーには問題があります。つまり、親オブジェクトのプロパティが配列または別のオブジェクトと等しい場合、実際には、子オブジェクトが取得するのはメモリ アドレスのみであり、実際のコピーではないため、親オブジェクトが改ざんされました。

ご覧ください。中国語に「出生地」属性を追加します。その値は配列です。

Chinese.birthPlaces = ['Beijing','Shanghai','Hong Kong'];

extendCopy() 関数を通じて、Doctor は中国語を継承します。

var Doctor = extendCopy(Japanese);

次に、Doctor の「出生地」の都市を追加します:

Doctor.birthPlaces.push('Xiamen');

入力結果を見てください

alert(Doctor . BirthPlaces); //北京、上海、香港、厦門
alert(Japanese.birthPlaces); //北京、上海、香港、厦門

その結果、両方の出身地が変更されました。

したがって、extendCopy() は基本的なタイプのデータのみをコピーします。このコピーを「浅いコピー」と呼びます。

2.ディープコピー

シャローコピーとディープコピーにはこのようなデメリットがあるので、次はディープコピーについて見ていきましょう

いわゆる「ディープコピー」とは、配列やオブジェクトの真のコピーを実現する機能です。実装は難しくなく、「浅いコピー」を再帰的に呼び出すだけです。

function deepCopy(p, c) {
    var c = c || {};
    for (var i in p) {
      if (typeof p[i] === 'object') {
        c[i] = (p[i].constructor === Array) ? [] : {};
        deepCopy(p[i], c[i]);
      } else {
         c[i] = p[i];
      }
    }
    return c;
  }

使用方法を見てみましょう:

var Doctor = deepCopy(Japanese);

次に、配列として値を持つプロパティを親オブジェクトに追加します。次に、子オブジェクトのこの属性を変更します。

Chinese.birthPlaces = ['北京','上海','香港'];
Doctor.birthPlaces.push('厦门');
 
alert(Doctor.birthPlaces); //北京, 上海, 香港, 厦门
alert(Chinese.birthPlaces); //北京, 上海, 香港

これでコピーが完了します。 jquery の

$.extend() も同じです。

$.extend( [deep ], target, object1 [, objectN ] )


•deep

Type: Boolean

true の場合、再帰 (ディープコピーとも呼ばれます) にマージします。
•ターゲット
タイプ: オブジェクト
オブジェクト拡張子。これにより、新しいプロパティが取得されます。
•object1
タイプ: オブジェクト
最初のパラメータにマージされた追加のプロパティを含むオブジェクト
•objectN
タイプ: オブジェクト
最初のパラメータにマージされた追加のプロパティが含まれます


2 つ以上のオブジェクトを指定すると、$ に渡されます。 .extend() を実行すると、オブジェクトのすべてのプロパティがターゲット オブジェクト (ターゲット パラメーター) に追加されます。

$.extend() に引数が 1 つだけ指定されている場合、これはターゲット引数が省略されていることを意味します。この場合、jQuery オブジェクト自体がデフォルトでターゲット オブジェクトになります。このようにして、jQuery 名前空間に新しい機能を追加できます。これは、jQuery に新しい機能を追加したいプラグイン開発者にとって役立ちます。

ターゲット オブジェクト (最初のパラメーター) が変更され、$.extend() 経由で返されることに注意してください。ただし、元のオブジェクトを保持したい場合は、空のオブジェクトをターゲット オブジェクトとして渡すことができます:

var object = $.extend({}, object1, object2);

デフォルトでは、$.extend() を渡します。マージ操作は再帰的ではありません。最初のオブジェクトのプロパティ自体がオブジェクトまたは配列である場合、2 番目のオブジェクトの同じキーを持つプロパティが完全に上書きされます。これらの値はマージされません。これは、以下の例でバナナの値を調べることでわかります。ただし、関数の最初の引数として true が渡された場合、オブジェクトに対して再帰的マージが実行されます。

警告: 最初の引数として false を渡すことはサポートされていません。

1. 2 つのオブジェクトを結合し、最初のオブジェクトを変更します。

var object1 = {
 apple: 0,
 banana: { weight: 52, price: 100 },
 cherry: 97
};
var object2 = {
 banana: { price: 200 },
 durian: 100
};
 
// Merge object2 into object1
$.extend( object1, object2 );
 
// Assuming JSON.stringify - not available in IE<8
console.log( JSON.stringify( object1 ) );
//{"apple":0,"banana":{"price":200},"cherry":97,"durian":100}

2. 2 つのオブジェクトを再帰的に結合し、最初のオブジェクトを変更します。

var object1 = {
 apple: 0,
 banana: { weight: 52, price: 100 },
 cherry: 97
};
var object2 = {
 banana: { price: 200 },
 durian: 100
};
 
// Merge object2 into object1, recursively
$.extend( true, object1, object2 );
 
// Assuming JSON.stringify - not available in IE<8
console.log( JSON.stringify( object1 ) );
//{"apple":0,"banana":{"weight":52,"price":200},"cherry":97,"durian":100}

3. デフォルト オブジェクトを変更せずに、デフォルト オブジェクトとオプション オブジェクトをマージします。これは、一般的に使用されるプラグイン開発モデルです。

var defaults = { validate: false, limit: 5, name: "foo" };
var options = { validate: true, name: "bar" };
 
// Merge defaults and options, without modifying defaults
var settings = $.extend( {}, defaults, options );
 
 
console.log(JSON.stringify( defaults ));
console.log(JSON.stringify( options ));
console.log(JSON.stringify( settings ));
//defaults -- {"validate":false,"limit":5,"name":"foo"}
//options -- {"validate":true,"name":"bar"}
//settings -- {"validate":true,"limit":5,"name":"bar"}

JavaScript はオブジェクトが等しいかどうかを判断します

Javascript の等価演算には、「==」と「====」が合同である必要はありません。この記事では、この 2 つの違いについて説明します。 2 つのオブジェクトが等しいかどうかを判断するにはどうすればよいですか? 2 つのオブジェクトが同じプロパティを持ち、それらのプロパティの値が同じであれば、それらのオブジェクトは等しいと考えるかもしれません。それでは、例を通してそれを示してみましょう:

var obj1 = {
  name: "Benjamin",
  sex : "male"
}
 
var obj2 = {
  name: "Benjamin",
  sex : "male"
}
 
//Outputs: false
console.log(obj1 == obj2);
 
//Outputs: false
console.log(obj1 === obj2);

上の例からわかるように、「==」を使用しても「===」を使用しても、 false が返されます。主な理由は、基本型の文字列と数値は値で比較されるのに対し、オブジェクト (日付、配列) と通常のオブジェクトはポインタが指すメモリ内のアドレスで比較されるためです。次の例を見てください:

var obj1 = {
  name: "Benjamin",
  sex : "male"
};
 
var obj2 = {
  name: "Benjamin",
  sex : "male"
};
 
var obj3 = obj1;
 
//Outputs: true
console.log(obj1 == obj3);
 
//Outputs: true
console.log(obj1 === obj3);
 
//Outputs: false
console.log(obj2 == obj3);
 
//Outputs: false
console.log(obj2 === obj3);

obj1 と ob3 のポインターがメモリ内の同じアドレスを指しているため、上の例は true を返します。オブジェクト指向言語 (Java/C++) における値の受け渡しと参照の受け渡しの概念に似ています。 なぜなら、2 つのオブジェクトが等しいかどうかを判断したい場合は、2 つのオブジェクトの属性が同じであるかどうか、または属性に対応する値が同じであるかどうかを明確にする必要があるからです。 ?

function person(name) { 
  this.name=name; 
} 
 
var p1 = new person("p1"); 
var p2 = new person("p2"); 
 
console.log(p1 == p2); //false 
 
person.prototype.sayHi = function() { 
  // do sayHi here 
} 
 
console.log(p1.sayHi() == p2.sayHi()); //true 
console.log(p1.sayHi() === p2.sayHi()); //true

以上がこの記事の全内容です。皆さんの学習に役立つことを願っています。また、皆さんも PHP 中国語 Web サイトを購読していただければ幸いです。

js オブジェクトの浅いコピーと深いコピーの詳細な説明については、PHP 中国語 Web サイトに注目してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。