จะทำซ้ำคุณสมบัติของวัตถุในวัตถุอื่นได้อย่างไร


185

รับวัตถุ:

var firstObject = {
    key1 : 'value1',
    key2 : 'value2'
};

ฉันจะคัดลอกคุณสมบัติภายในวัตถุอื่น ( secondObject) เช่นนี้ได้อย่างไร:

var secondObject = {
    key1 : 'value1',
    key2 : 'value2',
    key3 : 'value3',
    key4 : 'value4'
};

ใช้การอ้างอิงถึงfirstObject? บางสิ่งเช่นนี้

var secondObject = {
    firstObject,
    key3 : 'value3',
    key4 : 'value4'
};

(สิ่งนี้ไม่ทำงาน ... ฉันวางไว้เพื่อแสดงในบรรทัดใหญ่ว่าฉันต้องการจัดโครงสร้างโค้ดอย่างไร)

สามารถแก้ปัญหาได้โดยไม่ต้องใช้เฟรมเวิร์ก JavaScript หรือไม่


3
ตอบแล้วที่นี่: stackoverflow.com/questions/171251/…
Calvin

1
คำถามคือคุณต้องการสำเนาตื้นหรือลึก? ถ้าลึกจะลึกแค่ไหน?
georg

5
FWIW พวกเขาเรียกว่า "คุณสมบัติ" ไม่ใช่ "แอตทริบิวต์"
TJ Crowder

นี่คือสิ่งที่น่าเกลียดจริง ๆ ที่ทำงานอย่างไรก็ตาม (ไม่แนะนำจริง ๆ เพียงหลักฐานหนึ่งของแนวคิด):secondObject = JSON.parse('{' + JSON.stringify(firstObject).match(/^.(.*).$/)[1] + ',' + JSON.stringify(secondObject).match(/^.(.*).$/)[1] + '}');
Ben Lee

@TJCrowder: ฉันแก้ไขคำถาม ... ขอบคุณ
Igor Popov

คำตอบ:


213
for(var k in firstObject) secondObject[k]=firstObject[k];

3
@BenLee สิ่งที่คุณหายไปจากที่นี่ก็คืออิกอร์ได้แสดงให้เห็นถึงการใช้งานที่แท้จริงที่เขามีต่อมันซึ่งhasOwnPropertyมันไร้ประโยชน์ ในขณะที่ฉันพบว่าตัวชี้ของคุณมีประโยชน์ผมคิดว่าความคิดของการใช้ใด ๆกฎใด ๆสถานการณ์ที่เป็นอันตรายและไม่ฉลาด เช่นเดียวกับการพัฒนารูปแบบการพัฒนาที่เกิดขึ้นดังนั้นอย่าเป็นเรื่องส่วนตัว…
Michael Krelin - แฮกเกอร์

1
@ MichaelKrelin-hacker สิ่งที่คุณขาดไปคือ StackOverflow ไม่ได้มีไว้เพื่อผลประโยชน์ของ OP เท่านั้น มันถูกใช้เป็นข้อมูลอ้างอิงสำหรับผู้เยี่ยมชมในอนาคตที่อาจมีกรณีการใช้งานที่แตกต่างกันเล็กน้อยซึ่งตัวชี้นั้นอาจมีประโยชน์
Ben Lee

@BenLee ฉันไม่ใช่ IgorPopov ;-) และถ้าไม่ใช่ OP ฉันก็บอกแล้วว่าฉันพบว่าตัวชี้มีประโยชน์และคำตอบของคุณก็เป็นส่วนที่ "คุณควรจะใช้จริงๆ" ที่ฉันไม่ชอบ
Michael Krelin - แฮกเกอร์

