(Código Abierto) Ejemplos de OO Prototípico de JavaScript


Bounty Edit:

Estoy buscando código escrito en un paradigma OO prototípico puro (piense en sí mismo). No es una mezcla de OO prototípico y OO clásico. No quiero ver envoltorios genéricos de OO, sino simplemente el uso de técnicas prototípicas de OO y solo técnicas prototípicas de OO.

Pregunta Relacionada con la Referencia:

OO prototípico en JavaScript

En la pregunta anterior me centré principalmente en

Puede ¿escribir OO prototípico así?

¿Necesitamos constructores y lógica de inicialización, Cuáles son las alternativas?

Nueva pregunta:

Básicamente, ¿hay buenos ejemplos de javascript prototípico OO en grandes proyectos de código abierto?

Aclaración:

Tendré que aclarar lo que quiero decir con OO prototípico :

  • No hay clases. Sólo hay Objetos.
  • Hay cero emulación de los conceptos de clases, de nuevo solo hay objetos y objetos de clonación para crear nuevos objetos.

Mayor clarificación del OO prototípico:

La diferencia entre el OO prototípico en JavaScript y la emulación clásica de OO es una zona muy gris. No es que yo valore evitando OO clásico. Quiero aprender OO prototípico de una manera académica en su propio derecho, sin aprender el (probablemente más óptimo) combinación de emulación clásica de OO y OO prototípico.

Esta es la razón por la que "baneo" las clases, solo para que pueda ver estas técnicas de una manera pura y extender mi propio kit de herramientas OO.

Ejemplos:

Ejemplos populares como jQuery no cumplen con el segundo criterio. El objeto jQuery es una gran emulación de clase. Se centra en crear nuevos objetos a partir de una clase en lugar de clonar objetos existentes.

Si realmente conociera algún ejemplo de usar "puro" OO prototípico que te habría mostrado. Creo que el 99% de JavaScript OO está muy influenciado por la emulación clásica.

Puntos de bonificación

Si

  • Está bien comentado / documentado
  • Tiene pruebas unitarias
  • Está en github.

También aceptaré artículos / tutoriales y ejemplos sobre cómo escribir código OO prototípico que vaya más allá de su trivial aplicación hello world.

Author: Community, 2011-06-30

8 answers

No lo encontrarás.

Fui a buscar este tipo de cosas hace un tiempo, y esto es lo que encontré: el Auto Paper Organizando Programas Sin Clases (Mira Citeseer para una versión PDF .) Este artículo discute las mejores prácticas para Self, el lenguaje prototípico original, y la mejor práctica es usar el "modismo de objeto traits", que es hacer que sus objetos hereden de "objetos traits" que contienen solo métodos, y ningún objeto específico datos. En otras palabras, un objeto que es sospechosamente como una clase.

Incluso el lenguaje prototípico original emula las clases.

 9
Author: Sean McMillan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-07-08 20:57:54

¿Has echado un vistazo a OMeta/JS? OMeta es un lenguaje de búsqueda experimental basado en Smalltalk y Self. OMeta / JS es una implementación en javascript usando OO prototípico.

Está bien comentado y documentado con muchos ejemplos. También está en Github.

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

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

Editar: OMeta es el resultado de la tesis doctoral de Alexander Warth.

 4
Author: jsherer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-07-12 13:38:57

No estoy exactamente seguro de lo que está buscando, pero mi marco actual le permite programar de la manera OO como así:

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

    init: function() {
    },

    method: function() {
    },

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

Y luego puedes escribir código como:

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

MyApp.Logger.staticMethod();

No estoy tratando de emular OO clásico aquí. Estoy tratando de hacer una manera conveniente y útil para declarar herencia, mixins, interfaces y conceptos generales de OO para que sea fácil para el desarrollador escribir dicho código OO. Esto también me da la oportunidad de terminar mi componente de carga automática para que ya no te ocupes de las dependencias y puedas hacer compilaciones personalizadas y disfrutar de un desarrollo más rápido gracias a que no necesitas cargar 100 scripts por cada carga de página.

Si quieres aprender conceptos prototípicos de OO, creo que deberías escribir algún tipo de sistema de herencia. Echa un vistazo a Dojo Toolkit o ExtJS. Una buena cosa para recordar es que los sistemas basados en prototipos tuercen y destrozan, son más poderosos que los lenguajes OO basados en clases. En mi opinión, hay no hay una sola forma correcta de escribir código prototípico.

Sin embargo, me temo que la mayoría, si no todos los sistemas de herencia, podrían parecer emulados OO clásico. En mi opinión, mi marco no lo hace, pero entonces ni siquiera está terminado.

 1
Author: Tower,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-06-30 13:54:02

Probablemente JSLint (Crockford es un defensor de la herencia prototípica, pero no he revisado cada centímetro de ella). También se ve más funcional que Orientado a Objetos, pero entonces espero que sea generalmente el caso con el código que realmente abarca la herencia prototípica.

 1
