Existuje alias na ‚tento‘ na stroji?

hlasů
72

Já jsem se pokusil napsat třídu na stroji, který má metodu definovanou, která působí jako obsluha události zpětného volání na událost 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.
    }
}

V obsluze události onFocusIn, strojopisem vidí ‚to‘ jako bytí ‚to‘ ze třídy. Nicméně, jQuery přepíše tento odkaz a nastaví ji do objektu DOM spojeného s událostí.

Jednou z alternativ je definovat lambda v rámci konstruktoru jako rutinu události, přičemž v takovém případě strojopisu vytváří jakýsi uzavření se skrytým _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.
        });
    }
}

Moje otázka je, je tam jiný způsob, jak přistupovat k této referenci ve rutiny události metoda založená na použití strojopisu, překonat toto chování jQuery?

Položena 06/10/2012 v 04:26
zdroj uživatelem
V jiných jazycích...                            


12 odpovědí

hlasů
97

Rozsah thisje zachována při použití syntaxe funkce kurzorových () => { ... }- zde je příklad převzata z strojopisem pro JavaScript programátory .

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

Všimněte si, že this.textvám dává Text from outer functionprotože syntaxe šipka funkce zachovává „lexikální rozsah“.

Odpovězeno 06/10/2012 v 15:25
zdroj uživatelem

hlasů
21

Tak, jak je uvedeno není strojopisem mechanismus pro zajištění způsobu je vždy vázána na to thisukazatele (a to není jen otázka jQuery.) To ale neznamená, že se nejedná o poměrně jednoduchý způsob, jak řešit tento problém. To, co potřebujete, je generovat proxy pro metodu, která obnovuje thisukazatel před voláním vaši zpětné volání. Potom je třeba zabalit zpětné volání s touto zástupce před jeho odesláním do akce. jQuery má vestavěný mechanismus pro to nazývá jQuery.proxy(). Zde je příklad svého výše uvedeného kódu pomocí této metody (všimněte přidanou $.proxy()volání.)

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

Je to rozumné řešení, ale já osobně jsem zjistil, že vývojáři často zapomínají zahrnout proxy volání, takže jsem se přijít s řešením tohoto problému se střídají strojopisem založeném. Používání je HasCallbackstřída pod vše, co potřebujete udělat, je odvodit třídu z HasCallbacksa pak nějaké metody s předponou 'cb_'bude mít jejich thisukazatel trvale vázány. Si prostě nemůže volat tuto metodu s jiným thisukazatelem, který je ve většině případů je vhodnější. Buď mechanismus funguje, takže je to jen podle toho, co si budete lépe používat.

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({});
Odpovězeno 06/10/2012 v 06:28
zdroj uživatelem

hlasů
20

Na které se vztahuje některé z dalších odpovědí, pomocí syntaxe kurzorových definování funkce způsobí, že odkazy na thisvždy odkazovat na třídu ohradní.

Takže odpověď na vaši otázku, zde jsou dva jednoduché řešení.

Odkazovat na metodu pomocí syntaxe se šipkou

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

Definovat způsob pomocí syntaxe se šipkou

onFocusIn = (e: JQueryEventObject) => {
    var height = this.textarea.css('height');
}
Odpovězeno 23/12/2013 v 05:27
zdroj uživatelem

hlasů
6

Můžete svázat členské funkce pro své instance v konstruktoru.

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

Případně stačí svázat při přidání psovoda.

        this.textarea.focusin(onFocusIn.bind(this));
Odpovězeno 20/05/2014 v 15:47
zdroj uživatelem

hlasů
3

Steven Ickman Řešení je po ruce, ale neúplná. Danny Becket a odpovědi Samovy jsou kratší a více manuální a selhání ve stejném obecném případě, že bude zpětné volání, že potřebuje oba dynamický a lexically scoped „toto“ ve stejnou dobu. Přeskočit na můj kód, pokud níže moje vysvětlení je TL; DR ...

Musím zachovat „to“ dynamické scoping pro použití knihovny zpětné volání, a musím mít „to“ s lexikální scoping na instanci třídy. Tvrdím, že je nejelegantnější předat případ do generátoru zpětné volání, efektivně nechat uzavření parametru přes instanci třídy. Kompilátor vám řekne, jestli jste vynechal tom. I používat konvenci volání lexically rozsahem parametr „outerThis“, ale „já“ nebo jiný název by mohl být lepší.

Použití „této“ klíčové slovo je ukraden z OO světě, a když ji na psacím stroji přijato (od ECMAScript 6 specifikace já předpokládám), že se sjednotil se lexically scoped koncepci a dynamicky scoped koncept, kdykoli je metoda nazývá jiným subjektem , Jsem trochu naštvaný na to; Dal bych přednost „self“ klíčové slovo na psacím stroji, takže mohu předat instanci lexically scoped objekt mimo něj. Střídavě, JS, kterou lze předefinovat vyžadovat parametr explicitní první poloha „volajícím“, když je to potřeba (a tím porušit všechny webové stránky v naráz).

Tady je moje řešení (vystřižen z velké třídy). Mrkněte zejména nad tím, jak se nazývají metody a tělo „dragmoveLambda“ zejména:

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

}
Odpovězeno 21/03/2014 v 20:33
zdroj uživatelem

hlasů
3

Zkuste to

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
    }

}
Odpovězeno 24/05/2013 v 02:47
zdroj uživatelem

hlasů
2

Můžete použít js eval funkce: var realThis = eval('this');

Odpovězeno 20/09/2014 v 13:13
zdroj uživatelem

hlasů
2

Strojopisem neposkytuje žádnou další cestu (mimo pravidelné JavaScript prostředek) vrátit se do ‚skutečné‘ thisodkazem jiného než thispřemapování pohodlí poskytované v syntaxi tuk šipka lambda (což je přípustné z back-compat pohledu od neexistujícího JS kódu může být s použitím =>výrazu).

Dalo by se psát návrh na web CodePlex, ale z hlediska designu jazyka je to asi není moc, že může stát i tady, protože jakýkoli rozumný klíčové slovo kompilátor mohl poskytnout může být již používán existující kód JavaScript.

Odpovězeno 06/10/2012 v 04:35
zdroj uživatelem

hlasů
1

I čelí podobným problémem. Myslím, že můžete použít .each()v mnoha případech zachovat thisjako jinou hodnotu pro pozdější události.

JavaScript způsobem:

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

Strojopisu způsobem:

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

Doufám, že to někomu pomůže.

Odpovězeno 16/06/2014 v 09:17
zdroj uživatelem

hlasů
0

Tam je mnohem jednodušší řešení, než všechny výše uvedené odpovědi. V podstatě jsme se uchýlit k JavaScriptu pomocí funkce klíčového slova namísto ‚=>‘ konstrukt, který bude překládat ‚toto‘ do třídy ‚toto‘

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'); 
    }
}
Odpovězeno 11/05/2015 v 18:30
zdroj uživatelem

hlasů
0

Podívejte se na tento blog post http://lumpofcode.blogspot.com/2012/10/typescript-dart-google-web-toolkit-and.html , že má detailní diskuzi o technikách pro organizaci výzev v rámci jednotlivých tříd strojopisem.

Odpovězeno 06/12/2014 v 01:49
zdroj uživatelem

hlasů
0

Ty by mohly uložit odkaz na thisv jiné proměnné .. selfmožná, a přístup k odkazu, že cesta. Nechci používat strojopis, ale to je metoda, která je úspěšná pro mě s vanilkovou JavaScript v minulosti.

Odpovězeno 06/10/2012 v 04:30
zdroj uživatelem

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