2010-07-31 38 views
8

Được rồi, lần đầu tiên tôi cố gắng giải thích những gì tôi đã làm không thành công một cách thảm hại. Về cơ bản tôi đang sao chép Object.create của Crockford(), ngoại trừ với các biến riêng.Ý tưởng kế thừa Javascript (phần 2)

Nếu bạn nhìn vào câu trả lời được chấp nhận ở đây How to inherit from a class in javascript?, bạn sẽ thấy Object.create là mẫu cuối cùng, mà tôi nghĩ tốt hơn phù hợp với bản chất nguyên mẫu của Javascript (đối tượng beget objects) thay vì mô phỏng thừa kế cổ điển (lớp getget objects) .

Nếu bạn xem bài viết của Wikipedia về lập trình dựa trên nguyên mẫu (http://en.wikipedia.org/wiki/Prototype-based_programming), bạn có thể xem thêm ý của tôi.

Hạn chế với Object.create() mặc dù là không có hỗ trợ cho các thành viên riêng tư. Đây là những gì tôi đề xuất:

Function.prototype.from = function(obj) { 
    function F() {this.parent = Object(obj);} 
    F.prototype = obj; 
    var out = new F(); 
    this.apply(out); 
    return out; 
}; 

Sau đó, bạn tạo các đối tượng như vậy:

// Create an object 
var a = function() { 
    var private_property = 'blue'; 
    this.public_property = 7; 

    this.public_method = function() { 
     alert(this.public_property + ' ' + private_property); 
    } 
}.from(null); // .from() works too, but .from(null) is more revealing 


// Create a new object using 'a' as the prototype 
var b = function() { 
    var private_property = 'red'; 
    this.public_property = 8; 
}.from(a); 


// See the results 
a.public_method(); // Alerts '7 blue' 
b.public_method(); // Alerts '8 blue' - Parent methods use parent private variables 

a.public_method = function() { alert('rabbit'); }; 

a.public_method(); // Alerts 'rabbit' 
b.public_method(); // Alerts 'rabbit' 

b.public_method = function() { alert('dog'); }; 

a.public_method(); // Alerts 'rabbit' 
b.public_method(); // Alerts 'dog' - Parent method is overwritten 

Con đường tôi đã "từ" chức năng là như vậy mà khi một đối tượng cha mẹ thay đổi phương thức của nó, nếu bạn muốn ngăn thay đổi trong một phiên bản con, bạn có thể chỉ định:

trong trường hợp con.

Cũng lưu ý rằng các đối tượng được tạo cũ nihilo không được kế thừa từ Object (hasOwnProperty, v.v.). Bạn phải xác định rõ ràng điều này dưới dạng .from (Object).

Lợi ích của mô hình này:

  1. Memory không lãng phí cho mỗi trường hợp mới
  2. Nó tuân thủ một đúng nguyên chủng mẫu thừa kế
  3. Bạn có thể truy cập đến đối tượng phụ huynh sử dụng này. cha mẹ (điều này .__ proto__ là trình duyệt cụ thể)
  4. Biến riêng tư hiện tồn tại

Có một nhược điểm chính của phương pháp này mà tôi có thể nghĩ đến: cú pháp 'hàm()' có thể gây nhầm lẫn cho mọi người khi nghĩ rằng một hàm được gán cho biến thay vì một đối tượng.

Câu hỏi của tôi là, có những hạn chế khác mà tôi đang thiếu không? (Không bao gồm những hạn chế của mẫu nguyên mẫu - đó là chủ quan - nhưng chỉ thực hiện của tôi).

+2

Bạn nên đưa ý tưởng của mình lên làm bài đăng trên blog. – Corv1nus

+0

Các đối tượng được tạo bằng hàm "from()" của bạn thông qua một 'null' thực sự thừa hưởng từ Object. – Pointy

+0

Rất tiếc .. phiên bản đầu tiên của bài đăng này được sử dụng \ __ proto \ __ thay vào đó và từ (null) không được kế thừa từ Object. Tôi phải đi ngay bây giờ, nhưng tôi sẽ sửa chữa sau này ... – Nick

Trả lời

1

Đầu tiên, như đã đề cập, cách tiếp cận Function.prototype thực sự là một nỗi đau. Tại sao không thực hiện điều tương tự như thế này:

Object.createChild = function(obj, constructor) { 
    function F() { this.parent = Object(obj); } 
    F.prototype = obj; 
    var out = new F(); 
    if (typeof constructor == 'function') { 
     constructor.apply(out); 
    } 
    return out; 
}; 

Sau đó sử dụng

var a = Object.createChild(null, function() { /*...*/ }); 
var b = Object.createChild(a, function() { /*...*/ }); 

với kết quả tương tự như trên. Bonus: Bạn có thể bỏ qua đối số constructor, như thế này:

var c = Object.createChild(anything); 

Thứ hai, tôi không biết nếu có bất kỳ sử dụng cho các thừa kế nguyên chủng đúng, như bạn gọi nó. Trong cuộc sống thực, tôi khá chắc chắn rằng hàm xây dựng được đặc biệt phù hợp với đối tượng sắp được mở rộng (a). Như vậy, bạn đang gonna kết thúc gọi

var x = f.from(a); 
var y = f.from(a); 

với rất giống f-a kết hợp hơn và hơn nữa. Và có, bạn tiết kiệm một số byte bộ nhớ so với một cách tiếp cận hướng lớp, nhưng trung thực, những người quan tâm?

Tuy nhiên, toàn bộ điều là một ý tưởng thực sự tốt về lý thuyết.

+0

Bạn thực hiện một số điểm tốt. Tôi có thể đồng ý rằng sự thừa kế nguyên mẫu là cái gì đó hữu ích hơn lý thuyết hơn là thực hành (trên thực tế, tôi không bao giờ thực sự cần thừa kế trong dự án của mình, vì vậy tôi chỉ sử dụng mẫu mô-đun), nhưng ý tưởng của tôi về cơ bản là một cách để thử và tạo ra nguyên mẫu thừa kế hữu ích hơn. Bạn nhận được lợi ích của các biến cá thể riêng cũng như khả năng kế thừa mà không có quá nhiều "hack" ngôn ngữ (giống như tất cả các thư viện với các lớp giả). – Nick

+0

Cá nhân tôi thích ý tưởng tạo ra "các lớp" từ các đối tượng. Ý tưởng của bạn là tốt để làm điều đó, với những thay đổi nhỏ. Đặt 'constructor' bên trong phần thân' F' và trả về 'F'. Điều này có phần tương tự với [extJS's 'extend' method] (http://www.sencha.com/deploy/dev/docs/?class=Ext&member=extend), mà tôi thấy rất hữu ích. – user123444555621