23
คุณไม่ต้องhasOwnProperty()ทดสอบและสิ่งต่าง ๆ ยังคงทำงานอยู่ จนกว่าพวกเขาจะหยุดเพราะวัตถุของคุณมีความซับซ้อนเมื่อเวลาผ่านไป ยกเว้นว่ามันจะแบ่งอย่างลึกลับในส่วนที่ไม่เกี่ยวข้องของรหัสเพราะคัดลอกมากเกินไป และคุณไม่มีบริบทสำหรับการดีบัก JS ดูดแบบนั้นดังนั้นการเข้ารหัสอย่างระมัดระวังเพื่อป้องกันปัญหาดังกล่าวไม่ให้เกิดขึ้นอย่างรอบคอบ
Eli Bendersky

2
ฉันคิดว่าคำตอบนี้จำเป็นต้องได้รับการปรับปรุงตาม link developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… const target = {a: 1, b: 2}; const source = {b: 4, c: 5}; const returnTarget = Object.assign (เป้าหมายแหล่งที่มา); console.log (เป้าหมาย); // เอาต์พุตที่คาดไว้: วัตถุ {a: 1, b: 4, c: 5} console.log (returnTarget); // เอาท์พุตที่คาดไว้: วัตถุ {a: 1, b: 4, c: 5}
Elbassel

170

รับคิวจากคำตอบของ @ Bardzuśnyที่นี่ ES6 ได้มอบวิธีแก้ปัญหาดั้งเดิม: Object.assign()ฟังก์ชั่น!

การใช้งานง่าย:

Object.assign(secondObject, firstObject);

แค่นั้นแหละ!

การสนับสนุนในตอนนี้เห็นได้ชัดว่าแย่ มีเพียง Firefox (34+) เท่านั้นที่รองรับนอกขณะที่ Chrome (45+) และ Opera (32+) ต้องการ 'ตั้งค่าสถานะการทดลอง'

การสนับสนุนกำลังปรับปรุงพร้อมรองรับ Chrome, Firefox, Opera, Safari และ Edge เวอร์ชั่นล่าสุด (IE สะดุดตาไม่มีการสนับสนุน) มี Transpilers ให้บริการเช่น Babel และ Traceur ดูที่นี่สำหรับรายละเอียดเพิ่มเติม


4
+1 อีกหนึ่งฟีเจอร์ ES6 ที่ยอดเยี่ยม แน่นอนว่าเบราว์เซอร์ / แม้แต่ Node.JS ขาดการสนับสนุนในขณะนี้ แต่อย่างที่คุณพูดถึงมี transpilers และถ้าคุณไม่ชอบพวกเขา - shims: github.com/paulmillr/es6-shim (หรือแบบสแตนด์อโลนObject.assign()- -im เท่านั้น shim: github.com/ljharb/object.assign )
bardzusny

1
@Xoyce หากคุณตรวจสอบหน้าที่เชื่อมโยง MDN จะระบุอย่างชัดเจนว่า "หากค่าแหล่งข้อมูลเป็นการอ้างอิงไปยังวัตถุจะคัดลอกเฉพาะค่าอ้างอิงนั้นเท่านั้น" ดังนั้นมันจึงรักษาข้อมูลอ้างอิงและไม่คัดลอกวัตถุ คำเตือนของคุณต่อพฤติกรรมที่ไม่คาดคิดยังคงเป็นสิ่งที่เหมาะสมและมันก็มีความคาดหวังที่เหมาะสม
DIMM Reaper

@mostafiz ฉันย้อนกลับการแก้ไขของคุณเนื่องจากคำถามและคำตอบอื่น ๆ ในหน้านี้ใช้ชื่อ "firstObject" และ "secondObject" ดังนั้นฉันจึงใช้ชื่อเดียวกันที่นี่เพื่อความชัดเจนและสอดคล้องกัน
DIMM Reaper

หากสิ่งนี้สอดคล้องกับคำถามก็ไม่เป็นไร
Mostafiz Rahman

1
@pdem อ้อ - ดูคำตอบของ kingPuppy
The DIMM Reaper

101

ต่อES6 - ไวยากรณ์สเปรด :

คุณสามารถใช้:

const thirdObject = {
   ...firstObject,
   ...secondObject   
}

สิ่งนี้จะช่วยป้องกันปัญหาในการส่งวัตถุเหล่านี้โดยการอ้างอิง

