2011-09-21 59 views
16

Tôi đang xem qua các thư viện khác nhau và thấy mở rộng() bật lên rất nhiều, nhưng tôi cũng thấy mixin() hiển thị. YUI có cả mixin và phần mở rộng.Sự khác biệt giữa mixin() và extend() trong thư viện Javascript

Sự khác biệt giữa hai khái niệm này là gì? Khi nào tôi sẽ quyết định giữa một mixin và mở rộng một đối tượng?

Cảm ơn, Matt

Trả lời

16

Mixins không hoạt động với instanceof nhưng extends làm. Mixins cho phép nhiều thừa kế nhưng bằng cách giả mạo nó, không phải bằng cách đúng chuỗi các nguyên mẫu.

Tôi sẽ hiển thị ví dụ Ext-JS nhưng khái niệm áp dụng cho bất kỳ thư viện lớp nào cung cấp mixin, tất cả đều chỉ sao chép thuộc tính vào đối tượng thay vì chuỗi nguyên mẫu.

Ext.define('Ext.Window', { 
    extend: 'Ext.Panel', 
    requires: 'Ext.Tool', 
    mixins: { 
     draggable: 'Ext.util.Draggable' 
    } 
}); 

Ext.Window instanceof Ext.Panel //true 
Ext.Window instanceof Ext.util.Draggable // false 

Mixins là cách tuyệt vời để thêm một số chức năng vào đối tượng mà không cần phải thừa kế. Nếu bạn phải kế thừa một cái gì đó để có được một số chức năng, thì bạn không thể sử dụng chức năng từ hai lớp . Many people believe it's evil.

Ext-JS gặp phải sự cố đó khi họ muốn thêm chức năng Labelable vào FieldSet và các chức năng khác không được nhập như trường. Không có cách nào mà nó có thể hưởng lợi từ hành vi Labelable bên trong Field vì chúng không thể mở rộng Field vì nó có tất cả hành vi đầu vào trong nó.

+1

Câu trả lời này khá cụ thể đối với Ext.js và không áp dụng được cho nhiều thư viện JavaScript khác (jQuery và Underscore chỉ là hai ví dụ). – natlee75

+0

@ natlee75 Câu trả lời của tôi nói rằng mixins không sử dụng chuỗi nguyên mẫu, và nó không kiểm tra 'instanceof', Ext-JS là một trong những thực thi của chúng (chúng cho phép bạn kiểm tra xem một cái gì đó là mixin theo một cách khác). Theo như tôi biết, jquery hoặc gạch dưới không thực hiện trộn bằng cách đặt chúng trong chuỗi nguyên mẫu (họ chỉ cần sao chép tài sản). Nhận xét của bạn ngụ ý rằng jquery và gạch dưới có thể có mixins hoạt động chính xác với instanceof? Vui lòng giải thích/ –

+2

Không, nhưng chức năng 'mở rộng' của chúng cũng không thực hiện được. Chỉ có "thư viện lớp" (như 'Ext.define') sử dụng thuật ngữ" mở rộng "để thừa kế nguyên mẫu. – Bergi

0

Sửa cho rõ ràng: Đây là đôi khi điều tương tự và đôi khi không; mixin là tên của một mẫu được sử dụng để sử dụng lại các chức năng giữa nhiều đối tượng, và mở rộng là nhiều thuật toán/phương pháp được sử dụng để làm như vậy. Có những trường hợp chúng giống hệt nhau (ví dụ như dấu gạch dưới _.extend) và các trường hợp chúng khác nhau (mở rộng của backbone.js).

Trong trường hợp chúng khác nhau mở rộng nói chung sẽ liên kết nguyên mẫu với đối tượng đang được mở rộng, trong khi mixin sẽ sao chép danh sách các phương thức vào mục tiêu.

+0

Trừ khi bạn muốn hành vi mà hai lớp cung cấp cho bạn. Không thể sử dụng thừa kế cho điều đó trừ khi bạn đi vào nhiều thừa kế, trong đó có tập hợp các vấn đề riêng của nó. –

+0

Tôi không chắc chắn nó liên quan như thế nào, vì extend và mixin không liên quan trực tiếp đến thừa kế, vv, chúng chỉ là một phương thức để bắt chước hành vi đó. – taxilian

+0

Tôi chỉ giải thích trường hợp họ không có hành vi tương tự. –

2

Bạn chắc chắn có thể tạo mixin bằng cách sử dụng mở rộng.

Mixins cung cấp tất cả lợi ích của đa thừa kế, không có phân cấp (thừa kế nguyên mẫu trong JavaScript). Cả hai đều cho phép bạn sử dụng lại một giao diện (hoặc tập các hàm) trên nhiều đối tượng. Với mixin không gặp phải "vấn đề kim cương" mà bạn có thể gặp phải với các mối quan hệ cha-con.

Sự cố kim cương xảy ra khi một đối tượng thừa hưởng cùng một hàm (hoặc thậm chí tên hàm) từ hai đối tượng. Tại sao? Nếu một trong hai đối tượng đó sửa đổi hàm, thêm chức năng (ví dụ: trong Java được gọi là "siêu"), JavaScript không biết cách diễn giải/kết hợp hai phương thức nữa. Mixins là một cách để tránh sự thừa kế này. Chúng xác định chức năng mà bạn có thể dính vào bất cứ đâu. Mixins cũng thường không chứa dữ liệu của riêng mình.

Vì vậy, tôi có thể, ví dụ: viết một bản mixin với $.extend() trong jQuery. var newmixin = $.extend({}, mixin1, mixin2) sẽ kết hợp hai giao diện và làm phẳng chúng (ghi đè xung đột tên).

Dưới đây là 3 điều cần xem xét:

  1. Liệu sự kết hợp của hai giao diện có "thứ bậc" tức. mối quan hệ cha/con. Trong JavaScript, điều này có nghĩa là thừa kế prototypal.
  2. Các chức năng được sao chép hoặc được tham chiếu? Nếu phương pháp gốc thay đổi, thì các phương pháp kế thừa sẽ thay đổi không?
  3. Điều gì sẽ xảy ra khi hai phương thức cùng tên được kết hợp? Và những xung đột này được xử lý như thế nào?
5

Phương pháp mở rộng khá phổ biến trong các thư viện JavaScript và thường là phương pháp cho phép mã tiêu thụ thêm tất cả thuộc tính và phương thức "sở hữu" của một hoặc nhiều đối tượng vào đối tượng đích. Mã này thường khá đơn giản: lặp qua tất cả các khóa của mỗi đối số vượt quá đầu tiên và sao chép giá trị được lưu trữ ở đó vào đối số đầu tiên.

"Mixin" dùng để chỉ mẫu thiết kế mà bạn sử dụng một đối tượng làm loại vùng chứa cho một tập hợp thuộc tính và phương pháp cụ thể mà bạn muốn chia sẻ trên nhiều đối tượng trong hệ thống của mình. Ví dụ, bạn có thể có các getters và chiều cao và chiều cao có thể áp dụng cho tất cả các thành phần UI trong ứng dụng của bạn và do đó bạn sẽ tạo, trong trường hợp JavaScript, hoặc một hàm có thể được khởi tạo với "new" hoặc giữ các phương pháp này. Sau đó, bạn có thể sử dụng chức năng loại "mở rộng" để sao chép các phương thức này vào bất kỳ số lượng đối tượng nào trong hệ thống của bạn.

Dấu gạch dưới có phương thức mixin về bản chất chỉ là phần mở rộng trong đó tất cả các phương thức được truyền vào đối tượng được thêm vào đối tượng gạch dưới cơ sở để sử dụng trong chuỗi. jQuery thực hiện một điều tương tự với phương thức mở rộng của jQuery.fn.

Cá nhân tôi muốn tiếp tục mở rộng như một hành vi kiểu "sao chép tất cả mọi thứ từ những đối tượng này sang đối tượng này" trong khi có phương thức mixin riêng thay vì chỉ chấp nhận một đối tượng nguồn và sau đó xử lý tất cả đối số khác làm tên của thuộc tính và các phương thức để sao chép (nếu chỉ có mục tiêu và nguồn được truyền vào mà không có đối số nữa thì nó chỉ hoạt động như một nguồn mở rộng).

ví dụ:

function mixin(target, source) { 
    function copyProperty(key) { 
     target[key] = source[key]; 
    } 

    if (arguments.length > 2) { 
     // If there are arguments beyond target and source then treat them as 
     // keys of the specific properties/methods that should be copied over. 
     Array.prototype.slice.call(arguments, 2).forEach(copyProperty); 
    } else { 
     // Otherwise copy all properties/methods from the source to the target. 
     Object.keys(source).forEach(copyProperty); 
    } 
} 
+1

Bạn có thể cho tôi biết tại sao bạn sẽ làm 'Array.prototype.slice.call (đối số , 2) 'over' arguments.slice (2) '. Chỉ muốn biết khi nào nó hữu ích hơn. Cảm ơn trước – cantfindaname88

+3

@ cantfindaname88: 'arguments', trong khi' Array' giống như, không phải là một cá thể 'Array', vì vậy nó không có phương thức' .slice() '. –

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