JavaScript: Para que são utilizados o .extend e o .prototype?

122

Sou relativamente novo em JavaScript e continuo vendo .extend e .prototype em bibliotecas de terceiros que estou usando. Eu pensei que tinha a ver com a biblioteca javascript Prototype, mas estou começando a pensar que não é o caso. Para que são usados?

Andrew
fonte

Respostas:

136

A herança do Javascript é baseada em protótipo; portanto, você amplia os protótipos de objetos como Data, Matemática e até os seus próprios personalizados.

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

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

No trecho acima, defino um método para todos os objetos Date (já existentes e todos os novos).

extend geralmente é uma função de alto nível que copia o protótipo de uma nova subclasse que você deseja estender da classe base.

Então você pode fazer algo como:

extend( Fighter, Human )

E o Fighterconstrutor / object herdarão o protótipo Human, por isso, se você definir métodos, como livee dieem Humanseguida, Fightertambém herdará aqueles.

Esclarecimentos atualizados:

"função de alto nível", significando .extend não é incorporado, mas geralmente é fornecido por uma biblioteca como jQuery ou Prototype.

meder omuraliev
fonte
75
O significado de "função de alto nível" .extendnão é incorporado, mas geralmente é fornecido por uma biblioteca como jQuery ou Prototype.
141313 visum
13
Gostaria de acrescentar que não é sugerido para estender os protótipos de objetos nativos em JS
framp
1
@ medidor - você deve adicionar um comentário visum em sua resposta. :)
Manish Gupta
9
Na programação Javascript moderna, é habitual tratar objetos globais e nativos como elementos de um banheiro público; você não pode evitar entrar lá, mas tente minimizar o contato com as superfícies. Isso ocorre porque changing the native objects can break other developer's assumptions of these objects,leva a erros de javascript, que geralmente custam muitas horas para serem rastreados. A frase principal desta resposta parece deturpar essa valiosa prática de javascript.
Ninjaxor
24

.extend()é adicionado por muitas bibliotecas de terceiros para facilitar a criação de objetos a partir de outros objetos. Consulte http://api.jquery.com/jQuery.extend/ ou http://www.prototypejs.org/api/object/extend para alguns exemplos.

.prototype refere-se ao "modelo" (se você quiser chamá-lo assim) de um objeto, portanto, adicionando métodos ao protótipo de um objeto (você vê muito isso nas bibliotecas para adicionar a String, Data, Matemática ou até Função) esses métodos são adicionados a cada nova instância desse objeto.

pnomolos
fonte
19

O extendmétodo, por exemplo, em jQuery ou PrototypeJS , copia todas as propriedades da origem para o objeto de destino.

Agora, sobre a prototypepropriedade, ela é um membro dos objetos de função, faz parte do núcleo da linguagem.

Qualquer função pode ser usada como construtor , para criar novas instâncias de objetos. Todas as funções têm essa prototypepropriedade.

Quando você usa o newoperador com um objeto de função, um novo objeto será criado e herdado de seu construtor prototype.

Por exemplo:

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

var foo = new Foo();

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

A herança do Javascript parece ser um debate aberto em todos os lugares. Pode ser chamado "O curioso caso da linguagem Javascript".

A idéia é que exista uma classe base e você a estenda para obter um recurso semelhante a uma herança (não completamente, mas ainda).

A idéia é entender o que realmente significa protótipo. Eu não o comprei até que vi o código de John Resig (próximo ao que jQuery.extendfaz) escreveu um pedaço de código que o faz e ele afirma que as bibliotecas base2 e protótipo eram a fonte de inspiração.

Aqui está o 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;
  };
})();

Existem três partes que estão fazendo o trabalho. Primeiro, você percorre as propriedades e as adiciona à instância. Depois disso, você cria um construtor para ser adicionado posteriormente ao objeto. Agora, as linhas principais são:

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

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

Você primeiro aponta Class.prototypepara o protótipo desejado. Agora, todo o objeto mudou, o que significa que você precisa forçar o layout de volta ao seu próprio.

E o exemplo de uso:

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

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

Leia mais sobre isso aqui na Javascript Inheritance da publicação de John Resig .

ambodi
fonte
2

Algumas extendfunções em bibliotecas de terceiros são mais complexas que outras. O Knockout.js, por exemplo, contém um minimamente simples que não possui algumas das verificações feitas pelo jQuery:

function extend(target, source) {
    if (source) {
        for(var prop in source) {
            if(source.hasOwnProperty(prop)) {
                target[prop] = source[prop];
            }
        }
    }
    return target;
}
Simon_Weaver
fonte
2
  • .extends() crie uma classe que é filha de outra classe.
    nos bastidores Child.prototype.__proto__define seu valor para Parent.prototype
    que os métodos sejam herdados.
  • .prototype herdar recursos de um para outro.
  • .__proto__ é um getter / setter para Prototype.
humaid
fonte
Isso não deve ser .extend () e não .extends ()?
SJHowe