77 votes

Est-il un alias pour " il " en caractères d'imprimerie?

J'ai tenté d'écrire une classe en caractères d'imprimerie qui a une méthode qui agit comme un rappel de gestionnaires d'événement pour un événement jQuery.

class Editor {
    textarea: JQuery;

    constructor(public id: string) {
        this.textarea = $(id);
        this.textarea.focusin(onFocusIn);
    }

    onFocusIn(e: JQueryEventObject) {
        var height = this.textarea.css('height'); // <-- This is not good.
    }
}

Dans le onFocusIn gestionnaire d'événements, Tapuscrit voit " ce "comme étant le" il " de la classe. Cependant, jQuery remplace la référence et définit l'objet DOM associé à l'événement.

Une alternative consiste à définir un lambda dans le constructeur comme le gestionnaire d'événement, auquel cas la Machine crée une sorte de fermeture avec un caché _ce alias.

class Editor {
    textarea: JQuery;

    constructor(public id: string) {
        this.textarea = $(id);
        this.textarea.focusin((e) => {
            var height = this.textarea.css('height'); // <-- This is good.
        });
    }
}

Ma question est, est-il un autre moyen pour accéder à la référence à l'intérieur de la méthode de la fonction de gestionnaire d'événement à l'aide de la Machine, pour surmonter cette jQuery comportement?

104voto

Steve Fenton Points 55265

Le champ d'application de l' this est conservé lors de l'utilisation de la flèche en fonction de la syntaxe () => { ... } - voici un exemple tiré du texte dactylographié Pour les Programmeurs JavaScript.

var ScopeExample = { 
  text: "Text from outer function", 
  run: function() { 
    setTimeout( () => { 
      alert(this.text); 
    }, 1000); 
  } 
};

Notez que this.text vous donne Text from outer function parce que la flèche syntaxe de la fonction préserve la "portée lexicale".

23voto

Steven Ickman Points 882

Donc, comme l'a déclaré il n'y a pas de texte dactylographié mécanisme pour s'assurer d'une méthode est toujours lié à l' this pointeur (et ce n'est pas seulement un jQuery problème). Cela ne signifie pas qu'il n'y a pas un resonably simple pour résoudre ce problème. Ce que vous avez besoin est de générer un proxy pour votre méthode qui restaure l' this pointeur avant d'appeler votre fonction de rappel. Ensuite, vous devez emballer votre rappel avec proxy avant de le transmettre à l'événement. jQuery est intégré dans le mécanisme de ce qui est appelé' jQuery.proxy(). Voici un exemple de ton code ci-dessus à l'aide de cette méthode (avis de l'ajoutés $.proxy() appel.)

class Editor { 
    textarea: JQuery; 

    constructor(public id: string) { 
        this.textarea = $(id); 
        this.textarea.focusin($.proxy(onFocusIn, this)); 
    } 

    onFocusIn(e: JQueryEventObject) { 
        var height = this.textarea.css('height'); // <-- This is not good. 
    } 
} 

C'est une solution raisonnable, mais j'ai personnellement trouvé que les développeurs offten oubliez pas d'inclure le proxy appel donc je suis venu avec un autre fichier d'enregistrement en fonction de la solution à ce problème. L'aide, l' HasCallbacks catégorie ci-dessous tout ce que vous devez faire est de tirer votre classe à partir d' HasCallbacks puis de toutes les méthodes avec le préfixe 'cb_' ont leur this pointeur liés en permanence. Vous simplement ne pouvez pas appeler cette méthode avec une autre this pointeur qui, dans la plupart des cas, est préférable. Soit le mécanisme fonctionne alors c'est juste celui qui vous est le plus facile à utiliser.

class HasCallbacks {
    constructor() {
        var _this = this, _constructor = (<any>this).constructor;
        if (!_constructor.__cb__) {
            _constructor.__cb__ = {};
            for (var m in this) {
                var fn = this[m];
                if (typeof fn === 'function' && m.indexOf('cb_') == 0) {
                    _constructor.__cb__[m] = fn;                    
                }
            }
        }
        for (var m in _constructor.__cb__) {
            (function (m, fn) {
                _this[m] = function () {
                    return fn.apply(_this, Array.prototype.slice.call(arguments));                      
                };
            })(m, _constructor.__cb__[m]);
        }
    }
}

class Foo extends HasCallbacks  {
    private label = 'test';

    constructor() {
        super();

    }

    public cb_Bar() {
        alert(this.label);
    }
}

var x = new Foo();
x.cb_Bar.call({});

21voto

Sam Points 3542

Comme couverts par certains des autres réponses, à l'aide de la flèche de la syntaxe pour définir une fonction provoque des références à this de toujours se référer à la classe englobante.

Donc, pour répondre à votre question, voici deux solutions de contournement.

Référence de la méthode à l'aide de la flèche de la syntaxe

constructor(public id: string) {
    this.textarea = $(id);
    this.textarea.focusin(e => this.onFocusIn(e));
}

Définir la méthode à l'aide de la flèche de la syntaxe

onFocusIn = (e: JQueryEventObject) => {
    var height = this.textarea.css('height');
}

6voto

Drew Noakes Points 69288

Vous pouvez lier une fonction de membre d'une instance dans le constructeur.

class Editor {
    textarea: JQuery;

    constructor(public id: string) {
        this.textarea = $(id);
        this.textarea.focusin(onFocusIn);
        this.onFocusIn = this.onFocusIn.bind(this); // <-- Bind to 'this' forever
    }

    onFocusIn(e: JQueryEventObject) {
        var height = this.textarea.css('height');   // <-- This is now fine
    }
}

Sinon, juste lier lorsque vous ajoutez le gestionnaire.

        this.textarea.focusin(onFocusIn.bind(this));

4voto

Gabriel C. Points 31

Essayez ceci

class Editor 
{

    textarea: JQuery;
    constructor(public id: string) {
        this.textarea = $(id);
        this.textarea.focusin((e)=> { this.onFocusIn(e); });
    }

    onFocusIn(e: JQueryEventObject) {
        var height = this.textarea.css('height'); // <-- This will work
    }

}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X