Đây là giải pháp của tôi, dựa trên phương pháp kế thừa nguyên mẫu tiêu chuẩn được mô tả trong câu trả lời của Lorenzo Polidori .
Đầu tiên, tôi bắt đầu bằng cách xác định các phương thức trợ giúp này, giúp mọi thứ dễ hiểu hơn và dễ đọc hơn sau này:
Function.prototype.setSuperclass = function(target) {
this._superclass = target;
this.prototype = Object.create(this._superclass.prototype);
this.prototype.constructor = this;
};
Function.prototype.getSuperclass = function(target) {
return this._superclass;
};
Function.prototype.callSuper = function(target, methodName, args) {
if (arguments.length < 3) {
return this.callSuperConstructor(arguments[0], arguments[1]);
}
if (args === undefined || args === null) args = [];
var superclass = this.getSuperclass();
if (superclass === undefined) throw new TypeError("A superclass for " + this + " could not be found.");
var method = superclass.prototype[methodName];
if (typeof method != "function") throw new TypeError("TypeError: Object " + superclass.prototype + " has no method '" + methodName + "'");
return method.apply(target, args);
};
Function.prototype.callSuperConstructor = function(target, args) {
if (args === undefined || args === null) args = [];
var superclass = this.getSuperclass();
if (superclass === undefined) throw new TypeError("A superclass for " + this + " could not be found.");
return superclass.apply(target, args);
};
Bây giờ, bạn không chỉ có thể thiết lập lớp cha của một lớp SubClass.setSuperclass(ParentClass)
mà còn có thể gọi các phương thức được ghi đè với SubClass.callSuper(this, 'functionName', [argument1, argument2...])
:
function Transform() {
this.type = "2d";
}
Transform.prototype.toString = function() {
return "Transform";
}
function Translation(x, y) {
Translation.callSuper(this, arguments);
this.x = x;
this.y = y;
}
Translation.setSuperclass(Transform);
Translation.prototype.toString = function() {
return Translation.callSuper(this, 'toString', arguments) + this.type + " Translation " + this.x + ":" + this.y;
}
function Rotation(angle) {
Rotation.callSuper(this, arguments);
this.angle = angle;
}
Rotation.setSuperclass(Transform);
Rotation.prototype.toString = function() {
return Rotation.callSuper(this, 'toString', arguments) + this.type + " Rotation " + this.angle;
}
translation = new Translation(10, 15);
console.log(translation instanceof Transform);
console.log(translation instanceof Translation);
console.log(translation instanceof Rotation);
console.log(translation.toString())
Phải thừa nhận rằng ngay cả với các hàm helper thì cú pháp ở đây cũng khá khó xử. Mặc dù vậy, rất may, trong ECMAScript 6, một số đường cú pháp ( các lớp tối thiểu tối đa ) đã được thêm vào để làm cho mọi thứ đẹp hơn nhiều. Ví dụ:
class Transform {
constructor() {
this.type = "2d";
}
toString() {
return "Transform";
}
}
class Translation extends Transform {
constructor(x, y) {
super();
this.x = x;
this.y = y;
}
toString() {
return super(...arguments) + this.type + " Translation " + this.x + ":" + this.y;
}
}
class Rotation extends Transform {
constructor(angle) {
super(...arguments);
this.angle = angle;
}
toString() {
return super(...arguments) + this.type + " Rotation " + this.angle;
}
}
translation = new Translation(10, 15);
console.log(translation instanceof Transform);
console.log(translation instanceof Translation);
console.log(translation instanceof Rotation);
console.log(translation.toString())
Lưu ý rằng ECMAScript 6 vẫn đang trong giai đoạn dự thảo tại thời điểm này và theo tôi biết thì nó chưa được triển khai trong bất kỳ trình duyệt web lớn nào. Tuy nhiên, nếu bạn muốn, bạn có thể sử dụng một cái gì đó như trình biên dịch Traceur để biên dịch ECMAScript 6
xuống ECMAScript 5
JavaScript thuần túy dựa trên cũ . Bạn có thể xem ví dụ trên được biên dịch bằng Traceur tại đây .