Làm thế nào để sao chép các thuộc tính đối tượng trong một đối tượng khác?


184

Cho đối tượng:

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

Làm thế nào tôi có thể sao chép các thuộc tính bên trong một đối tượng khác ( secondObject) như thế này:

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

sử dụng một tham chiếu đến firstObject? Một cái gì đó như thế này:

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

(điều này không hoạt động ... Tôi đặt nó chỉ để hiển thị trong các dòng lớn cách tôi muốn cấu trúc mã).

Là một giải pháp có thể mà không cần sử dụng bất kỳ khung JavaScript nào?


3
Đã trả lời tại đây: stackoverflow.com/questions/171251/ Mạnh
Calvin

1
Câu hỏi là, bạn muốn một bản sao nông hay sâu? Nếu sâu thì sâu bao nhiêu?
georg

5
FWIW, chúng được gọi là "thuộc tính" chứ không phải "thuộc tính".
TJ Crowder

Tuy nhiên, đây là một cái gì đó thực sự xấu mà hoạt động (không thực sự được khuyến nghị! Chỉ là một bằng chứng khái niệm một lớp):secondObject = JSON.parse('{' + JSON.stringify(firstObject).match(/^.(.*).$/)[1] + ',' + JSON.stringify(secondObject).match(/^.(.*).$/)[1] + '}');
Ben Lee

@TJCrowder: Tôi đã sửa câu hỏi ... cảm ơn.
Igor Popov

Câu trả lời:


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

3
@BenLee, điều bạn đang thiếu ở đây là Igor đã cho thấy công dụng chính xác mà anh ta dành cho nó, trong đó hasOwnPropertylà vô dụng. Trong khi tôi thấy con trỏ của bạn hữu ích, tôi xem xét ý tưởng áp dụng bất kỳ quy tắc nào cho bất kỳ tình huống nào có hại và không khôn ngoan. Giống như tất cả các hoạt động phát triển theo mô hình này đang diễn ra, vì vậy đừng mang nó cá nhân
Michael Krelin - hacker

1
@ MichaelKrelin-hacker, điều bạn thiếu ở đây là StackOverflow không chỉ vì lợi ích của OP. Nó được sử dụng làm tài liệu tham khảo cho khách truy cập trong tương lai, những người có thể có các trường hợp sử dụng hơi khác nhau, trong đó con trỏ đó thể hữu ích.
Ben Lee

@BenLee, tôi không phải là IgorPopov ;-) Và không phải là OP, tôi đã nói rằng tôi thấy con trỏ hữu ích và câu trả lời của bạn cũng vậy, đó là phần "bạn thực sự nên sử dụng" mà tôi không thích.
Michael Krelin - hacker

23
Bạn bỏ qua một hasOwnProperty()bài kiểm tra và mọi thứ vẫn tiếp tục hoạt động. Cho đến khi họ dừng lại, bởi vì các đối tượng của bạn trở nên phức tạp hơn theo thời gian. Ngoại trừ sau đó nó phá vỡ một cách bí ẩn trong một phần không liên quan của mã vì quá nhiều đã được sao chép. Và bạn không có bất kỳ bối cảnh nào để gỡ lỗi. JS hút như vậy, vì vậy mã hóa cẩn thận để ngăn chặn các vấn đề như vậy xảy ra là thận trọng.
Eli Bendersky

2
Tôi nghĩ rằng câu trả lời này cần được cập nhật theo liên kết sau developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/ sắt const target = {a: 1, b: 2}; const nguồn = {b: 4, c: 5}; const returnTarget = Object.assign (đích, nguồn); console.log (mục tiêu); // đầu ra dự kiến: Object {a: 1, b: 4, c: 5} console.log (returnTarget); // đầu ra dự kiến: Đối tượng {a: 1, b: 4, c: 5}
Elbassel

170

Lấy một gợi ý từ câu trả lời của @ Bardzuśny tại đây, ES6 đã đưa ra một giải pháp tự nhiên: Object.assign()chức năng!

Cách sử dụng rất đơn giản:

Object.assign(secondObject, firstObject);

Đó là nó!

Hỗ trợ ngay bây giờ rõ ràng là kém; chỉ có Firefox (34+) hỗ trợ ngoài luồng, trong khi Chrome (45+) và Opera (32+) yêu cầu 'cờ thử nghiệm' được đặt.

Hỗ trợ đang được cải thiện, với các phiên bản mới nhất của Chrome, Firefox, Opera, Safari và Edge hỗ trợ nó (đáng chú ý là IE không có hỗ trợ.) Các bộ chuyển đổi cũng có sẵn, như Babel và Traceur. Xem ở đây để biết thêm chi tiết.


