Kaip prieiti prie teisingo „tai“ viduje atgalinio ryšio?

Turiu konstruktoriaus funkciją, kuri registruoja įvykių tvarkytoją:

29 нояб. įkūrė Felix Kling 29 nov. 2013-11-29 09:13 '13, 9:13, 2013-11-29 09:13
@ 9 atsakymai

Ką turėtumėte žinoti apie this

this (kitaip tariant, „kontekstas“) yra specialus kiekvienos funkcijos raktinis žodis, o jo vertė priklauso tik nuo to, kaip buvo vadinama funkcija, o ne nuo to, kaip / kada / kur jis buvo apibrėžtas. Tai neturi įtakos leksinėms sritims, pvz., Kitiems kintamiesiems (išskyrus rodyklių funkcijas, žr. Toliau). Štai keletas pavyzdžių:

 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' 

Jei norite daugiau sužinoti apie this , patikrinkite MDN dokumentaciją .


Kaip patekti į teisingą

Nenaudokite this

Jūs iš tikrųjų nenorite prieiti prie this informacijos, bet į objektą, į kurį jis remiasi. Todėl paprastas sprendimas yra tiesiog sukurti naują kintamąjį, kuris taip pat taikomas šiam objektui. Kintamasis gali turėti bet kokį vardą, bet bendrasis yra self ir that .

 function MyConstructor(data, transport) { this.data = data; var self = this; transport.on('data', function() { alert(self.data); }); } 

Kadangi self yra normalus kintamasis, jis laikosi leksikos srities taisyklių ir yra prieinamas atgalinio ryšio viduje. Tai taip pat turi pranašumą, kad galite patekti į this atgalinio ryšio vertę.

Aiškiai nustatoma, kad this yra atšaukimas - 1 dalis

Gali atrodyti, kad nekontroliuojate šios vertės, nes jos vertė nustatoma automatiškai, bet iš tikrųjų tai nėra.

Kiekviena funkcija turi .bind [docs] metodą, kuris grąžina naują funkciją su this privalomuoju. Funkcija turi tokį patį elgesį, kaip ir jūs .bind . Nepriklausomai nuo to, kaip ir kada ši funkcija vadinama, this visada reiškia perduotą vertę.

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

Tokiu atveju privalome tai vadinti „ MyConstructor this verte.

Pastaba Susiejant kontekstą su jQuery, vietoj to naudokite jQuery.proxy [docs] . Taip yra todėl, kad jums nereikia turėti nuorodos į funkciją, kai atšaukiate įvykio atšaukimą. jQuery tai tvarko viduje.

ECMAScript 6: Naudojant rodyklių funkcijas

ECMAScript 6 pristato rodyklių funkcijas, kurios gali būti laikomos lambda funkcijomis. Jie neturi savo įsipareigojimo. Vietoj to jis yra laikomas įprastu kintamuoju. Tai reiškia, kad jums nereikia skambinti .bind . Tai ne vienintelis specialus elgesys, kurį jie turi, daugiau informacijos rasite MDN dokumentacijoje.

 function MyConstructor(data, transport) { this.data = data; transport.on('data', () => alert(this.data)); } 

Nustatykite this atgalinio ryšio - 2 dalis

Kai kurios funkcijos ir metodai, kurie priima atgalines prievoles, taip pat atsižvelgia į vertę, į kurią turėtų būti nuorodos. Tai iš esmės yra tas pats dalykas kaip ir sau, bet funkcija / metodas tai daro už jus. Array#map [docs] yra toks metodas. Jo parašas:

 array.map(callback[, thisArg]) 

Pirmasis argumentas yra atšaukimas, o antrasis argumentas - tai vertė, į kurią turėtų būti remiamasi. Čia yra išgalvotas pavyzdys:

 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 

Pastaba Nepriklausomai nuo to, ar galite perduoti vertę, tai paprastai paminėta šios funkcijos / metodo dokumentacijoje. Pavyzdžiui, metodas jQuery $.ajax [docs] aprašo parametrą, vadinamą context :

Šis objektas taps visų Ajax atsiliepimų kontekstu.


Dažna problema: objekto metodų naudojimas kaip atgalinio ryšio / įvykių tvarkytojai

