Există un alias pentru „acest“ dactilografiat?

voturi
72

Am încercat să scrie o clasă de dactilografiat, care are o metodă definită care acționează ca un apel invers de tratare a evenimentului la un eveniment 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.
    }
}

In cadrul evenimentului onFocusIn handler, typescript vede „acest lucru“ ca fiind „această“ a clasei. Cu toate acestea, jQuery suprascrie această referință și setează-l la obiect DOM asociat cu evenimentul.

O alternativă este de a defini o lambda în interiorul constructorului ca tratare a evenimentului, caz în care creează un fel typescript de închidere cu un alias _this ascuns.

class Editor {
    textarea: JQuery;

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

Întrebarea mea este, există o altă modalitate de a accesa această referință în cadrul handler de eveniment bazată pe metoda folosind typescript, pentru a depăși acest comportament jQuery?

Întrebat 06/10/2012 la 04:26
sursa de către utilizator
În alte limbi...                            


12 răspunsuri

voturi
97

Domeniul de aplicare a thiseste păstrată atunci când se utilizează sintaxa funcției săgeată () => { ... }- aici este un exemplu luat din mașina de scris , pentru JavaScript programatori .

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

Rețineți că this.textvă oferă , Text from outer functiondeoarece sintaxa funcției săgeată păstrează „sfera lexicală“.

Publicat 06/10/2012 la 15:25
sursa de către utilizator

voturi
21

Deci , după cum se menționează nu există nici un mecanism pentru a asigura o mașină de scris metodă este întotdeauna legat de acesta este thisindicatorul (iar acest lucru nu este doar o problemă jQuery.) Asta nu înseamnă că nu este un mod rezonabil simplu de a rezolva această problemă. Ceea ce ai nevoie este de a genera un proxy pentru metoda care restaurează thisindicatorul înainte de a apela dvs. de apel invers. Va trebui apoi să -și încheie apel invers cu acel proxy înainte de a trece - l în eveniment. jQuery are un mecanism construit în acest numit jQuery.proxy(). Iată un exemplu de cod de mai sus utilizând această metodă (observați adăugat $.proxy()apelul.)

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

E o soluție rezonabilă , dar am constatat personal că dezvoltatorii de multe ori uita să includă apelul proxy , astfel că am venit cu o soluție pe bază de typescript alternativă la această problemă. Utilizat, HasCallbacksclasa de mai jos tot ce trebuie să faceți este derivă din clasa de la HasCallbacksși apoi orice metode cu prefixate 'cb_'vor avea lor thisindicatorul permanent legat. Pur și simplu nu se poate apela această metodă cu un alt thisindicator care , în cele mai multe cazuri , este de preferat. Fie mecanism funcționează astfel încât doar în funcție de valoarea sa de a găsi mai ușor de utilizat.

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({});
Publicat 06/10/2012 la 06:28
sursa de către utilizator

voturi
20

Ca acoperite de unele dintre celelalte răspunsuri, folosind sintaxa săgeată pentru a defini o funcție face ca trimiteri la a se thisreferi întotdeauna la clasa de îngrădire.

Deci, pentru a răspunde la întrebarea dumneavoastră, iată două soluții simple.

Metoda de referință folosind sintaxa săgeată

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

Definiți metoda folosind sintaxa săgeată

onFocusIn = (e: JQueryEventObject) => {
    var height = this.textarea.css('height');
}
Publicat 23/12/2013 la 05:27
sursa de către utilizator

voturi
6

Puteți lega o funcție de membru instanță în 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
    }
}

În mod alternativ, doar lega când adăugați handler.

        this.textarea.focusin(onFocusIn.bind(this));
Publicat 20/05/2014 la 15:47
sursa de către utilizator

voturi
3

Soluție Steven Ickman este la îndemână, dar incomplet. Danny Becket și răspunsurile lui Sam sunt mai scurte și mai manuale, și nu în același caz general, de a avea un apel invers, care are nevoie atât de dinamic și lexical scoped „acest lucru“, în același timp. Treci la codul meu, dacă explicația mea de mai jos este TL; DR ...

