mozilla
Vos résultats de recherche

    Function.prototype.bind()

    La fonction bind() crée une nouvelle fonction qui, lorsqu'elle est appelée, a pour contexte this la valeur passée en paramètre et éventuellement une suite d'arguments qui précéderont ceux fournis à l'appel de la fonction créée.

    Syntaxe

    fun.bind(thisArg[, arg1[, arg2[, ...]]])

    Paramètres

    thisArg
    La valeur que l'on doit passer au paramètre this de la fonction cible quand la fonction est appelée. La valeur est ignorée si la fonction liée est construite en utilisant l'opérateur new.
    arg1, arg2, ...
    Les arguments qui doivent précéder les arguments fournis lors de l'appel à la fonction liée lors de l'appel à la fonction cible.

    Description

    La fonction bind() crée une nouvelle fonction (une fonction liée) avec le même corps (la même propriété interne Call au sens ECMAScript 5) que la fonction appelante (la fonction cible de la fonction liée) avec la valeur de this comme premier argument de bind(), qui ne peut être surchargé. bind() accepte également les arguments principaux qui doivent être passés à la fonction cible quand celle ci sera appelée. Une fonction liée peut aussi être construite à l'aide de l'opérateur new : ce qui aura le même effet que si on avait appelé le constructeur de la fonction cible. Dans ce dernier cas, la valeur this sera ignorée et les arguments préremplis seront passés à la fonction émulée.

    Exemples

    Créer une fonction liée

    La façon la plus simple d'utiliser bind()est de faire une fonction qui, peu importe la façon dont elle est appellée, le sera avec une certaine valeur this donnée.

    Une erreur courante lorsqu'on débute en JavaScript est d'extraire une méthode d'un objet, puis plus tard d'appeller cette méthode depuis un objet et de s'attendre à utiliser l'objet original en tant que valeur de this (par exemple en utilisant cette méthode dans un callback). Sans précaution, cependant, l'objet original est perdu. Créer une fonction liée depuis la méthode, en utilisant l'objet original, résout simplement le problème :

    this.x = 9;
    var module = {
      x: 81,
      getX: function() { return this.x; }
    };
    
    module.getX(); // 81
    
    var getX = module.getX;
    getX(); // 9, car ici, this fait référence à l'objet global
    
    // On crée une nouvelle fonction à laquelle on lie module en
    // tant que 'this'
    var boundGetX = getX.bind(module);
    boundGetX(); // 81
    

    Fonctions partielles

    Dans l'exemple suivant, on utilise bind() afin de créer une fonction avec des arguments initiaux prédéfinis. Ces arguments, s'il y en a, suivent le this fourni et sont ensuite insérés au début des arguments passés à la fonction cible, suivis par les arguments passés à la fonction liée au moment où celle-ci est appelée.

    function list() {
      return Array.prototype.slice.call(arguments);
    }
    
    var list1 = list(1, 2, 3); // [1, 2, 3]
    
    // Créer une fonction avec un argument prédéfini
    var leadingThirtysevenList = list.bind(undefined, 37);
    
    var list2 = leadingThirtysevenList(); // [37]
    var list3 = leadingThirtysevenList(1, 2, 3); // [37, 1, 2, 3]
    

    Utiliser bind avec setTimeout

    Par défaut à l'intérieur de window.setTimeout(), le mot-clé this sera attribué à l'objet window (ou l'objet global). Lorsqu'on travaille avec des méthodes de classe utilisant this qui se réfère à l'instance, on peut lier this de façon explicite afin d'être certain de manipuler l'instance.

    function Fleur() {
      this.nbPétales = Math.ceil( Math.random() * 12 ) + 1;
    }
    
    // On déclare floraison après un délai d'une seconde
    Fleur.prototype.floraison = function() {
      window.setTimeout( this.declare.bind( this ), 1000 );
    };
    
    Fleur.prototype.declare = function() {
      console.log('Je suis une fleur avec ' +
         this.nbPétales + ' pétales !');
    };
    

    Les fonctions liées utilisées en tant que constructeurs

    Attention : Cette section illustre des capacités marginales et des cas aux limites concernant l'usage de la méthode bind(). Les méthodes montrées ci-après ne sont pas les façons les plus propres de faire les choses et ne devraient pas être utilisées en production.

    Les fonctions liées sont automatiquement disponibles à l'usage pour toutes les instances initialisées avec l'opérateur new sur la fonction cible. Quand une fonction liée est utilisée pour construire une valeur, le this fourni est ignoré. Cependant, les arguments fournis sont toujours préremplis lors de l'appel au constructeur :

    function Point(x, y) {
      this.x = x;
      this.y = y;
    }
    
    Point.prototype.toString = function() { 
      return this.x + "," + this.y; 
    };
    
    var p = new Point(1, 2);
    p.toString(); // "1,2"
    
    
    var emptyObj = {};
    var YAxisPoint = Point.bind(emptyObj, 0 /* x */);
    // non supporté dans le polyfill ci dessous,
    // fonctionne avec le bind natif :
    var YAxisPoint = Point.bind(null,0 /* x */);
    
    var axisPoint = new YAxisPoint(5);
    axisPoint.toString(); //  "0,5"
    
    axisPoint instanceof Point; // true
    axisPoint instanceof YAxisPoint; // true
    new Point(17, 42) instanceof YAxisPoint; // false 
    

    On notera qu'il n'y a rien à faire de particulier pour pouvoir utiliser new sur votre fonction liée. Le corollaire est qu'il n'y a rien à faire de plus pour créer une fonction liée qui soit appelée sans préfixe, même s'il est préférable d'appeler une fonction liée uniquement avec le mot-clé new.

    // Cet exemple fonctionne dans votre console JavaScript
    // ...(sous réserve d'avoir utilisé le code précédent)
    
    // Peut toujours être appelé comme une fonction normale
    // (même si ce n'est généralement pas l'effet )
    YAxisPoint(13);
    
    emptyObj.x + "," + emptyObj.y; // "0,13"
    

    Si on souhaite supporter le cas où la fonction liée  d'une fonction liée en utilisant seulement new, ou juste en l'appellant, la fonction cible doit outrepasser cette restriction.

    Créer des raccourcis

    bind() est également utile dans les cas où on souhaite créer un raccourci vers une fonction qui requiert un this ayant une certaine valeur.

    Si, par exemple, on considère la fonction Array.prototype.slice et qu'on souhaite l'utiliser pour convertir un objet semblable à un tableau en un objet array, on peut créer un raccourci de cette façon :

    var slice = Array.prototype.slice;
    
    // ... un peu plus loin
    
    slice.apply(arguments);

    Avec bind(), il est possible de simplifier cela. Dans l'exemple qui suit slice est une fonction liée à la fonction apply() de Function.prototype, et this défini en tant que fonction slice() de Array.prototype. Cela signifie que les appels à la méthode apply() peuvent être éliminés :

    // pareil que "slice" dans l'exemple précédent
    var unboundSlice = Array.prototype.slice;
    var slice = Function.prototype.apply.bind(unboundSlice);
    
    // ...
    
    slice(arguments);
    

    Prothèse d'émulation (polyfill)

    La fonction bind() a été ajoutée avec la cinquième édition de la spécification ECMA-262 (ECMAScript 5), en tant que telle, elle peut ne pas être supportée par tous les navigateurs. Pour parer à certains cas, il est possible d'utiliser le code suivant au début des scripts pour utiliser cette méthode dans les environnements qui ne la possèdent pas nativement.

    if (!Function.prototype.bind) {
      Function.prototype.bind = function (oThis) {
        if (typeof this !== "function") {
          // au plus proche de la fonction interne 
          // ECMAScript 5 IsCallable
          throw new TypeError("Function.prototype.bind - ce qui est à lier ne peut être appelé");
        }
    
        var aArgs = Array.prototype.slice.call(arguments, 1), 
            fToBind = this, 
            fNOP = function () {},
            fBound = function () {
              return fToBind.apply(this instanceof fNOP
                     ? this
                     : oThis,
                     aArgs.concat(Array.prototype.slice.call(arguments)));
            };
    
        fNOP.prototype = this.prototype;
        fBound.prototype = new fNOP();
    
        return fBound;
      };
    }
    

    Quelques-unes des nombreuses différences entre cet algorithme et celui spécifié par ECMAScript 5 sont : (liste non exhaustive)

    • Cette implémentation partielle dépend des méthodes natives Array.prototype.slice(), Array.prototype.concat(), Function.prototype.call() et Function.prototype.apply() en supposant qu'elles aient leur valeur originale.
    • Cette implémentation partielle crée des fonctions sans "pilule empoisonnée", les propriétés caller et arguments lancent des TypeError lorsque l'on fait un get, set, or deletion. (Peut être ajouté si l'implémentation supporte  Object.defineProperty, ou partiellement implémenté [sans le comportement throw-on-delete ] si l'implémentation supporte les extensions __defineGetter__ et __defineSetter__.)
    • Cette implémentation partielle crée des fonctions ayant une propriété prototype. (Les fonctions liées proprement n'en ont pas)
    • Cette implémentation partielle crée des fonctions pour lesquelles la propriété length est en désaccord avec la spécification ECMA-262 : cela crée des fonctions ayant une propriété length égale à 0, tandis qu'une implémentation complète, peut renvoyer une length différente de zéro, selon la valeur de la propriété length de la fonction cible et du nombre d'arguments prédéfinis.

    Si vous choisissez d'utiliser cette implémentation partielle, sachez que ces cas ne respectent pas la spécification ECMA-262 ! Malgré tout, (et certainement avec des modifications spécifiques à vos besoins), cette implémentation partielle devrait convenir comme solution de contournement en attendant que la méthode bind() soit largement implémentée selon la spécification.

    Spécifications

    Spécification Statut Commentaires
    ECMAScript 5.1 (ECMA-262)
    La définition de 'Function.prototype.bind' dans cette spécification.
    Standard Définition initiale.
    Implémentée avec JavaScript 1.8.5
    ECMAScript 6 (ECMA-262)
    La définition de 'Function.prototype.bind' dans cette spécification.
    En cours de validation comme recommandation  

    Compatibilité des navigateurs

    Fonctionnalité Chrome Firefox (Gecko) Internet Explorer Opera Safari
    Support simple 7 4.0 (2) 9 11.60 5.1.4
    Fonctionnalité Android Chrome pour Android Firefox Mobile (Gecko) IE Mobile Opera Mobile Safari Mobile
    Support simple 4.0 0.16 4.0 (2) ? 11.50 6.0

    Tableau basé sur  les tableaux de compatibilité de Kangax.

    Voir aussi

    Étiquettes et contributeurs liés au document

    Dernière mise à jour par : SphinxKnight,