procedimientos primera orientado objetos herencia funciones es6 clases clase javascript oop

javascript - primera - jquery orientado a objetos



¿Cómo heredar de una clase en javascript? (14)

Para aquellos que llegan a esta página en 2015 o después

Con la última versión del estándar ECMAScript (ES6) , puede usar de keywork extends

Tenga en cuenta que la definición de clase no es un object regular, por lo tanto, no hay comas entre los miembros de la clase. Para crear una instancia de una clase, debe usar la palabra clave new . Para heredar de una clase base, use extends :

class Vehicle { constructor(name) { this.name = name; this.kind = ''vehicle''; } getName() { return this.name; } } // Create an instance var myVehicle = new Vehicle(''rocky''); myVehicle.getName(); // => ''rocky''

Para heredar de una clase base, use extends :

class Car extends Vehicle { constructor(name) { super(name); this.kind = ''car'' } } var myCar = new Car(''bumpy''); myCar.getName(); // => ''bumpy'' myCar instanceof Car; // => true myCar instanceof Vehicle; // => true

Desde la clase derivada, puede usar super de cualquier constructor o método para acceder a su clase base:

  • Para llamar al constructor padre, use super().
  • Para llamar a otro miembro, use, por ejemplo, super.getName() .

Hay más para usar clases. Si desea profundizar en el tema, recomiendo " Clases en ECMAScript 6 " por el Dr. Axel Rauschmayer. *

source

En PHP / Java uno puede hacer:

class Sub extends Base { }

Y automáticamente todos los métodos / propiedades públicos / protegidos, propiedades, campos, etc. de la clase Súper se convierten en parte de la clase Sub, que puede anularse si es necesario.

¿Cuál es el equivalente para eso en Javascript?


Bueno, en JavaScript no hay "herencia de clase", solo hay "herencia de prototipo". Entonces no haces un "camión" de clase y luego lo marcas como una subclase de "automóvil". En cambio, haces un objeto "Jack" y dices que usa "John" como prototipo. Si John sabe cuánto es "4 + 4", entonces Jack también lo sabe.

Le sugiero que lea el artículo de Douglas Crockford sobre la herencia prototípica aquí: Crockford También muestra cómo puede hacer que JavaScript tenga una herencia "similar" como en otros lenguajes de OO y luego explica que esto en realidad significa romper javaScript de una manera que no debe ser utilizada.



Después de leer muchas publicaciones, se me ocurrió esta solución ( jsfiddle aquí ). La mayoría de las veces no necesito algo más sofisticado

var Class = function(definition) { var base = definition.extend || null; var construct = definition.construct || definition.extend || function() {}; var newClass = function() { this._base_ = base; construct.apply(this, arguments); } if (definition.name) newClass._name_ = definition.name; if (definition.extend) { var f = function() {} f.prototype = definition.extend.prototype; newClass.prototype = new f(); newClass.prototype.constructor = newClass; newClass._extend_ = definition.extend; newClass._base_ = definition.extend.prototype; } if (definition.statics) for (var n in definition.statics) newClass[n] = definition.statics[n]; if (definition.members) for (var n in definition.members) newClass.prototype[n] = definition.members[n]; return newClass; } var Animal = Class({ construct: function() { }, members: { speak: function() { console.log("nuf said"); }, isA: function() { return "animal"; } } }); var Dog = Class({ extend: Animal, construct: function(name) { this._base_(); this.name = name; }, statics: { Home: "House", Food: "Meat", Speak: "Barks" }, members: { name: "", speak: function() { console.log( "ouaf !"); }, isA: function(advice) { return advice + " dog -> " + Dog._base_.isA.call(this); } } }); var Yorkshire = Class({ extend: Dog, construct: function(name,gender) { this._base_(name); this.gender = gender; }, members: { speak: function() { console.log( "ouin !"); }, isA: function(advice) { return "yorkshire -> " + Yorkshire._base_.isA.call(this,advice); } } }); var Bulldog = function() { return _class_ = Class({ extend: Dog, construct: function(name) { this._base_(name); }, members: { speak: function() { console.log( "OUAF !"); }, isA: function(advice) { return "bulldog -> " + _class_._base_.isA.call(this,advice); } } })}(); var animal = new Animal("Maciste"); console.log(animal.isA()); animal.speak(); var dog = new Dog("Sultan"); console.log(dog.isA("good")); dog.speak(); var yorkshire = new Yorkshire("Golgoth","Male"); console.log(yorkshire.isA("bad")); yorkshire.speak(); var bulldog = new Bulldog("Mike"); console.log(bulldog.isA("nice")); bulldog.speak();


