Am o funcție constructor care înregistrează un handler de eveniment:
function MyConstructor(data, transport) {
this.data = data;
transport.on('data', function () {
alert(this.data);
});
}
// Mock transport object
var transport = {
on: function(event, callback) {
setTimeout(callback, 1000);
}
};
// called as
var obj = new MyConstructor('foo', transport);
Cu toate acestea, am'm a nu putea accesa "date" proprietatea obiect creat în interiorul apel invers. Se pare ca "asta" nu se referă la obiectul pe care a fost creat, dar la o alta.
Am încercat de asemenea să utilizați o metodă obiect în loc de o funcție anonim:
function MyConstructor(data, transport) {
this.data = data;
transport.on('data', this.alert);
}
MyConstructor.prototype.alert = function() {
alert(this.name);
};
dar aceasta prezintă aceleași probleme.
Cum pot accesa obiectul corect?
"asta" (aka "context") este un cuvânt cheie special în interiorul fiecare funcție și de valoarea sa depinde numai de cum funcția a fost numit, nu cum/când/unde a fost definită. Nu este afectat de domenii lexicale ca și alte variabile (cu excepția săgeată funcții, a se vedea mai jos). Aici sunt câteva exemple:
function foo() {
console.log(this);
}
// normal function call
foo(); // `this` will refer to `window`
// as object method
var obj = {bar: foo};
obj.bar(); // `this` will refer to `obj`
// as constructor function
new foo(); // `this` will refer to an object that inherits from `foo.prototype`
Tu de fapt don't doriți să accesați asta
, în special, dar obiectul se referă la. Ca's de ce o soluție simplă este de a pur și simplu a crea o nouă variabilă care, de asemenea, se referă la acel obiect. Variabila poate avea orice nume, dar cele comune sunt "sine" și "că".
function MyConstructor(data, transport) {
this.data = data;
var self = this;
transport.on('data', function() {
alert(self.data);
});
}
De "sine" este o variabila normala, ea se supune lexicale domeniul de aplicare a normelor și este accesibil în interiorul apel invers. Acest lucru are, de asemenea, avantajul că puteți accesa "această" valoare de apel invers în sine.
S-ar putea arata ca nu ai nici un control peste valoarea de "asta" pentru că valoarea sa este setată în mod automat, dar care nu este de fapt cazul.
Fiecare funcție are metoda .lega
[documente], care returnează o nouă funcție cu "asta" legat la o valoare. Funcția are exact același comportament ca unul te-au sunat.lega` pe, numai că acest lucru a fost stabilit de tine. Indiferent cum sau când această funcție este numit, "asta" va referi întotdeauna la trecut valoarea.
function MyConstructor(data, transport) {
this.data = data;
var boundFunction = (function() { // parenthesis are not necessary
alert(this.data); // but might improve readability
}).bind(this); // <- here we are calling `.bind()`
transport.on('data', boundFunction);
}
În acest caz, ne sunt obligatorii apel invers's a acest
a pe valoarea a MyConstructor
's "acesta".
Notă: atunci Când obligatorii context pentru jQuery, utilizarea jQuery.proxy
[documente] în loc. Motivul pentru a face acest lucru este astfel încât tu nu't nevoie pentru a stoca referire la funcția de când dezlegăm un eveniment de apel invers. jQuery mânere că pe plan intern.
ECMAScript 6 introduce săgeată funcții, care poate fi considerat ca lambda funcții. Ei nu't au propriile lor "asta" cu caracter obligatoriu. În schimb, "asta" este privit în sus în aplicare ca o variabila normala. Asta înseamnă că don't trebuie să sun.lega`. Ca's nu numai speciale de comportament au, vă rugăm să consultați MDN documentația pentru mai multe informații.
function MyConstructor(data, transport) {
this.data = data;
transport.on('data', () => alert(this.data));
}
Unele funcții/metode care accepta callback accepta, de asemenea, o valoare la care callback's "această" ar trebui să se refere la. Aceasta este în esență același ca obligatorii, dar funcția/metodă nu este pentru tine. [Matrice#harta
[documente]][harta] este o astfel de metodă. Semnarea acestuia este:
array.map(callback[, thisArg])
Primul argument este callback și cel de-al doilea argument este valoarea "asta" ar trebui să se refere la. Aici este un contrived exemplu:
var arr = [1, 2, 3];
var obj = {multiplier: 42};
var new_arr = arr.map(function(v) {
return v * this.multiplier;
}, obj); // <- here we are passing `obj` as second argument
Notă: Dacă aveți sau nu poate adopta o valoare pentru "asta" este, de obicei, menționate în documentația de acea functie/metoda. De exemplu, jQuery's `$.ajax metoda [documente] descrie o opțiune numită "context":
Acest obiect va fi făcut contextul tuturor Ajax legate de callback.
Problemă comună: obiect Folosind metode callback/stivuitoare eveniment
O altă manifestare comună a acestei probleme este atunci când un obiect este utilizată metoda ca callback/event handler. Funcțiile sunt de prima clasa cetățenilor în JavaScript și termenul "metoda" este doar un termen colocvial pentru o funcție care este o valoare a unui obiect de proprietate. Dar această funcție nu't au un anumit link-ul de la sale "conține" obiect. Luați în considerare următorul exemplu:
function Foo() {
this.data = 42,
document.body.onclick = this.method;
}
Foo.prototype.method = function() {
console.log(this.data);
};
Funcția asta.metoda este desemnat ca de tratare a evenimentului click, dar daca `document.corpul este apasat, valoarea conectat va fi "nedefinit", pentru că în interiorul handler de eveniment, asta "se referă la" document.corpul, nu o instanță de "Foo". După cum sa menționat deja la începutul, ce "asta" se referă la depinde de modul în care funcția este numit, nu cum este definit. Dacă codul a fost ca urmare, s-ar putea fi mai evident că funcția nu't au o referință implicită la obiect:
function method() {
console.log(this.data);
}
function Foo() {
this.data = 42,
document.body.onclick = this.method;
}
Foo.prototype.method = method;
Solutia este la fel ca mai sus: Dacă este disponibil, utilizați .lega
explicit lega "asta" la o anumită valoare
document.body.onclick = this.method.bind(this);
sau a apela în mod explicit funcția ca un "metoda" obiect, folosind o funcție anonim ca callback / tratare a evenimentului și de a atribui un obiect ("acesta") la o altă variabilă:
var self = this;
document.body.onclick = function() {
self.method();
};
sau de a folosi o săgeată funcția:
document.body.onclick = () => this.method();
function MyConstructor(data, transport) {
this.data = data;
transport.on('data', ( function () {
alert(this.data);
}).bind(this) );
}
// Mock transport object
var transport = {
on: function(event, callback) {
setTimeout(callback, 1000);
}
};
// called as
var obj = new MyConstructor('foo', transport);
Dacă utilizați
transport.on('data', _.bind(function () {
alert(this.data);
}, this));
function MyConstructor(data, transport) {
var self = this;
this.data = data;
transport.on('data', function() {
alert(self.data);
});
}
function MyConstructor(data, transport) {
this.data = data;
transport.on('data', () => {
alert(this.data);
});
}
L's toate în "magic" sintaxa de a apela o metoda:
object.property();
Atunci când vei ajunge de proprietate de la obiect și de apel-l într-un du-te, obiectul va fi contextul metodei. Dacă suni la aceeași metodă, dar în două etape distincte, contextul este domeniul global (fereastră) în loc:
var f = object.property;
f();
Atunci când vei ajunge de referință de o metodă, o's nu mai este atașat la obiect, l's doar o trimitere la o simplă funcție. Același lucru se întâmplă atunci când vei ajunge de referință pentru a utiliza ca un apel:
this.saveNextLevelData(this.setAll);
Ca's în cazul în care ar lega contextul în funcție de:
this.saveNextLevelData(this.setAll.bind(this));
Dacă utilizați jQuery ar trebui să utilizați $.proxy
metoda în schimb, ca lega
nu este acceptată în toate browserele:
this.saveNextLevelData($.proxy(this.setAll, this));
Termenul "context" este folosit uneori pentru a se referi la obiectul referit de asta. Utilizarea sa este nepotrivit pentru că nu't se potrivesc, fie semantic sau din punct de vedere tehnic cu ECMAScript's acest.
"Context" înseamnă circumstanțele ceva care se adaugă sens, sau unele precedent și următoarele informații, care oferă un plus de semnificație. Termenul "context" este folosit în ECMAScript pentru a se referi la context de executie, care este în toți parametrii, domeniul de aplicare și acest în cadrul domeniului de aplicare a unor executarea de cod.
Acest lucru este arătat în ECMA-262 secțiunea 10.4.2:
Setați ThisBinding la aceeași valoare ca ThisBinding de apel context de executie
care indică în mod clar că acest este parte a unui context de executie.
Un context de execuție oferă informațiile jur care se adaugă în sensul cod care este executat. Aceasta include mult mai multe informații decât thisBinding.
Astfel valoarea de asta e't "context", a's doar o parte dintr-un context de executie. L's, în esență, o variabilă locală care pot fi setate prin apelul la orice obiect și în modul strict, la orice valoare, la toate.
Trebuie Să știți despre "acest" cuvinte Cheie.
Conform meu de vedere, se poate pune în aplicare "acest" în trei moduri (Auto/Săgeată funcția/Bind Metoda)
O funcție's acest cuvânt cheie se comporta un pic diferit în JavaScript, comparativ cu alte limbi.
Ea are, de asemenea, unele diferențe între modul strict și non-modul strict.
În cele mai multe cazuri, valoarea este determinată de cât o funcție este numit.
Se poate't fi stabilite de misiune în timpul execuției, și poate fi diferită de fiecare dată când funcția este apelată.
ES5 introdus bind() metoda pentru a seta valoarea unei funcții's acest lucru, indiferent de cât de l's a numit,
și ES2015 introdus săgeată funcții care nu't oferi propriile lor acest obligatorii (se păstrează această valoare de inchiderea lexicale context).
Metoda1: auto - Auto este folosit pentru a menține o trimitere la original, asta chiar ca contextul se schimbă. L's o tehnică des utilizată în stivuitoare eveniment (mai ales în închidere).
Referință : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this
function MyConstructor(data, transport) {
this.data = data;
var self = this;
transport.on('data', function () {
alert(self.data);
});
}
Method2: Arrow funcția - O săgeată funcția de exprimare este un punct de vedere sintactic compact alternativă la un regulat funcția de exprimare,
deși fără propriile sale legături cu aceasta, argumente, super, sau noi.cuvinte cheie țintă.
Săgeata în funcție expresii sunt bolnavi potrivite ca metode, și nu pot fi utilizate pentru constructori.
Referință: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions
function MyConstructor(data, transport) {
this.data = data;
transport.on('data',()=> {
alert(this.data);
});
}
Method3:Bind bind() metodă creează o nouă funcție care,
când a sunat, are acest set de cuvinte cheie furnizate de valoare,
cu o anumită secvență de argumente care precede orice furnizate în cazul în care noua funcție este numit.
Referință: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_objects/Function/bind
function MyConstructor(data, transport) {
this.data = data;
transport.on('data',(function() {
alert(this.data);
}).bind(this);
În primul rând, aveți nevoie pentru a avea o înțelegere clară a "domeniul de aplicare" și comportamentul "asta" cuvinte cheie în contextul "domeniul de aplicare".
"această" & "domeniul de aplicare":
there are two types of scope in javascript. They are :
1) Global Scope
2) Function Scope
pe scurt, domeniu de aplicare global se referă la obiectul fereastră.Variabilele declarate într-un domeniu de aplicare global sunt accesibile de oriunde.Pe de altă parte, funcție de domeniul de aplicare se află în interiorul unei funcții.variabilă declarată în interiorul unei funcții nu pot fi accesate din afara lumii în mod normal.acest lucru
cuvinte cheie la nivel mondial în domeniul de aplicare se referă la obiectul fereastră.acest lucru
în interiorul funcției, de asemenea, se referă la obiectul fereastră.Deci, "asta" va referi mereu la fereastră până când vom găsi o modalitate de a manipula "asta" pentru a indica un context de propria noastră alegere.
--------------------------------------------------------------------------------
- -
- Global Scope -
- ( globally "this" refers to window object) -
- -
- function outer_function(callback){ -
- -
- // outer function scope -
- // inside outer function"this" keyword refers to window object - -
- callback() // "this" inside callback also refers window object -
- } -
- -
- function callback_function(){ -
- -
- // function to be passed as callback -
- -
- // here "THIS" refers to window object also -
- -
- } -
- -
- outer_function(callback_function) -
- // invoke with callback -
--------------------------------------------------------------------------------
Diferite moduri de a manipula "asta" în interiorul funcții callback:
Aici am o funcție numită constructor Persoană. Ea are o proprietate numita nume
și patru metoda numita sayNameVersion1
,sayNameVersion2
,sayNameVersion3
,sayNameVersion4
. Toate cele patru dintre ele are o anumită sarcină.Accepta un apel și a-l invoca.Callback are o anumită sarcină, care este de a conecta numele de proprietate de la un exemplu de Persoană cu funcție constructor.
function Person(name){
this.name = name
this.sayNameVersion1 = function(callback){
callback.bind(this)()
}
this.sayNameVersion2 = function(callback){
callback()
}
this.sayNameVersion3 = function(callback){
callback.call(this)
}
this.sayNameVersion4 = function(callback){
callback.apply(this)
}
}
function niceCallback(){
// function to be used as callback
var parentObject = this
console.log(parentObject)
}
Acum las's a crea o instanță de persoana constructor si invoca diferite versiuni de sayNameVersionX
( X se referă la 1,2,3,4 ) metoda cu niceCallback
pentru a vedea cât de multe moduri în care putem manipula "asta" interior de apel invers pentru a se referi la "persoană" exemplu.
var p1 = new Person('zami') // create an instance of Person constructor
Ce lega faceți este de a crea o nouă funcție cu "asta" set de cuvinte cheie a valorii furnizate.
sayNameVersion1 " și "sayNameVersion2
bind de a manipula "asta" din funcția de apel invers.
this.sayNameVersion1 = function(callback){
callback.bind(this)()
}
this.sayNameVersion2 = function(callback){
callback()
}
primul se leagă "asta" cu apel invers în interiorul metodă în sine.Și pentru cel de-al doilea apel invers este trecut cu obiect legat de aceasta.
p1.sayNameVersion1(niceCallback) // pass simply the callback and bind happens inside the sayNameVersion1 method
p1.sayNameVersion2(niceCallback.bind(p1)) // uses bind before passing callback
La primul argument` a sun
metoda este folosită ca "asta" în funcție de care este invocat cu "apel" atașat la acesta.
sayNameVersion3
utilizează "apel" pentru a manipula "asta" să se refere la persoana obiect pe care l-am creat, în loc de fereastra obiect.
this.sayNameVersion3 = function(callback){
callback.call(this)
}
și aceasta se numește, cum ar fi următoarele :
p1.sayNameVersion3(niceCallback)
Similar cu sun
, primul argument al "aplică" se referă la obiectul pe care vor fi indicate prin: * "asta" ** cuvinte cheie.
sayNameVersion4
utilizează "aplică" pentru a manipula "asta" să se refere la persoana obiect
this.sayNameVersion4 = function(callback){
callback.apply(this)
}
și aceasta se numește, cum ar fi următoarele.Pur și simplu apel invers este trecut,
p1.sayNameVersion4(niceCallback)
Nu putem lega asta setTimeout()
, cum se executa întotdeauna cu obiect global (Fereastră), dacă doriți să accesați acest context, în funcție de apel invers atunci prin utilizarea `bind () la funcția de apel invers, putem realiza ca:
setTimeout(function(){
this.methodName();
}.bind(this), 2000);
Problema se învârte în jurul a cât de "această" cheie se comportă în javascript. "asta" se comportă diferit ca mai jos,
sun()
, bind ()", și " se aplică()
Ca cele mai multe dintre răspunsurile sugerează, putem folosi Săgeată funcția sau bind()
Metoda sau Auto var. Aș cita un punct despre lambda (Săgeată) funcția de Google JavaScript Ghid de Stil
Preferă utilizarea săgeată funcțiile peste f.bind(acest lucru), și mai ales peste goog.bind(f, acest lucru). Evita scris const auto = acest lucru. Săgeată funcții sunt deosebit de utile pentru callback, care trec uneori neașteptate argumente suplimentare.
Google în mod clar recomandă să utilizați lambda, mai degrabă decât de a lega sau const auto = acest lucru
Deci, cea mai bună soluție ar fi utilizarea lambda ca mai jos,
function MyConstructor(data, transport) {
this.data = data;
transport.on('data', () => {
alert(this.data);
});
}
Referințe:
În prezent, nu există o altă abordare posibilă în cazul în care clasele sunt folosite în cod.
Cu sprijinul clasa domenii l's posibil pentru a face următorul mod:
class someView {
onSomeInputKeyUp = (event) => {
console.log(this); // this refers to correct value
// ....
someInitMethod() {
//...
someInput.addEventListener('input', this.onSomeInputKeyUp)
Pentru că sub capotă se's toate vechi bun săgeata în funcție de care se leagă de context, dar în această formă se pare mult mai clar că explicite cu caracter obligatoriu.
Deoarece's Etapa 3 Propunere va trebui babel și adecvat babel plugin la proces, pentru ca acum(08/2018).
O altă abordare, care este standard de DOM2 pentru a lega "asta" în cadrul evenimentului ascultător, ca să vă scoateți întotdeauna ascultător (printre alte beneficii), este handleEvent(evt)
metoda din EventListener` interfata:
var obj = {
handleEvent(e) {
// always true
console.log(this === obj);
}
};
document.body.addEventListener('click', obj);
Informații detaliate despre utilizarea handleEvent
poate fi găsit aici: https://medium.com/@WebReflection/dom-handleevent-a-cross-platform-standard-since-year-2000-5bf17287fd38