4
+1, một tính năng ES6 thú vị khác. Tất nhiên trình duyệt / thậm chí hỗ trợ Node.JS hiện đang thiếu, nhưng như bạn đã đề cập, có sẵn các bộ chuyển đổi. Và nếu bạn không thích chúng - shims: github.com/paulmillr/es6-shim (hoặc độc lập, Object.assign()-only shim: github.com/ljharb/object.assign ).
bardzusny

1
@Xoyce Nếu bạn kiểm tra trang MDN được liên kết, nó sẽ ghi rõ "Nếu giá trị nguồn là tham chiếu đến một đối tượng, nó chỉ sao chép giá trị tham chiếu đó." Vì vậy, nó thực sự bảo tồn tài liệu tham khảo, và không sao chép đối tượng. Cảnh báo của bạn chống lại hành vi bất ngờ vẫn còn thích hợp, và nó có được những kỳ vọng đúng đắn.
Máy cắt DIMM

@ mostafiz Tôi đã khôi phục chỉnh sửa của bạn, vì câu hỏi và các câu trả lời khác trên trang này sử dụng tên "FirstObject" và "secondObject", vì vậy tôi đã sử dụng cùng tên ở đây để rõ ràng và nhất quán.
Máy cắt DIMM

Nếu điều này phù hợp với câu hỏi thì không sao.
Mostafiz Rahman


100

Mỗi ES6 - Cú pháp lây lan :

Bạn chỉ có thể sử dụng:

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

Điều này tránh các vấn đề về việc vượt qua các đối tượng này bằng cách tham khảo.

Ngoài ra, nó chăm sóc các đối tượng có lồng sâu.


2
Wow, điều này thực sự tuyệt vời :) Cảm ơn câu trả lời. Rõ ràng, tôi không cần nó nữa (vì cách đây một thời gian), nhưng nó có thể giúp đỡ người khác.
Igor Popov

1
+1 cho việc sử dụng ES6 thậm chí mát hơn! Các tài liệu MDN được tham chiếu ở trên không đề cập đến việc sử dụng toán tử trải trên các đối tượng, vì vậy tôi đã thực hiện một thao tác để thấy nó hoạt động: es6fiddle.net/im3ifsg0
DIMM Reaper

1
@jaepage - Nhận xét tốt để tham khảo. Một đối tượng (theo câu hỏi ban đầu) với tên thuộc tính đơn giản là có thể lặp lại.
kingPuppy

1
Hoạt động trong Chrome, đây là ES6, bạn sẽ cần Babel hoặc một số bộ chuyển mã ES6 hiện tại. Trong tương lai, tất cả các trình duyệt dự kiến ​​sẽ hỗ trợ cú pháp này.
kingPuppy

89

Lặp qua các thuộc tính của đối tượng đầu tiên và gán chúng cho đối tượng thứ hai, như thế này:

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];
    }
}

Các for- invòng lặp là không đủ; bạn cần hasOwnProperty. Xem http://bonsaiden.github.com/JavaScript-Garden/#object.forinloop để được giải thích chi tiết về lý do.


@RobW, tôi không nghĩ OP đang sử dụng referencetheo nghĩa kỹ thuật. Tôi nghĩ anh ấy chỉ có nghĩa là "nói đến" ngôn ngữ tự nhiên.
Ben Lee

1
@RobW: OP thực sự đã nói "bản sao".
TJ Crowder

49

Chơi necromancer ở đây, vì ES5 mang lại cho chúng tôi Object.keys(), với tiềm năng cứu chúng tôi khỏi tất cả các .hasOwnProperty()kiểm tra này .

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

Hoặc, gói nó vào một chức năng ("bản sao" giới hạn của 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()là phương thức tương đối mới, đáng chú ý nhất: không có sẵn trong IE <9. Điều tương tự thực sự xảy ra với .forEach()phương thức mảng, mà tôi đã sử dụng thay cho forvòng lặp thông thường .

May mắn thay, có sẵn es5-shim cho các trình duyệt cổ này, sẽ cung cấp nhiều tính năng ES5 (bao gồm cả hai tính năng này).

(Tôi hoàn toàn dành cho các polyfill thay vì giữ lại từ việc sử dụng các tính năng ngôn ngữ mới, thú vị.)


Đột nhiên, 2 downvote ra khỏi hư không. Có cơ hội nhỏ rằng những kẻ đó sẽ đọc bình luận này - lý do thực sự của chúng là gì? Bất cứ điều gì bạn muốn đề nghị thay đổi / cải thiện trong câu trả lời của tôi?
bardzusny

1
Điều này chắc chắn xứng đáng để tăng lên hàng đầu, cũng như trình khởi tạo trải rộng đối tượng xuống sâu hơn (ES6) - điều này trông thậm chí còn sạch hơn với các chức năng mũi tên!
mjohnsonengr

12

Necro'ing để mọi người có thể tìm thấy một phương pháp sao chép sâu với hasOwnProperty và kiểm tra đối tượng thực tế:

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;
};

