การผสานวัตถุ (อาร์เรย์ที่เชื่อมโยง)


147

อะไรคือวิธีที่ดีที่สุด / มาตรฐานในการรวมอาเรย์สองตัวใน JavaScript ทุกคนทำได้โดยการforวนซ้ำของตัวเองหรือไม่?


10
ไม่มีอาเรย์เชื่อมโยงใน javascript btw วัตถุเท่านั้น
gblazex

crossref คำถามเดียวกันใน Perl: stackoverflow.com/questions/350018/…
dreftymac

อาร์เรย์ที่เกี่ยวข้องใน javascript: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Chris Martin

คำตอบ:


204

ด้วย jquery คุณสามารถโทรหา $.extend

var obj1 = {a: 1, b: 2};
var obj2 = {a: 4, c: 110};

var obj3 = $.extend(obj1, obj2); 

obj1 == obj3 == {a: 4, b: 2, c: 110} // Pseudo JS

(assoc. อาร์เรย์เป็นวัตถุใน js)

ดูที่นี่: http://api.jquery.com/jQuery.extend/


แก้ไข:เหมือน rymo แนะนำมันจะดีกว่าที่จะทำอย่างนี้:

obj3 = $.extend({}, obj1, obj2); 
obj3 == {a: 4, b: 2, c: 110}

เช่นเดียวกับที่นี่ obj1 (และ obj2) ยังคงไม่เปลี่ยนแปลง


edit2:ในปี 2018 วิธีการทำคือผ่านObject.assign:

var obj3 = Object.assign({}, obj1, obj2); 
obj3 === {a: 4, b: 2, c: 110} // Pseudo JS

หากทำงานกับ ES6 สามารถทำได้ด้วยSpread Operator :

const obj3 = { ...obj1, ...obj2 };

54
หรือเพื่อหลีกเลี่ยงการล้อเล่นobj1ให้ใช้วัตถุเปล่าเป็นเป้าหมาย:$.extend({}, obj1, obj2)
rymo

ใช่เมื่อต้องจัดการกับการปิดและวัตถุที่ส่งผ่านโดยการอ้างอิงให้ใช้คำแนะนำของ rymo เพื่อหลีกเลี่ยงผลกระทบต่อวัตถุดั้งเดิมสำหรับการดำเนินการที่ตามมา
นาธานสมิ ธ

2
สำหรับเบราว์เซอร์รุ่นใหม่ให้ตรวจสอบวิธีแก้ปัญหาโดย @manfred โดยใช้Object.assign()ซึ่งไม่ต้องพึ่งพา JQuery หากคุณไม่ได้ใช้ห้องสมุดอยู่แล้ว
Phil

ใช้งานได้ แต่แก้ไขพารามิเตอร์แรกและนั่นคือสิ่งที่คุณต้องระวัง ดูdeveloper.mozilla.org/en-US/docs/Web/JavaScript/Reference/
......

62

ตอนนี้ในปี 2559 ฉันจะบอกว่าวิธีที่ดีที่สุด / มาตรฐานคือObject.assign ()
Pure Javascript ไม่จำเป็นต้องใช้ jQuery

obj1 = {a: 1, b: 2};
obj2 = {a: 4, c: 110};
obj3 = Object.assign({},obj1, obj2);  // Object {a: 4, b: 2, c: 110}

ข้อมูลตัวอย่างและโพลีฟิลเพิ่มเติมที่นี่:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign


obj3 ประเภทใด จะทำอย่างไรถ้า obj1 เป็นประเภท IABC, obj3 จะรักษาชนิดนั้นในภายหลังหรือไม่
windmaomao

49

นี่คือวิธีที่ต้นแบบทำ:

Object.extend = function(destination, source) {
    for (var property in source) {
        if (source.hasOwnProperty(property)) {
            destination[property] = source[property];
        }
    }
    return destination;
};

เรียกว่าเป็นตัวอย่างเช่น:

var arr1 = { robert: "bobby", john: "jack" };
var arr2 = { elizabeth: "liz", jennifer: "jen" };

var shortnames = Object.extend(arr1,arr2);

แก้ไข : เพิ่ม hasOwnProperty () ตรวจสอบอย่างถูกต้องชี้ให้เห็นโดย bucabay ในความคิดเห็น


6
คุณจะต้องทดสอบ source.hasOwnProperty (คุณสมบัติ) เพื่อให้แน่ใจว่าคุณคัดลอกเฉพาะคุณสมบัติในทันที มันเป็นเช่นนี้อาจจะคัดลอกคุณสมบัติทั้งหมดรวมทั้งผู้ที่ได้รับมาจาก Object.prototype
bucabay

22

ง่าย ๆ เข้าไว้...

function mergeArray(array1,array2) {
  for(item in array1) {
    array2[item] = array1[item];
  }
  return array2;
}

