Функциональное наследование Javascript с прототипами
у Дугласа Крокфорда JavaScript: Хорошие Части он рекомендует использовать функциональное наследование. Вот пример:
var mammal = function(spec, my) {
    var that = {};
    my = my || {};
    // Protected
    my.clearThroat = function() { 
        return "Ahem";
    };
    that.getName = function() {
        return spec.name;
    };
    that.says = function() {
        return my.clearThroat() + ' ' + spec.saying || '';
    };
    return that;
};
var cat = function(spec, my) {
    var that = {};
    my = my || {};
    spec.saying = spec.saying || 'meow';
    that = mammal(spec, my);
    that.purr = function() { 
        return my.clearThroat() + " purr"; 
    };
    that.getName = function() { 
        return that.says() + ' ' + spec.name + ' ' + that.says();
    };
    return that;
};
var kitty = cat({name: "Fluffy"});
главная проблема у меня заключается в том, что каждый раз, когда я делаю mammal или cat интерпретатор JavaScript должен повторно скомпилировать все функции в нем.  То есть вы не можете делиться кодом между экземплярами.
мой вопрос: как сделать этот код более эффективным?  Например, если бы я делал тысячи cat объекты, каков наилучший способ изменить этот шаблон, чтобы воспользоваться 
4 ответов
Ну, вы просто не можете сделать это таким образом, если вы планируете сделать много mammal или cat. Вместо этого сделайте это старомодным способом (прототипом) и наследуйте по свойству. Вы все еще можете делать конструкторы так, как у вас есть выше, но вместо that и my вы используете неявное this и некоторая переменная, представляющая базовый класс (в этом примере, this.mammal).
cat.prototype.purr = function() { return this.mammal.clearThroat() + "purr"; }
Я бы использовал другое имя, чем my для базового доступа и хранить его в this на cat конструктор. В этом примере я использовал mammal но это может быть не лучшим, если вы хотите иметь статический доступ к глобальному 
позвольте мне представить вам классическое наследование, которое никогда не использует prototype. Это плохое упражнение кодирования, но научит вас реальному Классическое Наследование который всегда сравнивается с прототипного наследования:
сделайте custructor:
function Person(name, age){
  this.name = name;
  this.age = age;
  this.sayHello = function(){return "Hello! this is " + this.name;}
}
сделать еще один cunstructor, который наследует от него:
function Student(name, age, grade){
  Person.apply(this, [name, age]);
  this.grade = grade
}
очень удобно! Student вызовов(применяется) Person на себя name и age аргументы заботятся о grade аргументы сами по себе.
теперь давайте сделаем экземпляр Student. 
var pete = new Student('Pete', 7, 1);
из
Если вы хотите конфиденциальности, и вам не нравится protyping вы можете или не может-не нравится этот подход:
(Примечание.: он использует 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();
единственным недостатком является то, что из-за области конфиденциальности вы можете расширять только виртуальные классы, а не экземплярные классы.
вот пример того, как я расширяю пространство имен.база, для привязки/отмены / запуска пользовательских событий.
// 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);
};
для правильного использования наследования на основе JavaScript-prototype вы можете использовать fastClass https://github.com/dotnetwise/Javascript-FastClass
у вас есть проще inheritWith аромат:
  var Mammal = function (spec) {
    this.spec = spec;
}.define({
    clearThroat: function () { return "Ahem" },
    getName: function () {
        return this.spec.name;
    },
    says: function () {
        return this.clearThroat() + ' ' + spec.saying || '';
    }
});
var Cat = Mammal.inheritWith(function (base, baseCtor) {
    return {
        constructor: function(spec) { 
            spec = spec || {};
            baseCtor.call(this, spec); 
        },
        purr: function() {
            return this.clearThroat() + " purr";
        },
        getName: function() {
            return this.says() + ' ' + this.spec.name + this.says();
        }
    }
});
var kitty = new Cat({ name: "Fluffy" });
kitty.purr(); // Ahem purr
kitty.getName(); // Ahem Fluffy Ahem
и если вы очень беспокоитесь о производительности, то у вас есть fastClass аромат:
var Mammal = function (spec) {
    this.spec = spec;
}.define({
    clearThroat: function () { return "Ahem" },
    getName: function () {
        return this.spec.name;
    },
    says: function () {
        return this.clearThroat() + ' ' + spec.saying || '';
    }
});
var Cat = Mammal.fastClass(function (base, baseCtor) {
    return function() {
        this.constructor = function(spec) { 
            spec = spec || {};
            baseCtor.call(this, spec); 
        };
        this.purr = function() {
            return this.clearThroat() + " purr";
        },
        this.getName = function() {
            return this.says() + ' ' + this.spec.name + this.says();
        }
    }
});
var kitty = new Cat({ name: "Fluffy" });
kitty.purr(); // Ahem purr
kitty.getName(); // Ahem Fluffy Ahem
Кстати, Ваш первоначальный код не имеет никакого смысла, но я уважал его буквально.
fastClass утилита:
Function.prototype.fastClass = function (creator) {
    var baseClass = this, ctor = (creator || function () { this.constructor = function () { baseClass.apply(this, arguments); } })(this.prototype, this)
    var derrivedProrotype = new ctor();
    if (!derrivedProrotype.hasOwnProperty("constructor"))
        derrivedProrotype.constructor = function () { baseClass.apply(this, arguments); }
    derrivedProrotype.constructor.prototype = derrivedProrotype;
    return derrivedProrotype.constructor;
};
inheritWith утилиты:
Function.prototype.inheritWith = function (creator, makeConstructorNotEnumerable) {
    var baseCtor = this;
    var creatorResult = creator.call(this, this.prototype, this) || {};
    var Derrived = creatorResult.constructor ||
    function defaultCtor() {
        baseCtor.apply(this, arguments);
    }; 
    var derrivedPrototype;
    function __() { };
    __.prototype = this.prototype;
    Derrived.prototype = derrivedPrototype = new __;
    for (var p in creatorResult)
        derrivedPrototype[p] = creatorResult[p];
    if (makeConstructorNotEnumerable && canDefineNonEnumerableProperty) //this is not default as it carries over some performance overhead
        Object.defineProperty(derrivedPrototype, 'constructor', {
            enumerable: false,
            value: Derrived
        });
    return Derrived;
};
define утилиты:
Function.prototype.define = function (prototype) {
    var extendeePrototype = this.prototype;
    if (prototype)
        for (var p in prototype)
            extendeePrototype[p] = prototype[p];
    return this;
}
[* отказ от ответственности, я являюсь автором пакета с открытым исходным кодом, и имена самих методов могут быть переименованы в будущем` *]
