Maison > interface Web > js tutoriel > le corps du texte

Astuce Function.prototye.bind_javascript en javascript

WBOY
Libérer: 2016-05-16 15:52:39
original
933 Les gens l'ont consulté

La liaison de fonction est probablement la chose à laquelle vous prêtez le moins d'attention lorsque vous commencez à utiliser JavaScript, mais lorsque vous réalisez que vous avez besoin d'une solution pour maintenir ce contexte dans une autre fonction, vous avez vraiment besoin de Function.prototype. bind(), mais vous ne vous en rendez peut-être toujours pas compte.

La première fois que vous rencontrez ce problème, vous pourriez être tenté de le définir sur une variable afin de pouvoir continuer à y faire référence après avoir changé le contexte. De nombreuses personnes choisissent d'utiliser self, _this ou context comme noms de variables (certains l'utilisent également). Ces méthodes sont toutes utiles et bien sûr, il n’y a rien de mal à elles. Mais il existe une méthode meilleure et plus spécialisée.

Quel est le vrai problème que nous devons résoudre ?
Dans l'exemple de code suivant, nous pouvons légitimement mettre en cache le contexte dans une variable :

var myObj = {
 
  specialFunction: function () {
 
  },
 
  anotherSpecialFunction: function () {
 
  },
 
  getAsyncData: function (cb) {
    cb();
  },
 
  render: function () {
    var that = this;
    this.getAsyncData(function () {
      that.specialFunction();
      that.anotherSpecialFunction();
    });
  }
};
 
myObj.render();

Copier après la connexion

Si nous utilisons simplement this.specialFunction() pour appeler la méthode, nous recevrons l'erreur suivante :

Uncaught TypeError : l'objet [object global] n'a pas de méthode 'specialFunction'
Nous devons conserver une référence au contexte de l'objet myObj pour l'exécution de la fonction de rappel. Appeler that.specialFunction() nous permet de maintenir le contexte de portée et d'exécuter notre fonction correctement. Cependant, il existe un moyen plus simple et plus propre d'utiliser Function.prototype.bind() :

render: function () {
 
  this.getAsyncData(function () {
 
    this.specialFunction();
 
    this.anotherSpecialFunction();
 
  }.bind(this));
 
}

Copier après la connexion

