Y at-il un alias pour « ce » dactylographiée?

voix
72

J'ai essayé d'écrire une classe dactylographiée qui a une méthode définie qui agit comme un rappel de gestionnaire d'événements à 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 gestionnaire d'événement onfocusin, tapuscrit voit « ceci » comme étant « ceci » de la classe. Cependant, jQuery remplace la cette référence et il met à l'objet DOM associé à l'événement.

Une alternative consiste à définir un lambda dans le constructeur en tant que gestionnaire d'événements, dans lequel tapuscrit cas crée une sorte de fermeture avec un alias _this caché.

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 d'accéder à la cette référence dans le gestionnaire d'événements fondé sur la méthode utilisant tapuscrit, pour surmonter ce comportement jQuery?

Créé 06/10/2012 à 04:26
source utilisateur
Dans d'autres langues...                            


12 réponses

voix
97

Le champ d'application thisest conservée lorsque vous utilisez la syntaxe de la fonction flèche () => { ... }- voici un exemple tiré de tapuscrit Pour les programmeurs JavaScript .

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

Notez que this.textvous donne Text from outer functionparce que la syntaxe de la fonction flèche préserve la « portée lexicale ».

Créé 06/10/2012 à 15:25
source utilisateur

voix
21

Ainsi , comme il est dit qu'il n'y a pas de mécanisme pour assurer tapuscrit une méthode est toujours lié à son thispointeur (et ce n'est pas seulement une question jQuery.) Cela ne signifie pas qu'il n'y a pas un moyen assez 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 le thispointeur avant d' appeler votre rappel. Vous devez ensuite envelopper votre rappel avec cette procuration avant de passer dans l'événement. jQuery dispose d' un mécanisme intégré pour cette appelé jQuery.proxy(). Voici un exemple de votre code ci - dessus en utilisant cette méthode (notez la valeur ajoutée $.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 je l' ai personnellement constaté que les développeurs oublient souvent d'inclure l'appel proxy donc je suis venu avec une solution à base tapuscrit alternative à ce problème. L' utilisation, la HasCallbacksclasse ci - dessous tout ce que vous devez faire est de tirer votre classe à partir HasCallbackset toutes les méthodes préfixées 'cb_'auront leur thispointeur en permanence lié. Vous ne pouvez pas appeler cette méthode avec un autre thispointeur qui , dans la plupart des cas est préférable. Soit le mécanisme fonctionne si son juste selon vous trouverez 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({});
Créé 06/10/2012 à 06:28
source utilisateur

voix
20

Comme couvert par quelques - unes des autres réponses, en utilisant la syntaxe de flèche pour définir une fonction provoque des références à thistoujours se référer à la classe englobante.

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

La méthode de référence en utilisant la syntaxe de flèche

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

Définition de la méthode utilisant la syntaxe de la flèche

onFocusIn = (e: JQueryEventObject) => {
    var height = this.textarea.css('height');
}
Créé 23/12/2013 à 05:27
source utilisateur

voix
6

Vous pouvez lier une fonction membre à son 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, bind quand vous ajoutez le gestionnaire.

        this.textarea.focusin(onFocusIn.bind(this));
Créé 20/05/2014 à 15:47
source utilisateur

voix
3

La solution de Steven Ickman est à portée de main, mais incomplète. Danny Becket et les réponses de Sam sont plus courtes et plus manuel, et ne parviennent pas dans le même cas général d'avoir un rappel qui a besoin à la fois dynamique et lexicalement scope « ce » en même temps. Passer à mon code si mon explication ci-dessous est TL; DR ...

Je dois préserver « cette » pour la portée dynamique pour une utilisation avec callbacks bibliothèque, et je dois avoir un « ce » avec une portée lexicale à l'instance de classe. Je soutiens qu'il est le plus élégant de passer l'instance dans un générateur de rappel, laissant effectivement la fermeture des paramètres sur l'instance de classe. Le compilateur vous indique si vous avez manqué le faire. J'utilise une convention d'appeler le paramètre « scope outerThis lexicalement », mais « moi » ou un autre nom peut - être mieux.

L'utilisation du « ce » mot-clé est volé dans le monde OO, et quand tapuscrit a adopté (à partir ECMAScript 6 spécifications Je présume), ils confondait un concept lexicalement scope et un concept dynamique scope, chaque fois qu'une méthode est appelée par une autre entité . Je suis un peu vexé à ce; Je préférerais un mot-clé « auto » en caractères d'imprimerie afin que je puisse remettre l'instance d'objet scope lexicalement hors de lui. Alternativement, JS pourrait être redéfinie comme exigeant une première position de paramètre « appelant » quand il est nécessaire (et donc briser toutes les pages Web d'un seul coup).

Voici ma solution (excisé une grande classe). Prenez un coup d'oeil en particulier la façon dont les méthodes sont appelées, et le corps de « dragmoveLambda » en particulier:

export class OntologyMappingOverview {

initGraph(){
...
// Using D3, have to provide a container of mouse-drag behavior functions
// to a force layout graph
this.nodeDragBehavior = d3.behavior.drag()
        .on("dragstart", this.dragstartLambda(this))
        .on("drag", this.dragmoveLambda(this))
        .on("dragend", this.dragendLambda(this));

...
}

dragmoveLambda(outerThis: OntologyMappingOverview): {(d: any, i: number): void} {
    console.log("redefine this for dragmove");

    return function(d, i){
        console.log("dragmove");
        d.px += d3.event.dx;
        d.py += d3.event.dy;
        d.x += d3.event.dx;
        d.y += d3.event.dy; 

        // Referring to "this" in dynamic scoping context
        d3.select(this).attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });

        outerThis.vis.selectAll("line")
            .filter(function(e, i){ return e.source == d || e.target == d; })
            .attr("x1", function(e) { return e.source.x; })
            .attr("y1", function(e) { return e.source.y; })
            .attr("x2", function(e) { return e.target.x; })
            .attr("y2", function(e) { return e.target.y; });

    }
}

