web-dev-qa-db-fra.com

JavaScript: À quoi servent .extend et .prototype?

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?

119
Andrew

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.

129
meder omuraliev

.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.

24
pnomolos

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
18
CMS

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 .

18
ambodi

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;
}
2
Simon_Weaver