(Открытый исходный код) Примеры JavaScript Prototypical OO - PullRequest
28 голосов
/ 30 июня 2011

Bounty Edit:

Я ищу код, написанный в pure прототипной OO-парадигме (подумайте Self).Не смесь прототипного ОО и классического ОО.Я не хочу видеть универсальные OO-оболочки, а просто использование прототипных OO-технологий и только прототипических OO-методов.

Справочный вопрос:

Прототип ОО в JavaScript

В вышеупомянутом вопросе я в основном сосредоточился на

Можно ли написать прототип ОО, как это?

Нужно ли намконструкторы и логика инициализации. Какие есть альтернативы?

Новый вопрос:

В принципе есть ли хорошие примеры прототипов javascript OOв больших проектах с открытым исходным кодом?

Пояснение:

Мне нужно уточнить, что я имею в виду с прототипом OO :

  • Нет классов.Есть только объекты.
  • Существует ноль эмуляция концепций классов, снова есть только объекты и объекты клонирования для создания новых объектов.

Дальнейшее разъяснение прототипного ОО:

Разница между прототипным ОО в JavaScript и классической эмуляцией ОО - очень серая область .Дело не в том, что я значение избегаю классического ОО.Я хочу изучать прототипные ОО в академической манере самостоятельно, не изучая (возможно, более оптимальную) комбинацию классической эмуляции ОО и прототипных ОО.

Вот почему я "запрещаю" занятия, просто чтобыЯ могу увидеть эти методы в чистом виде и расширить свой собственный набор инструментов OO.

Примеры:

Популярные примеры, такие как jQuery, не соответствуют вторым критериям.Объект jQuery - это эмуляция большого класса.Он фокусируется на создании новых объектов из класса, а не на клонировании существующих объектов.

Если бы я действительно знал какой-либо пример использования "чистого" прототипа ОО, я бы показал вам.Я считаю, что на 99% JavaScript OO слишком сильно влияет классическая эмуляция.

Бонусные баллы

Если

  • Это хорошо документировано / задокументировано
  • Имеет модульные тесты
  • На github.

Я также приму статьи / учебные пособия и примеры о том, как написать прототипный OO-код, который выходит за рамки вашего простого приветствиямировое приложение.

Ответы [ 8 ]

9 голосов
/ 09 июля 2011

Вы его не найдете.

Я давно искал подобные вещи, и вот что я нашел: Self Paper Организация программ без классов (посмотрите на Citeseer для PDF версия .) В этой статье обсуждаются лучшие практики для Self , исходного языка-прототипа, и лучшая практика заключается в использовании «идиомы объекта признаков», которая заключается в том, чтобы ваши объекты наследовали объекты признаков », которые содержат только методы и не содержат специфических для объекта данных. Другими словами, объект, который подозрительно похож на класс.

Даже оригинальный язык прототипа эмулирует классы.

4 голосов
/ 12 июля 2011

Вы смотрели на OMeta / JS?OMeta - это экспериментальный язык сопоставления образцов, основанный на Smalltalk и Self.OMeta / JS - это реализация в javascript, использующая прототип OO.

Это хорошо прокомментировано и задокументировано со многими примерами.Это также на Github.

http://tinlizzie.org/ometa-js/

https://github.com/alexwarth/ometa-js

Редактировать: OMeta является результатом докторской диссертации Александра Варт.

1 голос
/ 12 июля 2011

В моей структуре все является объектом или "интерфейсом".

Интерфейсы определяют общие функции (методы / property_gets / property_sets), которые могут иметь объекты.

Вы создаете интерфейскак это: var some_interface = GetInterface(constructor, interface_setup, parent_interface..)

Вы можете указать любое количество parent_interfaces.Поэтому, если interface_A наследует interface_B и interface_C, вы можете создать interface_A следующим образом: GetInterface(constructor, interface_setup, interface_B, interface_C);

Если interface_A наследует interface_X, а interface_X наследует interface_Y, тогда interface_A будет иметь все функции, которые есть у interface_X и interface_Y.

Интерфейсы, которые не требуют конструктора, оставят аргумент конструктора как нулевой.Interface_setup - это функция, которая выглядит следующим образом:

function(proto){
}

Объект, на который указывает аргумент proto , имеет 4 метода: SetM, ShadowM, SetP иShadowP.

Эти 4 метода используются для настройки вашего интерфейса.

Эта структура также обеспечивает ленивую реализацию интерфейсов.(другими словами, код установки фактически никогда не будет выполняться до тех пор, пока он в действительности не понадобится).