6
คุณต้องตรวจสอบ hasOwnProperty เพื่อหลีกเลี่ยงการคัดลอกคุณสมบัติใด ๆ ในarrau1.prototype
LeeGee

@LeeGee ถูกต้อง คุณต้องhasOwnPropertyตรวจสอบนั้น อ้างถึงวัตถุในขณะที่อาร์เรย์ยังทำให้เข้าใจผิด (พวกเขาเป็นวัตถุ) ชื่อหาเรื่องควรถ่ายทอดว่าอาเรย์ที่ 2 จะกลายพันธุ์หรือวัตถุใหม่ควรจะกลับมา ฉันจะแก้ไขคำตอบ แต่ผลที่ตามมามันจะกลายเป็นคำตอบที่แก้ไขโดยโจนาธานฟิงแลนด์ซึ่งได้รับการแก้ไขแล้ว
Vaz

14

ขีดล่างยังมีวิธีการขยาย:

คัดลอกคุณสมบัติทั้งหมดในวัตถุต้นทางไปยังวัตถุปลายทาง มันเป็นแบบตามลำดับดังนั้นแหล่งสุดท้ายจะแทนที่คุณสมบัติของชื่อเดียวกันในอาร์กิวเมนต์ก่อนหน้า

_.extend(destination, *sources) 

_.extend({name : 'moe'}, {age : 50});
=> {name : 'moe', age : 50}


6

คุณต้องการเขียนทับคุณสมบัติหรือไม่ถ้าชื่อเหมือนกัน แต่มีค่าไม่?

และคุณต้องการเปลี่ยนหนึ่งในวัตถุดั้งเดิมอย่างถาวรหรือไม่

หรือคุณต้องการส่งคืนวัตถุที่ผสานใหม่หรือไม่

function mergedObject(obj1, obj2, force){
    for(var p in obj1) this[p]= obj1[p];
    for(var p in obj2){
        if(obj2.hasOwnProperty(p)){
            if(force || this[p]=== undefined) this[p]= obj2[p];
            else{
                n= 2;
                while(this[p+n]!== undefined)++n;
                this[p+n]= obj2[p];
            }
        }
    }
}

6

การหมุนฟังก์ชั่นExtend / Mixinของคุณเอง

function extend(objects) {
    var args
        , first = Array.prototype.slice.call(arguments, 0, 1)[0]
        , second;

    if (arguments.length > 1) {
        second = Array.prototype.splice.call(arguments, 1, 1)[0];
        for (var key in second) {
            first[key] = second[key];
        }
        args = Array.prototype.slice.call(arguments, 0);
        return extend.apply(this, args);
    }

    return first;
}

...

var briansDirections = {
    step1: 'Remove pastry from wrapper.',
    step2: 'Place pastry toaster.',
    step3: 'Remove pastry from toaster and enjoy.',
};
extend(briansDirections, { step1: 'Toast Poptarts' }, { step2: 'Go ahead, toast \'em' }, { step3: 'Hey, are you sill reading this???' });

...

นี้ก็ขยายสัญญาณของวัตถุซ้ำ นอกจากนี้โปรดทราบว่าฟังก์ชั่นวนซ้ำนี้เป็น TCO ( Tail-Call Optimized ) เนื่องจากการส่งคืนเป็นการโทรครั้งสุดท้ายกับตัวเอง

นอกจากนี้คุณอาจต้องการคุณสมบัติที่ตรงเป้าหมาย ในกรณีนี้คุณอาจต้องการที่จะรวมตัววัตถุที่อยู่บนพื้นฐานของid, quantityหรือทรัพย์สินอื่น วิธีการนี้อาจมีหนังสือเล่มเล็ก ๆ เขียนเกี่ยวกับมันและต้องมีการตีข่าววัตถุและอาจซับซ้อนมาก ฉันได้เขียนห้องสมุดขนาดเล็กสำหรับสิ่งนี้ซึ่งสามารถใช้ได้ตามคำขอ

หวังว่านี่จะช่วยได้!


4
  1. ใน Javascript ไม่มีความคิดของอาเรย์เชื่อมโยงมีวัตถุ
  2. วิธีเดียวที่จะรวมสองวัตถุคือการวนซ้ำสำหรับคุณสมบัติและคัดลอกพอยน์เตอร์ไปยังค่าที่ไม่ใช่ประเภทดั้งเดิมและค่าสำหรับประเภทดั้งเดิมไปยังอินสแตนซ์อื่น

8
วัตถุใน Javascript ถูกนำมาใช้เป็นอาเรย์แบบเชื่อมโยงดังนั้นจึงมีความคิดเหมือนกันอย่างแน่นอน
Dexygen

2

ในปี 2562 คุณมี 2 ตัวเลือกที่ดี:

การกำหนดวัตถุ [ doc ]

const result = Object.assign({}, baseObject, updatingObject);

การแพร่กระจายวัตถุ [ doc ]

const result = { ...baseObject, ...updatingObject};

คนแรกมีแนวโน้มที่จะปลอดภัยกว่ามาตรฐานและมีจำนวนมาก ข้อดีและข้อเสียที่ดีที่นี่



1

jquery มีบูลีนสำหรับทำสำเนาลึก คุณสามารถทำอะไรเช่นนั้น:

MergeRecursive = function(arr1, arr2){
    $.extend(true, arr1, arr2);
    return arr1;                
};

นอกจากนี้คุณสามารถแก้ไขฟังก์ชั่นนี้เพื่อรองรับ n-arrays เพื่อทำการผสาน

ArrayMergeRecursive = function(){
     if(arguments.length < 2){
          throw new Error("ArrayMergeRecursive: Please enter two or more objects to merge!");
     }

    var arr1=arguments[0];
    for(var i=0; i<=arguments.length; i++ ){
        $.extend(true, arr1, arguments[i]);                 
    }

    return arr1;                
};

ดังนั้นตอนนี้คุณสามารถทำได้

var arr1 = {'color': {'mycolor': 'red'}, 3: 5},
    arr2 = {4: 10, 'color': {'favorite': 'green', 0: 'blue'}},
    arr3 = ['Peter','Jhon','Demosthenes'],
    results = ArrayMergeRecursive(arr1, arr2, arr3); // (arr1, arr2 ... arrN)
console.log("Result is:", results);

0

ฉันต้องการการผสานวัตถุอย่างลึกซึ้ง ดังนั้นคำตอบอื่น ๆ ทั้งหมดไม่ได้ช่วยฉันมาก _.extend และ jQuery.extend ทำได้ดีเว้นแต่คุณจะมีอาร์เรย์แบบเรียกซ้ำเหมือนฉัน แต่มันไม่ได้แย่คุณสามารถตั้งโปรแกรมได้ภายในห้านาที:

var deep_merge = function (arr1, arr2) {
    jQuery.each(arr2, function (index, element) {
        if (typeof arr1[index] === "object" && typeof element === "object") {
            arr1[index] = deep_merge(arr1[index], element);
        } else if (typeof arr1[index] === "array" && typeof element === "array") {
            arr1[index] = arr1[index].concat(element);
        } else {
            arr1[index] = element;
        }
    });
    return arr1;
}

0

ในการรวมอาร์เรย์ใน jQuery มีอะไรบ้างเกี่ยวกับ $ .merge

var merged = $.merge([{id:3, value:'foo3'}], [{id:1, value:'foo1'}, {id:2, value:'foo2'}]);
merged[0].id == 3;
merged[0].value == 'foo3';
merged[1].id == 1;
merged[1].value == 'foo1';
merged[2].id == 2;
merged[2].value == 'foo2';

0

โซลูชันแบบเรียกซ้ำ (ขยายขอบเขตของวัตถุด้วย) + การตรวจสอบ null

var addProps = function (original, props) {
    if(!props) {
        return original;
    }
    if (Array.isArray(original)) {
        original.map(function (e) {
            return addProps(e, props)
        });
        return original;
    }
    if (!original) {
        original = {};
    }
    for (var property in props) {
        if (props.hasOwnProperty(property)) {
            original[property] = props[property];
        }
    }
    return original;
};

การทดสอบ

console.log(addProps([{a: 2}, {z: 'ciao'}], {timestamp: 13}));
console.log(addProps({single: true}, {timestamp: 13}));
console.log(addProps({}, {timestamp: 13}));
console.log(addProps(null, {timestamp: 13}));

[ { a: 2, timestamp: 13 }, { z: 'ciao', timestamp: 13 } ]
{ single: true, timestamp: 13 }
{ timestamp: 13 }
{ timestamp: 13 }

ฉันพยายามใช้สิ่งนี้กับ Node JS แต่Object.getOwnPropertyNames is not a functionจะขัดข้องแอป
Legoless

ฉันใช้สิ่งนี้กับเอ็นจิ้น v8 เก่า ๆ ภายใน plv8 PostgreSQL extension และมันใช้งานได้ในเบราว์เซอร์ เพียงหาวิธีในเครื่องมือ JS ของคุณเพื่อทำสิ่งที่เทียบเท่าได้เป็น "hasOwnProperty" จากนั้นคุณสามารถใช้ตรรกะนี้ซ้ำได้
sscarduzio

0

นี่คือทางออกที่ดีที่สุด

obj1.unshift.apply( obj1, obj2 );

นอกจากนี้ยังobj1สามารถเติบโตในวงโดยไม่มีปัญหาใด ๆ (สมมติว่าobj2เป็นแบบไดนามิก)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.