Trebuie să păstreze „acest“ pentru definire a domeniului dinamic pentru utilizarea cu callback bibliotecă, și am nevoie pentru a avea un „acest“ cu definire a domeniului lexicală la instanța de clasă. Eu susțin că este cel mai elegant de a trece instanța într - un generator de apel invers, lăsând în mod eficient închiderea parametrul peste instanță de clasă. Compilatorul va spune dacă ai pierdut acest lucru. Eu folosesc o convenție de asteptare lexical Scoped parametru „outerThis“, ci „ de sine“ , sau un alt nume ar putea fi mai bine.

Utilizarea „acest“ cuvânt cheie este furat din lumea OO, iar când typescript a adoptat (de la ECMAScript 6 specificatii presupun), au contopit un concept lexical scoped și un concept scoped dinamic, ori de câte ori o metodă este numită de către o altă entitate . Sunt puțin bosumflat la acest lucru; Aș prefera o „sine“ cuvânt cheie dactilografiat, astfel încât să pot mână instanța de obiect lexical scoped de pe ea. Alternativ, JS ar putea fi redefinit pentru a solicita o primă poziție parametru explicit „apelant“, atunci când este nevoie (și, prin urmare, rupe toate paginile web într-o singură lovitură).

Iată soluția mea (excizat dintr-o clasă mare). Ia un gânsac, în special, la modul în care sunt numite metode, iar corpul „dragmoveLambda“, în special:

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

}
Publicat 21/03/2014 la 20:33
sursa de către utilizator

voturi
3

Incearca asta

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
    }

}
Publicat 24/05/2013 la 02:47
sursa de către utilizator

voturi
2

Puteți utiliza funcția de js eval: var realThis = eval('this');

Publicat 20/09/2014 la 13:13
sursa de către utilizator

voturi
2

Typescript nu oferă nici un fel suplimentar (dincolo de regulate JavaScript înseamnă) pentru a reveni la „real“ de thisreferință , alta decât thiscomoditate remaparea furnizate în sintaxa grăsime săgeată lambda (care este permisă dintr - o perspectivă din spate compat , deoarece nici un cod JS existent ar putea folosi o =>expresie).

Ai putea posta o sugestie pentru site - ul CodePlex, dar dintr - o perspectivă de design de limbă nu există , probabil , nu de mult că se poate întâmpla aici, deoarece orice cuvânt cheie sănătos compilator ar putea oferi ar putea fi utilizat deja de cod JavaScript existent.

Publicat 06/10/2012 la 04:35
sursa de către utilizator

voturi
1

Am confruntat cu o problemă similară. Cred că se poate utiliza , .each()în multe cazuri , pentru a păstra thisca o valoare diferită pentru evenimente ulterioare.

Modul JavaScript:

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

Fișierul script astfel:

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

Sper că acest lucru ajută cineva.

Publicat 16/06/2014 la 09:17
sursa de către utilizator

voturi
0

Există o soluție mult mai simplă decât toate răspunsurile de mai sus. Practic vom cădea înapoi la JavaScript folosind funcția cheie cuvânt în loc de a folosi „=>“ construct care se va traduce „această“ clasa în „această“

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'); 
    }
}
Publicat 11/05/2015 la 18:30
sursa de către utilizator

voturi
0

Check out acest blog post http://lumpofcode.blogspot.com/2012/10/typescript-dart-google-web-toolkit-and.html , are o discuție detaliată a tehnicilor pentru organizarea apelurilor în și între clase dactilografiate.

Publicat 06/12/2014 la 01:49
sursa de către utilizator

voturi
0

Ai putea stoca referință la thisîntr -o altă variabilă .. selfpoate, și pentru a accesa de referință în acest fel. Eu nu folosesc dactilografiat, dar asta este o metodă care a fost de succes pentru mine cu javascript de vanilie în trecut.

Publicat 06/10/2012 la 04:30
sursa de către utilizator

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