Ограничения этой платформы требуют как минимум поддержки Object.keys, Object.getOwnPropertyDescriptor и Object.defineProperty.(Другими словами, он работает в последних версиях FireFox, IE, Chrome, Safari, но не Opera)

TestPage2.html:

<!doctype html>
<script src="js.js"></script>
<script>
var human = GetInterface(function(){
},function(proto){
    //alert("trace: initing human");
    proto.$SetM("Sleep",function(){
        alert(this.Name+" is sleeping");
    });
    proto.$SetP("Name",function(){
        return this._name;
    },function(value){
        this._name=value;
    });
});

var female = GetInterface(function(){
},function(proto){
    //alert("trace: initing female");
    proto.$SetM("Dance",function(){
        alert(this.Name+" is dancing");
    });
},human);

var male = GetInterface(function(){
},function(proto){
    //alert("trace: initing male");
    proto.$SetM("Fight",function(){
        alert(this.Name+" is fighting");
    });
    proto.$ShadowP("Name",function(parent_get){
        return "Mr. "+parent_get();
    },function(parent_set,value){
        parent_set(value);
    });
},human);

var child = GetInterface(function(){
},function(proto){
    //alert("trace: initing child");
    proto.$SetM("Play",function(){
        alert(this.Name+" is playing");
    });
},human);

var adult = GetInterface(function(){
},function(proto){
    //alert("trace: initing adult");
    proto.$SetM("Work",function(){
        alert(this.Name+" is working");
    });
},human);

var mammal = GetInterface(function(){
},function(proto){
    //alert("trace: initing mammal");
    proto.$SetM("DoMammalStuff",function(){
        alert("doing mammal stuff");
    });
});


var john=new male();
john.Name="john";
john.Sleep();

var mary=new female();
mary.$IsA(child);
mary.$IsA(mammal);
mary.$Setup(function(proto){
    proto.$ShadowP("Name",function(parent_get){
        return "Miss "+parent_get.call(this);
    },function(parent_set,value){
        parent_set.call(this,value);
    });
});
mary.Name="mary";
mary.Play();
</script>

TestPage.html:

 <!doctype html>
<script src="js.js"></script>
<script>
var human_interface = GetInterface(function(){
},function(proto){
    alert("trace: initing human");
    proto.$SetM("Sleep",function(){
        alert(this.Name+" is sleeping");
    });
    proto.$SetP("Name",function(){
        return this._name;
    },function(value){
        this._name=value;
    });
});

var female_interface = GetInterface(function(){
},function(proto){
    alert("trace: initing female");
    proto.$SetM("Dance",function(){
        alert(this.Name+" is dancing");
    });
},human_interface);

var male_interface = GetInterface(function(){
},function(proto){
    alert("trace: initing male");
    proto.$SetM("Fight",function(){
        alert(this.Name+" is fighting");
    });
},human_interface);

var child_interface = GetInterface(function(){
},function(proto){
    alert("trace: initing child");
    proto.$SetM("Play",function(){
        alert(this.Name+" is playing");
    });
},human_interface);

var adult_interface = GetInterface(function(){
},function(proto){
    alert("trace: initing adult");
    proto.$SetM("Work",function(){
        alert(this.Name+" is working");
    });
},human_interface);

var mammal_interface = GetInterface(function(){
},function(proto){
    alert("trace: initing mammal");
    proto.$SetM("DoMammalStuff",function(){
        alert("doing mammal stuff");
    });
});

var john={};
john.$IsA(adult_interface);
//the above 2 lines are equal to simply doing:
//var john=new adult_interface();
//you can think of it as a shortcut
john.$IsA(mammal_interface);
john.DoMammalStuff();
john.Name="john";
john.Sleep();

var mary=new female_interface();
mary.$IsA(child_interface);
mary.$IsA(mammal_interface);
mary.DoMammalStuff();
mary.Name="mary";
mary.Play();
mary.Dance();
</script>

Js.js:

"use strict";
var GetInterface;
(function(){
    //================================================================================//
    //(constructor:Function, setup:Function?, parent_interfaces:Function..):Function
    GetInterface = function (constructor, setup) {
        var parent_classes = GetParray(arguments, 2);
        var output = function () {
            output.$Init();
            for (var x = parent_classes.length - 1; x >= 0; --x) {
                parent_classes[x](this);
            }
            if(constructor===null){
                constructor.apply(this, arguments);
            }
        };
        output.$Init = Mize(function () {
            var output_proto = output.prototype;
            parent_classes.forEach(function (parent_class) {
                parent_class.$Init();
                Infect(output_proto, parent_class.prototype);
            });
            init_proto(output_proto,setup);
            if(setup!==undefined){
                setup(output_proto);
            }
        });
        return output;
    };
    var init_proto=function(proto){
        $defineProperty(proto, "$SetM", { value: set_m, writable: true, configurable: true });
        $defineProperty(proto, "$ShadowM", { value: shadow_m, writable: true, configurable: true });
        $defineProperty(proto, "$SetP", { value: set_p, writable: true, configurable: true });
        $defineProperty(proto, "$ShadowP", { value: shadow_p, writable: true, configurable: true });
    };
    var set_m = function (method_name, method) {
        this[method_name] = method;
    };
    var set_p = function (property_name, getter, setter) {
        $defineProperty(this, property_name, { get: getter, set: setter, enumerable: true, configurable: true });
    };
    var shadow_m = function (method_name, supplied_method) {
        var old_method = this[method_name];
        this[method_name] = function () {
            var args = GetParray(arguments);
            args.unshift(old_method.bind(this));
            supplied_method.apply(this, args);
        };
    };
    var shadow_p = function (property_name, getter, setter) {
        var old_descriptor = $getOwnPropertyDescriptor(this, property_name);
        var old_get = old_descriptor.get;
        var old_set = old_descriptor.set;
        $defineProperty(this, property_name, { get: function () {
            return getter.call(this, old_get.bind(this));
        }, set: function (value) {
            setter.call(this, old_set.bind(this), value);
        }, enumerable: true, configurable: true
        });
    };
    var $slice=Array.prototype.slice;
    var $defineProperty=Object.defineProperty;
    var $getOwnPropertyDescriptor=Object.getOwnPropertyDescriptor;
    if($defineProperty===undefined){
        throw "Object.defineProperty, Object.getOwnPropertyDescriptor, Object.keys are required";
    }
    //================================================================================//
    //(victim:Object, disease:Object):void
    var Infect=function (victim, disease, excludes) {
        var keys=Object.keys(disease);
        if(excludes!==undefined){
            excludes.forEach(function(exclude){
                ForEach(keys,function(key,x){
                    if(key===exclude){
                        keys.splice(x,1);
                        return false;
                    }
                });
            });
        }
        keys.forEach(function(key){
            $defineProperty(victim, key, $getOwnPropertyDescriptor(disease, key));
        });
    };
    //================================================================================//
    //(args:Object # arguments object #, start_index:int?):Array
    var GetParray = function (args, start_index) {
        if (start_index === undefined) {
            start_index = 0;
        }
        return $slice.call(args, start_index);
    };
    //================================================================================//
    //(array:Array, f:Function(item:Object|null, index:pint):boolean?):Object
    var ForEach=function(array,f){
        for (var x = 0, xx = array.length, last_index=xx-1; x < xx; ++x) {
            var result = f(array[x], x, last_index);
            if (result !== undefined) {
                return result;
            }
        }
    };
    //================================================================================//
    //provides memoization.
    //(f:Function, arity_fixed:boolean?true):Function
    //caching is done according to the inputs. the results of calling function(undefined) and function() are cached differently.
    //if arity is fixed, optimizations can be done
    var Mize=function(f, arity_fixed) {
        if (arity_fixed === undefined) {
            arity_fixed = true;
        }
        var used; //for 0 arg
        var result; //for 0 arg
        var results; //for >0 args
        var used_params; //for 1 arg
        var used_param_sets; //for >1 args
        var f_length = f.length;
        var use_generic = !arity_fixed || f_length > 3;
        if (use_generic) { //if `f_length` <= 3, it will be optimized (i.e. not using generic function)
            results = [];
            used_param_sets = [];
            return function () {
                var params = GetParray(arguments);
                var result_found = false;
                var result = ForEach(used_param_sets,function (used_param_set, x) {
                    if (used_param_set.length === params.length) {
                        var params_match = true;
                        ForEach(params,function (param, y) {
                            if (used_param_set[y] !== param) {
                                params_match = false;
                                return false;
                            }
                        });
                        if (params_match) {
                            result_found = true;
                            return results[x];
                        }
                    }
                });
                if (!result_found) {
                    used_param_sets.push(params);
                    result = f.apply(null, params);
                    results.push(result);
                }
                return result;
            };
        }
        if (f_length === 0) {
            used = false;
            return function () {
                if (!used) {
                    result = f();
                    used = true;
                }
                return result;
            };
        }
        if (f_length === 1) {
            used_params = [];
        } else {
            used_param_sets = [];
        }
        results = [];
        switch (f_length) {
            case 1:
                return function (arg) {
                    var result_found = false;
                    var result = ForEach(used_params,function (used_param, x) {
                        if (arg === used_param) {
                            result_found = true;
                            return results[x];
                        }
                    });
                    if (!result_found) {
                        used_params.push(arg);
                        result = f(arg);
                        results.push(result);
                    }
                    return result;
                };
                break;
            case 2:
                return function (arg1, arg2) {
                    var result_found = false;
                    var result = ForEach(used_param_sets,function (used_param_set, x) {
                        if (arg1 === used_param_set[0] && arg2 === used_param_set[1]) {
                            result_found = true;
                            return results[x];
                        }
                    });
                    if (!result_found) {
                        used_param_sets.push([arg1, arg2]);
                        result = f(arg1, arg2);
                        results.push(result);
                    }
                    return result;
                };
                break;
            case 3:
                return function (arg1, arg2, arg3) {
                    var result_found = false;
                    var result = ForEach(used_param_sets,function (used_param_set, x) {
                        if (arg1 === used_param_set[0] && arg2 === used_param_set[1] && arg3 === used_param_set[2]) {
                            result_found = true;
                            return results[x];
                        }
                    });
                    if (!result_found) {
                        used_param_sets.push([arg1, arg2, arg3]);
                        result = f(arg1, arg2, arg3);
                        results.push(result);
                    }
                    return result;
                };
                break;
            default:
                throw "Invalid `f_length`: " + f_length;
        }
    };
    //================================================================================//
    Object.prototype.$Setup=function(setup){
        setup(Object.getPrototypeOf(this));
    };
    //================================================================================//
    Object.prototype.$IsA=function(_interface){
        var excludes=GetParray(arguments,1);
        if(this.$SetM===undefined){
            this.$SetM=set_m;
            this.$SetP=set_p;
            this.$ShadowM=shadow_m;
            this.$ShadowP=shadow_p;
        }
        _interface.$Init();
        /*var this_proto={};
        init_proto(this_proto);
        Infect(this_proto,Object.getPrototypeOf(this));
        this.__proto__=this_proto;*/
        Infect(Object.getPrototypeOf(this),_interface.prototype,excludes);
    };
    //================================================================================//
})();
1 голос
/ 07 июля 2011

