2009-05-31 39 views
8

Tôi biết có rất nhiều câu hỏi tương tự là rất nhiều câu trả lời tuyệt vời cho điều này. Tôi đã cố gắng để xem xét các phương pháp kế thừa cổ điển, hoặc những phương pháp đóng cửa vv. Bằng cách nào đó tôi cho rằng họ là nhiều hơn hoặc ít hơn "hack" phương pháp với tôi, vì nó không thực sự những gì javascript được thiết kế để làm. (Chào mừng ai cũng sửa tôi nếu tôi sai). OK, miễn là nó hoạt động, tôi hài lòng với mô hình thừa kế cổ điển như:thừa kế javascript

PARENTClass = function (basevar) { do something here; }; 
PARENTClass.prototype = { a: b, c: d}; // prototype is auto gen 

// Inheritance goes here 
CHILDClass = function (childvar) { do something; }; 
CHILDClass.prototype = new PARENTClass(*1); // Actual inheritance to the prototype statement 
// Instance 
CHILDInstance = new CHILDClass(whatever); 

Trên đây là bằng cách nào đó, sự hiểu biết của tôi thừa kế của JS. Nhưng một kịch bản mà tôi không biết cách triển khai, đó là điều gì sẽ xảy ra nếu tôi muốn thực hiện khởi tạo đối tượng DURING (ví dụ, bên trong hàm tạo), và đối tượng mới có thể được sử dụng ngay lập tức .... là quá rõ ràng, vì vậy hãy để tôi sử dụng C# psuedo sau đây để giải thích những gì tôi muốn làm: (. như init phần UI)

class PARENT { 
    public PARENT (basevar) { ... } 
} 
class CHILD : PARENT { 
    public CHILD (basevar) : PARENT (basevar) // constructor of child, and call parent constructor during construct. 
    { ... } 
} 

Đối với một số lý do, đặt chúng trong constructor dường như là cách tốt nhất để làm. Bất cứ ai cũng có ý tưởng về làm thế nào tôi có thể làm điều đó.

PS: trong * 1, tôi không biết nên đặt gì ở đó. PS2: Tình huống trên tôi DID tìm thấy thư viện jquery.inherit có thể làm, tôi chỉ tự hỏi nếu không sử dụng thư viện có thể đạt được nó. PS3: Hoặc sự hiểu biết của tôi là sai. Vì javascript không có ý định bắt chước OOP (đó là lý do tại sao tôi gọi nó là hack), logic "CORRECT" là gì để thực hiện điều này.

+0

Kiểm tra này ra: http://stackoverflow.com/questions/7486825/javascript-inheritance/12816953#12816953 –

+0

Sử dụng Object.create() để kế thừa nguyên mẫu từ lớp cơ sở. Bằng cách đó thay đổi thành lớp cơ sở gợn xuống lớp con nhưng không phải là cách khác xung quanh. Các chi tiết khác trên blog của tôi: http://ncombo.wordpress.com/2013/07/11/javascript-inheritance-done-right/ – Jon

Trả lời

17

Nó không phải là hack như vậy; JavaScript là một ngôn ngữ tạo nguyên mẫu, theo quy định của Wikipedia như nơi:

..classes không có mặt, và tái sử dụng hành vi (được gọi là thừa kế bằng các ngôn ngữ dựa trên lớp) được thực hiện thông qua một quá trình nhân bản đối tượng hiện có phục vụ như nguyên mẫu.

Như đã nói, các lớp học không được sử dụng trong JavaScript; mỗi đối tượng mà bạn tạo ra được lấy từ JavaScript Object; tất cả các đối tượng trong JavaScript có đối tượng prototype và tất cả các đối tượng của các đối tượng mà bạn tạo các phương thức và các thuộc tính 'kế thừa' từ đối tượng nguyên mẫu của đối tượng của chúng. Hãy xem tài liệu tham khảo MDC prototype đối tượng để biết thêm thông tin.

Như vậy, khi bạn gọi dòng:

CHILDClass.prototype = new PARENTClass(); 

Điều này cho phép các đối tượng CHILDClass để thêm các phương pháp và tài sản cho đối tượng nguyên mẫu của nó từ đối tượng PARENTClass, mà tạo ra một hiệu ứng tương tự như ý tưởng về thừa kế có mặt trong các ngôn ngữ dựa trên lớp học. Vì đối tượng prototype ảnh hưởng đến mọi cá thể được tạo ra của đối tượng đó, điều này cho phép các phương thức và thuộc tính của đối tượng cha mẹ có mặt trong mọi cá thể của đối tượng con bạn.

Nếu bạn muốn gọi hàm tạo của lớp cha của bạn trong hàm tạo của lớp con, bạn sử dụng hàm JavaScript call; điều này cho phép bạn gọi hàm tạo của lớp cha trong ngữ cảnh của hàm tạo của lớp con, do đó thiết lập các thuộc tính mới được tạo mẫu trong lớp con của bạn thành những gì chúng được thiết lập như trong lớp cha.

Bạn cũng không cần đặt bất kỳ thứ gì bạn đã chỉ định *1, vì dòng đó chỉ được sử dụng để thêm các phương thức và thuộc tính vào đối tượng nguyên mẫu của lớp con; tuy nhiên, hãy nhớ rằng nó gọi hàm tạo của lớp cha, vì vậy nếu có bất kỳ đối số nào là cơ bản trong hoạt động của hàm tạo lớp cha, bạn nên kiểm tra xem chúng có tồn tại để tránh các lỗi JavaScript hay không.

+0

Câu trả lời hay và toàn diện. Chỉ cần thêm một điều nữa .. Trong trường hợp, ví dụ, khi gọi hàm tạo của phụ huynh, cái gì đó, có thể là cổ tích đắt tiền (như đọc từ XML) hoặc nhận biết người dùng (như cảnh báo gọi) sẽ được thực thi. Thậm chí tôi không đặt gì trong * 1, về cơ bản vẫn sẽ được thực thi; Trừ khi tôi đặt một cách rõ ràng kiểm tra trong phụ huynh (ví dụ, nếu (arguments.length == 0) return;). Nó là một giải pháp "thích hợp" cho điều này? Xin lỗi vì tôi đến từ một nền OOP thuần túy nghiêm ngặt, tôi vẫn chưa thực sự quen với lập trình logic định hướng js. – xandy

+0

Vâng, đó là cách tôi sẽ làm điều đó - nếu ai đó tạo ra một thể hiện của đối tượng của bạn đòi hỏi các đối số thì bạn không muốn thực hiện các hành động đó. –

10

Bạn có thể tự gọi constructor mẹ trong constructor lớp con như thế này:

CHILDClass = function (basevar) { 
    PARENTClass.call(this, basevar); 
    // do something; 
}; 

Bí quyết ở đây là sử dụng phương pháp call, cho phép bạn để gọi một phương pháp trong bối cảnh của một đối tượng khác nhau. Xem the documentation of call để biết thêm chi tiết.

+0

Tôi đã tìm kiếm tất cả các chức năng này. Tôi chưa bao giờ thấy nó đơn giản như thế. Câu hỏi của tôi là, đây có phải là cách "chấp nhận" được không? Như trong, điều này có được coi là hack không? Ngoài ra, là hiện tại, như trong không được chấp nhận như '__proto__'? –

1

JavaScript không có hỗ trợ tích hợp cho các cấu trúc thừa kế vì phần mở rộng loại được thực hiện thông qua tập hợp, nghĩa là thêm chức năng mong muốn trực tiếp vào chính đối tượng hoặc nguyên mẫu của nó nếu thuộc tính được chia sẻ giữa các phiên bản.

Tuy nhiên, JS đủ mạnh để thực hiện các hình thức xây dựng đối tượng khác có thể, bao gồm cả thừa kế cổ điển.

Cho một clone function - đó là đủ để thêm thừa kế 'true' nguyên mẫu, và không bastardization JavaScript của chúng - exampe của bạn có thể được thực hiện như thế này:

function ParentClass(baseVar) { 
    // do stuff 
} 

// don't overwrite the prototype object if you want to keep `constructor` 
// see http://joost.zeekat.nl/constructors-considered-mildly-confusing.html 
ParentClass.prototype.a = 'b'; 
ParentClass.prototype.c = 'd'; 

function ChildClass(childVar) { 
    // call the super constructor 
    ParentClass.call(this, childVar); 
} 

// don't inherit from a ParentClass instance, but the actual prototype 
ChildClass.prototype = clone(ParentClass.prototype); 
ChildClass.prototype.e = 'f'; 

