2012-03-24 28 views
32

Tôi là một lập trình viên đã lập trình bằng nhiều ngôn ngữ, cả hai chức năng và định hướng OO. Tôi lập trình một số Javascript quá, nhưng không bao giờ được sử dụng (hoặc đã phải sử dụng) đa hình trong đó.Tôi có nên sử dụng đa hình trong javascript không?

Bây giờ, như là một dự án sở thích, tôi muốn chuyển một số ứng dụng được viết bằng Java và C# sử dụng rất nhiều polymorhpism cho Javascript.

Nhưng ngay từ cái nhìn đầu tiên, tôi đã đọc rất nhiều 'Có thể nhưng ...'

Vậy có cách nào khác thay thế không?

Một ví dụ về những gì tôi muốn viết trong JS trong pseudolang:

abstract class Shape{ { printSurface() } ; } 

class Rect : Shape() { printSurface() { print (sideA*sideB}} 

class Circle : Shape() { printSurface() { print { pi*r*r }} 

TheApp { myshapes.iterate(shape s) {s.printSurface() } } 

Vì vậy, một trường hợp đa hình cổ điển: iterating trên baseclass.

Tôi muốn đạt được loại hành vi này. Tôi biết nó polymorhism, nhưng có bất kỳ 'mô hình' khác mà tôi đang xem mà đạt được loại hành vi này hay tôi nên nghiên cứu khả năng thừa kế trong Javascript?

Trả lời

43

Như đã nói, JavaScript là ngôn ngữ được nhập động dựa trên sự thừa kế nguyên mẫu, vì vậy bạn không thể thực sự sử dụng cùng một cách tiếp cận của các ngôn ngữ đã nhập.Một phiên bản JS về những gì bạn đã viết, có thể là:

function Shape(){ 
    throw new Error("Abstract class") 
} 

Shape.prototype.printSurface = function() { 
    throw new Error ("Not implemented"); 
} 

function Rect() { 
    // constructor; 
} 

Rect.prototype = Object.create(Shape.prototype); 
Rect.prototype.printSurface = function() { 
    // Rect implementation 
} 

function Circle() { 
    // constructor; 
} 

Circle.prototype = Object.create(Shape.prototype); 
Circle.prototype.printSurface = function() { 
    // Circle implementation 
} 

Sau đó, trong ứng dụng của bạn:

var obj = new Circle(); 

if (obj instanceof Shape) { 
    // do something with a shape object 
} 

Hoặc, với gõ vịt:

if ("printSurface" in obj) 
    obj.printSurface(); 

// or 

if (obj.printSurface) 
    obj.printSurface(); 

// or a more specific check 
if (typeof obj.printSurface === "function") 
    obj.printSurface(); 

Bạn lạnh cũng có Shape như đối tượng không có bất kỳ hàm tạo nào, rằng nó có nhiều "lớp trừu tượng" như:

var Shape = { 
    printSurface : function() { 
     throw new Error ("Not implemented"); 
    } 
} 

function Rect() { 
    // constructor; 
} 

Rect.prototype = Object.create(Shape); 
Rect.prototype.printSurface = function() { 
    // Rect implementation 
} 

function Circle() { 
    // constructor; 
} 

Circle.prototype = Object.create(Shape); 
Circle.prototype.printSurface = function() { 
    // Circle implementation 
} 

Chú ý rằng trong trường hợp này, bạn không thể sử dụng instanceof nữa, vì vậy hoặc bạn dự phòng để gõ vịt hoặc bạn phải sử dụng isPrototypeOf, nhưng chỉ có trong các trình duyệt gần đây:

if (Shape.isPrototypeOf(obj)) { 
    // do something with obj 
} 

Object.create không có sẵn trong trình duyệt không triển khai thông số kỹ thuật ES5, nhưng bạn có thể dễ dàng sử dụng một polyfill (xem liên kết).

+0

Tx, câu trả lời rất hay. Nhưng thực tế, tôi sẽ đi cho JOOSE, lớp học. – Peter

+0

Điều này không hoạt động đối với Tài liệu. Tôi muốn tạo NMLDocument kế thừa từ Document nhưng một lỗi '[LenientThis]' lạ xuất hiện. – m93a

14

Mẫu "" ở đây sẽ là "giao diện". Miễn là tất cả các đối tượng trong bộ sưu tập myshapes thực hiện phương thức printSurface(), bạn sẽ ổn.

Vì Javascript là ngôn ngữ được nhập động, các đối tượng trong bộ sưu tập không cần liên quan gì cả.

+1

có đổ chuông, trăn như thế nào? – Peter

+1

Ngay cả ví dụ tôi đã sử dụng cũng được hiển thị ở đây: http://knol.google.com/k/programming-to-the-interface-in-javascript-yes-it-can-be-done-er-i- có nghĩa là giả mạo # – Peter

+1

Tôi không hiểu tại sao câu trả lời này không được bỏ phiếu nhiều hơn. Nó chỉ ra sự thật đơn giản về JavaScript và đó là đa hình chỉ là đặt tên các thuộc tính giống nhau. Không có bất kỳ ràng buộc loại nào để lo lắng. – hayavuk

7

tôi biết điều này có thể được thực hiện với nguyên mẫu nhưng tôi không phải là tổng thể sử dụng nó. i prefer the object literal approach (dễ hình dung và có một phạm vi "private")

//shape class 
var shape = function() { 
    //return an object which "shape" represents 
    return { 
     printSurface: function() { 
      alert('blank'); 
     }, 
     toInherit: function() { 
      alert('inherited from shape'); 
     } 
    } 
}; 

//rect class 
var rect = function() { 
    //inherit shape 
    var rectObj = shape(); 

    //private variable 
    var imPrivate = 'Arrr, i have been found by getter!'; 

    //override shape's function 
    rectObj.printSurface = function(msg) { 
     alert('surface of rect is ' + msg); 
    } 

    //you can add functions too 
    rectObj.newfunction = function() { 
     alert('i was added in rect'); 
    } 

    //getters and setters for private stuff work too 
    rectObj.newGetter = function(){ 
     return imPrivate; 
    } 

    //return the object which represents your rectangle 
    return rectObj; 
} 



//new rectangle 
var myrect = rect(); 

//this is the overridden function 
myrect.printSurface('foo'); 

//the appended function 
myrect.newfunction(); 

//inherited function 
myrect.toInherit(); 

//testing the getter 
alert(myrect.newGetter()); 

+0

Tôi phải xem trong nó sau, nhưng luôn luôn +1 cho những người nỗ lực để cung cấp codedamples! – Peter

+1

@Weston: không phải là chủ đề đủ để có một câu trả lời riêng biệt? Các khung công tác có thể được thảo luận ở đó. Hiện tại: hình phạt hiệu suất có được chấp nhận không? – Peter

4

Như Weston nói, nếu bạn không có nhu cầu về thừa kế thì bản chất vịt-gõ của một ngôn ngữ động như vậy như Javascript cung cấp cho bạn đa hình vì không có yêu cầu trong ngôn ngữ chính nó cho một lớp cơ sở mạnh mẽ hoặc giao diện.

Nếu bạn muốn sử dụng thừa kế và thực hiện những việc như gọi điện thoại của một siêu lớp dễ dàng, thì điều này có thể đạt được với nguyên mẫu hoặc chữ tượng hình như Joeseph.

Một điều khác sẽ là xem xét Coffescript vì điều này biên dịch xuống Javascript mang lại cho bạn tất cả sự tốt lành OO trong một cú pháp đơn giản. Nó sẽ viết tất cả các công cụ tạo mẫu bollerplate cho bạn. Điểm bất lợi là nó thêm bước biên dịch bổ sung này. Điều đó nói rằng viết một hệ thống phân cấp lớp đơn giản như ví dụ của bạn ở trên và sau đó nhìn thấy những gì javascript bật ra như là kết quả giúp hiển thị như thế nào tất cả có thể được thực hiện.

+0

Coffeescript Tôi biết, nhưng bước biên dịch là một quá nhiều cho tôi .. – Peter

4

Ghi chú khác. Nếu bạn muốn lập trình Javascript theo kiểu OO sử dụng các lớp, bạn có thể xem xét nhiều "hệ thống lớp" cho Javascript. Một ví dụ là Joose (http://joose.it).

Nhiều khung bên khách hàng triển khai hệ thống lớp học của riêng chúng. Một ví dụ về điều này là ExtJS.

+2

thử nó ngay bây giờ, nó thực sự rất tốt đẹp – Peter

+0

Hoặc chỉ cần quên đi các lớp và nắm lấy các đối tượng. – hayavuk

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