Gibt es ein Alias ​​für ‚this‘ in Typoskript?

stimmen
72

Ich habe eine Klasse in Typoskript zu schreiben versucht, das eine Methode hat definiert, die zu einem jQuery Ereignisse als Event-Handler Callback fungiert.

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

Im onFocusIn Ereignishandler sieht Typoskript ‚this‘ als das ‚dies‘ der Klasse. Allerdings überschreibt jQuery die diese Referenz und stellt es auf den DOM-Objekt mit dem Ereignis verknüpft ist.

Eine Alternative ist es, eine Lambda im Konstruktor als Event-Handler zu definieren, in welchem ​​Fall Typoskript schafft eine Art Verschluss mit einem versteckten _this 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.
        });
    }
}

Meine Frage ist, gibt es eine andere Art und Weise die diese Referenz innerhalb der Methode basierten Event-Handler mit Typoskript zuzugreifen, diese jQuery Verhalten zu überwinden?

Veröffentlicht am 06/10/2012 um 04:26
quelle vom benutzer
In anderen Sprachen...                            


12 antworten

stimmen
97

Der Umfang thiserhalten bleibt , wenn die Pfeil Funktion Syntax () => { ... }- hier ein Beispiel aus genommen Typoskript für JavaScript - Programmierer .

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

Beachten Sie, dass this.textgibt Ihnen Text from outer functionda der Pfeil Funktion Syntax der „lexikalischen Gültigkeitsbereich“ bewahrt.

Beantwortet am 06/10/2012 um 15:25
quelle vom benutzer

stimmen
21

Also wie gesagt gibt es keine Typoskript Mechanismus ein Verfahren zur Sicherstellung ist immer gebunden , es ist thisZeiger (und das ist nicht nur ein jQuery - Ausgabe.) , Die nicht dort bedeutet , ist nicht eine ziemlich einfache Möglichkeit , dieses Problem zu beheben. Was Sie brauchen , ist ein Proxy für Ihre Methode zu erzeugen, das die Wiederherstellung thisZeiger , bevor Sie Ihren Rückruf anrufen. Sie müssen dann mit dem Proxy Ihren Rückruf wickeln , bevor es in die Veranstaltung vorbei. jQuery hat einen eingebauten Mechanismus hierfür genannt jQuery.proxy(). Hier ist ein Beispiel des obigen Code mit dieser Methode (beachten Sie den zusätzlichen $.proxy()Anruf.)

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

Das ist eine vernünftige Lösung , aber ich persönlich habe festgestellt , dass Entwickler oft vergessen , den Proxy - Aufruf enthalten , so habe ich mit einer alternativen Typoskript basierte Lösung für dieses Problem kommen. Unter Verwendung der HasCallbacksist Klasse unter alles , was Sie tun müssen , Ihre Klasse stammen aus HasCallbacksund dann mit dem Präfix all Verfahren 'cb_'ihrer haben thisZeiger dauerhaft gebunden. Sie können einfach nicht , dass die Methode mit einem anderen Aufruf thisZeiger, der in den meisten Fällen vorzuziehen ist. Entweder Mechanismus funktioniert so seine nur je nachdem , was Sie leichter zu bedienen.

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({});
Beantwortet am 06/10/2012 um 06:28
quelle vom benutzer

stimmen
20

Wie von einigen der anderen Antworten abgedeckt, die Pfeil - Syntax zur Definition einer Funktion bewirkt , dass Verweise auf thisimmer auf der umgebenden Klasse zu verweisen.

So Ihre Frage zu beantworten, hier sind zwei einfache Abhilfen.

Verweisen Sie auf das Verfahren auf die Pfeil-Syntax

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

Definieren Sie die Methode auf die Pfeil-Syntax

onFocusIn = (e: JQueryEventObject) => {
    var height = this.textarea.css('height');
}
Beantwortet am 23/12/2013 um 05:27
quelle vom benutzer

stimmen
6

Sie können eine Member-Funktion in seine Instanz im Konstruktor binden.

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

Alternativ einfach es binden, wenn Sie die Handler hinzufügen.

        this.textarea.focusin(onFocusIn.bind(this));
Beantwortet am 20/05/2014 um 15:47
quelle vom benutzer

stimmen
3

Steven Ickman Lösung ist praktisch, aber unvollständig. Danny Becket und Sams Antworten sind kürzer und manuelle, und nicht in dem gleichen allgemeinen Fall einen Rückruf aufweist, die sowohl dynamische als auch lexikalische „diese“ zur gleichen Zeit benötigt. Weiter zu meinen Code, wenn meine Erklärung unten ist TL; DR ...

Ich brauche „diese“ für dynamischen Scoping für die Verwendung mit Bibliothek Rückrufen zu bewahren, und ich brauche ein „this“ mit lexikalischem Scoping auf die Klasseninstanz haben. Ich behaupte , dass es eleganteste ist die Instanz in einen Callback - Generator passieren, effektiv den Parameter Schließung über die Klasseninstanz im Stich gelassen. Der Compiler sagt Ihnen , wenn Sie dies tun verpassten. Ich benutze eine Konvention , die lexikalische Parameter „outerThis“ nennen, sondern „Selbst“ oder ein anderer Name könnte besser sein.

Die Verwendung des „this“ Schlüsselwort aus der OO-Welt gestohlen, und als Typoskript es angenommen (von ECMAScript 6 Spezifikationen nehme ich an), sie verschmelzt ein lexikalisches Konzept und ein dynamisch scoped Konzept, wann immer eine Methode, mit einer anderen Einheit aufgerufen wird . Ich bin ein wenig an diesem verstimmt; Ich würde ein „Selbst“ Schlüsselwort in Typoskript bevorzugen, so dass ich die lexikalischen Objektinstanz aus der es von Hand kann. Alternativ könnte JS neu definiert werden, um einen expliziten erste Position „Anrufer“ Parameter erforderlich ist, wenn es benötigt wird (und damit alle Web-Seiten auf einem Schlag brechen).

Hier ist meine Lösung (aus einer großen Klasse ausgeschnitten). Nehmen Sie einen Blick insbesondere auf die Art und Weise der Verfahren genannt werden, und um den Körper von „dragmoveLambda“ insbesondere:

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

}
Beantwortet am 21/03/2014 um 20:33
quelle vom benutzer

stimmen
3

Versuche dies

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
    }

}
Beantwortet am 24/05/2013 um 02:47
quelle vom benutzer

stimmen
2

Sie können js eval-Funktion verwenden: var realThis = eval('this');

Beantwortet am 20/09/2014 um 13:13
quelle vom benutzer

stimmen
2

Typoskript bietet keine zusätzliche Art und Weise (über die reguläre JavaScript bedeutet) , um zurück zum ‚echten‘ zu bekommen thisReferenz andere als thisRemapping Bequemlichkeit zur Verfügung gestellt in der Fett Pfeil Lambda - Syntax (die von einem Back-compat Perspektive , da keine bestehenden JS - Code zulässig ist könnte unter Verwendung eines =>Ausdrucks).

Sie könnten einen Vorschlag die CodePlex - Website veröffentlichen, sondern aus einer Sprache Design - Perspektive gibt es wahrscheinlich nicht viel , das kann hier, da jedes vernünftiges Schlüsselwort könnten bieten die Compiler von vorhandenen JavaScript - Code könnte schon seine in Gebrauch passieren.

Beantwortet am 06/10/2012 um 04:35
quelle vom benutzer

stimmen
1

Ich habe ein ähnliches Problem konfrontiert. Ich denke , dass Sie verwenden können , .each()in vielen Fällen zu halten thisals ein anderer Wert für die späteren Ereignisse.

Der JavaScript-Weg:

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

Typoskript Weg:

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

Ich hoffe, das jemand hilft.

Beantwortet am 16/06/2014 um 09:17
quelle vom benutzer

stimmen
0

Es ist viel einfachere Lösung als alle oben genannten Antworten. Grundsätzlich wir JavaScript zurückgreifen durch Schlüsselwort-Funktion anstelle der Verwendung von ‚=>‘ konstruieren, die die ‚this‘ in der Klasse ‚this‘ werden übersetzen

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'); 
    }
}
Beantwortet am 11/05/2015 um 18:30
quelle vom benutzer

stimmen
0

Schauen Sie sich diese Blog - Post http://lumpofcode.blogspot.com/2012/10/typescript-dart-google-web-toolkit-and.html , hat es eine ausführliche Diskussion über Techniken für Anrufe innerhalb und zwischen Typoskript Klassen zu organisieren.

Beantwortet am 06/12/2014 um 01:49
quelle vom benutzer

stimmen
0

Sie könnten Ihre Referenz speichern , um thisin einer anderen Variable .. selfvielleicht, und die Referenz zugreifen , die Art und Weise. Ich benutze keine Typoskript, aber das ist eine Methode , die für mich mit Vanille Javascript in der Vergangenheit erfolgreich gewesen ist.

Beantwortet am 06/10/2012 um 04:30
quelle vom benutzer

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