Qu'est-ce qu'on vient de faire ?
.bind() crée une fonction. Lorsque cette fonction est appelée, son mot-clé this sera défini sur la valeur transmise (fait référence ici au paramètre transmis lors de l'appel de bind()). On passe donc dans le contexte souhaité, this (en fait myObj), à la fonction .bind(). Ensuite, lorsque la fonction de rappel est exécutée, elle pointe vers l'objet myObj.

Si vous souhaitez savoir à quoi ressemble Function.prototype.bind() en interne et comment cela fonctionne, voici un exemple très simple :

Function.prototype.bind = function (scope) {
  var fn = this;
  return function () {
    return fn.apply(scope);
  };
}
Copier après la connexion

Il existe également un cas d'utilisation très simple :

var foo = {
  x: 3
}
 
var bar = function(){
  console.log(this.x);
}
 
bar(); 
// undefined
 
var boundFunc = bar.bind(foo);
 
boundFunc(); 
// 3
Copier après la connexion

Nous créons une nouvelle fonction, et lorsqu'elle sera exécutée, elle sera définie sur foo - pas sur la portée globale comme lorsque nous avons appelé bar().

Prise en charge du navigateur
Prise en charge de la version du navigateur
Chrome 7
Firefox (Gecko) 4.0 (2)
Internet Explorer 9
Opéra 11h60
Safari 5.1.4
Comme vous pouvez le constater, Function.prototype.bind n'est malheureusement pas pris en charge dans IE8 et versions antérieures, donc si vous n'avez pas de solution de secours, vous risquez de rencontrer des problèmes.

Heureusement, le Mozilla Developer Network (une excellente bibliothèque de ressources) fournit une alternative solide pour les navigateurs qui n'implémentent pas eux-mêmes la méthode .bind() :

if (!Function.prototype.bind) {
 Function.prototype.bind = function (oThis) {
  if (typeof this !== "function") {
   
// closest thing possible to the ECMAScript 5 internal IsCallable function
   throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
  }
 
  var aArgs = Array.prototype.slice.call(arguments, 1), 
    fToBind = this, 
    fNOP = function () {},
    fBound = function () {
     return fToBind.apply(this instanceof fNOP && oThis
                 ? this
                 : oThis,
                aArgs.concat(Array.prototype.slice.call(arguments)));
    };
 
  fNOP.prototype = this.prototype;
  fBound.prototype = new fNOP();
 
  return fBound;
 };
}

Copier après la connexion

Modes applicables

Lors de l'apprentissage des points techniques, j'ai trouvé que ce qui est utile n'est pas seulement d'étudier et de comprendre en profondeur le concept, mais aussi de voir s'il y a une application dans le travail en cours, ou quelque chose de proche. J'espère que certains des exemples ci-dessous s'appliqueront à votre code ou résoudront les problèmes auxquels vous êtes confronté.

Gestionnaires de clics (fonction de gestionnaire de clics)
Une utilisation consiste à enregistrer un événement de clic (ou à effectuer une action après un clic), ce qui peut nous obliger à stocker certaines informations dans un objet, telles que :

var logger = {
  x: 0,    
  updateCount: function(){
    this.x++;
    console.log(this.x);
  }
}

Copier après la connexion

Nous pouvons spécifier la fonction de traitement des clics de la manière suivante, puis appeler la méthode updateCount() dans l'objet logger.

document.querySelector('button').addEventListener('click', function(){
  logger.updateCount();
});
Copier après la connexion

Mais nous devons créer une fonction anonyme supplémentaire pour garantir que le mot-clé this dans la fonction updateCount() a la valeur correcte.

Nous pouvons utiliser la méthode plus propre suivante :

document.querySelector('button').addEventListener('click', logger.updateCount.bind(logger));
Nous utilisons intelligemment la fonction pratique .bind() pour créer une nouvelle fonction et lier sa portée à l'objet enregistreur.

SETTIMEOUT
Si vous avez utilisé un moteur de modèles (tel que guidon) ou en particulier certains des frameworks MV* (d'après mon expérience, je ne peux parler que de Backbone.js), alors vous connaissez peut-être la discussion ci-dessous sur l'accès au nouveau DOM immédiatement après le rendu du template Problèmes rencontrés lors de l'utilisation des nœuds.

Supposons que nous voulions instancier un plugin jQuery :

var myView = {
 
  template: '/* 一个包含 <select /> 的模板字符串*/',
 
  $el: $('#content'),
 
  afterRender: function () {
    this.$el.find('select').myPlugin();
  },
 
  render: function () {
    this.$el.html(this.template());
    this.afterRender();
  }
}
 
myView.render();

Copier après la connexion

Vous constaterez peut-être que cela fonctionne - mais pas à chaque fois car il y a des problèmes. C'est une question de compétition : celui qui arrive le premier gagne. Parfois le rendu vient en premier, et parfois l’instanciation du plugin vient en premier. [Note du traducteur : si le processus de rendu n'est pas terminé (le nœud DOM n'a pas été ajouté à l'arborescence DOM), alors find('select') ne pourra pas trouver le nœud correspondant pour effectuer l'instanciation. 】

Maintenant, peut-être que peu de gens le savent, nous pouvons utiliser un léger hack basé sur setTimeout() pour résoudre le problème.

Réécrivons légèrement notre code pour instancier en toute sécurité notre plug-in jQuery après le chargement du nœud DOM :

afterRender: function () {
    this.$el.find('select').myPlugin();
  },
 
  render: function () {
    this.$el.html(this.template());
    setTimeout(this.afterRender, 0);    
  }

Copier après la connexion

然而,我们获得的是 函数 .afterRender() 不能找到 的错误信息。

我们接下来要做的,就是将.bind()使用到我们的代码中:

//
 
  afterRender: function () {
    this.$el.find('select').myPlugin();
  },
 
  render: function () {
    this.$el.html(this.template());
    setTimeout(this.afterRender.bind(this), 0);    
  }
 
//
Copier après la connexion

以上所述就是本文的全部内容了,希望大家能够喜欢。

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal