2013-05-12 23 views
11

jsFiddle here.jquery.extend (đúng, [], obj) không tạo bản sao sâu

Nếu sao chép sâu hoạt động, đầu ra sẽ là "Curious George" chứ không phải "Trò chơi của Ender". Làm thế nào tôi có thể tạo một bản sao sâu? Câu trả lời cho this question cho biết rằng $.extend(true, [], obj) tạo bản sao sâu. Tuy nhiên, ví dụ của tôi cho thấy rằng nó không.

function Person(){} 
Person.prototype.favorite_books = []; 

var george = new Person(); 
george.favorite_books = ["Curious George"]; 

var kate = new Person(); 
kate.favorite_books = ["The Da Vinci Code", "Harry Potter"]; 

var people = [kate, george]; 

var people_copy = $.extend(true, [], people); 
people_copy[0].favorite_books[0] = "Ender's Game"; 

$('#text').text(people[0].favorite_books[0]); 

SOLUTION

tôi cập nhật các jsFiddle. Nó chỉ ra tôi cần phải sâu sao chép từng đối tượng trong mảng riêng lẻ nếu đối tượng là một đối tượng tùy chỉnh (có nghĩa là, $.isPlainObject trả về false).

+0

sử dụng .clone() xem http://api.jquery.com/clone/ –

+6

@Paul Sullivan: '.clone()' là được sử dụng với các thực thể DOM – zerkms

+0

okay để duyệt .extend mã nguồn và xem tại sao chức năng đệ quy không sao chép các thuộc tính –

Trả lời

17

Và bây giờ đây là thực câu trả lời:

Tại thời điểm jQuery chỉ có thể nhân bản đối tượng JavaScript thuần túy, trong khi bạn đang sử dụng các đối tượng tùy chỉnh. Và điều đó hiển nhiên, vì jQuery không thể biết chính xác làm thế nào để khởi tạo một đối tượng tùy chỉnh mới. Vì vậy, điều này làm việc như mong đợi:

var george = {}; 
george.favorite_books = ["Curious George"]; 

var kate = {}; 
kate.favorite_books = ["The Da Vinci Code", "Harry Potter"]; 

var people = [kate, george]; 

var people_copy = $.extend(true, [], people); 

console.log(people_copy[0].favorite_books == people[0].favorite_books); 

Tham chiếu đến một mã jQuery: https://github.com/jquery/jquery/blob/master/src/core.js#L305

Thấy rằng nó sẽ kiểm tra nếu nó jQuery.isPlainObject(copy) hoặc nó là một mảng. Nếu không, nó chỉ thực hiện một bản sao tham chiếu.

+0

@Rose Perrone: vì bạn đã tạo bản sao sâu. Vì vậy, các đối tượng ban đầu được giữ nguyên như là, và một trong những sửa đổi được sửa đổi một cách độc lập. Không chắc điều gì làm bạn khó hiểu. – zerkms

+0

@RoyiNamir bạn đã chỉ định rằng nó phải là một bản sao sâu (đối số đầu tiên) – zerkms

+0

Vui lòng kiểm tra đối số boolean đầu tiên trong phương thức gọi hàm '$ .extend'. Và hỏi một câu hỏi khác nếu nó vẫn không rõ ràng cho bạn. – zerkms

2

Thú vị .... nó không giống như mảng bản sao sâu.

Bạn phải sao chép sâu từng đối tượng riêng lẻ.

var people_copy = []; 
$.each(people,function(i,obj) { 
    people_copy.push($.extend(true,{},obj)); 
}); 

EDIT: Chắc chắn, nhìn vào ngã ba này của fiddle của OP:

http://jsfiddle.net/s2bLv/4/

+0

"đối tượng bản sao sâu, không phải mảng" --- bất kỳ bằng chứng nào cho điều đó? Không phải là mảng một loại đối tượng đặc biệt? – zerkms

+0

https://github.com/jquery/jquery/blob/master/src/core.js # L305 - nó phải xử lý mảng – zerkms

+0

Nếu bạn phải sao chép sâu từng đối tượng riêng lẻ, bạn sẽ cần một số mã đệ quy để sao chép toàn bộ xuống - trừ khi điều này chỉ được đề cập đến trong trường hợp thử nghiệm đơn giản của OP chứ không phải là giải pháp chung? – nnnnnn

7

Đây là cách tôi đã thực hiện nó sau khi thử nhiều cách tiếp cận:

var newArray = JSON.parse(JSON.stringify(orgArray)); 

này sẽ tạo ra một bản sao sâu mới, không phải là một bản sao cạn. Ngoài ra điều này rõ ràng sẽ không sao chép các sự kiện và chức năng, nhưng điều tốt là bạn có thể làm điều đó trong một dòng, và nó có thể được sử dụng cho bất kỳ vị vua nào của đối tượng (mảng, chuỗi, số, đối tượng, v.v.).

+2

Nó sẽ không hoạt động cho các đối tượng ngày tháng. –

Các vấn đề liên quan