如何让子类覆盖基类的特权方法?
如果不可能,是否有其他方法可以实现我想在下面的简单代码示例中完成的工作?
我无法将基类函数parseXML()转换为public,因为它需要访问私有变量
function BaseClass()
{
var map = {};
// I cannot make this function public BECAUSE it accesses & changes private variables
this.parseXML = function( key, value )
{
alert("BaseClass::parseXML()");
map[key] = value;
}
}
function ChildClass()
{
BaseClass.call(this);
this.parseXML = function( key, value, otherData )
{
alert("ChildClass()::parseXML()");
// How can I call the base class function parseXML()?
//this.parseXML(); // calls this function not the parent function
//MyClass.prototype.doStuff.call
BaseClass.prototype.parseXML.call(this, key, value); // fails
//BaseClass.prototype.parseXML(); // fails
// perform specialised actions here with otherData
}
}
ChildClass.prototype = new BaseClass;
var a = new ChildClass();
a.parseXML();
答案 0 :(得分:16)
function BaseClass() {
var map = {};
this.parseXML = function(key, value) {
alert("BaseClass::parseXML()");
map[key] = value;
}
}
function ChildClass() {
BaseClass.call(this);
var parseXML = this.parseXML;
this.parseXML = function(key, value, otherData) {
alert("ChildClass()::parseXML()");
parseXML.call(this, key, value);
}
}
ChildClass.prototype = new BaseClass;
var a = new ChildClass();
a.parseXML();
基本上,您缓存特权方法(仅在对象上定义),然后在您分配给特权方法名称的新函数内调用它。
然而,更优雅的解决方案是:
function BaseClass() {
this._map = {};
};
BaseClass.prototype.parseXML = function(key, value) {
alert("BaseClass::parseXML()");
this._map[key] = value;
}
function ChildClass() {
BaseClass.call(this);
}
ChildClass.prototype = Object.create(BaseClass.prototype);
ChildClass.prototype.parseXML = function(key, value, otherData) {
alert("ChildClass()::parseXML()");
BaseClass.prototype.parseXML.call(this, key, value);
}
var a = new ChildClass();
a.parseXML();
答案 1 :(得分:-5)
IMO,您需要使用像Ext Js这样的Javascript库来简化此任务。无论如何,以下示例说明了如何编写一些辅助方法。它是我正在开发的未发布的开源项目的一部分。
var JWObject = (function () {
var jwobj = function (){};
jwobj.prototype = { };
return jwobj;
})();
var Prototype = (function () {
var scopeQueue = [ window ];
return {
beginScope: function (namespace) {
var parts = namespace.split('.');
for (var i = 0; i < parts.length; i++) {
var name = parts[i],
parent = this.getScope(),
part = parent[name];
if (part && !part.__namespace) {
throw Error('/* ERROR MESSAGE */');
}
scopeQueue.push(parent[name] = (part || { __namespace: true }));
}
},
endScope: function () {
if (scopeQueue.length > 1) {
scopeQueue.pop();
}
},
getScope: function () {
return scopeQueue.pick();
},
define: function (name, members) {
var scope = this.getScope();
if (scope[name]) {
throw Error('The prototype already exist.');
}
this.extend(members, {
scope: scope,
extend: JWObject,
statics: {}
});
// Getting constructor
var ctor = (members.constructor === Object) ? function() { } : members.constructor;
delete members.constructor;
if (typeof members.extend === 'string') {
members.extend = scope[members.extend];
}
if (!members.extend) {
throw Error('The base class is not specified.');
}
// Deriving from parent type
ctor.prototype = new members.extend();
members.super = members.extend.prototype;
delete members.extend;
members.statics.__class = true;
this.extend(ctor, members.statics, true);
delete members.statics;
// Adding new members
this.extend(ctor.prototype, members, true);
// Adding and returning the created prototype
return scope[name] = ctor;
},
extend: function (expando, members, override) {
for (var m in members) {
if (override || !expando[m]) {
expando[m] = members[m];
}
}
}
};
})();
Prototype.extend(Array.prototype, {
pick: function() {
return this[this.length - 1];
}
});
结果如下:
Prototype.beginScope('Sample');
/**
* Prototype: Sample.Plugin
*/
Prototype.define('Plugin', {
init: function() {
alert('init!');
}
});
Prototype.beginScope('Extension');
/**
* Prototype: Sample.Extensions.Plugin
* Extend : Sample.Plugin
*/
Prototype.define('Foo', {
extend: Sample.Plugin,
init: function() {
this.super.init.call(this);
alert('child: init!');
},
fun: function() {
this.init();
},
statics: {
create: function() {
return new Sample.Extension.Foo();
}
}
});
Prototype.endScope();
Prototype.endScope();
正如您在上面的代码中所看到的,Prototype对象提供了一些定义命名空间(Prototype.beginScope
,Prototype.endScope
和Prototype.getScope
)或定义原型({{1})的功能。 })。
您可以使用像java这样的扩展来继承另一个原型。
Prototype.define
或者按如下方式调用基类方法:
Prototype.define('Foo', {
extend: Sample.Plugin,
此外,您使用上述代码定义的每个原型都将默认从JWObject派生。