Nó cũng có thể thêm một số đường cú pháp cho các lớp học dựa trên thừa kế - thực hiện của riêng tôi can be found here.

Ví dụ từ trên cao sau đó sẽ đọc

var ParentClass = Class.extend({ 
    constructor: function(baseVar) { 
     // do stuff 
    }, 
    a: 'b', 
    c: 'd' 
}); 

var ChildClass = ParentClass.extend({ 
    e: 'f' 
}); 
1

Tôi đã có một trọng lượng nhẹ javascript OOP wrapper cung cấp 'Class-như' thừa kế nơi bạn có thể ghi đè lên các phương pháp cơ bản hoặc gọi constructor cơ sở hoặc thành viên.

Bạn xác định lớp học của bạn như thế này:

//Define the 'Cat' class 
function Cat(catType, firstName, lastName) 
{ 
    //Call the 'Animal' constructor. 
    Cat.$baseNew.call(this, firstName, lastName); 

    this.catType = catType; 
} 
//Extend Animal, and Register the 'Cat' type. 
Cat.extend(Animal, { type: 'Cat' }, { 
    hello: function(text) 
    { 
     return "meaoow: " + text; 
    }, 
    getFullName: function() 
    { 
     //Call the base 'Animal' getFullName method. 
     return this.catType + ": " + Cat.$base.getFullName.call(this); 
    } 
}) 

//It has a built-in type system that lets you do stuff like: 

var cat = new Cat("ginger", "kitty", "kat"); 
Cat.getType()      // "Cat" 
cat.getBaseTypesAndSelf()   // ["Cat","Animal","Class"] 
cat.getType()      // "Cat" 
cat.isTypeOf(Animal.getType()) // "True" 

var dynamicCat = Class.createNew("Cat", ["tab","fat","cat"]) 
dynamicCat.getBaseTypesAndSelf() // ["Cat","Animal","Class"] 
dynamicCat.getFullName()   // tab: fat cat 

mã nguồn có sẵn tại địa chỉ: Class.js

Tôi cũng có thêm chi tiết trong bài viết trên blog của tôi về OOP in javascript

1

Chỉ cần nghĩ rằng tôi muốn đề cập đến một số trong số các vấn đề với mẫu cổ điển bạn sẽ tìm kiếm:

  1. Các tham chiếu trên các lớp siêu sẽ có sẵn như là các số liệu thống kê trên tất cả các trường hợp. Ví dụ, nếu bạn có var arr = [1,2,3] trong super, và làm instance_1.arr.push (4) instance_2.arr.push (5) TẤT CẢ những trường hợp này sẽ "nhìn thấy" các thay đổi.
  2. Vì vậy, bạn giải quyết 1. với giải pháp của Ayman mà Zakas gọi là "Constructor Stealing", nhưng bây giờ bạn gọi hàm tạo hai lần: một lần cho nguyên mẫu của bạn và một lần cho việc đánh cắp nhà xây dựng. Giải pháp - cho nguyên mẫu của bạn sử dụng một helper như inheritPrototype (tôi đã cho thấy toàn bộ việc thực hiện điều này trong bài này: inheritPrototype method FWIW, điều này chủ yếu đến từ sự kết hợp của trang 181 của cuốn sách Zakas và một số nghiên cứu Crockford.

  3. Không riêng tư (nhưng sau đó một lần nữa, bạn cần phải sử dụng một cái gì đó giống như mô hình Object Durable để có được điều này và điều đó có thể không phải những gì bạn muốn) định nghĩa

  4. Object còn lại "treo lủng lẳng": Giải pháp - đặt một tuyên bố nếu kiểm tra cho bất kỳ chức năng của nguyên mẫu của bạn và sau đó xác định nguyên mẫu với một nguyên mẫu chữ.

Tôi đã chạy các ví dụ về tất cả điều này trên github !!!

Nó đã là một thách thức lớn đối với tôi để thực sự grok cả: Zakas và Crockford sách về tạo đối tượng và thừa kế. Tôi cũng cần thử một số khung công tác JavaScript TDD khác nhau. Vì vậy, tôi quyết định tạo một bài luận về cả hai khung TDD và tạo đối tượng JavaScript & Thừa kế. Nó có chạy thử nghiệm mã và jspec! Đây là liên kết: * My GitHub Open Source Essay/Book

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