Lưu ý rằng điều này không sao chép sâu các mảng hoặc các đối tượng hàm (nhưng nó sao chép sâu tất cả các loại đối tượng khác).
Matt Browne

1
Vâng, nếu bạn muốn sao chép sâu các mảng, bạn chỉ cần sửa đổi loại kiểm tra để bao gồm'[object Array]'
Nijikokun

12

Người ta có thể sử dụng Object.assign để kết hợp các đối tượng. Nó sẽ kết hợp và ghi đè tài sản chung từ phải sang trái tức là, cùng một tài sản ở bên trái sẽ bị ghi đè bên phải.

Và điều quan trọng là cung cấp một đối tượng trống trong lần đầu tiên để tránh làm biến đổi các đối tượng nguồn. Các đối tượng nguồn nên được giữ sạch sẽ vì Object.assign()chính nó trả về một đối tượng mới.

Hi vọng điêu nay co ich!

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

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

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

console.log(finalObject)


Nhưng nếu bạn muốn nó biến đổi đối tượng đầu tiên thì sao? Bạn có đối tượng A và đối tượng B, và bạn muốn nó biến đổi đối tượng A sao cho tất cả các thuộc tính đều bằng với những gì chúng có trên đối tượng B? Bạn sẽ làm Object.assign (A, B) chứ?
TKoL

Đáng buồn là không được hỗ trợ trên IE, Android WebView, Android Opera theo trang Mạng của Nhà phát triển Mozilla.
Yetti99

6

Cải thiện ý tưởng kingPuppy và ý tưởng OP (bản sao nông) - Tôi chỉ thêm 3 dấu chấm vào OP "ví dụ" :)

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


4

Điều này nên làm việc, thử nghiệm ở đây .

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

Lưu ý : điều này sẽ không sao chép các phương thức của firstObject
Note 2 : để sử dụng trong các trình duyệt cũ hơn, bạn sẽ cần một trình phân tích cú pháp json
Lưu ý 3 : gán theo tham chiếu là một tùy chọn khả thi, đặc biệt là nếu firstObjectchứa các phương thức. Điều chỉnh ví dụ jsfiddle đã cho phù hợp


3

Thật không may, bạn không thể đặt một tham chiếu đến một biến trong một đối tượng như thế. Tuy nhiên, bạn có thể tạo một hàm sao chép các giá trị của đối tượng vào một đối tượng khác.

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 );

Điều này cũng sẽ sao chép các thuộc tính bản địa. Và làm thế nào về các thuộc tính mà chính là Đối tượng?
KooiInc

1

Nếu bạn muốn lấy chỉ các thuộc tính mà tồn tại trong đối tượng thứ hai, bạn có thể sử dụng Object.keysđể lấy các thuộc tính của đối tượng đầu tiên, bạn có thể làm hai phương pháp:

A.) map để gán các thuộc tính của đối tượng thứ nhất cho đối tượng thứ hai bằng cách sử dụng các hiệu ứng phụ:

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.) hoặc reduceđể tạo một đối tượng mới và gán nó cho đối tượng thứ hai. Xin lưu ý rằng phương thức này thay thế các thuộc tính khác mà đối tượng thứ hai có thể có trước đó không khớp với đối tượng thứ nhất:

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

Sử dụng ký hiệu lây lan tài sản. Nó đã được thêm vào trong ES2018 (lây lan cho mảng / iterables trước đó, ES2015), {... firstObject} trải đều tất cả các thuộc tính có thể đếm được dưới dạng các thuộc tính riêng biệt.

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

bạn có thể vui lòng đưa ra một số bối cảnh cho câu trả lời của bạn không và tại sao nó lại giải quyết được câu hỏi
Tamir Klein

0

Tôi thà sử dụng FirstObject làm nguyên mẫu của secondObject và thêm mô tả thuộc tính:

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

Nó chắc chắn không phải là một lớp lót, nhưng nó cho phép bạn kiểm soát nhiều hơn. Nếu bạn quan tâm đến các mô tả tài sản, tôi khuyên bạn nên đọc bài viết này: http://patrickdelancy.com/2012/09/property-descriptors-in-javascript/#comment-2062 và trang MDN https: //developer.mozilla. org / en-US / docs / Web / JavaScript / Reference / Global_Objects / Object / tạo

Bạn cũng có thể chỉ định các giá trị và bỏ qua các mô tả và làm cho nó ngắn hơn một chút:

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

Khả năng tương thích: ECMAScript 5, vì vậy 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;
     }
 };

Sử dụng phương thức follwing sẽ sao chép các thuộc tính

secondObject.copy(firstObject)

Tôi rất mới với javascript, nhưng thấy nó hoạt động. Một chút quá lâu tôi đoán, nhưng nó hoạt động.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.