ฉันจะรวมสองวัตถุจาวาสคริปต์เข้าด้วยกันใน ES6 + ได้อย่างไร


141

ฉันเบื่อที่จะต้องเขียนโค้ดแบบนี้:

function shallowExtend(obj1,obj2){
  var key;
  for ( key in obj2 ) {
    if ( obj2.hasOwnProperty(key) === false )  continue;
    obj1[key] = obj2[key]
  }
}

หรือถ้าฉันไม่ต้องการเขียนโค้ดด้วยตัวเองให้ใช้ไลบรารี่ที่ทำไปแล้ว แน่นอนว่า ES6 + กำลังจะมาช่วยเหลือสิ่งนี้จะทำให้เรามีอะไรบางอย่างที่เหมือนObject.prototype.extend(obj2...)หรือObject.extend(obj1,obj2...)

ES6 + จะให้ฟังก์ชั่นดังกล่าวหรือไม่ ถ้ายังไม่ได้มีการวางแผนการใช้งานเช่นนั้น? หากไม่ได้วางแผนมาทำไมล่ะ


3
เหตุใดคุณจึงไม่เพิ่มลงในห้องสมุดของคุณ
RobG

12
@ RobG คำถามนี้เป็นเรื่องเกี่ยวกับความหวังว่า ES6 จะลบเราออกจากที่ต้องมีอึต้มสำเร็จรูปในสถานที่แรกสำหรับสิ่งที่คุ้มค่า: github.com/balupton/bal-util/blob/ …
balupton

ฉันไม่คิดว่าจะมีวิธีทั่วไปในการคัดลอกคู่ชื่อ / ค่าจากวัตถุหนึ่งไปยังอีก คุณจัดการกับคุณสมบัติของตัวเองหรือผู้ที่อยู่ใน[[Prototype]]ห่วงโซ่? คุณทำสำเนา "ลึก" หรือ "ตื้น" หรือไม่? แล้วคุณสมบัติที่ไม่สามารถนับได้และไม่สามารถเขียนได้? ฉันคิดว่าฉันควรมีฟังก์ชั่นห้องสมุดขนาดเล็กที่ทำในสิ่งที่ฉันต้องการและส่วนใหญ่มันสามารถหลีกเลี่ยงได้
RobG

คำตอบ:


206

คุณจะสามารถทำการผสาน / ขยาย / กำหนดตื้นใน ES6 โดยใช้ Object.assign:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign

ไวยากรณ์:

Object.assign ( เป้าหมาย , แหล่งที่มา );

โดยที่... แหล่งที่มาแสดงถึงวัตถุต้นฉบับ

ตัวอย่าง:

var obj1 = {name: 'Daisy', age: 30};
var obj2 = {name: 'Casey'};

Object.assign(obj1, obj2);

console.log(obj1.name === 'Casey' && obj1.age === 30);
// true

64
ข้อสังเกตเล็ก ๆ : Object.assign ทำให้เป้าหมายกลายพันธุ์ หากนั่นไม่ใช่สิ่งที่คุณต้องการคุณสามารถเรียกมันว่าด้วยวัตถุว่างเปล่า:let merged = Object.assign({}, source1, source2);
david

20
โปรดสังเกตว่านี่เป็นส่วนขยายที่ตื้น ... วัตถุที่ซ้อนกันจะไม่ถูกรวมเข้าด้วยกัน
monzonj

@monzonj ไม่มีตัวเลือกในการขยายวัตถุที่ซ้อนกันโดยไม่ใช้ lodash หรือ mout หรือไม่?
Joao Falcao

1
มีวิธีที่ดีที่จะผสานวัตถุที่ซ้อนกันอย่างลึกซึ้งโดยไม่ต้องห้องสมุดโดยใช้เพียงเป็นObject.assign: ดูคำตอบของฉันที่นี่
Ruslan

วิธีเก่า ๆ ในการขยายวัตถุที่ซ้อนกันใช้JSON.parse(JSON.stringify(src))
Andre Figueiredo

162

คุณสามารถใช้ไวยากรณ์การกระจายวัตถุสำหรับสิ่งนี้:

const merged = {...obj1, ...obj2}

สำหรับอาร์เรย์ตัวดำเนินการสเปรดนั้นเป็นส่วนหนึ่งของ ES6 (ES2015) แล้ว แต่สำหรับออบเจกต์จะถูกเพิ่มไปยังข้อมูลจำเพาะภาษาที่ ES9 (ES2018) ข้อเสนอของมันถูกเปิดใช้งานโดยค่าเริ่มต้นในเครื่องมือเช่น Babel นานก่อนหน้านั้น


3
ไม่มีชื่ออย่างเป็นทางการตอนนี้เรียกว่า ES2015: P ตั้งแต่เมื่อใดการทำลายล้างจึงไม่ใช่ส่วนหนึ่งของ ES6 developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… กำลังเรียกใช้ babel-node: const ob1 = {foo: 123}; const ob2 = {bar: 234}; const merged = {...ob1, ...ob2}; console.log(merged) เอาต์พุต:{ foo: 123, bar: 234 }
Thijs Koerselman