Вероятно JSLint (Крокфорд является сторонником прототипического наследования, но я не прочесывал каждый его дюйм). Он также выглядит более функциональным, чем объектно-ориентированный, но тогда я ожидаю, что это обычно происходит с кодом, который действительно охватывает прототипное наследование.

1 голос
/ 30 июня 2011

Я не совсем уверен, что вы ищете, но мой текущий фреймворк позволяет вам программировать в ОО-стиле следующим образом:

Cin.define({
    name: 'MyApp.Logger',
    extends: 'Cin.Component',
    implements: ['MyApp.ILogger'],
    mixes: {
        SomeMixin: 'MyApp.SomeMixin'
    },

    init: function() {
    },

    method: function() {
    },

    statics: {
        staticMethod: function() {}
    }
});

И тогда вы можете написать код вроде:

var instance = new MyApp.Logger();
instance.method();

MyApp.Logger.staticMethod();

Я не пытаюсь подражать классическому ОО здесь.Я пытаюсь найти удобный и полезный способ декларировать наследование, миксины, интерфейсы и общие концепции ОО, чтобы разработчику было легко писать такой ОО-код.Это также дает мне возможность завершить мой компонент автозагрузки, так что вы больше не заботитесь о зависимостях, и вы можете создавать собственные сборки и получать удовольствие от более быстрой разработки благодаря тому, что нет необходимости загружать 100 скриптов на каждую загрузку страницы.

Если вы хотите изучить прототипные концепции ОО, я думаю, что вы должны написать какую-то систему наследования.Взгляните на Dojo Toolkit или ExtJS .Хорошо помнить, что системы на основе прототипов крутятся и деформируются, они более мощные, чем ОО-языки на основе классов.На мой взгляд, не существует единственно правильного способа написания прототипа кода.

Боюсь, что большинство, если не все системы наследования, могут выглядеть так, будто они эмулируют классическую ОО.На мой взгляд, мой фреймворк не работает, но тогда он даже не закончен.

0 голосов
/ 12 июля 2011