นอกจากนี้ยังดูแลวัตถุที่มีการทำรังลึก


2
ว้าวนี่มันยอดเยี่ยมจริงๆ :) ขอบคุณสำหรับคำตอบ เห็นได้ชัดว่าฉันไม่ต้องการมันอีกแล้ว (เพราะเมื่อไม่นานมานี้) แต่มันอาจช่วยคนอื่นได้
Igor Popov

1
+1 สำหรับการใช้ ES6 ที่ยอดเยี่ยมยิ่งขึ้น! เอกสาร MDN ที่อ้างถึงข้างต้นไม่ได้กล่าวถึงการใช้ตัวดำเนินการแพร่กระจายบนวัตถุดังนั้นฉันจึงทำซอที่จะเห็นมันในการดำเนินการ: es6fiddle.net/im3ifsg0
DIMM Reaper

1
@jaepage - ความคิดเห็นที่ดีสำหรับการอ้างอิง วัตถุ (ตามคำถามเดิม) ที่มีชื่อคุณสมบัติง่าย ๆสามารถทำซ้ำได้
kingPuppy

1
ใช้งานได้ใน Chrome นี่คือ ES6 คุณจะต้องใช้ Babel หรือ ES6 transpiler ในปัจจุบัน ในอนาคตเบราว์เซอร์ทั้งหมดคาดว่าจะรองรับไวยากรณ์นี้
kingPuppy

89

วนรอบคุณสมบัติของวัตถุแรกและกำหนดให้กับวัตถุที่สองเช่นนี้

var firstObject = {
    key1 : 'value1',
    key2 : 'value2'
};

var secondObject = {
    key3 : 'value3',
    key4 : 'value4'
};

for (var prop in firstObject) {
    if (firstObject.hasOwnProperty(prop)) {
        secondObject[prop] = firstObject[prop];
    }
}

for- inห่วงไม่เพียงพอ hasOwnPropertyคุณจำเป็นต้อง ดูhttp://bonsaiden.github.com/JavaScript-Garden/#object.forinloopสำหรับคำอธิบายโดยละเอียดเกี่ยวกับสาเหตุ


@ RobW ฉันไม่คิดว่า OP จะใช้referenceในแง่เทคนิค ฉันคิดว่าเขาหมายถึงภาษาธรรมชาติ "อ้างอิงถึง"
Ben Lee

1
@RobW: OP จริง ๆ แล้วพูดว่า "คัดลอก"
TJ Crowder

49

การเล่นหมอผีที่นี่เพราะ ES5 นำเรามาObject.keys()พร้อมศักยภาพในการช่วยเราจากการ.hasOwnProperty()ตรวจสอบทั้งหมดเหล่านี้

Object.keys(firstObject).forEach(function(key) {
  secondObject[key] = firstObject[key];
});

หรือห่อมันเป็นฟังก์ชั่น (จำกัด "สำเนา" ของ lodash _.assign()):

function assign(object, source) {
  Object.keys(source).forEach(function(key) {
    object[key] = source[key];
  });
}

assign(secondObject, firstObject); // assign firstObject properties to secondObject

Object.keys()เป็นวิธีการใหม่ที่ค่อนข้างสะดุดตาที่สุด: ไม่สามารถใช้งานได้ใน IE <9. วิธีการเดียวกันนี้ใช้สำหรับ.forEach()อาร์เรย์ซึ่งฉันใช้แทนforลูปปกติ

โชคดีที่มีes5-shimสำหรับเบราว์เซอร์โบราณเหล่านี้ซึ่งจะรวมคุณสมบัติหลายอย่างของ ES5 (รวมทั้งสอง)

(ฉันทุกคนใช้ polyfills แทนที่จะถือกลับมาจากการใช้คุณสมบัติภาษาใหม่ ๆ ที่เท่ห์)


ทันใดนั้นมีดาวน์สตรีม 2 อันจากที่ไหนเลย ขับเคี่ยวโอกาสเล็กน้อยที่พวกเขาจะอ่านความคิดเห็นนี้ - อะไรคือเหตุผลที่แท้จริงสำหรับพวกเขา? มีคำแนะนำอะไรให้คุณเปลี่ยน / ปรับปรุงในคำตอบของฉัน?
bardzusny