Author: Ryan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-07-07 18:58:27

En mi framework, todo es un objeto o una "interfaz".

Las interfaces definen las funciones comunes (methods / property_gets / property_sets) que los objetos pueden tener.

Se crea una interfaz como esta: var some_interface = GetInterface(constructor, interface_setup, parent_interface..)

Puede especificar cualquier número de parent_interfaces. Así que si interface_A hereda tanto interface_B como interface_C, puede crear interface_A como tal: GetInterface(constructor, interface_setup, interface_B, interface_C);

Si interface_A hereda interface_X y interface_X hereda interface_Y, entonces interface_A tendrá todas las funciones que tanto interface_X como interface_Y tiene.

Las interfaces que no requieren un constructor dejarán el argumento constructor como null. La interface_setup es una función que se ve así:

function(proto){
}

El objeto al que apunta el argumento proto tiene 4 métodos: SetM, ShadowM, SetP, y ShadowP.

Utiliza estos 4 métodos para configurar su interfaz.

Este framework también proporciona instanciación perezosa de interfaces. (en otras palabras, el código de configuración nunca se ejecutará realmente hasta que realmente se necesite primero).

Las limitaciones de este marco requieren al menos apoyo para Object.keys, Object.getOwnPropertyDescriptor y Object.defineProperty. (En otras palabras, funciona en las últimas versiones de FireFox, IE, Chrome, Safari pero no Opera)

Página de prueba2.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>

Página de prueba.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
Author: Pacerier,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-07-12 11:35:27

ExtJS es un excelente ejemplo de JavaScript OO. Implementa una jerarquía de OO realmente sofisticada a nivel empresarial en JavaScript que hace muchas cosas fuera de la caja. Puede ser una lectura desalentadora (la última vez que me registré en 3.X, era más de 1MB de raw, JavaScript sin comprimir), pero te daría un montón de ideas. Puede comenzar por revisando la documentación para obtener una vista de alto nivel.

 0
Author: Mike Thomsen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-06-30 13:47:40

Actualmente estoy usando un modelo de plugin de herencia que intenta combinar el patrón prototípico OO con el patrón de plugin jQuery. Su publicado en detalle en mi respuesta aquí: adjuntar una clase a un objeto jQuery

Nota: no obtener rechazados por la mención de la palabra Class

 0
Author: Mrchief,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:14:28

Aquí hay un ejemplo que muestra la base de la programación OO que está buscando. El mejor ejemplo del mundo real sería probablemente jQuery.

Al aprender JavaScript, debe tener en cuenta que en realidad está más cerca de Scheme que de C o Java en sus raíces. Básicamente es Scheme en la sintaxis de C.

Casi nunca hay un caso en el que deba usar "nuevo" en JavaScript, especialmente si está escribiendo API. Parece como el "nuevo" operador se añadió en porque JavaScript no estaba seguro sobre su marco prototípico. Para la mayoría de nosotros que comenzamos a programar con lenguajes clásicos como C, C++ y Java, esto parece extraño, ya que "nuevo" es generalmente exactamente lo que estamos buscando, porque se traduce fácilmente.

¿Por qué no debería usar "nuevo"? Bueno, debido a la implementación de "nuevo", puede comenzar inadvertidamente a borrar sus datos globales (que recuerde, es todo no en una función en JavaScript). Si por casualidad caes presa de esto, entonces no verá ningún error o notificación, sino que solo verá un comportamiento impredecible en su programa. También, puede o no ser claro en cuanto a lo que "esto" realmente está ligado dentro de su "clase".

El problema de borrar su memoria global sin saberlo ocurre principalmente cuando escribe una función que está destinada a ser llamada con "new" y el usuario no usa "new". Sugiere por qué usarlo en las API puede llevar a usuarios descontentos.

La forma correcta de "clases" orientadas a objetos y la herencia es usar el atributo más poderoso de JavaScript...objeto.

Puede escribir una función para devolver un objeto para establecer una "clase". Cualquier cosa que ponga en este objeto (números, cadenas, métodos, etc.).) son todas las propiedades públicas de su "clase". Cualquier cosa que escribas dentro de tu función que no esté dentro de ese objeto que está siendo devuelto, es privada.

Para heredar de su "clase", simplemente puede inicializar su objeto que regresará a su " base clase " resultado y luego ampliar su funcionalidad.

Las siguientes secciones de código mostrarán cómo construir una clase base con variables privadas y públicas, y los niveles do 2 de herencia.

Objeto base

//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'

Herencia

//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 : Me alertaron de que no había usado el objeto "prototype". Hice esto, para evitar tener que usar el operador "nuevo", como se mencionó en el texto anterior. Para completar, voy a dar un ejemplo usando el objeto prototipo a continuación...

Herencia con el Objeto Prototipo

//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'

Por favor, siéntase libre de preguntarme acerca de cualquiera de este post. Disfrutar.

 0
Author: jyore,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-07-12 10:52:11