Javascript functional inheritance with prototypes

后端 未结 4 1764
心在旅途
心在旅途 2021-02-01 08:58

In Douglas Crockford\'s JavaScript: The Good Parts he recommends that we use functional inheritance. Here\'s an example:

var mammal = function(spec, my         


        
4条回答
  •  甜味超标
    2021-02-01 09:03

    if you want privacy and you dont like protyping you may or may-not like this approach:

    (note.: it uses jQuery.extend)

    var namespace = namespace || {};
    
    // virtual base class
    namespace.base = function (sub, undefined) {
    
        var base = { instance: this };
    
        base.hierarchy = [];
    
        base.fn = {
    
            // check to see if base is of a certain class (must be delegated)
            is: function (constr) {
    
                return (this.hierarchy[this.hierarchy.length - 1] === constr);
            },
    
            // check to see if base extends a certain class (must be delegated)
            inherits: function (constr) {
    
                for (var i = 0; i < this.hierarchy.length; i++) {
    
                    if (this.hierarchy[i] == constr) return true;
                }
                return false;
            },
    
            // extend a base (must be delegated)
            extend: function (sub) {
    
                this.hierarchy.push(sub.instance.constructor);
    
                return $.extend(true, this, sub);
            },
    
            // delegate a function to a certain context
            delegate: function (context, fn) {
    
                return function () { return fn.apply(context, arguments); }
            },
    
            // delegate a collection of functions to a certain context
            delegates: function (context, obj) {
    
                var delegates = {};
    
                for (var fn in obj) {
    
                    delegates[fn] = base.fn.delegate(context, obj[fn]);
                }
    
                return delegates;
            }
        };
    
        base.public = {
            is: base.fn.is,
            inherits: base.fn.inherits
        };
    
        // extend a sub-base
        base.extend = base.fn.delegate(base, base.fn.extend);
    
        return base.extend(sub);
    };
    
    namespace.MyClass = function (params) {
    
        var base = { instance: this };
    
        base.vars = {
            myVar: "sometext"
        }
    
        base.fn = {
            init: function () {
    
                base.vars.myVar = params.myVar;
            },
    
            alertMyVar: function() {
    
                alert(base.vars.myVar);
            }
    
        };
    
        base.public = {
            alertMyVar: base.fn.alertMyVar
        };
    
        base = namespace.base(base);
    
        base.fn.init();
    
        return base.fn.delegates(base,base.public);
    };
    
    newMyClass = new namespace.MyClass({myVar: 'some text to alert'});
    newMyClass.alertMyVar();
    

    the only downside is that because of the privacy scope you can only extend the virtual classes and not the instanceable classes.

    here is an example of how i extend the namespace.base, to bind/unbind/fire custom events.

    // virtual base class for controls
    namespace.controls.base = function (sub) {
    
        var base = { instance: this };
    
        base.keys = {
            unknown: 0,
            backspace: 8,
            tab: 9,
            enter: 13,
            esc: 27,
            arrowUp: 38,
            arrowDown: 40,
            f5: 116
        }
    
        base.fn = {
    
            // bind/unbind custom events. (has to be called via delegate)
            listeners: {
    
                // bind custom event
                bind: function (type, fn) {
    
                    if (fn != undefined) {
    
                        if (this.listeners[type] == undefined) {
                            throw (this.type + ': event type \'' + type + '\' is not supported');
                        }
    
                        this.listeners[type].push(fn);
                    }
    
                    return this;
                },
    
                // unbind custom event
                unbind: function (type) {
    
                    if (this.listeners[type] == undefined) {
                        throw (this.type + ': event type \'' + type + '\' is not supported');
                    }
    
                    this.listeners[type] = [];
    
                    return this;
                },
    
                // fire a custom event
                fire: function (type, e) {
    
                    if (this.listeners[type] == undefined) {
                        throw (this.type + ': event type \'' + type + '\' does not exist');
                    }
    
                    for (var i = 0; i < this.listeners[type].length; i++) {
    
                        this.listeners[type][i](e);
                    }
    
                    if(e != undefined) e.stopPropagation();
                }
            }
        };
    
        base.public = {
            bind: base.fn.listeners.bind,
            unbind: base.fn.listeners.unbind
        };
    
        base = new namespace.base(base);
    
        base.fire = base.fn.delegate(base, base.fn.listeners.fire);
    
        return base.extend(sub);
    };
    

提交回复
热议问题