В настоящее время я использую модель плагина наследования, которая пытается объединить прототип шаблона OO с шаблоном плагина jQuery. Подробно опубликовано в моем ответе здесь: присоединение класса к объекту jQuery

Примечание: Не отвлекайтесь при упоминании слова Class

0 голосов
/ 12 июля 2011

Вот пример, показывающий основы программирования ОО, которое вы ищете.Лучшим примером в реальном мире, вероятно, был бы jQuery.

При изучении JavaScript вы должны помнить, что он на самом деле ближе к Scheme, чем к его корням C или Java.По сути, это схема в синтаксисе Си.

Практически никогда не следует использовать «новое» в JavaScript, особенно если вы пишете API.Похоже, что оператор "new" был добавлен, потому что JavaScript не был уверен в своей прототипной структуре.Для большинства из нас, кто начинает программирование с классических языков, таких как C, C ++ и Java, это кажется странным, поскольку «новое», как правило, именно то, что мы ищем, потому что оно легко переводится.

Почему не следуетт я использую "новый", спросите вы?Что ж, благодаря реализации «new», вы можете непреднамеренно начать уничтожение ваших глобальных данных (помните, что все это не в функции в JavaScript).Если вам случится стать жертвой этого, то вы не увидите никаких ошибок или уведомлений, а увидите только непредсказуемое поведение в вашей программе.Кроме того, может быть, а может и не быть ясно, с чем на самом деле связано это «this» внутри вашего «класса».

Стирание вашей глобальной памяти, даже не зная, что проблема возникает в основном, когда вы пишете функцию, котораяпредназначен для вызова с «новым», и пользователь не использует «новый».Подсказки, почему использование его в API может привести к несчастью пользователей.

Правильный путь к объектно-ориентированным "классам" и наследованию - использовать самый мощный атрибут JavaScript ... объект.

Вы можетенаписать функцию для возврата объекта для создания «класса».Все, что вы помещаете в этот объект (числа, строки, методы и т. Д.), Является общедоступными свойствами вашего «класса».Все, что вы пишете в своей функции и не находится внутри возвращаемого объекта, является частным.

Чтобы унаследовать от вашего "класса", вы можете просто инициализировать ваш объект, который вы будете возвращать в свою "базу".class "result, а затем расширяют его функциональные возможности.

В следующих разделах кода будет показано, как создать базовый класс с закрытыми и открытыми переменными, а также с двумя уровнями наследования.

Базовый объект

//Base Object
var Animal = function(spec) {

    //This is our output object
    //Everything provided from 'spec' and
    //everything not addded to 'that' will
    //be 'private'. Everything added to
    //'that' is 'public'.
    var that = {};

    //Private Methods
    function extend(obj1,obj2) {
        for(var key in obj2) {
            obj1[key] = obj2[key];
        }
    }

    //Private Variables
    var defaults = {
        name : 'Default Name',
        food : 'Default Food',
        saying : 'Default Saying',
    }

    extend(defaults,spec);

    //Public Methods
    that.name = function() {
        return defaults.name;
    }

    that.eats = function() {
        if(typeof(defaults.food) === 'string') {
            return defaults.food;
        } else if(typeof(defaults.food) === 'object') {
            return defaults.food.join(', ');
        }
    }

    that.says = function() {
        return defaults.saying;
    }

    return that;
}

var myAnimal = Animal();       //Create a new instance
alert(myAnimal.name());        //Alerts 'Default Name'
alert(myAnimal.eats());        //Alerts 'Default Food'
alert(myAnimal.says());        //Alerts 'Default Saying'
alert(myAnimal.saying);        //Alerts 'undefined'
//alert(myAnimal.extend());    //Has No Method Error

var myAnimal2 = Animal({       //Create a new instance using a spec
    name : 'Mike',
    food : ['Chicken','Duck'],
    saying : 'Rawr',
});    
alert(myAnimal2.name());        //Alerts 'Mike'
alert(myAnimal2.eats());        //Alerts 'Chicken, Duck'
alert(myAnimal2.says());        //Alerts 'Rawr'

Наследование

