Is er een alias voor 'dit' de schrijfmachine?

stemmen
72

Ik heb geprobeerd om een ​​klasse met de schrijfmachine, dat een methode die is gedefinieerd die fungeert als een event handler callback naar een jQuery evenement te schrijven.

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.
    }
}

Binnen het onFocusIn event handler, typoscript ziet 'dit' als de 'dit' van de klas. Echter, jQuery voorrang op de dit en bepaalt aan de DOM object geassocieerd met de gebeurtenis.

Een alternatief is om een ​​lambda in de constructor de event handler, waarbij schrijfmachine ontstaat een soort sluiting met een verborgen _this alias definiëren.

class Editor {
    textarea: JQuery;

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

Mijn vraag is, is er een andere manier om de deze verwijzing in de methodische event handler gebruiken Typescript, om dit probleem te overwinnen jQuery?

De vraag is gesteld op 06/10/2012 om 04:26
bron van user
In andere talen...                            


12 antwoorden

stemmen
97

Het toepassingsgebied van thisbehouden blijft bij gebruik van de pijl functiesyntax () => { ... }- hier een voorbeeld uit de schrijfmachine voor JavaScript programmeurs .

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

Merk op dat this.textgeeft je Text from outer function, omdat de pijl syntaxis van de functie behoudt de "lexicale scope".

antwoordde op 06/10/2012 om 15:25
bron van user

stemmen
21

Dus zoals gezegd is er geen typoscript mechanisme voor het waarborgen van een methode wordt altijd gebonden aan het thispointer (en dit is niet alleen een jQuery kwestie.) Dat betekent niet dat er niet een redelijk eenvoudige manier om dit probleem aan te pakken. Wat je nodig hebt is een proxy voor de methode die het herstelt genereren thispointer roept daarvoor jullie callback. Vervolgens moet u uw callback met die proxy wikkel voordat deze in het evenement. jQuery heeft een ingebouwd mechanisme hiervoor genoemd jQuery.proxy(). Hier is een voorbeeld van uw bovenstaande code met behulp van deze methode (de toegevoegde merken $.proxy()gesprek.)

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. 
    } 
} 

Dat is een redelijke oplossing, maar ik persoonlijk vond dat ontwikkelaars vaak vergeten om de proxy gesprek te nemen, zodat ik met een alternatieve Typescript gebaseerde oplossing voor dit probleem gekomen. Met behulp van de HasCallbacksklasse onder de alles wat je hoeft te doen is af te leiden uw klas uit HasCallbacksen vervolgens alle methoden voorafgegaan 'cb_'zullen hun thispointer permanent gebonden. Je kan gewoon niet bellen die methode met een andere thispointer die in de meeste gevallen de voorkeur. Ofwel mechanisme werkt dus het is gewoon afhankelijk van wat u gemakkelijker te gebruiken zijn.

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({});
antwoordde op 06/10/2012 om 06:28
bron van user

stemmen
20

Zoals besproken door een aantal van de andere antwoorden, met behulp van de pijl syntax definiëren van een functie zorgt ervoor dat de verwijzingen naar thisom altijd te verwijzen naar de omsluitende klasse.

Dus om je vraag te beantwoorden, hier zijn twee eenvoudige oplossingen.

Verwijzen naar de werkwijze met de pijl syntax

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

Definieer de werkwijze met de pijl syntax

onFocusIn = (e: JQueryEventObject) => {
    var height = this.textarea.css('height');
}
antwoordde op 23/12/2013 om 05:27
bron van user

stemmen
6

U kunt een lid functie om zijn voorbeeld te binden in de constructor.

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
    }
}

Als alternatief, gewoon binden wanneer u de handler toe te voegen.

        this.textarea.focusin(onFocusIn.bind(this));
antwoordde op 20/05/2014 om 15:47
bron van user

stemmen
3

Steven Ickman's oplossing is handig, maar niet volledig. Danny Becket en antwoorden Sam's zijn korter en meer handmatige en falen in dezelfde algemene geval van het hebben van een callback die zowel dynamische als lexicaal scoped "dit" op hetzelfde moment nodig heeft. Doorgaan naar mijn code als mijn uitleg hieronder is TL; DR ...

