類別的模擬主要就是先前觀念的綜合應用,以類別定義與繼承來說,基本上可以如下:
function Circle(x, y, r) {
// 設定物件各自狀態
this.x = x;
this.y = y;
this.r = r;
}
Circle.PI = 3.14159; // 相當於Java類別的靜態方法
// 共用的物件方法設定在 prototype 上
Circle.prototype.area = function() {
return this.r * this.r * Circle.PI;
};
Circle.prototype.toString = function() {
var text = [];
for(var p in this) {
if(typeof this[p] != 'function') {
text.push(p + ':' + this[p]);
}
}
return '[' + text.join() + ']';
};
function Cylinder(x, y, r, h) {
Circle.call(this, x, y, r); // 呼叫父建構式
this.h = h;
}
// 原型繼承
Cylinder.prototype = new Circle();
// 設定原型物件之constructor為目前建構式
Cylinder.prototype.constructor = Cylinder;
// 以下在new時會再建構,不需要留在原型物件上
delete Cylinder.prototype.x;
delete Cylinder.prototype.y;
delete Cylinder.prototype.r;
// 共用的物件方法設定在 prototype 上
Cylinder.prototype.volumn = function() {
return this.area() * this.h;
};
// 設定物件各自狀態
this.x = x;
this.y = y;
this.r = r;
}
Circle.PI = 3.14159; // 相當於Java類別的靜態方法
// 共用的物件方法設定在 prototype 上
Circle.prototype.area = function() {
return this.r * this.r * Circle.PI;
};
Circle.prototype.toString = function() {
var text = [];
for(var p in this) {
if(typeof this[p] != 'function') {
text.push(p + ':' + this[p]);
}
}
return '[' + text.join() + ']';
};
function Cylinder(x, y, r, h) {
Circle.call(this, x, y, r); // 呼叫父建構式
this.h = h;
}
// 原型繼承
Cylinder.prototype = new Circle();
// 設定原型物件之constructor為目前建構式
Cylinder.prototype.constructor = Cylinder;
// 以下在new時會再建構,不需要留在原型物件上
delete Cylinder.prototype.x;
delete Cylinder.prototype.y;
delete Cylinder.prototype.r;
// 共用的物件方法設定在 prototype 上
Cylinder.prototype.volumn = function() {
return this.area() * this.h;
};
如果你想讓外觀上看起來更像是Java之類的類別定義。可以將以上的流程封起來。例如,將建立類別的流程封裝起來:
var Class = {};
Class.create = function(methods) {
var Clz = methods.initialize;
for(var mth in methods) {
if(mth != 'initialize') {
Clz.prototype[mth] = methods[mth];
}
}
return Clz;
};
Class.create = function(methods) {
var Clz = methods.initialize;
for(var mth in methods) {
if(mth != 'initialize') {
Clz.prototype[mth] = methods[mth];
}
}
return Clz;
};
那麼你就可以這麼使用:
var Circle = Class.create({
initialize : function(x, y, r) { // 作為建構式
this.x = x;
this.y = y;
this.r = r;
},
area : function() {
return Math.PI * Math.pow(this.r, 2);
},
toString : function() {
var text = [];
for(var p in this) {
if(typeof this[p] != 'function') {
text.push(p + ':' + this[p]);
}
}
return '[' + text.join() + ']';
}
});
var circle = new Circle(10, 10, 5);
initialize : function(x, y, r) { // 作為建構式
this.x = x;
this.y = y;
this.r = r;
},
area : function() {
return Math.PI * Math.pow(this.r, 2);
},
toString : function() {
var text = [];
for(var p in this) {
if(typeof this[p] != 'function') {
text.push(p + ':' + this[p]);
}
}
return '[' + text.join() + ']';
}
});
var circle = new Circle(10, 10, 5);
如果想封裝類別的繼承,則可以這麼作:
Class.extend = function(Superclz, methods) {
var Subclz = this.create(methods);
var subproto = Subclz.prototype;
Subclz.prototype = new Superclz();
for(var p in Subclz.prototype) {
if(Subclz.prototype.hasOwnProperty(p)) {
delete Subclz.prototype[p];
}
}
Subclz.prototype.constructor = Subclz;
for(var p in subproto) {
Subclz.prototype[p] = subproto[p];
}
return Subclz;
};
var Subclz = this.create(methods);
var subproto = Subclz.prototype;
Subclz.prototype = new Superclz();
for(var p in Subclz.prototype) {
if(Subclz.prototype.hasOwnProperty(p)) {
delete Subclz.prototype[p];
}
}
Subclz.prototype.constructor = Subclz;
for(var p in subproto) {
Subclz.prototype[p] = subproto[p];
}
return Subclz;
};
例如,想繼承先前建立的Circle,則可以如下:
var Cylinder = Class.extend(Circle, {
initialize : function(x, y, r, h) {
Circle.call(this, x, y, r);
this.h = h;
},
volumn : function() {
return this.area() * this.h;
}
});
var cylinder = new Cylinder(10, 10, 5, 15);
initialize : function(x, y, r, h) {
Circle.call(this, x, y, r);
this.h = h;
},
volumn : function() {
return this.area() * this.h;
}
});
var cylinder = new Cylinder(10, 10, 5, 15);
以上僅是類別模擬的概念,至於想要模擬到什麼程度,或者是想達到什麼樣的風格,其實有各種的設計方式。