2013-05-19 41 views
5

Tôi đã cố gắng nắm bắt được mã OO JavaScript và tạo một ví dụ đơn giản.Phương thức cha mẹ gọi hàm JavaScript OO

function BasePage(name) { 
    this.init(name); 
} 

BasePage.prototype = { 
    init: function(name) { 
     this.name = name; 
    }, 
    getName: function() { 
     return this.name; 
    } 
} 

function FaqPage (name, faq) { 
    this.init(name, faq); 
} 

FaqPage.prototype = new BasePage(); 

FaqPage.prototype = { 
    init: function(name, faq) { 
     BasePage.prototype.init.call(this, name); 
     this.faq = faq; 
    }, 
    getFaq: function() { 
     return this.faq; 
    } 
} 

var faqPage = new FaqPage('Faq Page', 'Faq'); 

var text = faqPage.getName() + ' ' + faqPage.getFaq(); 
$('body').text(text); 

Kết quả của việc chạy kết quả này trong các thông báo sau:

Uncaught TypeError: Object #<Object> has no method 'getName'

Những gì tôi muốn biết là làm thế nào tôi có thể gọi phương thức getName() trong lớp siêu mà không cần phải ghi đè lên và gọi nó là trong lớp phụ?

Ngoài ra nếu tôi nếu bạn cho rằng phương pháp này là xấu/tốt.

Trả lời

1

Tôi cảm thấy đau đớn của bạn. Như những người khác đã đề cập getNameundefined vì bạn ghi đè prototype trong số FaqPage. Do đó tôi sẽ không nhắc lại lời giải thích đó.

Điều đó được cho là tôi đồng ý rằng việc đóng gói các phương pháp prototype trong một phạm vi duy nhất là tốt. Có lẽ bạn nên sử dụng một thư viện JavaScript cho mục đích này. Cái nhỏ nhất ở ngoài là augment.Trong thực tế nó chỉ có 17 dòng dài:

Function.prototype.augment = function (body) { 
    var base = this.prototype; 
    var prototype = Object.create(base); 
    body.apply(prototype, Array.from(arguments, 1).concat(base)); 
    if (!Object.ownPropertyOf(prototype, "constructor")) return prototype; 
    var constructor = prototype.constructor; 
    constructor.prototype = prototype; 
    return constructor; 
}; 

(function funct() { 
    var bind = funct.bind; 
    var bindable = Function.bindable = bind.bind(bind); 
    var callable = Function.callable = bindable(funct.call); 
    Object.ownPropertyOf = callable(funct.hasOwnProperty); 
    Array.from = callable([].slice); 
}()); 

Sau đây là cách mã của bạn sẽ xem xét nếu bạn sử dụng augment:

var BasePage = Object.augment(function() { 
    this.constructor = function (name) { 
     this.name = name; 
    }; 

    this.getName = function() { 
     return this.name; 
    }; 
}); 

var FaqPage = BasePage.augment(function (base) { 
    this.constructor = function (name, faq) { 
     base.constructor.call(this, name); 
     this.faq = faq; 
    }; 

    this.getFaq = function() { 
     return this.faq; 
    }; 
}); 

Sau đó, bạn có thể sử dụng nó như bình thường:

var faqPage = new FaqPage("Faq Page", "Faq"); 
var text = faqPage.getName() + " " + faqPage.getFaq(); 
$("body").text(text); 

Hy vọng rằng sẽ giúp.

+0

Cảm ơn Aadit, tôi thấy Augment khá tốt trong tiêu chuẩn bạn đã làm, nhưng điều gì đã xảy ra trong Chrome? Biểu đồ cho thấy hoạt động bằng không? – Stokedout

+0

@Stokedout - Các điểm chuẩn nên được thực hiện với một hạt muối. Không có nghi ngờ 'augment' là nhanh. Tuy nhiên, hầu hết các lập trình viên JavaScript đều là những người chuyên nghiệp viết mã sloppy. Để bù đắp cho hầu hết các công cụ JavaScript như V8, nó đã tối ưu hóa nó rất nhiều. Kết quả là ngay cả mã xấu chạy nhanh chóng (đôi khi thậm chí còn nhanh hơn mã tốt vì các mẫu thiết kế xấu cũng được tối ưu hóa tốt). Tuy nhiên đó không phải là lý do để viết mã xấu. Mã tốt không chỉ nhanh mà còn có thể đọc được, diễn cảm và dễ hiểu và dễ bảo trì; và 'augment' đánh trúng tất cả những điểm này. Nó thực sự nhanh chóng trong Chrome 26. Làm chậm trong 27. –

