nodejs herencia example es6 ejemplos ecmascript javascript oop class

herencia - ¿Qué técnicas se pueden usar para definir una clase en JavaScript y cuáles son sus concesiones?



static class javascript (19)

Prefiero usar OOP en proyectos a gran escala como el que estoy trabajando en este momento. Necesito crear varias clases en JavaScript pero, si no me equivoco, hay al menos un par de maneras de hacerlo. ¿Cuál sería la sintaxis y por qué se haría de esa manera?

Me gustaría evitar el uso de bibliotecas de terceros, al menos al principio.
Buscando otras respuestas, encontré el artículo Programación orientada a objetos con JavaScript, Parte I: Herencia - Doc. JavaScript que trata sobre la programación orientada a objetos en JavaScript. ¿Hay una mejor manera de hacer la herencia?


Clases de ES2015

En la especificación ES2015, puede usar la sintaxis de clase que es solo azúcar sobre el sistema prototipo.

class Person { constructor(name) { this.name = name; } toString() { return `My name is ${ this.name }.`; } } class Employee extends Person { constructor(name, hours) { super(name); this.hours = hours; } toString() { return `${ super.toString() } I work ${ this.hours } hours.`; } }

Beneficios

El principal beneficio es que a las herramientas de análisis estático les resulta más fácil dirigir esta sintaxis. También es más fácil para otros que vienen de lenguajes basados ​​en clases usar el lenguaje como un políglota.

Advertencias

Tenga cuidado con sus limitaciones actuales. Para lograr propiedades privadas, hay que recurrir al uso de Símbolos o WeakMaps . En futuras versiones, las clases probablemente se expandirán para incluir estas características faltantes.

Apoyo

El soporte del navegador no es muy bueno en este momento (compatible con casi todos, excepto IE), pero puede usar estas funciones ahora con un transpiler como Babel .

Recursos


Aquí está la manera de hacerlo sin usar ninguna biblioteca externa:

// Define a class like this function Person(name, gender){ // Add object properties like this this.name = name; this.gender = gender; } // Add methods like this. All Person objects will be able to invoke this Person.prototype.speak = function(){ alert("Howdy, my name is" + this.name); }; // Instantiate new objects with ''new'' var person = new Person("Bob", "M"); // Invoke methods like this person.speak(); // alerts "Howdy, my name is Bob"

Ahora la respuesta real es mucho más compleja que eso. Por ejemplo, no hay tal cosa como clases en JavaScript. JavaScript utiliza un esquema de herencia basado en prototype .

Además, hay numerosas bibliotecas de JavaScript populares que tienen su propio estilo de aproximación de funcionalidad similar a clase en JavaScript. Usted querrá revisar al menos Prototype y jQuery .

Decidir cuál de estos es el "mejor" es una excelente manera de comenzar una guerra santa en . Si se está embarcando en un proyecto más grande de JavaScript, definitivamente vale la pena aprender una biblioteca popular y hacerlo a su manera. Soy un tipo de prototipo, pero parece inclinarse hacia jQuery.

En la medida en que solo hay "una forma de hacerlo", sin ninguna dependencia de bibliotecas externas, la forma en que escribí es prácticamente la misma.


Basado en el ejemplo de Tríptico, esto podría ser incluso más simple:

// Define a class and instantiate it var ThePerson = new function Person(name, gender) { // Add class data members this.name = name; this.gender = gender; // Add class methods this.hello = function () { alert(''Hello, this is '' + this.name); } }("Bob", "M"); // this instantiates the ''new'' object // Use the object ThePerson.hello(); // alerts "Hello, this is Bob"

Esto solo crea una instancia de un solo objeto, pero sigue siendo útil si desea encapsular un montón de nombres para variables y métodos en una clase. Normalmente no habría argumentos "Bob, M" al constructor, por ejemplo, si los métodos serían llamadas a un sistema con sus propios datos, como una base de datos o una red.

Todavía soy demasiado nuevo con JS para ver por qué esto no usa el prototype .


Código de golf para la answer de @liammclennan.

var Animal = function (args) { return { name: args.name, getName: function () { return this.name; // member access }, callGetName: function () { return this.getName(); // method call } }; }; var cat = Animal({ name: ''tiger'' }); console.log(cat.callGetName());


Clases basadas en objetos con herencia

var baseObject = { // Replication / Constructor function new : function(){ return Object.create(this); }, aProperty : null, aMethod : function(param){ alert("Heres your " + param + "!"); }, } newObject = baseObject.new(); newObject.aProperty = "Hello"; anotherObject = Object.create(baseObject); anotherObject.aProperty = "There"; console.log(newObject.aProperty) // "Hello" console.log(anotherObject.aProperty) // "There" console.log(baseObject.aProperty) // null

Sencillo, dulce, y se hace bien.


Creo que deberías leer Herencia prototípica de Douglas Crockford en JavaScript y Herencia clásica en JavaScript .

Ejemplos de su página:

Function.prototype.method = function (name, func) { this.prototype[name] = func; return this; };

¿Efecto? Te permitirá añadir métodos de forma más elegante:

function Parenizor(value) { this.setValue(value); } Parenizor.method(''setValue'', function (value) { this.value = value; return this; });

También recomiendo sus videos: JavaScript avanzado .

Puede encontrar más videos en su página: http://javascript.crockford.com/ En el libro John Reisig puede encontrar muchos ejemplos del sitio web de Douglas Crockfor.


JavaScript está object-oriented , pero es radicalmente diferente a otros lenguajes OOP como Java, C # o C ++. No trates de entenderlo así. Tire ese viejo conocimiento y comience de nuevo. JavaScript necesita un pensamiento diferente.

Yo sugeriría obtener un buen manual o algo sobre el tema. Yo mismo encontré que los Tutoriales de ExtJS son los mejores para mí, aunque no he usado el marco antes o después de leerlo. Pero sí da una buena explicación sobre qué es qué en el mundo de JavaScript. Lo sentimos, parece que ese contenido ha sido eliminado. Aquí hay un enlace a la copia de archive.org en su lugar. Trabaja hoy :PAG


La forma más sencilla es:

function Foo(a) { var that=this; function privateMethod() { .. } // public methods that.add = function(b) { return a + b; }; that.avg = function(b) { return that.add(b) / 2; // calling another public method }; } var x = new Foo(10); alert(x.add(2)); // 12 alert(x.avg(20)); // 15

La razón de that es que this puede vincularse a otra cosa si le da un método como un controlador de eventos, por lo que guarda el valor durante la creación de instancias y lo usa más adelante.

Edit: definitivamente no es la mejor manera, solo una manera simple. ¡Estoy esperando buenas respuestas también!


La mejor manera de definir una clase en JavaScript es no definir una clase.

Seriamente.

Hay varios sabores diferentes de orientación a objetos, algunos de ellos son:

  • OO basado en clase (introducido por primera vez por Smalltalk)
  • OO basado en prototipo (introducido por primera vez por Self)
  • OO basado en métodos múltiples (introducido por primera vez por CommonLoops, creo)
  • OO basado en predicados (sin idea)

Y probablemente otros que no conozco.

JavaScript implementa prototipos basados ​​en OO. En la OO basada en prototipos, los nuevos objetos se crean al copiar otros objetos (en lugar de crear una instancia de una plantilla de clase) y los métodos viven directamente en los objetos en lugar de en las clases. La herencia se realiza a través de la delegación: si un objeto no tiene un método o propiedad, se busca en su prototipo (s) (es decir, el objeto desde el que se clonó), luego los prototipos del prototipo y así sucesivamente.

En otras palabras: no hay clases.

JavaScript realmente tiene un buen ajuste de ese modelo: constructores. No solo puede crear objetos copiando los existentes, sino que también puede construirlos "de la nada", por así decirlo. Si llama a una función con la new palabra clave, esa función se convierte en un constructor y this palabra clave no apuntará al objeto actual, sino a uno "vacío" creado recientemente. Por lo tanto, puede configurar un objeto de la manera que desee. De esa manera, los constructores de JavaScript pueden asumir uno de los roles de las clases en el OO tradicional basado en clases: servir como plantilla o modelo para nuevos objetos.

Ahora, JavaScript es un lenguaje muy poderoso, por lo que es bastante fácil implementar un sistema OO basado en clases dentro de JavaScript, si así lo desea. Sin embargo, solo debes hacer esto si realmente lo necesitas y no solo porque así lo hace Java.


Las siguientes son las formas de crear objetos en javascript, que he usado hasta ahora

Ejemplo 1:

obj = new Object(); obj.name = ''test''; obj.sayHello = function() { console.log(''Hello ''+ this.name); }

Ejemplo 2:

obj = {}; obj.name = ''test''; obj.sayHello = function() { console.log(''Hello ''+ this.name); } obj.sayHello();

Ejemplo 3:

var obj = function(nameParam) { this.name = nameParam; } obj.prototype.sayHello = function() { console.log(''Hello ''+ this.name); }

Ejemplo 4: Beneficios reales de Object.create (). por favor consulte [este enlace]

var Obj = { init: function(nameParam) { this.name = nameParam; }, sayHello: function() { console.log(''Hello ''+ this.name); } }; var usrObj = Object.create(Obj); // <== one level of inheritance usrObj.init(''Bob''); usrObj.sayHello();

Ejemplo 5 (Crockford''s Object.create personalizado):

Object.build = function(o) { var initArgs = Array.prototype.slice.call(arguments,1) function F() { if((typeof o.init === ''function'') && initArgs.length) { o.init.apply(this,initArgs) } } F.prototype = o return new F() } MY_GLOBAL = {i: 1, nextId: function(){return this.i++}} // For example var userB = { init: function(nameParam) { this.id = MY_GLOBAL.nextId(); this.name = nameParam; }, sayHello: function() { console.log(''Hello ''+ this.name); } }; var bob = Object.build(userB, ''Bob''); // Different from your code bob.sayHello(); Mantener la respuesta actualizada con ES6 / ES2015.

Una clase se define así:

class Person { constructor(strName, numAge) { this.name = strName; this.age = numAge; } toString() { return ''((Class::Person) named '' + this.name + '' & of age '' + this.age + '')''; } } let objPerson = new Person("Bob",33); console.log(objPerson.toString());


Porque no admitiré el plan de fábrica de YUI / Crockford y porque me gusta mantener las cosas independientes y extensibles, esta es mi variante:

function Person(params) { this.name = params.name || defaultnamevalue; this.role = params.role || defaultrolevalue; if(typeof(this.speak)==''undefined'') //guarantees one time prototyping { Person.prototype.speak = function() {/* do whatever */}; } } var Robert = new Person({name:''Bob''});

donde, idealmente, la prueba de tipo está en algo como el primer método prototipado


Prefiero usar {SUPER: SYSTEM} Daniel X. Moore. Esta es una disciplina que proporciona beneficios tales como variables de instancia reales, herencia basada en rasgos, jerarquías de clase y opciones de configuración. El siguiente ejemplo ilustra el uso de verdaderas variables de instancia, que creo que es la mayor ventaja. Si no necesita variables de instancia y está satisfecho con solo las variables públicas o privadas, entonces probablemente haya sistemas más simples.

function Person(I) { I = I || {}; Object.reverseMerge(I, { name: "McLovin", age: 25, homeState: "Hawaii" }); return { introduce: function() { return "Hi I''m " + I.name + " and I''m " + I.age; } }; } var fogel = Person({ age: "old enough" }); fogel.introduce(); // "Hi I''m McLovin and I''m old enough"

Wow, eso no es realmente muy útil por sí mismo, pero echa un vistazo a la adición de una subclase:

function Ninja(I) { I = I || {}; Object.reverseMerge(I, { belt: "black" }); // Ninja is a subclass of person return Object.extend(Person(I), { greetChallenger: function() { return "In all my " + I.age + " years as a ninja, I''ve never met a challenger as worthy as you..."; } }); } var resig = Ninja({name: "John Resig"}); resig.introduce(); // "Hi I''m John Resig and I''m 25"

Otra ventaja es la capacidad de tener módulos y herencia basada en rasgos.

// The Bindable module function Bindable() { var eventCallbacks = {}; return { bind: function(event, callback) { eventCallbacks[event] = eventCallbacks[event] || []; eventCallbacks[event].push(callback); }, trigger: function(event) { var callbacks = eventCallbacks[event]; if(callbacks && callbacks.length) { var self = this; callbacks.forEach(function(callback) { callback(self); }); } }, }; }

Un ejemplo de tener la clase de persona incluye el módulo enlazable.

function Person(I) { I = I || {}; Object.reverseMerge(I, { name: "McLovin", age: 25, homeState: "Hawaii" }); var self = { introduce: function() { return "Hi I''m " + I.name + " and I''m " + I.age; } }; // Including the Bindable module Object.extend(self, Bindable()); return self; } var person = Person(); person.bind("eat", function() { alert(person.introduce() + " and I''m eating!"); }); person.trigger("eat"); // Blasts the alert!

Divulgación: Soy Daniel X. Moore y este es mi {SUPER: SYSTEM} . Es la mejor manera de definir una clase en JavaScript.


Probablemente quieras crear un tipo usando el patrón de plegado:

// Here is the constructor section. var myType = function () { var N = {}, // Enclosed (private) members are here. X = this; // Exposed (public) members are here. (function ENCLOSED_FIELDS() { N.toggle = false; N.text = ''''; }()); (function EXPOSED_FIELDS() { X.count = 0; X.numbers = [1, 2, 3]; }()); // The properties below have access to the enclosed fields. // Careful with functions exposed within the closure of the // constructor, each new instance will have it''s own copy. (function EXPOSED_PROPERTIES_WITHIN_CONSTRUCTOR() { Object.defineProperty(X, ''toggle'', { get: function () { var before = N.toggle; N.toggle = !N.toggle; return before; } }); Object.defineProperty(X, ''text'', { get: function () { return N.text; }, set: function (value) { N.text = value; } }); }()); }; // Here is the prototype section. (function PROTOTYPE() { var P = myType.prototype; (function EXPOSED_PROPERTIES_WITHIN_PROTOTYPE() { Object.defineProperty(P, ''numberLength'', { get: function () { return this.numbers.length; } }); }()); (function EXPOSED_METHODS() { P.incrementNumbersByCount = function () { var i; for (i = 0; i < this.numbers.length; i++) { this.numbers[i] += this.count; } }; P.tweak = function () { if (this.toggle) { this.count++; } this.text = ''tweaked''; }; }()); }());

Ese código te dará un tipo llamado myType . Tendrá campos privados internos llamados alternar y enviar texto . También tendrá estos miembros expuestos: los campos cuentan y los números ; las propiedades toggle , text y numberLength ; Los métodos incrementNumbersByCount y tweak .

El patrón de plegado está completamente detallado aquí: Javascript patrón de plegado


Si va por algo simple, puede evitar por completo la palabra clave "nueva" y simplemente usar los métodos de fábrica. Prefiero esto, a veces, porque me gusta usar JSON para crear objetos.

function getSomeObj(var1, var2){ var obj = { instancevar1: var1, instancevar2: var2, someMethod: function(param) { //stuff; } }; return obj; } var myobj = getSomeObj("var1", "var2"); myobj.someMethod("bla");

Sin embargo, no estoy seguro de cuál es el impacto de rendimiento para objetos grandes.


Una base

function Base(kind) { this.kind = kind; }

Una clase

// Shared var var _greeting; (function _init() { Class.prototype = new Base(); Class.prototype.constructor = Class; Class.prototype.log = function() { _log.apply(this, arguments); } _greeting = "Good afternoon!"; })(); function Class(name, kind) { Base.call(this, kind); this.name = name; } // Shared function function _log() { console.log(_greeting + " Me name is " + this.name + " and I''m a " + this.kind); }

Acción

var c = new Class("Joe", "Object"); c.log(); // "Good afternoon! Me name is Joe and I''m a Object"


MooTools (My Object Oriented Tools) se centra en la idea de las classes . Incluso se puede ampliar e implementar con herencia.

Cuando se domina, lo convierte en un potente y ridículamente reutilizable javascript.


//new way using this and new function Persons(name) { this.name = name; this.greeting = function() { alert(''Hi! I/'m '' + this.name + ''.''); }; } var gee=new Persons("gee"); gee.greeting(); var gray=new Persons("gray"); gray.greeting(); //old way function createPerson(name){ var obj={}; obj.name=name; obj.greeting = function(){ console.log("hello I am"+obj.name); }; return obj; } var gita=createPerson(''Gita''); gita.greeting();


var Animal = function(options) { var name = options.name; var animal = {}; animal.getName = function() { return name; }; var somePrivateMethod = function() { }; return animal; }; // usage var cat = Animal({name: ''tiger''});


var Student = (function () { function Student(firstname, lastname) { this.firstname = firstname; this.lastname = lastname; this.fullname = firstname + " " + lastname; } Student.prototype.sayMyName = function () { return this.fullname; }; return Student; }()); var user = new Student("Jane", "User"); var user_fullname = user.sayMyName();

Esa es la forma en que TypeScript compila la clase con el constructor a JavaScript.