Kita paplitusi šios problemos išraiška yra ta, kad objekto metodas yra naudojamas kaip atgalinio / įvykio tvarkytojas. Funkcijos yra pirmojo lygio „JavaScript“ piliečiai, o terminas „metodas“ yra tiesiog kalbinis terminas, skirtas funkcijai, kuri yra objekto nuosavybės vertė. Tačiau ši funkcija neturi konkrečios nuorodos į jo turinį.

Apsvarstykite šį pavyzdį:

 function Foo() { this.data = 42, document.body.onclick = this.method; } Foo.prototype.method = function() { console.log(this.data); }; 

Funkcija this.method priskiriama paspaudimo įvykių tvarkytojui, tačiau, jei spustelėsite document.body , registruota vertė bus undefined , nes this įvykio tvarkytojo viduje this nurodo document.bodyFoo , o ne „ Foo .
Kaip minėta pradžioje, this reiškia, kaip funkcija vadinama , o ne kaip ji apibrėžiama .
Jei kodas atrodo taip, gali būti aiškiau, kad funkcija neturi numanomos objekto nuorodos:

 function method() { console.log(this.data); } function Foo() { this.data = 42, document.body.onclick = this.method; } Foo.prototype.method = method; 

Sprendimas yra tas pats, kaip nurodyta pirmiau: jei yra, naudokite .bind kad tai aiškiai susieti su konkrečia verte

 document.body.onclick = this.method.bind(this); 

arba aiškiai iškviesti funkciją kaip objekto „metodą“, naudojant anoniminę funkciją kaip atgalinio ryšio / įvykio tvarkytoją ir priskirti objektą kitam kintamajam:

 var self = this; document.body.onclick = function() { self.method(); }; 

arba naudokite rodyklės funkciją:

 document.body.onclick = () => this.method(); 
1420 m
29 нояб. Atsakymą pateikė Felixas Klingas lapkričio 29 d. 2013-11-29 09:13 '13, 9:13, 2013-11-29 09:13

Štai keletas būdų, kaip pasiekti pagrindinį kontekstą vaiko kontekste -

  1. Galite naudoti „ bind () funkciją.
  2. Laikykite nuorodą į kontekstą / viduje kitą kintamąjį (žr. Toliau pateiktą pavyzdį).
  3. Naudokite ES6 rodyklių funkcijas.
  4. Pakeiskite kodo / funkcijos dizainą / architektūrą - tam reikia turėti komandą į „JavaScript“ dizaino modelius .

1. Naudokite funkciją bind()

http://underscorejs.org/#bind 

 transport.on('data', _.bind(function () { alert(this.data); }, this)); 

2 Išsaugokite nuorodą į kontekstą / viduje kitą kintamąjį.

 function MyConstructor(data, transport) { this.data = data; transport.on('data', () => { alert(this.data); }); } 
160
13 авг. Atsakymas, kurį pateikė Mohan Dere rugpjūčio 13 d 2016-08-13 13:26 '16, 13:26 pm 2016-08-13 13:26

Visa tai „metiško“ metodo skambučio sintaksėje:

 object.property(); 

