覆盖基类的特权方法

问题描述 投票:13回答:2

我怎样才能使子类覆盖基类的特权方法?

如果它不可能,还有另一种方法来实现我想在下面的简单代码示例中完成的工作吗?

我无法将基类函数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();
javascript inheritance override
2个回答
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();

Live Example

基本上,您缓存特权方法(仅在对象上定义),然后在分配给特权方法名称的新函数内调用它。

然而,更优雅的解决方案是:

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();

Live Example

还有bonus implementation using pd


-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.beginScopePrototype.endScopePrototype.getScope)或定义原型(Prototype.define)的功能。

您可以使用像java这样的扩展从另一个继承原型。

Prototype.define('Foo', {
    extend: Sample.Plugin,

或者调用基类方法如下:

    init: function() {
        this.super.init.call(this);

此外,您使用上述代码定义的每个原型都将默认从JWObject派生。

© www.soinside.com 2019 - 2024. All rights reserved.