1
สิ่งนี้สมควรอย่างยิ่งที่จะขึ้นไปด้านบนเช่นเดียวกับการเริ่มต้นของวัตถุที่แพร่กระจายไปไกลกว่า (ES6) - ดูดียิ่งขึ้นด้วยฟังก์ชั่นลูกศร!
mjohnsonengr

12

การทำซ้ำเพื่อให้ผู้คนสามารถค้นหาวิธีการทำสำเนาแบบลึกด้วย hasOwnProperty และการตรวจสอบวัตถุจริง:

var extend = function (original, context, key) {
  for (key in context)
    if (context.hasOwnProperty(key))
      if (Object.prototype.toString.call(context[key]) === '[object Object]')
        original[key] = extend(original[key] || {}, context[key]);
      else
        original[key] = context[key];
  return original;
};

โปรดทราบว่านี่ไม่ได้คัดลอกอาร์เรย์ลึกหรือวัตถุฟังก์ชั่น (แต่มันจะคัดลอกลึกวัตถุชนิดอื่น ๆ ทั้งหมด)
Matt Browne

1
ใช่ถ้าคุณต้องการที่จะคัดลอกอาร์เรย์ลึกคุณเพียงแค่ปรับการตรวจสอบประเภทที่จะรวม'[object Array]'
Nijikokun

12

หนึ่งสามารถใช้Object.assignเพื่อรวมวัตถุ มันจะรวมและแทนที่คุณสมบัติทั่วไปจากขวาไปซ้ายกล่าวคือคุณสมบัติเดียวกันในด้านซ้ายจะถูกแทนที่โดยขวา

และเป็นสิ่งสำคัญที่จะต้องจัดหาวัตถุที่ว่างเปล่าในตอนแรกเพื่อหลีกเลี่ยงการกลายพันธุ์ของวัตถุที่มา วัตถุต้นฉบับควรจะถูกทิ้งให้สะอาดเหมือนเดิมObject.assign()ด้วยการส่งคืนวัตถุใหม่

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

var firstObject = {
    key1 : 'value1',
    key2 : 'value2'
};

var secondObject = {
    key3 : 'value3',
    key4 : 'value4'
};

var finalObject = Object.assign({}, firstObject, secondObject)

console.log(finalObject)


แต่ถ้าคุณต้องการให้มันกลายพันธุ์วัตถุแรก คุณมีวัตถุ A และวัตถุ B และคุณต้องการให้กลายพันธุ์วัตถุ A เพื่อให้คุณสมบัติทั้งหมดเท่ากับสิ่งที่พวกเขาอยู่ในวัตถุ B? คุณจะทำ Object.assign (A, B) หรือไม่
TKoL

น่าเศร้าที่ไม่รองรับบน IE, Android WebView, Android Opera ตามหน้า Mozilla Developer Network
Yetti99

6

การปรับปรุงแนวคิดkingPuppyและแนวคิด OP (คัดลอกตื้น) - ฉันเพิ่ม 3 จุดไปที่ OP "ตัวอย่าง" :)

var secondObject = {
    ...firstObject,
    key3 : 'value3',
    key4 : 'value4'
};


4

นี้จะทำงานผ่านการทดสอบที่นี่

var secondObject = {
    firstObject: JSON.parse(JSON.stringify(firstObject)),
    key3 : 'value3',
    key4 : 'value4'
};

หมายเหตุ : นี่จะไม่คัดลอกวิธีของfirstObject
Note 2 : สำหรับใช้ในเบราว์เซอร์รุ่นเก่าคุณจะต้องใช้json parser
หมายเหตุ 3 : การกำหนดโดยการอ้างอิงเป็นตัวเลือกที่ทำงานได้โดยเฉพาะอย่างยิ่งหากfirstObjectมีวิธีการ ปรับตัวอย่าง jsfiddle ที่ได้รับตามนั้น