//Inheritance Object
var Mammal = function(spec) {

    //Private Methods

    //Have to redefine this since
    //I decided to use this as an
    //example of a private method
    function extend(obj1,obj2) {
        for(var key in obj2) {
            obj1[key] = obj2[key];
        }
    }

    //Private Variables
    //New list of defaults
    var defaults = {
        name : 'Mammal',
        attributes : ['fur'],
    }

    extend(defaults,spec);

    //Inherrit from our Animal Object
    //Use Mammal defaults
    var that = Animal(defaults);


    that.attributes = function() {
        if(typeof(defaults.attributes) === 'string') {
            return defaults.attributes;
        } else if(typeof(defaults.attributes) === 'object') {
            return defaults.attributes.join(', ');
        } else {
            return false;
        }
    }

    return that;
}

//Second-Level Inheritance
var Cat = function(spec) {

    //Private Methods

    //Have to redefine this since
    //I decided to use this as an
    //example of a private method
    function extend(obj1,obj2) {
        for(var key in obj2) {
            obj1[key] = obj2[key];
        }
    }

    //Private Variables
    //New list of defaults
    var defaults = {
        name : 'Cat',
        saying : 'Meow',
        food : ['fish','birds','frogs','MeowMix'],
        fur_color : 'Default Fur Color',
        attributes : ['fur','claws','crazy eyes','long tail'],
    }

    extend(defaults,spec);

    //Inherrit from our Mammal Object
    //We use our defaults for the cat
    var that = Mammal(defaults);

    that.fur_color = function() {
        return defaults.fur_color; 
    }

    that.purr = function(n) {
        var str = '';

        for(var i=0;i<n;i++) {
            if(i === 0) {
                str = 'p-';
            } else if(i === n-1) {
                str += 'r';
            } else {
                str += 'r-';
            }
        }

        return str
    };

    return that;
}


var myMammal = Mammal();
alert(myMammal.name());        //Alerts Mammal
alert(myMammal.attributes());  //Alerts 'fur'

var myCat = Cat();
alert(myCat.name());            //Alerts Cat
alert(myCat.says());            //Alerts Meow

var toonces = Cat({
    name : 'Toonces the Driving Cat',
    food : ['Whiskas','ham'],
    saying : 'Meeeooooowww',
    fur_color : 'Black',
    attributes : [ 
        'Can Drive a Car', 'Claws',
        'fur','crazy eyes','long tail',
        'Steals Hub Caps',
    ],
});

alert(toonces.name());            //Alerts 'Toonces the Driving Cat'
alert(toonces.says());            //Alerts 'Meeooooowww'
alert(toonces.eats());            //Alerts 'Whiskas, ham'
alert(toonces.fur_color());       //Alerts 'Black'
alert(toonces.attributes());      //Alerts 'Can Drive a Car, Claws,
                                  //fur, crazy eyes, long tail,
                                  // Steals Hub Caps',
alert(toonces.purr(5));           //Alerts 'p-r-r-r-r'

EDIT : меня предупредили, что я не использовал "прототип""объект.Я сделал это, чтобы не пришлось использовать оператор «new», как упомянуто в тексте выше.Для полноты приведу пример использования объекта-прототипа ниже ...

Наследование с объектом-прототипом

//Building a class to use the prototype object
var Dog = function(spec) {

var that = this;

//Private Methods

    //Have to redefine this since
    //I decided to use this as an
    //example of a private method
    function extend(obj1,obj2) {
        for(var key in obj2) {
            obj1[key] = obj2[key];
        }
    }

    //Private Variables
    //New list of defaults
    var defaults = {
        name : 'Dog',
        saying : 'Woof',
        food : ['bacon'],
        fur_color : 'Default Fur Color',
        attributes : ['fur','Barks at Mailman'],
    }


    //Attach the properties of a Mammal to "self"
    this.self = new Mammal(defaults);

    //Add a function to get the name
    this.getName = function() {
        return that.self.name();
    }
}

//Extend the prototype
Dog.prototype.growl = "grrrrrrr";

//Make a new dog...HAVE TO CALL NEW HERE OR ELSE BAD THINGS CAN HAPPEN
d= new Dog();

alert(d.growl);            //Alerts 'grrrrrrr'
alert(d.getName());        //Alerts 'Dog'
alert(d.self.says());      //Alerts 'Woof'

Пожалуйста, не стесняйтесь спрашивать меня о любыхэтого поста.Наслаждайтесь.

0 голосов
/ 30 июня 2011

ExtJS является отличным примером JavaScript OO. Он реализует действительно сложную OO-иерархию корпоративного уровня в JavaScript, которая делает многое из коробки. Это может быть сложное чтение (в последний раз я проверял в 3.X, это было более 1 МБ необработанного, несжатого JavaScript), но это дало бы вам много идей Вы можете начать с просмотра документации , чтобы получить представление высокого уровня.

...