最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Override privileged method of base class - Stack Overflow

programmeradmin2浏览0评论

How can I go about making a child class override a privileged method of a base class?

If its not possible, is there another way to achieve what I am trying to accomplish in the simple code example below?

I cannot convert the baseclass function parseXML() to public because it requires access to private variables

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

How can I go about making a child class override a privileged method of a base class?

If its not possible, is there another way to achieve what I am trying to accomplish in the simple code example below?

I cannot convert the baseclass function parseXML() to public because it requires access to private variables

    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();
Share Improve this question edited Mar 30, 2019 at 18:17 user4639281 asked Nov 7, 2011 at 0:16 sazrsazr 25.9k70 gold badges211 silver badges385 bronze badges 3
  • possible duplicate of Possible to override a base classes privileged function? ... please edit your original question instead. – Felix Kling Commented Nov 7, 2011 at 0:23
  • 2 Suggestion: Don't try to force method visibility into JavaScript. It is not designed to have private and protected methods. Document your code properly. Mark this method as private in the comment. If someone uses the method anyway and therefore breaks his code when he uses your library -> his problem. – Felix Kling Commented Nov 7, 2011 at 0:43
  • possible duplicate of Calling base method using javascript prototype – outis Commented Nov 7, 2011 at 6:24
Add a comment  | 

2 Answers 2

Reset to default 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

Basically you cache the privileged method (which is only defined on the object) and then call it inside the new function you assign to the privileged method name.

However a more elegant solution would be:

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

Also bonus implementation using pd

IMO, you need to use a Javascript library like Ext Js to simplify this task. Anyway, the following example illustrates how you can write some helper methods. It's a part of an unreleased open source project that I'm working on.

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];
    }

});

Here is the result:

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

As you can see in the preceding code, the Prototype object provides some functionality to defining a namespace (Prototype.beginScope, Prototype.endScope and Prototype.getScope) or defining a prototype (Prototype.define).

You can inherit a prototype from another using extend like java.

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

Or call the base class method as follows:

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

Also, every prototype you define with above code will be derived from JWObject by default.

发布评论

评论列表(0)

  1. 暂无评论