Kai gaunate objektą iš objekto ir jį skambinate iš karto, objektas bus metodo kontekstas. Jei skambinate tuo pačiu metodu, bet atskirais etapais kontekstas yra pasaulinė sritis (>

 var f = object.property; f(); 

Kai gaunate nuorodą į metodą, jis nebėra susietas su objektu, tai tik nuoroda į įprastą funkciją. Tas pats atsitinka, kai gaunate nuorodą, kurią norite naudoti kaip atgalinį:

 this.saveNextLevelData(this.setAll); 

Kur susiejate kontekstą su funkcija:

 this.saveNextLevelData(this.setAll.bind(this)); 

Jei naudojate „jQuery“, turite naudoti $.proxy metodą, o bind nepalaikomas visose naršyklėse:

 this.saveNextLevelData($.proxy(this.setAll, this)); 
40
21 мая '14 в 3:11 2014-05-21 03:11 atsakymą pateikė Guffa gegužės 21 d. 14 val

Problema su „kontekstu“

Terminas „kontekstas“ kartais vartojamas nurodant objektą, kuriam jis skirtas. Jo naudojimas yra netinkamas, nes jis netinka semantiškai, nei techniškai su ECMAScript .

„Kontekstas“ - tai aplinkybės, susijusios su kažkuo, kuris prideda prasmę, arba kai kurie ankstesni ir vėlesni duomenys, suteikiantys papildomą reikšmę. Sąvoka „kontekstas“ naudojama ECMAScript, kad būtų nuoroda į vykdymo kontekstą , kuris yra visi parametrai, apimtis, ir tai yra tam tikru vykdomuoju kodu.

Tai parodyta ECMA-262 10.4.2 skirsnyje :

Nustatykite „ThisBinding“ reikšmę tokiai pačiai vertei, kaip skambučio kontekstui

kuris aiškiai rodo, kad tai yra vykdymo konteksto dalis.

Vykdymo kontekste pateikiama aplinkinė informacija, kuri priduria vertei vykdomam kodui. Jame pateikiama daug daugiau informacijos, kurią tik pateikia tai .

Taigi šio reiškinio reikšmė nėra „kontekstas“, tai yra tik viena vykdymo konteksto dalis. Tai iš esmės yra vietinis kintamasis, kurį galima nustatyti paskambinus bet kuriam objektui ir griežtai bet kokiai vertei.

22
01 июня '14 в 3:44 2014-06-01 03:44 atsakymą pateikė RobG birželio 1 d. 14 d. 3:44 2014-06-01 03:44

Pirma, jums reikia aiškiai suprasti this raktinio žodžio scope ir elgesį, atsižvelgiant į scope .

this ir scope :


 there are two types of scope in javascript. They are : 1) Global Scope 2) Function Scope 

Trumpai tariant, visuotinė taikymo sritis yra susijusi su >this raktinis žodis visame pasaulyje reiškia >this vidinė funkcija taip pat nurodo >this visada bus nuoroda į >

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

Įvairūs būdai valdyti this vidinę atgalinio ryšio funkciją:

Čia turiu konstruktoriaus funkciją, vadinamą Asmuo. Jis turi nuosavybę, vadinamą name ir keturis metodus, vadinamus „ sayNameVersion1 , sayNameVersion2 , sayNameVersion3 , sayNameVersion4 . Visi keturi iš jų turi vieną konkrečią užduotį. Grįžti atgal ir paskambinkite. Atgalinis ryšys turi konkrečią užduotį, ty registruoti konstruktoriaus funkcijos „Asmuo“ pavadinimo savybę.

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

Dabar sukurkite egzempliorių iš asmens konstruktoriaus ir paskambinkite skirtingomis „ sayNameVersionX (X reiškia 1,2,3,4) su „ niceCallback metodu, kad sužinotumėte, kiek būdų valdyti this vidinį atgalinį skambutį, kad paskambintumėte person .

 var p1 = new Person('zami') // create an instance of Person constructor 

susieti:

Ką reikia padaryti, tai sukurti naują funkciją su this raktiniu žodžiu su pateikta verte.

sayNameVersion1 ir sayNameVersion2 naudoti susieti manipuliuoti this atgalinio ryšio funkcija.

 this.sayNameVersion1 = function(callback){ callback.bind(this)() } this.sayNameVersion2 = function(callback){ callback() } 

pirmiausia susieti this su atgaliniu ryšiu per patį metodą. Ir antrojo atgalinio ryšio atveju perduodamas susijęs objektas.

 p1.sayNameVersion1(niceCallback) // pass simply the callback and bind happens inside the sayNameVersion1 method p1.sayNameVersion2(niceCallback.bind(p1)) // uses bind before passing callback 

iššūkis:

first argument call metodo first argument naudojamas kaip funkcija, priskiriama prie jo prijungto call .

sayNameVersion3 naudoja call kad galėtume manipuliuoti this nuoroda į asmenį, kurį sukūrėme, o ne į >

 this.sayNameVersion3 = function(callback){ callback.call(this) } 

ir jis vadinamas taip:

 p1.sayNameVersion3(niceCallback) 

pateikti pareiškimą:

Kaip ir call , pirmasis argumentas apply nurodo objektą, kurį nurodys this raktinis žodis.

sayNameVersion4 norite valdyti this prieigą prie asmens objekto

 this.sayNameVersion4 = function(callback){ callback.apply(this) } 

ir tai vadinama taip. Persiunčiamas tik atgalinis ryšys,

 p1.sayNameVersion4(niceCallback) 
17
18 авг. Atsakymas pateikiamas AL-zami 18 rug . 2017-08-18 20:58 '17, 08:58 pm 2017-08-18 20:58