+0

Cảm ơn bạn, lý do tôi thay đổi thành OO JS là tất cả những gì bạn vừa đề cập. Tôi không thể theo kịp các bản phát hành của Chrome và không thể chờ để được phát hành bản phát hành IE ;-). Một bình luận cuối cùng về mã trên. Nếu tôi sử dụng constructor thì chắc chắn init là một bản sao của cùng một điều? – Stokedout

6

Lỗi này xảy ra vì mặc dù bạn đã đặt mẫu thử nghiệm của FaqPage thành một phiên bản BasePage, dòng tiếp theo của bạn ngay lập tức sẽ ghi đè điều đó. Vì vậy, FaqPage không được kế thừa từ BasePage. Thêm thuộc tính/phương pháp để FaqPage 's nguyên mẫu thay vì định nghĩa nó một lần thứ hai:

FaqPage.prototype.init = function(name, faq) { 
    BasePage.prototype.init.call(this, name); 
    this.faq = faq; 
} 
FaqPage.prototype.getFaq = function() { 
    return this.faq; 
} 
+0

Cảm ơn, tôi có cảm giác đó sẽ là lý do. Đây có phải là cách duy nhất/cách được khuyến nghị để thêm các phương thức trong OO JS? Đối với tôi đến từ C# nó có vẻ xấu xí không thể nhóm các phương pháp lớp học trong một {scope} – Stokedout

+0

Tôi biết những gì bạn có ý nghĩa nhưng có đây là cách được đề nghị. Nó có thể phát triển trên bạn. Hãy nhớ rằng bạn cũng có thể đặt các phương thức trên 'BasePage'. – sh0ber

2

Dòng đầu tiên là đúng, bạn tạo một nguyên mẫu từ các đối tượng cơ sở.

FaqPage.prototype = new BasePage(); 

Nhưng sau đó bạn ghi đè lên nó, như vậy là không kế thừa các đối tượng cơ sở nữa

FaqPage.prototype = { 
    init: function(name, faq) { 
     BasePage.prototype.init.call(this, name); 
     this.faq = faq; 
    }, 
    getFaq: function() { 
     return this.faq; 
    } 
} 

Thay vì xác định toàn bộ nguyên mẫu, ghi đè lên các chức năng chỉ cá nhân:

FaqPage.prototype.init = function(name, faq) { 
    BasePage.prototype.init.call(this, name); 
    this.faq = faq; 
}; 

FaqPage.prototype.getFaq = function() { 
    return this.faq; 
}; 
1

Nếu thừa kế là những gì bạn đang làm sau, nó không phải là rất đơn giản để thực hiện trong JavaScript như xa như tôi biết. Tôi đã sử dụng đoạn trích này bởi John Resig và nó hoạt động như một sự quyến rũ. http://ejohn.org/blog/simple-javascript-inheritance/

Trong trường hợp của bạn này là cách nó sẽ làm việc,

BasePage

var BasePage = Class.extend({ 
    init: function(name){ 
    this.name = name; 
    }, 
getName: function(){ 
    return this.name; 
} 
}); 

lớp FaqPage kế thừa BasePage

var FaqPage = BasePage.extend({ 
    init: function(name, faq){ 
    this._super(name); 
    this.faq = faq; 
    }, 
    getFaq: function() { 
    return this.faq; 
    } 
}); 

Và sau đó

var faqPage = new FaqPage('Faq Page', 'Faq'); 
var text = faqPage.getName() + ' ' + faqPage.getFaq(); 
$('body').text(text); 

Tất nhiên, để làm việc này bạn sẽ phải bao gồm mã triển khai trên trang tôi đã liên kết.

Đây là fiddle, http://jsfiddle.net/c8yjY/

+0

Mã của John Resig hơi lỗi thời. Có rất nhiều thư viện OOP tốt hơn ở đó: http://jsperf.com/oop-benchmark/127 Vui lòng đọc câu trả lời của tôi ở trên. –

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