Je suis relativement nouveau en JavaScript et ne cesse de voir les fichiers .extend et .prototype dans les bibliothèques tierces que j'utilise. Je pensais que cela avait à voir avec la bibliothèque javascript Prototype, mais je commence à penser que ce n'est pas le cas. A quoi servent-ils?
L'héritage Javascript est basé sur un prototype. Vous étendez donc les prototypes d'objets tels que Date, Math et même vos propres objets personnalisés.
Date.prototype.lol = function() {
alert('hi');
};
( new Date ).lol() // alert message
Dans l'extrait de code ci-dessus, je définis une méthode pour tous objets Date (déjà existants et tous nouveaux).
extend
est généralement une fonction de haut niveau qui copie le prototype d'une nouvelle sous-classe que vous souhaitez étendre à partir de la classe de base.
Donc, vous pouvez faire quelque chose comme:
extend( Fighter, Human )
Et le constructeur/objet Fighter
héritera du prototype de Human
, donc si vous définissez des méthodes telles que live
et die
sur Human
alors Fighter
en héritera également.
Clarification mise à jour:
"fonction de haut niveau" signifiant .extend n'est pas intégré mais souvent fourni par une bibliothèque telle que jQuery ou Prototype.
.extend()
est ajouté par de nombreuses bibliothèques tierces pour faciliter la création d'objets à partir d'autres objets. Voir http://api.jquery.com/jQuery.extend/ ou http://www.prototypejs.org/api/object/extend pour quelques exemples.
.prototype
fait référence au "modèle" (si vous voulez l'appeler ainsi) d'un objet, donc en ajoutant des méthodes au prototype d'un objet (vous le voyez souvent dans les bibliothèques à ajouter à String, Date, Math ou même à Function) ces méthodes sont ajoutées à chaque nouvelle instance de cet objet.
La méthode extend
, par exemple dans jQuery ou PrototypeJS , copie toutes les propriétés de la source vers l'objet de destination.
Parlons maintenant de la propriété prototype
, elle est membre des objets fonction, elle fait partie du noyau du langage.
Toute fonction peut être utilisée en tant que constructeur , pour créer de nouvelles instances d'objet. Toutes les fonctions ont cette propriété prototype
.
Lorsque vous utilisez l'opérateur new
avec un objet fonction, un nouvel objet est créé et il hérite de son constructeur prototype
.
Par exemple:
function Foo () {
}
Foo.prototype.bar = true;
var foo = new Foo();
foo.bar; // true
foo instanceof Foo; // true
Foo.prototype.isPrototypeOf(foo); // true
L'héritage Javascript semble être un débat ouvert partout. On peut l'appeler "Le cas curieux du langage Javascript".
L'idée est qu'il existe une classe de base et que vous étendez ensuite la classe de base pour obtenir une fonctionnalité semblable à l'héritage (pas complètement, mais quand même).
L'idée est de savoir ce que signifie réellement prototype. Je ne l'ai pas eu avant d'avoir vu le code de John Resig (proche de quoi jQuery.extend
fait) a écrit un morceau de code qui le fait et il affirme que les bibliothèques de base2 et de prototypes étaient la source d’inspiration.
Voici le code.
/* 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;
};
})();
Il y a trois parties qui font le travail. Tout d'abord, vous parcourez les propriétés et les ajoutez à l'instance. Après cela, vous créez un constructeur pour qu'il soit ajouté ultérieurement à l'objet. Les lignes de clé sont les suivantes:
// Populate our constructed prototype object
Class.prototype = prototype;
// Enforce the constructor to be what we expect
Class.prototype.constructor = Class;
Vous pointez d'abord le Class.prototype
au prototype souhaité. Désormais, l’ensemble de l’objet a changé, ce qui signifie que vous devez forcer la mise en page pour qu'elle reprenne sa propre.
Et l'exemple d'utilisation:
var Car = Class.Extend({
setColor: function(clr){
color = clr;
}
});
var volvo = Car.Extend({
getColor: function () {
return color;
}
});
Pour en savoir plus à ce sujet, rendez-vous sur le site Javascript Héritage de John Resig .
Certaines fonctions extend
des bibliothèques tierces sont plus complexes que d’autres. Knockout.js , par exemple, en contient un très simple qui ne possède pas certaines des vérifications que fait jQuery:
function extend(target, source) {
if (source) {
for(var prop in source) {
if(source.hasOwnProperty(prop)) {
target[prop] = source[prop];
}
}
}
return target;
}