dragging: boolean  =false;
// *Call* these callback Lambda methods rather than passing directly to the callback caller.
 dragstartLambda(outerThis: OntologyMappingOverview): {(d: any, i: number): void} {
        console.log("redefine this for dragstart");

        return function(d, i) {
            console.log("dragstart");
            outerThis.dragging = true;

            outerThis.forceLayout.stop();
        }
    }

dragendLambda(outerThis: OntologyMappingOverview): {(d: any, i: number): void}  {
        console.log("redefine this for dragend");

        return function(d, i) {
            console.log("dragend");
            outerThis.dragging = false;
            d.fixed = true;
        }
    }

}
Créé 21/03/2014 à 20:33
source utilisateur

voix
3

Essaye ça

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
    }

}
Créé 24/05/2013 à 02:47
source utilisateur

voix
2

Vous pouvez utiliser la fonction eval js: var realThis = eval('this');

Créé 20/09/2014 à 13:13
source utilisateur

voix
2

Tapuscrit ne fournit aucun moyen supplémentaire (au - delà des moyens JavaScript réguliers) pour revenir à la « vraie » thisréférence autre que la thiscommodité remappant fourni dans la syntaxe de graisse flèche lambda ( ce qui est admissible dans une perspective de back-compat puisqu'aucun code JS existant pourrait utiliser une =>expression).

Vous pouvez poster une suggestion sur le site CodePlex, mais d'un point de vue de la conception du langage il n'y a probablement pas grand - chose qui peut arriver ici, car un mot clé sain d' esprit le compilateur pourrait fournir peut - être déjà utilisé par le code JavaScript existant.

Créé 06/10/2012 à 04:35
source utilisateur

voix
1

J'ai fait face à un problème similaire. Je pense que vous pouvez utiliser .each()dans de nombreux cas pour maintenir thisune valeur différente pour les événements ultérieurs.

La façon JavaScript:

$(':input').on('focus', function() {
  $(this).css('background-color', 'green');
}).on('blur', function() {
  $(this).css('background-color', 'transparent');
});

La façon dactylographiée:

$(':input').each((i, input) => {
  var $input = $(input);
  $input.on('focus', () => {
    $input.css('background-color', 'green');
  }).on('blur', () => {
    $input.css('background-color', 'transparent');
  });
});

J'espère que ça aidera quelqu'un.

Créé 16/06/2014 à 09:17
source utilisateur

voix
0

Il y a une solution beaucoup plus simple que toutes les réponses ci-dessus. Fondamentalement, nous retombons à JavaScript en utilisant la fonction de mot-clé au lieu d'utiliser « => » construire qui se traduira par « ceci » dans la classe « ce »

class Editor {
    textarea: JQuery;

    constructor(public id: string) {
        var self = this;                      // <-- This is save the reference
        this.textarea = $(id);
        this.textarea.focusin(function() {   // <-- using  javascript function semantics here
             self.onFocusIn(this);          //  <-- 'this' is as same as in javascript
        });
    }

    onFocusIn(jqueryObject : JQuery) {
        var height = jqueryObject.css('height'); 
    }
}
Créé 11/05/2015 à 18:30
source utilisateur

voix
0

Découvrez ce blog http://lumpofcode.blogspot.com/2012/10/typescript-dart-google-web-toolkit-and.html , il a une discussion détaillée des techniques pour l' organisation des appels à l' intérieur et à travers les classes tapuscrit.

Créé 06/12/2014 à 01:49
source utilisateur

voix
0

Vous pouvez stocker votre référence à thisune autre variable .. selfpeut - être, et accéder à la référence de cette façon. Je ne me tapuscrit, mais c'est une méthode qui a été couronnée de succès pour moi avec javascript vanille dans le passé.

Créé 06/10/2012 à 04:30
source utilisateur

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more