JavaScript: per cosa vengono utilizzati .extend e .prototype?


122

Sono relativamente nuovo in JavaScript e continuo a vedere .extend e .prototype nelle librerie di terze parti che sto utilizzando. Pensavo avesse a che fare con la libreria javascript Prototype, ma comincio a pensare che non sia così. A cosa servono?

Risposte:


136

L'ereditarietà di Javascript è basata su prototipi, quindi estendi i prototipi di oggetti come Date, Math e persino quelli personalizzati.

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

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

Nello snippet sopra, definisco un metodo per tutti gli oggetti Date (quelli già esistenti e tutti quelli nuovi).

extend è solitamente una funzione di alto livello che copia il prototipo di una nuova sottoclasse che si desidera estendere dalla classe base.

Quindi puoi fare qualcosa come:

extend( Fighter, Human )

E il Fightercostruttore / oggetto erediterà il prototipo di Human, quindi se si definisce metodi come livee diein Humanpoi Fightersarà anche ereditare quelli.

Chiarimento aggiornato:

"funzione di alto livello" che significa .extend non è integrato ma spesso fornito da una libreria come jQuery o Prototype.


75
Il significato di "funzione di alto livello" .extendnon è integrato ma spesso fornito da una libreria come jQuery o Prototype.
visum

13
Vorrei aggiungere che non è suggerito di estendere i prototipi di oggetti nativi in JS
framp

1
@meder - dovresti aggiungere un commento visum nella tua risposta. :)
Manish Gupta

9
Nella moderna programmazione Javascript, è consuetudine trattare le variabili globali e gli oggetti nativi come elementi di un bagno pubblico; non puoi evitare di entrare lì, ma dovresti cercare di ridurre al minimo il contatto con le superfici. Questo perché changing the native objects can break other developer's assumptions of these objects,porta a bug di javascript che spesso possono costare molte ore per rintracciarli. La frase principale di questa risposta sembra travisare questa preziosa pratica di javascript.
Ninjaxor

24

.extend()viene aggiunto da molte librerie di terze parti per semplificare la creazione di oggetti da altri oggetti. Vedi http://api.jquery.com/jQuery.extend/ o http://www.prototypejs.org/api/object/extend per alcuni esempi.

.prototype si riferisce al "modello" (se vuoi chiamarlo così) di un oggetto, quindi aggiungendo metodi al prototipo di un oggetto (lo vedi spesso nelle librerie da aggiungere a String, Date, Math o anche Function) quei metodi vengono aggiunti a ogni nuova istanza di quell'oggetto.


19

Il extendmetodo, ad esempio in jQuery o PrototypeJS , copia tutte le proprietà dall'origine all'oggetto di destinazione.

Ora riguardo alla prototypeproprietà, è un membro degli oggetti funzione, fa parte del nucleo del linguaggio.

Qualsiasi funzione può essere utilizzata come costruttore per creare nuove istanze di oggetti. Tutte le funzioni hanno questa prototypeproprietà.

Quando usi l' newoperatore con su un oggetto funzione, verrà creato un nuovo oggetto, che erediterà dal suo costruttore prototype.

Per esempio:

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

var foo = new Foo();

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

18

L'ereditarietà di Javascript sembra essere come un dibattito aperto ovunque. Può essere chiamato "Il curioso caso del linguaggio Javascript".

L'idea è che esista una classe base e quindi estendi la classe base per ottenere una caratteristica simile all'ereditarietà (non completamente, ma comunque).

L'idea è di capire cosa significa veramente prototipo. Non l'ho capito fino a quando non ho visto il codice di John Resig (vicino a quello che jQuery.extendfa) ha scritto un blocco di codice che lo fa e afferma che le librerie base2 e prototipo erano la fonte di ispirazione.

Ecco il codice.

    /* 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;
  };
})();

Ci sono tre parti che stanno facendo il lavoro. Innanzitutto, scorri le proprietà e le aggiungi all'istanza. Dopodiché, crei un costruttore da aggiungere in seguito all'oggetto, ora le linee chiave sono:

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

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

Per prima cosa punti il Class.prototypeprototipo desiderato. Ora, l'intero oggetto è cambiato, il che significa che è necessario forzare il layout di nuovo al proprio.

E l'esempio di utilizzo:

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

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

Per saperne di più qui su Javascript Inheritance dal post di John Resig .


2

Alcune extendfunzioni nelle librerie di terze parti sono più complesse di altre. Knockout.js, ad esempio, ne contiene uno minimamente semplice che non ha alcuni dei controlli che fa jQuery:

function extend(target, source) {
    if (source) {
        for(var prop in source) {
            if(source.hasOwnProperty(prop)) {
                target[prop] = source[prop];
            }
        }
    }
    return target;
}

2
  • .extends() creare una classe che sia figlia di un'altra classe.
    dietro le quinte Child.prototype.__proto__imposta il suo valore in Parent.prototype
    modo che i metodi vengano ereditati.
  • .prototype ereditano le caratteristiche l'una dall'altra.
  • .__proto__ è un getter / setter per Prototype.

Non dovrebbe essere .extend () e non .extends ()?
SJHowe
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.