4

I am playing with classical inheritance in Javascript (in Chrome) following the example of Crockford. I like the parasitic interface but am looking for a bit cleaner way to encapsulate inheritance.

There are a couple additional requirements I am trying to meet:

  1. I'd like to be able to override methods of the parent class with methods in the child class that can call the parent method
  2. I don't want to have to re-declare properties of the parent class in the child class.

This is my parent class Parasite with an extend method that tries to encapsulate inheritance and take advantage of Object.defineProperty:

function Parasite(host) {
    var self = {};
    self.host = host;
    self.swollen = false;

    self.init = function() {
        console.debug('Parasite.init');
        return self;
    };

    self.suck = function() {
        console.log("I'm a parasite who sucks on " + self.host);
        self.swollen = true;
        return self;
    };

    self.extend = function(child) {        
        for(var prop in self) {
            if (prop == 'extend') {     // skip extend
                console.debug('skip extend');
                continue;
            }

            var is_extended = child.hasOwnProperty(prop);
            var is_accessor = typeof self[prop] != "function";

            // inherit prop
            if (! is_extended) {
                child[prop] = self[prop];
                console.debug('prop', prop, 'inherited by child');
            }
            // default: override
            else {
                console.debug('prop', prop, 'overridden by child');
            }

            // For accessors, parent should reference child. This tries to
            // synchronize them on the child's accesor.
            if (is_accessor) {
                var accessor = prop.toString();
                console.warn('define accessor for', accessor, ':', child[accessor]);
                Object.defineProperty(self, accessor, {                      
                    get: function() {
                        var val = child[accessor];
                        console.debug('getting', accessor, val, 'from', child, 'for', self);
                        return val;
                    },
                    set: function(val) { 
                        console.debug('setting', accessor, val, 'from', child, 'for', self);
                        child[accessor] = val;
                    },
                    enumerable: true,
                    configurable: true
                });
            };
        }

        child.parent = self;
        return child;
    };

    self = self.init();
    return self;
}

This is my child class, Tick:

function Tick(host) {
    var self = {};

    self.suck = function() {
        self.parent.suck.call();
        self.engorge();
    };

    self.engorge = function() {
        console.log("And now I'm engorged with blood.");
    };

    self.init = function() {
        var parent = new Parasite(host);
        self = parent.extend(self);
        return self;
    };

    self = self.init();
    return self;
}

You can find my latest fiddle here (warning: infinitely recurses in Firefox, but not in Chrome):

http://jsfiddle.net/SSDgv/23/

The console output illustrates where the accessor issues are occurring.

4

1 回答 1

1

这本身不是我的问题的答案,但这里有一个更简单的实现,似乎可以满足我的要求。它遵循此 Stack Overflow 答案中提出的模式。

function Parasite(host) {
    var self = {};
    self.host = host;
    self.hungry = true;

    self.init = function() {
        console.debug('Parasite.init');
        return self;
    };

    self.suck = function() {
        console.log("I'm a parasite who sucks on " + self.host);        
        self.hungry = false;
        return self;
    };

    self.init();
    return self;
}

function Tick(host) {
    var self = new Parasite(host);
    self.engorged = false;

    var base_suck = self.suck;
    self.suck = function() {
        base_suck();
        self.engorge();
    };

    self.engorge = function() {
        console.log("And now I'm engorged with blood.");
        self.engorged = true;
    };

    self.init = function() {};

    self.init();
    return self;
}

可以在这里找到测试:http: //jsfiddle.net/AvdK2/3/

于 2013-09-16T19:08:32.733 回答