JavaScript: ¿Para qué se usan .extend y .prototype?

122

Soy relativamente nuevo en JavaScript y sigo viendo .extend y .prototype en las bibliotecas de terceros que estoy usando. Pensé que tenía que ver con la biblioteca Prototype javascript, pero estoy empezando a pensar que ese no es el caso. ¿Para qué se usan estos?

Andrés
fuente

Respuestas:

136

La herencia de Javascript se basa en prototipos, por lo que puede extender los prototipos de objetos como Fecha, Matemáticas e incluso sus propios objetos personalizados.

Date.prototype.lol = function() {
 alert('hi');
};

( new Date ).lol() // alert message

En el fragmento anterior, defino un método para todos los objetos Date (ya existentes y todos los nuevos).

extend Por lo general, es una función de alto nivel que copia el prototipo de una nueva subclase que desea extender desde la clase base.

Entonces puedes hacer algo como:

extend( Fighter, Human )

Y el Fighterconstructor / objeto heredará el prototipo de Human, por lo que si se define como métodos livey dieel Humanentonces Fightertambién herede esos.

Aclaración actualizada:

"función de alto nivel", que significa .extend, no está integrado, sino que a menudo lo proporciona una biblioteca como jQuery o Prototype.

meder omuraliev
fuente
75
El significado de "función de alto nivel" .extendno está integrado, pero a menudo lo proporciona una biblioteca como jQuery o Prototype.
visum
13
Agregaría
1
@meder: debe agregar un comentario visum en su respuesta. :)
Manish Gupta
9
En la programación moderna de Javascript, es habitual tratar los objetos globales y nativos como elementos de un baño público; No puede evitar entrar allí, pero debe tratar de minimizar el contacto con las superficies. Esto se debe a que changing the native objects can break other developer's assumptions of these objects,conduce a errores de JavaScript que a menudo pueden costar muchas horas rastrear. La oración principal de esta respuesta parece tergiversar esta valiosa práctica de JavaScript.
Ninjaxor
24

.extend()es agregado por muchas bibliotecas de terceros para facilitar la creación de objetos a partir de otros objetos. Consulte http://api.jquery.com/jQuery.extend/ o http://www.prototypejs.org/api/object/extend para ver algunos ejemplos.

.prototype se refiere a la "plantilla" (si quiere llamarlo así) de un objeto, por lo que al agregar métodos al prototipo de un objeto (lo ve mucho en las bibliotecas para agregar a String, Date, Math o incluso Function) esos métodos se agregan a cada nueva instancia de ese objeto.

pnomolos
fuente
19

El extendmétodo, por ejemplo, en jQuery o PrototypeJS , copia todas las propiedades del origen al objeto de destino.

Ahora sobre la prototypepropiedad, es un miembro de objetos de función, es parte del núcleo del lenguaje.

Cualquier función se puede utilizar como constructor , para crear nuevas instancias de objeto. Todas las funciones tienen esta prototypepropiedad.

Cuando utiliza el newoperador con en un objeto de función, se creará un nuevo objeto y heredará de su constructor prototype.

Por ejemplo:

function Foo () {
}
Foo.prototype.bar = true;

var foo = new Foo();

foo.bar; // true
foo instanceof Foo; // true
Foo.prototype.isPrototypeOf(foo); // true
CMS
fuente
18

La herencia de Javascript parece ser como un debate abierto en todas partes. Se le puede llamar "El curioso caso del lenguaje Javascript".

La idea es que haya una clase base y luego extienda la clase base para obtener una característica similar a la herencia (no completamente, pero aún así).

La idea es entender qué significa realmente un prototipo. No lo entendí hasta que vi el código de John Resig (cerca de lo que jQuery.extendhace) escribió un fragmento de código que lo hace y afirma que las bibliotecas base2 y prototipo fueron la fuente de inspiración.

Aquí está el código.

    /* Simple JavaScript Inheritance
     * By John Resig http://ejohn.org/
     * MIT Licensed.
     */  
     // Inspired by base2 and Prototype
    (function(){
  var initializing = false, fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/;

  // The base Class implementation (does nothing)
  this.Class = function(){};

  // Create a new Class that inherits from this class
  Class.extend = function(prop) {
    var _super = this.prototype;

    // Instantiate a base class (but only create the instance,
    // don't run the init constructor)
    initializing = true;
    var prototype = new this();
    initializing = false;

    // Copy the properties over onto the new prototype
    for (var name in prop) {
      // Check if we're overwriting an existing function
      prototype[name] = typeof prop[name] == "function" &&
        typeof _super[name] == "function" && fnTest.test(prop[name]) ?
        (function(name, fn){
          return function() {
            var tmp = this._super;

            // Add a new ._super() method that is the same method
            // but on the super-class
            this._super = _super[name];

            // The method only need to be bound temporarily, so we
            // remove it when we're done executing
            var ret = fn.apply(this, arguments);        
            this._super = tmp;

            return ret;
          };
        })(name, prop[name]) :
        prop[name];
    }

    // The dummy class constructor
    function Class() {
      // All construction is actually done in the init method
      if ( !initializing && this.init )
        this.init.apply(this, arguments);
    }

    // Populate our constructed prototype object
    Class.prototype = prototype;

    // Enforce the constructor to be what we expect
    Class.prototype.constructor = Class;

    // And make this class extendable
    Class.extend = arguments.callee;

    return Class;
  };
})();

Hay tres partes que están haciendo el trabajo. Primero, recorre las propiedades y las agrega a la instancia. Después de eso, crea un constructor para luego agregarlo al objeto. Ahora, las líneas clave son:

// Populate our constructed prototype object
Class.prototype = prototype;

// Enforce the constructor to be what we expect
Class.prototype.constructor = Class;

Primero apunta el Class.prototypeprototipo deseado. Ahora, todo el objeto ha cambiado, lo que significa que debe forzar el diseño a su propio diseño.

Y el ejemplo de uso:

var Car = Class.Extend({
  setColor: function(clr){
    color = clr;
  }
});

var volvo = Car.Extend({
   getColor: function () {
      return color;
   }
});

Lea más sobre esto aquí en Herencia de Javascript por la publicación de John Resig .

ambodi
fuente
2

Algunas extendfunciones en bibliotecas de terceros son más complejas que otras. Knockout.js, por ejemplo, contiene uno mínimamente simple que no tiene algunas de las comprobaciones que tiene jQuery:

function extend(target, source) {
    if (source) {
        for(var prop in source) {
            if(source.hasOwnProperty(prop)) {
                target[prop] = source[prop];
            }
        }
    }
    return target;
}
Simon_Weaver
fuente
2
  • .extends() crear una clase que es hija de otra clase.
    Detrás de escena Child.prototype.__proto__establece su valor para Parent.prototype
    que los métodos se hereden.
  • .prototype heredar características de uno a otro.
  • .__proto__ es un getter / setter para Prototype.
sirena
fuente
¿No debería ser .extend () y no .extends ()?
SJHowe