JavaScript: a cosa servono .extend e .prototype?

Sono relativamente nuovo a JavaScript e continuo a vedere .extend e .prototype nelle librerie di terze parti che sto usando. Pensavo che avesse a che fare con la libreria javascript di Prototype, ma sto cominciando a pensare che non sia così. Per cosa sono usati?

L’ereditarietà di Javascript è basata sul prototipo, quindi estendi i prototipi di oggetti come Data, Matematica e persino quelli personalizzati.

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

Nel frammento sopra, definisco un metodo per tutti gli oggetti Date (già esistenti e tutti i nuovi).

extend è di solito una funzione di alto livello che copia il prototipo di una nuova sottoclass che si desidera estendere dalla class base.

Quindi puoi fare qualcosa come:

 extend( Fighter, Human ) 

E il costruttore / object Fighter erediterà il prototipo di Human , quindi se si definiscono metodi come live e die su Human Fighter erediterà anche quelli.

Chiarimento aggiornato:

“funzione di alto livello” che significa .extend non è built-in, ma spesso è fornito da una libreria come jQuery o Prototype.

.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 riferisce al “template” (se vuoi chiamarlo così) di un object, quindi aggiungendo metodi al prototipo di un object (lo vedi molto nelle librerie da aggiungere a String, Date, Math o anche Function) quei metodi sono aggiunti a ogni nuova istanza di quell’object.

Il metodo di extend , ad esempio in jQuery o PrototypeJS , copia tutte le proprietà dall’origine all’object di destinazione.

Ora sulla proprietà prototype , è un membro di oggetti funzione, fa parte del nucleo linguistico.

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

Quando si utilizza il new operatore con un object funzione, verrà creato un nuovo object che erediterà dal suo prototype costruttore.

Per esempio:

 function Foo () { } Foo.prototype.bar = true; var foo = new Foo(); foo.bar; // true foo instanceof Foo; // true Foo.prototype.isPrototypeOf(foo); // true 

L’ereditarietà di Javascript sembra essere un dibattito aperto ovunque. Può essere chiamato “Il curioso caso del linguaggio Javascript”.

L’idea è che esiste una class base e quindi estendi la class base per ottenere una funzione simile all’eredità (non completamente, ma ancora).

L’idea è quella di ottenere ciò che significa realmente il prototipo. Non l’ho capito fino a quando non ho visto il codice di John Resig (vicino a quanto fa jQuery.extend ) che ha scritto un pezzo di codice che lo fa e sostiene che le basi2 e le librerie di prototipi 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. Per prima cosa, esegui il loop delle proprietà e aggiungili all’istanza. Successivamente, si crea un costruttore per essere successivamente aggiunto all’object.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, punta Class.prototype al prototipo desiderato. Ora, l’intero object è cambiato nel senso 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; } }); 

Leggi di più qui su Javascript Inheritance di John Resig .

Alcune extend funzioni nelle librerie di terze parti sono più complesse di altre. Knockout.js per esempio 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; }