Ik moet het behoud van "dit" voor dynamische scoping voor gebruik met bibliotheek callbacks, en ik moet hebben een "dit" met lexicale scoping de klasse-instantie. Ik betoog dat het het meest elegant tot de instantie overgaan in een callback generator, effectief te laten de parameter sluiting over de klasse-instantie. De compiler vertelt u als u dat doet gemist. Ik gebruik een conventie van het aanroepen van de lexicaal scoped parameter "outerThis", maar "zelf" of een andere naam misschien beter.

Het gebruik van het "dit" keyword wordt gestolen uit de OO wereld, en wanneer typoscript heeft zij (van ECMAScript 6 specs neem ik aan), ze samengevoegd een lexicaal scoped concept en een context-afhankelijke concept, wanneer een methode wordt aangeroepen door een andere entiteit . Ik ben een beetje miffed op dit; Ik zou liever een "zelf" keyword met de schrijfmachine, zodat ik de lexicaal scoped object kan bijvoorbeeld de hand van het weg. Alternatief zou JS opnieuw worden gedefinieerd om een ​​expliciete eerste positie parameter "beller" nodig wanneer het nodig is (en dus alle webpagina's in een klap te breken).

Hier is mijn oplossing (uitgesneden uit een grote klasse). Neem een ​​kijkje in het bijzonder naar de manier waarop de methoden worden genoemd, en het lichaam van "dragmoveLambda" in het bijzonder:

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;
        }
    }

}
antwoordde op 21/03/2014 om 20:33
bron van user

stemmen
3

Probeer dit

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
    }

}
antwoordde op 24/05/2013 om 02:47
bron van user

stemmen
2

U kunt js eval functie te gebruiken: var realThis = eval('this');

antwoordde op 20/09/2014 om 13:13
bron van user

stemmen
2

Typescript levert geen aanvullende wijze (uit buiten de normale JavaScript middelen) terug naar de "echte instappen thisreferentiewaarde dan thisremapping gemak in de dikke pijl lambda syntax (die toelaatbaar is uit een back-compat perspectief omdat er geen bestaande JS code kan zijn door middel van =>expressie).

Je kan een suggestie om de CodePlex website te plaatsen, maar vanuit een taal ontwerp perspectief is er waarschijnlijk niet veel dat kan hier gebeuren, aangezien ieder weldenkend zoekwoord de compiler zou kunnen bieden misschien al in gebruik door bestaande JavaScript-code.

antwoordde op 06/10/2012 om 04:35
bron van user

stemmen
1

Ik heb een soortgelijk probleem geconfronteerd. Ik denk dat je kunt gebruiken .each()in veel gevallen te houden thisals een andere waarde voor latere gebeurtenissen.

De JavaScript-manier:

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

De getypte manier:

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

Ik hoop dat dit helpt iemand.

antwoordde op 16/06/2014 om 09:17
bron van user

stemmen
0

Er is veel eenvoudiger oplossing dan al het bovenstaande antwoorden. In principe terugvallen we JavaScript met behulp sleutelwoord functie in plaats van '=>' te bouwen, die de 'dit' in class 'dit' zal vertalen

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'); 
    }
}
antwoordde op 11/05/2015 om 18:30
bron van user

stemmen
0

Bekijk deze blogpost http://lumpofcode.blogspot.com/2012/10/typescript-dart-google-web-toolkit-and.html , het heeft een gedetailleerde bespreking van technieken voor het organiseren van gesprekken binnen en tussen typoscript klassen.

antwoordde op 06/12/2014 om 01:49
bron van user

stemmen
0

Je kon je verwijzing opslaan thisin een andere variabele .. selfmisschien, en toegang tot de referentie op die manier. Ik gebruik geen typoscript, maar dat is een methode die succesvol is geweest voor mij met vanille javascript in het verleden.

antwoordde op 06/10/2012 om 04:30
bron van user

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