2012-01-04 48 views
6

Tôi đang cố gắng áp dụng thừa kế nguyên mẫu cho một hàm trong Javascript. Đó là tất cả khá đơn giản và thậm chí được mô tả trong Wikipedia's javascript lemma. Nó hoạt động nếu tài sản của tôi là loại javascript đơn giản:javascript prototyped thừa kế và thuộc tính đối tượng

function Person() { 
    this.age = 0; 
    this.location = { 
     x: 0, 
     y: 0, 
     absolute: false 
    }; 
}; 

function Employee() {}; 

Employee.prototype = new Person(); 
Employee.prototype.celebrate = function() { 
    this.age++; 
} 

var pete = new Employee(); 
pete.age = 5; 
pete.celebrate(); 
var bob = new Employee(); 
bob.celebrate(); 
console.log("bob is " + bob.age + " pete is " + pete.age); 

Với Employee.prototype = new Person();, tính tất cả của Người và phương pháp (prototyped) đều được thừa hưởng bởi nhân viên, trong đó là nền tảng cho thừa kế.

này hoạt động như mong đợi: bob is 1 pete is 6

Bây giờ tôi bắt đầu trở nên vớ vẩn với vị trí của Pete (sau khi ăn mừng)

pete.celebrate(); 
pete.location.absolute=true; 

Hiển thị bob.location.absolute cho thấy: true, đó là Contra trực quan (Tôi đã không chạm vào vị trí của bob vì vậy tôi hy vọng nó có giá trị ban đầu được khai báo trong Person) và hủy hoại giải pháp của tôi.

Trong sự hiểu biết ban đầu của tôi, điều này phải là sai. Tôi nhận ra rằng tôi có lẽ nên nhân bản đối tượng vị trí từ người ban đầu, nhưng tôi không chắc chắn nơi hoặc làm thế nào để làm điều này. Và nếu có những kỹ thuật tốt hơn để thừa kế?

Trả lời

3

Khi bạn khởi tạo Nhân viên mới, tất cả các thuộc tính của Người được sao chép. Vì đây là một bản sao nông, pete và bob chia sẻ cùng một đối tượng vị trí. Đối với vấn đề của bạn, có vẻ như không phải là một giải pháp rất tốt. Bạn có thể sử dụng khung làm việc hoặc thực hiện việc hack như sau:

function Employee() { Person.apply(this); }; 

Điều này gọi hàm tạo Người trong ngữ cảnh của đối tượng này.

Các MDC có biết thêm về vấn đề này: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/apply

3

Không chạy constructor Person khi kế thừa, một Employee thậm chí không nên có một .location bởi vì nó không có trong Person.prototype.

function createObject(fn){ 
    function f(){} 
    f.prototype = fn.prototype; 
    return new f; 
} 

Sau đó:

Employee.prototype = createObject(Person); 

này sẽ kế thừa đúng mà không có tác dụng phụ (chạy constructor).

Bạn sẽ chỉ chạy các nhà xây dựng cha mẹ trong các nhà xây dựng con:

function Employee() { 
Person.apply(this, arguments); 
} 
+0

Ưu điểm của việc sử dụng createObject (Person) thay vì Person mới() là gì? Nó chỉ thêm một lớp nguyên mẫu indirection. – Kosta

+0

@Kosta để tránh tác dụng phụ khi chạy một hàm tạo khi kế thừa. Các nhà xây dựng thường có mã khởi tạo trong đó mà bạn không muốn chạy khi bạn không khởi tạo bất kỳ thứ gì. một 'Employee' mới sẽ vẫn là' instanceof Person' bởi vì cả hai 'Person.prototype' và' f.prototype' trỏ đến cùng một đối tượng. – Esailija

+0

Nhưng bạn vẫn đang chạy hàm tạo trong createObject() (một lần). Ngoài ra, bạn đang chạy constructor trong Employee() (trên mỗi instantiation). Bạn có thể đưa ra một ví dụ trong đó createObject() có hữu ích không? – Kosta

0

Tôi chạy vào vấn đề tương tự. Tôi đã kết thúc bằng cách sử dụng một hàm tạo riêng cho đối tượng bên trong.

function engine(cc, fuel) { 
     this.cc = cc; 
     this.fuel = fuel 
} 

function car(type, model, cc, fuel) { 
     this.type = type; 
     this.model = model; 
     this.engine = new engine(cc, fuel); 
} 


var mycar = new car("sedan", "toyota corolla", 1500, "gas"); 
console.log(mycar.type); 
//sedan 
console.log(mycar.engine.cc); 
//1500 

Nếu tôi có bất kỳ phương pháp nào trên nguyên mẫu của các nhà thầu 'động cơ' hoặc 'xe hơi', chúng vẫn có sẵn. Tuy nhiên, tôi không bắt nguồn từ lớp "xe hơi" từ lớp "động cơ" trong ý nghĩa OOP. Tôi không cần. "Động cơ" được sử dụng như một thành phần của "xe hơi".

Trong khi đó, để thừa hưởng, tôi thích sử dụng các phương pháp mới được kết hợp trong ECMAScript 5 có nghĩa là sử dụng Object.create, Object.defineProperties, vv Chúng được hỗ trợ ngay cả trong IE9. Trước đó tôi đã sử dụng phương pháp 'apply()' tương tự do Kosta đề xuất.

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