Negalime to susieti su setTimeout() , nes jis visuomet vykdomas naudojant pasaulinį objektą (> jei norite prieiti prie this konteksto atgalinio ryšio funkcija, ir tada naudokite funkciją „ bind() atgalinio ryšio), kurią galime pasiekti kaip:

 setTimeout(function(){ this.methodName(); }.bind(this), 2000); 
15
17 нояб. Atsakymą pateikė Datta Chanewad lapkričio 17 d 2017-11-17 17:32 '17 17:32 pm 2017-11-17 17:32

Kitas metodas, kuris yra standartinis būdas, nes DOM2 this priskiria įvykio klausytojui, kuris leidžia visada pašalinti klausytoją (be kitų privalumų), yra „ EventListener sąsajos handleEvent(evt) metodas:

 var obj = { handleEvent(e) { // always true console.log(this === obj); } }; document.body.addEventListener('click', obj); 

Išsamią informaciją apie „ handleEvent galite rasti čia: https://medium.com/@WebReflection/dom-handleevent-a-cross-platform-standard-since-year-year-year-year-year-000-bb17287fd38

2
28 авг. Andrea Puddu atsakymas 28 rug . 2018-08-28 12:10 '18, 12:10 pm 2018-08-28 12:10

Turėtumėte žinoti apie šį raktinį žodį.

Mano nuomone, galite tai įgyvendinti trimis būdais (funkcija „Savęs / rodyklės funkcija“ / „Bind Method“)

Šio raktinio žodžio funkcija „JavaScript“ šiek tiek skiriasi, palyginti su kitomis kalbomis.

Ji taip pat turi tam tikrų skirtumų tarp griežtų ir griežtų reikalavimų.

Daugeliu atvejų tai lemia tai, kaip funkcija vadinama.

Jis negali būti nustatomas priskyrimu vykdymo metu, ir jis gali skirtis nuo kiekvieno funkcijų skambučio.

ES5 įdiegė „bind“ () metodą, kad nustatytų šios funkcijos vertę, neatsižvelgiant į tai, kaip jis vadinamas,

ir ES2015 pristatė rodyklių funkcijas, kurios nesuteikia savo privalomo (tai išlaiko šio leksinio konteksto vertę).

1 metodas. Savęs savarankiškai naudojamas palaikyti nuorodą į originalą, net jei pasikeičia kontekstas. Šis metodas dažnai naudojamas renginių tvarkytojams (ypač uždarymams).

Nuoroda : 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); }); } 

2 metodas : rodyklės funkcija - rodyklės funkcijos išraiška yra sintaksiškai kompaktiška alternatyva įprastai išraiškos funkcijai,

nors tai nėra susiję su raktiniais žodžiais, argumentais, super arba new.target.

Funkcijų išraiškos su rodyklėmis yra netinkamos kaip metodai ir negali būti naudojamos kaip konstruktoriai.

Nuoroda : 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); }); } 

3 metodas : Bind- The bind () metodas sukuria naują funkciją, kuri

skambinant, jis turi raktinį žodį, kurio vertė yra nustatyta,

su tam tikra argumentų seka prieš bet kurią, pateiktą skambinant naujai funkcijai.

Nuoroda: 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); 
2
30 янв. atsakymą pateikė ashish Jan 30 2019-01-30 14:01 '19 at 2:01 pm 2019-01-30 14:01

Šiuo metu yra dar vienas požiūris, jei klasėse naudojami kodai.

Pagal klasių laukus galite atlikti šiuos veiksmus:

 class someView { onSomeInputKeyUp = (event) => { console.log(this); // this refers to correct value // .... someInitMethod() { //... someInput.addEventListener('input', this.onSomeInputKeyUp) 

Žinoma, po gaubtu, visos senosios geros rodyklės funkcijos, kurios susieja kontekstą, bet šioje formoje atrodo daug aiškesnės nei aiškus susiejimas.

Nuo šio 3 etapo pasiūlymo jums reikės kūdikio ir atitinkamo kūdikio įskiepio, kad galėtumėte jį tvarkyti taip, kaip dabar (08/2018).

1
22 сент. Skyboyer atsakymas rugsėjo 22 d 2018-09-22 16:38 '18, 4:38 pm 2018-09-22 16:38

Kiti klausimai apie „ etiketes klausimą arba Užduoti klausimą