web-dev-qa-db-fra.com

Coffeescript 'this' dans jQuery .each ()

J'ai quelques scripts comme celui-ci:

class foo:
    @bar = 'bob loblaw'

    processRows: ->
        $("#my-table>tr").each ->
            id = $(this).attr("id")
            @processRow id

    processRow: (id) ->
        console.log @bar + id

Donc mon problème est: j'ai besoin de this pour référencer le contexte .each À l'intérieur de la boucle pour arriver à id, mais je voudrais aussi que this fasse référence à la instance de classe à l'intérieur de foo.processRow()--- ce qu'elle ne fait pas actuellement.

Utiliser quelque chose comme _this = this En dehors de la fonction .each Et le faire circuler n'est pas non plus une excellente solution, car je référence de nombreuses variables de classe dans processRow.

Des pensées? Suis-je en train de manquer quelque chose d'évident? Merci!

54
user524276

jQuery.each passe l'élément courant comme deuxième paramètre du rappel, donc vous n'avez pas ayez à réserver this pour jQuery:

processRows: ->
    $("#my-table>tr").each (index, element) =>
        id = $(element).attr("id")
        @processRow id

Remarquez l'utilisation du grosse flèche (=>) syntaxe pour la fonction de rappel; il lie le contexte de la fonction à la valeur actuelle de this. (this dans la fonction de rappel est toujours le même this que celui au moment où vous avez défini la fonction.)

128
Arnaud Le Blanc

Vous dites

Utiliser quelque chose comme _this = this En dehors de la fonction .each Et le faire circuler n'est pas non plus une excellente solution, car je référence de nombreuses variables de classe à l'intérieur de processRow.

C'est cependant la solution la plus efficace. this de JavaScript est une bête étrange; vous pouvez le garder fixe à l'intérieur d'une fonction imbriquée en utilisant l'opérateur =>, comme le suggère arnaud576875 dans sa réponse (qui est élégante mais inefficace), ou vous pouvez copier this dans une autre variable (qui est efficace mais inélégant). Le choix t'appartient.

Notez que certains navigateurs modernes prennent en charge une méthode bind sur chaque fonction, ce qui est plus efficace que => De CoffeeScript. Il y a un ticket ouvert pour que => Utilise le bind natif lorsqu'il est disponible: https://github.com/jashkenas/coffee-script/pull/1408

Addendum: Bien sûr, une alternative plus efficace que tout ce qui précède serait d'écrire

for element, index in $('#my-table>tr')
  ...

ce qui résoudrait également votre problème this.

6
Trevor Burnham

Votre code...

class foo
    @bar = 'bob loblaw'

    processRows: ->
        $("#my-table>tr").each ->
            id = $(this).attr("id")
            @processRow id

    processRow: (id) ->
        console.log @bar + id

Est transposé en ...

var foo;
foo = (function() {
  function foo() {}
  foo.bar = 'bob loblaw';
  foo.prototype.processRows = function() {
    return $("#my-table>tr").each(function() {
      var id;
      id = $(this).attr("id");
      return this.processRow(id);
    });
  };
  foo.prototype.processRow = function(id) {
    return console.log(this.bar + id);
  };
  return foo;
})();

Ce qui a beaucoup supposé le contexte actuel dans lequel il se traduit. Malheureusement, puisque jQuery gère le contexte, vous devrez être explicite ou déclarer une référence au this de votre classe.

Par ailleurs, il y a d'autres problèmes avec ce code généré, jetez un œil à ce cas réduit:

class foo
    @bar = 'bob loblaw'

    getBar: () ->
        @bar

Transpile vers:

var foo;
foo = (function() {
  function foo() {}
  foo.bar = 'bob loblaw';
  foo.prototype.getBar = function() {
    return this.bar;
  };
  return foo;
})();

Les résultats de la tentative d'utilisation de ce morceau de code:

> foo.bar;
"bob loblaw"

> var f = new foo();
undefined

> f.getBar();
undefined

Votre code semble s'attendre à ce que @bar est une propriété propre, mais elle est créée en tant que propriété statique de la fonction foo

4
Rick