En JavaScript no tiene clases, pero puede obtener la herencia y la reutilización del comportamiento de muchas maneras:

Herencia pseudo-clásica (mediante creación de prototipos):

function Super () { this.member1 = ''superMember1''; } Super.prototype.member2 = ''superMember2''; function Sub() { this.member3 = ''subMember3''; //... } Sub.prototype = new Super();

Debería usarse con el new operador:

var subInstance = new Sub();

Aplicación de función o "encadenamiento de constructor":

function Super () { this.member1 = ''superMember1''; this.member2 = ''superMember2''; } function Sub() { Super.apply(this, arguments); this.member3 = ''subMember3''; }

Este enfoque también se debe usar con el new operador:

var subInstance = new Sub();

La diferencia con el primer ejemplo es que cuando apply el constructor Super a this objeto dentro de Sub , agrega las propiedades asignadas a this en Super , directamente en la nueva instancia, por ejemplo, subInstance contiene las propiedades member1 y member2 directamente ( subInstance.hasOwnProperty(''member1'') == true; ).

En el primer ejemplo, esas propiedades se alcanzan a través de la cadena de prototipos , existen en un objeto interno [[Prototype]] .

Herencia parasitaria o constructores de potencia:

function createSuper() { var obj = { member1: ''superMember1'', member2: ''superMember2'' }; return obj; } function createSub() { var obj = createSuper(); obj.member3 = ''subMember3''; return obj; }

Este enfoque se basa básicamente en el "aumento de objetos", no necesita usar el new operador, y como puede ver, this palabra clave no está involucrada.

var subInstance = createSub();

ECMAScript 5th Ed. Método Object.create :

// Check if native implementation available if (typeof Object.create !== ''function'') { Object.create = function (o) { function F() {} // empty constructor F.prototype = o; // set base object as prototype return new F(); // return empty object with right [[Prototype]] }; } var superInstance = { member1: ''superMember1'', member2: ''superMember2'' }; var subInstance = Object.create(superInstance); subInstance.member3 = ''subMember3'';

El método anterior es una técnica de herencia prototípica propuesta por Crockford .

Las instancias de objeto heredan de otras instancias de objetos, eso es todo.

Esta técnica puede ser mejor que el simple "aumento de objetos" porque las propiedades heredadas no se copian en todas las instancias de objetos nuevos, ya que el objeto base se establece como [[Prototype]] del objeto extendido , en el ejemplo anterior subInstance contiene físicamente solo la propiedad de member3 .


Encuentro que esta cita es la más esclarecedora:

En esencia, una "clase" de JavaScript es solo un objeto Function que sirve como un constructor más un objeto prototipo adjunto. ( Fuente: Guru Katz )

Me gusta usar constructores en lugar de objetos, por lo que soy parcial al método de "herencia pseudo-clásica" descrito aquí por CMS . Aquí hay un ejemplo de herencia múltiple con una cadena de prototipos :

// Lifeform "Class" (Constructor function, No prototype) function Lifeform () { this.isLifeform = true; } // Animal "Class" (Constructor function + prototype for inheritance) function Animal () { this.isAnimal = true; } Animal.prototype = new Lifeform(); // Mammal "Class" (Constructor function + prototype for inheritance) function Mammal () { this.isMammal = true; } Mammal.prototype = new Animal(); // Cat "Class" (Constructor function + prototype for inheritance) function Cat (species) { this.isCat = true; this.species = species } Cat.prototype = new Mammal(); // Make an instance object of the Cat "Class" var tiger = new Cat("tiger"); console.log(tiger); // The console outputs a Cat object with all the properties from all "classes" console.log(tiger.isCat, tiger.isMammal, tiger.isAnimal, tiger.isLifeform); // Outputs: true true true true // You can see that all of these "is" properties are available in this object // We can check to see which properties are really part of the instance object console.log( "tiger hasOwnProperty: " ,tiger.hasOwnProperty("isLifeform") // false ,tiger.hasOwnProperty("isAnimal") // false ,tiger.hasOwnProperty("isMammal") // false ,tiger.hasOwnProperty("isCat") // true ); // New properties can be added to the prototypes of any // of the "classes" above and they will be usable by the instance Lifeform.prototype.A = 1; Animal.prototype.B = 2; Mammal.prototype.C = 3; Cat.prototype.D = 4; console.log(tiger.A, tiger.B, tiger.C, tiger.D); // Console outputs: 1 2 3 4 // Look at the instance object again console.log(tiger); // You''ll see it now has the "D" property // The others are accessible but not visible (console issue?) // In the Chrome console you should be able to drill down the __proto__ chain // You can also look down the proto chain with Object.getPrototypeOf // (Equivalent to tiger.__proto__) console.log( Object.getPrototypeOf(tiger) ); // Mammal console.log( Object.getPrototypeOf(Object.getPrototypeOf(tiger)) ); // Animal // Etc. to get to Lifeform

Aquí hay otro buen recurso de MDN , y aquí hay un jsfiddle para que lo pruebes .


Gracias a la respuesta de CMS y después de jugar un rato con el prototipo y Object.create y lo que no, pude encontrar una solución ordenada para mi herencia usando apply como se muestra aquí:

var myNamespace = myNamespace || (function() { return { BaseClass: function(){ this.someBaseProperty = "someBaseProperty"; this.someProperty = "BaseClass"; this.someFunc = null; }, DerivedClass:function(someFunc){ myNamespace.BaseClass.apply(this, arguments); this.someFunc = someFunc; this.someProperty = "DerivedClass"; }, MoreDerivedClass:function(someFunc){ myNamespace.DerivedClass.apply(this, arguments); this.someFunc = someFunc; this.someProperty = "MoreDerivedClass"; } }; })();


He cambiado la forma en que hago esto ahora, trato de evitar el uso de funciones de constructor y su propiedad de prototype , pero mi respuesta anterior de 2010 todavía está en la parte inferior. Ahora prefiero Object.create() . Object.create está disponible en todos los navegadores modernos.

Debo señalar que Object.create suele ser mucho más lento que usar new con un constructor de funciones.

//The prototype is just an object when you use `Object.create()` var Base = {}; //This is how you create an instance: var baseInstance = Object.create(Base); //If you want to inherit from "Base": var subInstance = Object.create(Object.create(Base)); //Detect if subInstance is an instance of Base: console.log(Base.isPrototypeOf(subInstance)); //True

jsfiddle

Uno de los grandes beneficios de usar Object.create es poder pasar un argumento defineProperties , que le da un control significativo sobre cómo se puede acceder y enumerar las propiedades de la clase, y también uso funciones para crear instancias, estas sirven como constructores en cierto modo, ya que puede hacer la inicialización al final en lugar de simplemente devolver la instancia.

var Base = {}; function createBase() { return Object.create(Base, { doSomething: { value: function () { console.log("Doing something"); }, }, }); } var Sub = createBase(); function createSub() { return Object.create(Sub, { doSomethingElse: { value: function () { console.log("Doing something else"); }, }, }); } var subInstance = createSub(); subInstance.doSomething(); //Logs "Doing something" subInstance.doSomethingElse(); //Logs "Doing something else" console.log(Base.isPrototypeOf(subInstance)); //Logs "true" console.log(Sub.isPrototypeOf(subInstance)); //Logs "true

jsfiddle

Esta es mi respuesta original de 2010:

function Base ( ) { this.color = "blue"; } function Sub ( ) { } Sub.prototype = new Base( ); Sub.prototype.showColor = function ( ) { console.log( this.color ); } var instance = new Sub ( ); instance.showColor( ); //"blue"


La herencia de Javascript es un poco diferente de Java y PHP, porque realmente no tiene clases. En cambio, tiene prototipos de objetos que proporcionan métodos y variables miembro. Puede encadenar esos prototipos para proporcionar herencia de objeto. El patrón más común que encontré al investigar esta pregunta se describe en Mozilla Developer Network . He actualizado su ejemplo para incluir una llamada a un método de superclase y para mostrar el registro en un mensaje de alerta:

// Shape - superclass function Shape() { this.x = 0; this.y = 0; } // superclass method Shape.prototype.move = function(x, y) { this.x += x; this.y += y; log += ''Shape moved./n''; }; // Rectangle - subclass function Rectangle() { Shape.call(this); // call super constructor. } // subclass extends superclass Rectangle.prototype = Object.create(Shape.prototype); Rectangle.prototype.constructor = Rectangle; // Override method Rectangle.prototype.move = function(x, y) { Shape.prototype.move.call(this, x, y); // call superclass method log += ''Rectangle moved./n''; } var log = ""; var rect = new Rectangle(); log += (''Is rect an instance of Rectangle? '' + (rect instanceof Rectangle) + ''/n''); // true log += (''Is rect an instance of Shape? '' + (rect instanceof Shape) + ''/n''); // true rect.move(1, 1); // Outputs, ''Shape moved.'' alert(log);

Personalmente, creo que la herencia en Javascript es incómoda, pero esta es la mejor versión que he encontrado.


No puede heredar de una clase en JavaScript, porque no hay clases en JavaScript.


Puede usar la github.com/dotnetwise/Javascript-FastClass .inheritWith y .fastClass . Es más rápido que la mayoría de las bibliotecas populares y, a veces incluso más rápido que la versión nativa.

Muy fácil de usar:

function Super() { this.member1 = "superMember";//instance member }.define({ //define methods on Super''s prototype method1: function() { console.log(''super''); } //prototype member }.defineStatic({ //define static methods directly on Super function staticMethod1: function() { console.log(''static method on Super''); } }); var Sub = Super.inheritWith(function(base, baseCtor) { return { constructor: function() {//the Sub constructor that will be returned to variable Sub this.member3 = ''subMember3''; //instance member on Sub baseCtor.apply(this, arguments);//call base construcor and passing all incoming arguments }, method1: function() { console.log(''sub''); base.method1.apply(this, arguments); //call the base class'' method1 function } }

Uso

var s = new Sub(); s.method1(); //prints: //sub //super


no puedes (en el sentido clásico). Javascript es un lenguaje prototípico. Observará que nunca declara una "clase" en Javascript; simplemente defines el estado y los métodos de un objeto. Para producir herencia, toma algún objeto y prototipo. El prototipo se amplía con nuevas funcionalidades.


function Base() { this.doSomething = function () { } } function Sub() { Base.call(this); // inherit Base''s method(s) to this instance of Sub } var sub = new Sub(); sub.doSomething();


function Person(attr){ this.name = (attr && attr.name)? attr.name : undefined; this.birthYear = (attr && attr.birthYear)? attr.birthYear : undefined; this.printName = function(){ console.log(this.name); } this.printBirthYear = function(){ console.log(this.birthYear); } this.print = function(){ console.log(this.name + ''('' +this.birthYear+ '')''); } } function PersonExt(attr){ Person.call(this, attr); this.print = function(){ console.log(this.name+ ''-'' + this.birthYear); } this.newPrint = function(){ console.log(''New method''); } } PersonExt.prototype = new Person(); // Init object and call methods var p = new Person({name: ''Mr. A'', birthYear: 2007}); // Parent method p.print() // Mr. A(2007) p.printName() // Mr. A var pExt = new PersonExt({name: ''Mr. A'', birthYear: 2007}); // Overwriten method pExt.print() // Mr. A-2007 // Extended method pExt.newPrint() // New method // Parent method pExt.printName() // Mr. A