9
นั่นไม่ใช่การทำลายล้างมันแพร่กระจาย - และไม่สำหรับวัตถุที่ไม่ได้เป็นส่วนหนึ่งของ ES6 คุณควรปิดการใช้งาน ES7 ฉบับร่างทดลองใน Babel ของคุณ
Bergi

2
อภัยให้ฉันด้วย คุณพูดถูก มันเป็นคุณสมบัติของ babel stage 2 ในขณะนี้ github.com/sebmarkbage/ecmascript-rest-spreadฉันไม่เคยรู้เลยว่าเพราะฉันใช้มันตั้งแต่เริ่มต้นด้วย babel และมันเปิดใช้งานโดยค่าเริ่มต้น แต่เนื่องจากคุณจำเป็นต้อง transpile อยู่ดีและการแพร่กระจายของวัตถุนั้นเป็นสิ่งที่ตรงไปตรงมาฉันขอแนะนำต่อไป ฉันรักมัน.
Thijs Koerselman

พวกเขากำลังเปิดใช้งานโดยค่าเริ่มต้นจริงเหรอ? นั่นฟังดูเหมือนแมลง
Bergi

2
"ข้อเสนอที่เป็นขั้นตอนที่ 2 ขึ้นไปจะเปิดใช้งานตามค่าเริ่มต้น" babeljs.io/docs/usage/experimental
Thijs Koerselman

14

ฉันรู้ว่านี่เป็นปัญหาเล็กน้อย แต่ทางออกที่ง่ายที่สุดใน ES2015 / ES6 นั้นค่อนข้างง่ายโดยใช้ Object.assign ()

หวังว่านี่จะช่วยได้สิ่งนี้จะรวมเข้ากับDEEP ได้เช่นกัน:

/**
 * Simple is object check.
 * @param item
 * @returns {boolean}
 */
export function isObject(item) {
  return (item && typeof item === 'object' && !Array.isArray(item) && item !== null);
}

/**
 * Deep merge two objects.
 * @param target
 * @param source
 */
export function mergeDeep(target, source) {
  if (isObject(target) && isObject(source)) {
    for (const key in source) {
      if (isObject(source[key])) {
        if (!target[key]) Object.assign(target, { [key]: {} });
        mergeDeep(target[key], source[key]);
      } else {
        Object.assign(target, { [key]: source[key] });
      }
    }
  }
  return target;
}

ตัวอย่างการใช้งาน:

mergeDeep(this, { a: { b: { c: 123 } } });
// or
const merged = mergeDeep({a: 1}, { b : { c: { d: { e: 12345}}}});  
console.dir(merged); // { a: 1, b: { c: { d: [Object] } } }

7

นอกจากObject.mixinนี้กำลังมีการหารือกันเพื่อดูแลพฤติกรรมที่คุณขอ https://mail.mozilla.org/pipermail/es-discuss/2012-December/027037.html

แม้ว่ามันจะไม่ได้อยู่ในร่าง ES6 แต่ดูเหมือนว่ามีการสนับสนุนมากมายดังนั้นฉันคิดว่ามันจะปรากฏในร่างเร็ว ๆ นี้



5
คำเตือน - คำตอบนี้ไม่ถูกต้องอีกต่อไปดูคำตอบโดยแจ็คสำหรับวิธีการที่ถูกต้องและการทำงาน
Benjamin Gruenbaum

Object.mixin ถูกแทนที่โดย Object.assign
gotofritz

7

ES6

Object.assign(o1,o2) ; 
Object.assign({},o1,o2) ; //safe inheritance
var copy=Object.assign({},o1); // clone o1
//------Transform array of objects to one object---
var subjects_assess=[{maths:92},{phy:75},{sport:99}];
Object.assign(...subjects_assess); // {maths:92,phy:75,sport:99}

ES7 หรือ Babel

{...o1,...o2} // inheritance
 var copy= {...o1};

1
@FilipBartuzi ไม่ใช่ ES6 ที่คุณเชื่อมโยง แต่โดยทั่วไปแล้วจะทำหน้าที่เทียบเท่ากับ _.extend () ใน lodash / ขีดล่าง
Nostalg.io

5

บางทีObject.definePropertiesวิธีES5 จะทำงานได้หรือไม่

เช่น

var a = {name:'fred'};
var b = {age: {value: 37, writeable: true}};

Object.defineProperties(a, b);

alert(a.age); // 37

เอกสาร MDN: https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/defineProperties


ระวังตัวด้วย บนเบราว์เซอร์อย่างน้อยหนึ่งนี้มีผลกระทบต่อประสิทธิภาพการทำงาน
รูเบน Morais

1
ฉันคิดว่าส่วนที่น่าสนใจที่สุดคือการdefinePropertiesกำหนดคุณสมบัติของตัวเอง มันไม่ได้เขียนทับคุณสมบัติของ[[prototype]]ห่วงโซ่มันเงาพวกเขา
RobG

2
คำแนะนำที่ดีแม้ว่าจะไม่ได้ขยายออกไปมากนักเพราะมันเป็นมากกว่าการกำหนดว่าคุณสมบัติควรทำอย่างไร ... การทำ Object.defineProperties (obj1, obj2) ตรงไปตรงมาจะทำให้เกิดผลลัพธ์ที่ไม่คาดคิด
balupton

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