Подтвердить что ты не робот

Переопределить функцию базового класса

В Javascript я отчаянно нуждаюсь в том, чтобы дочерний класс переопределял привилегированную функцию базовых классов. Я не уверен, что это можно сделать, но было бы здорово, если бы кто-нибудь мог сказать мне, если это так и как это сделать. Если это невозможно, есть ли другой способ добиться того, что я пытаюсь сделать в примере с простым кодом ниже?

Я не могу преобразовать функцию базового класса parseXML() в общедоступную, поскольку для этого требуется доступ к закрытым переменным

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

Ответ 1

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

Живой пример

Также бонусная реализация с использованием pd

Ответ 2

IMO, вам необходимо использовать Javascript-библиотеку, такую ​​как Ext Js, для упрощения этой задачи. Во всяком случае, следующий пример иллюстрирует, как вы можете написать некоторые вспомогательные методы. Это часть невыпущенного проекта с открытым исходным кодом, над которым я работаю.

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) или определения прототипа (Prototype.define).

Вы можете наследовать прототип из другого, используя расширение, например java.

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

Или вызовите метод базового класса следующим образом:

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

Кроме того, каждый прототип, который вы определяете с помощью вышеприведенного кода, будет выводиться из JWObject по умолчанию.