超実用的なJavaScriptコードセグメントItem 8--jsオブジェクトの(深い)コピー


jsオブジェクトの浅いコピーと深いコピー
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に「出生地」属性を追加します.その値は配列です.
Chinese.birthPlaces = ['  ','  ','  '];
extendCopy()関数によりDoctorはChineseを継承する.
var Doctor = extendCopy(Chinese);

その後、Doctorの「出身地」に都市を追加します.
Doctor.birthPlaces.push('  ');

入力結果を見て
alert(Doctor.birthPlaces); //  ,   ,   ,   
alert(Chinese.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(Chinese);

親オブジェクトにアトリビュートを追加します.値は配列です.次に、このプロパティをサブオブジェクトに変更します.
Chinese.birthPlaces = ['  ','  ','  '];
Doctor.birthPlaces.push('  ');

alert(Doctor.birthPlaces); //  ,   ,   ,   
alert(Chinese.birthPlaces); //  ,   ,   

これでコピーが完了しました.
$.extend()
jquery中$.extend()は同じです.
$.extend( [deep ], target, object1 [, objectN ] )
  • deepタイプ:Booleanがtrueの場合、統合は再帰(深コピーとも呼ばれる)になります.
  • targetタイプ:Objectオブジェクト拡張.これにより、新しいプロパティが受信されます.
  • object 1タイプ:Object 1オブジェクトで、最初のパラメータに追加の属性がマージされます.
  • objectNタイプ:Objectには追加の属性が含まれています.最初のパラメータ
  • にマージされます.$.extend()に2つ以上のオブジェクトを指定すると、オブジェクトのすべてのプロパティがターゲットオブジェクト(targetパラメータ)に追加されます.
    1つのパラメータのみが$.extend()に提供される場合、これは、ターゲットパラメータが省略されることを意味する.この場合、jQueryオブジェクト自体がターゲットオブジェクトとしてデフォルト設定されます.これにより、jQueryのネーミングスペースに新しい機能を追加できます.これは,プラグイン開発者がjQueryに新しい関数を追加したい場合に有用である.
    ターゲットオブジェクト(最初のパラメータ)が変更され、$.extend()で返されます.ただし、元のオブジェクトを保持したい場合は、空のオブジェクトをターゲットオブジェクトとして渡すことができます.
    var object = $.extend({}, object1, object2);

    デフォルトでは、$.extend()によるマージ操作は再帰的ではありません.最初のオブジェクトのプロパティ自体がオブジェクトまたは配列である場合、2番目のオブジェクトと同じkeyでプロパティが完全に書き換えられます.これらの値はマージされません.次の例のbananaの値をチェックすることで、この点がわかります.ただし、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.defaultsオブジェクトとoptionsオブジェクトを結合し、defaultsオブジェクトは変更しません.これはよく使われるプラグイン開発モデルです.
    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が返されることがわかります.主な理由は、基本タイプstring、numberは値で比較され、オブジェクト(Date,Array)および通常のオブジェクトはポインタが指すメモリのアドレスで比較されます.次の例を参照してください.
    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);

    上記の例では、obj 1とob 3のポインタがメモリ内の同じアドレスを指しているため、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