3

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

function extend( obj1, obj2 ) {
    for ( var i in obj2 ) {
        obj1[i] = obj2[i];
    }
    return obj1;
}

var firstObject = {
    key1: "value1",
    key2: "value2"
};

var secondObject = extend({
    key3: "value3",
    key4: "value4"
}, firstObject );

สิ่งนี้จะคัดลอกคุณสมบัติดั้งเดิม แล้วคุณสมบัติที่เป็นวัตถุเป็นอย่างไร
KooiInc

1

ถ้าคุณต้องการคว้าเฉพาะคุณสมบัติที่มีอยู่ในวัตถุที่สองคุณสามารถใช้Object.keysเพื่อคว้าคุณสมบัติของวัตถุแรกคุณสามารถทำได้สองวิธี:

A. ) mapเพื่อกำหนดคุณสมบัติของวัตถุแรกให้กับวัตถุที่สองโดยใช้ผลข้างเคียง:

var a = {a:100, b:9000, c:300};
var b = {b:-1};

Object.keys(a).map(function(key, index) {
    if (typeof b[key] !== 'undefined') {
        console.log(key);
        b[key] = a[key];    
    }
});

B. )หรือreduceเพื่อสร้างวัตถุใหม่และกำหนดให้กับวัตถุที่สอง โปรดทราบว่าวิธีนี้จะแทนที่คุณสมบัติอื่นที่วัตถุที่สองอาจมีอยู่ก่อนหน้าซึ่งไม่ตรงกับวัตถุแรก:

var a = {a:100, b:9000, c:300};
var b = {b:-1, d:-1}; // d will be gone

b = Object.keys(a).reduce(function(result, current) {
    if (typeof b[current] !== 'undefined') {
        result[current] = a[current];   
    }
    return result;
}, {});

1

ใช้สัญกรณ์การแพร่กระจายคุณสมบัติ มันถูกเพิ่มใน ES2018 (สเปรดสำหรับอาร์เรย์ / iterables ก่อนหน้านี้คือ ES2015), {... firstObject} กระจายคุณสมบัติที่นับได้ทั้งหมดออกเป็นคุณสมบัติที่ไม่ต่อเนื่อง

let secondObject = {
      ...firstObject,
      key3 : 'value3',
      key4 : 'value4'
    }

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

0

ฉันอยากจะใช้ firstObject เป็นต้นแบบของ secondObject และเพิ่ม descriptor คุณสมบัติ:

var secondObject = Object.create(firstObject, {
      key3: {value: "value3", writable: true, configurable: true, enumerable: true},
      key4: {value: "value4", writable: true, configurable: true, enumerable: true}
      });

แน่นอนว่าไม่ใช่ซับเดี่ยว แต่ให้คุณควบคุมได้มากกว่า หากคุณมีความสนใจในคำอธิบายคุณสมบัติฉันขอแนะนำให้อ่านบทความนี้: http://patrickdelancy.com/2012/09/property-descriptors-in-javascript/#comment-2062 และหน้า MDN https: //developer.mozilla org / en-US / เอกสาร / Web / JavaScript / อ้างอิง / Global_Objects / วัตถุ / สร้าง

นอกจากนี้คุณยังสามารถกำหนดค่าและละเว้น descriptors และทำให้สั้นลงเล็กน้อย:

var secondObject = Object.create(firstObject, {
      key3: {value: "value3"}
      key4: {value: "value4"}
  });

ความเข้ากันได้: ECMAScript 5 ดังนั้น IE9 +


0
var firstObject = {
     key1: "value1",
     key2: "value2"
};

var secondObject = {
     key3: "value3",
     key4: "value4"
     copy: function(firstObject){
           this.key1 = firstObject.key1;
           this.key2 = firstObject.key2;
     }
 };

การใช้วิธีการ follwing จะเป็นการคัดลอกคุณสมบัติ

secondObject.copy(firstObject)

ฉันยังใหม่กับ javascript แต่พบว่าใช้งานได้ ยาวไปหน่อยฉันเดา แต่ใช้งานได้

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