2012-06-12 21 views
5

Tôi đang gặp một số sự cố với JavaScript. Tôi có mã sau:JavaScript: Thêm lớp được thừa kế vào mảng không hoạt động

<html> 
<head> 
<title>Test</title> 
<script type="text/javascript"> 
function Control(){ 
    var name; 

    this.setName = function(newName){ 
     name = newName; 
    }; 

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

function SpecializedControl(){ 
} 
SpecializedControl.prototype = new Control(); 

function Form(){ 
    var formControls = []; 

    this.addControl = function(control){ 
     formControls.push(control); 

     alert(formControls[0].getName()); 
    }; 
} 

var form = new Form(); 

var control1 = new SpecializedControl(); 
control1.setName("Control1"); 
form.addControl(control1); 

var control2 = new SpecializedControl(); 
control2.setName("Control2"); 
form.addControl(control2); 

</script> 
</head> 
<body> 
</body> 
</html> 

SpecializedControl kế thừa từ lớp Điều khiển.

Hàm addControl trong lớp Biểu mẫu chỉ thêm điều khiển vào mảng.

Vấn đề là khi tôi thêm nhiều hơn một SpecializedControl, các giá trị trong mảng là loại overriden, có nghĩa là khi tôi truy cập mục đầu tiên trong mảng, mà nên là "Control1" tôi nhận được "Control2" . Control1 không nằm trong mảng nữa.

Khi tôi sử dụng cùng chức năng với đối tượng Kiểm soát làm thông số, mọi thứ hoạt động như mong đợi.

Có ai biết tại sao điều này xảy ra và có thể làm gì để sửa lỗi này không?

Trả lời

5

Các giá trị trong mảng không được ghi đè ; vấn đề là cả hai điều khiển đều có chung biến số name. Vì hàm Control chỉ thực thi một lần, chỉ có một biến name được khai báo.

Bạn có hai tùy chọn chính để sửa lỗi này. (1) Tạo name biến thể hiện cụ thể cho từng điều khiển riêng lẻ (ví dụ: this._name). (2) Thực thi hàm Control từ bên trong hàm tạo SpecializedControl. (Trên thực tế, IMO, cho một mô hình kế thừa cân bằng và toàn diện, bạn nên làm một chút về cả hai phương pháp này).

Dưới đây là ba giải pháp làm việc. Hai tùy chọn sử dụng đầu tiên (1) và (2) tương ứng. Thứ ba kết hợp cả hai phương pháp và là cách tôi sẽ làm điều đó (nhưng yêu cầu joi).

Lựa chọn 1:

function Control(){ 

    this.setName = function(newName){ 
     this._name = newName; 
    }; 

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

Phương án 2:

function SpecializedControl(){ 
    Control.apply(this, arguments); 
} 

Lựa chọn 3:

var Control = joi.Unit.sub(function() { 

    function constructor() { 
     this.base(); 
    } 

    constructor.prototype = { 
     '#name': null, 
     setName: function(name) { 
      this['#name'] = name; 
     }, 
     getName: function() { 
      return this['#name']; 
     } 
    }; 

    return constructor; 

}()); 

var SpecializedControl = Control.sub(function() { 

    function constructor() { 
     this.base(); 
    } 

    return constructor; 

}()); 

var Form = joi.Unit.sub(function() { 

    function constructor() { 
     this.base(); 
     this['#formControls'] = []; 
    } 

    constructor.prototype = { 
     '#formControls': null, 
     addControl: function(control) { 
      this['#formControls'].push(control); 
      alert(this['#formControls'][0].getName()); 
     } 
    }; 

    return constructor; 

}()); 

var form = new Form(); 

var control1 = new SpecializedControl(); 
control1.setName("Control1"); 
form.addControl(control1); 

var control2 = new SpecializedControl(); 
control2.setName("Control2"); 
form.addControl(control2);​ 
+1

tôi khuyên bạn nên lựa chọn thứ hai, gọi constructor của lớp cha trong constructor lớp con. Nó có vẻ như là điều đúng đắn để làm. Tùy chọn đầu tiên yêu cầu hiển thị biến 'name' và tùy chọn thứ ba sử dụng một thư viện phụ cố gắng triển khai kế thừa dựa trên lớp thông thường như là sự thay thế thừa kế nguyên mẫu của JavaScript. –

+0

joi sử dụng thừa kế nguyên mẫu, không phải thừa kế cổ điển –

+0

Ồ, xấu của tôi. Tuy nhiên, '# name' chỉ là nội bộ theo quy ước và không thực sự ngăn bạn truy cập nó từ bên ngoài. Với bao đóng, bạn có thể có các biến riêng tư thực sự. –

5

Các hàm get/setName của bạn đang nhận/đặt giá trị của biến số name là cục bộ cho hàm xây dựng Control.

Lần duy nhất bạn gọi hàm đó, là tạo một cá thể làm đối tượng prototype của SpecializedControl. Vì vậy, mỗi lần bạn gọi setName từ một cá thể SpecializedControl, biến duy nhất đó đang được cập nhật.

Vì vậy, vì các phương thức tham chiếu get/setName biến đó nằm trong chuỗi mẫu của tất cả các trường hợp SpecializedControl, tất cả chúng sẽ quan sát cùng một name.


Trong setName, bạn nên làm ...

this.name = newName; 

Và trong getName, bạn nên làm ...

return this.name; 
Các vấn đề liên quan