Puščične funkcije in ključna beseda this v JavaScriptu

Zadnja posodobitev: 02/10/2026
  • Funkcije s puščicami zagotavljajo jedrnato sintakso in zajem this leksikalno iz svojega okoliškega obsega, namesto da bi ustvarili lastno vezavo.
  • Vrednost this v regularnih funkcijah je odvisno od načina njihovega klica, kar vpliva na funkcije, metode, konstruktorje, razrede in povratne klice.
  • Puščične funkcije so idealne za povratne klice in metode polj, vendar so slaba izbira za objektne metode, obdelovalce dogodkov DOM in konstruktorje.
  • Razumevanje, kdaj this Razlika med dinamičnim in leksikalnim je bistvena za izogibanje subtilnim napakam in izbiro med puščičnimi in tradicionalnimi funkcijami.

Funkcije puščic in to v JavaScriptu

Če ste se kdaj prijavili this v različnih funkcijah JavaScripta in dobili zelo različne rezultate, niste sami. Mnogi razvijalci naletijo na primere, ko metoda izpiše pričakovani objekt, puščična funkcija pa window, in vgnezdena puščica nenadoma »čarobno« pokaže nazaj na okoliški objekt. Razumevanje, zakaj se to zgodi, je ključ do pisanja predvidljive kode brez napak.

Funkcije puščic in this Ključna beseda tvori eno najpomembnejših (in napačno razumljenih) kombinacij v sodobnem JavaScriptu. Funkcije s puščicami so videti le kot krajša sintaksa, vendar v bistvu spreminjajo način this kako se obravnavajo povratni klici in celo kdaj jih je treba ali ne smete uporabljati kot metode. Oglejmo si vse korak za korakom, od sintakse do konteksta izvajanja, z uporabo preprostega jezika in veliko praktičnih primerov.

Sintaksa puščične funkcije brez zmede

Puščične funkcije so funkcijski izrazi, zapisani z => sintaksa namesto function ključna beseda. Konceptualno si jih lahko predstavljate kot jedrnat način zapisa: »vzemi te parametre, ovrednoti ta izraz ali blok kode in vrne vrednost.« V osnovi so še vedno funkcije, vendar se na več pomembnih načinov obnašajo drugače.

Najosnovnejša puščična funkcija se neposredno preslika v izraz regularne funkcije. Na primer, ta klasični izraz funkcije:

const multiplyByTwo = function (value) { return value * 2; };

Lahko se prepiše kot puščična funkcija, kot je ta:

const multiplyByTwo = (value) => { return value * 2; };

Puščične funkcije so učinkovite, ko je telo en sam izraz. Če je telo samo en stavek, ki nekaj vrne, lahko izpustite tako zavite oklepaje kot eksplicitno return, kar omogoča implicitno vrnitev:

const multiplyByTwo = value => value * 2;

Ko je parameter natanko en, lahko oklepaje izpustite, vendar le v tem specifičnem primeru. So x => x * 2 je veljaven, če pa imate nič ali več parametrov, morate ohraniti oklepaje:

  • Ničelni parametri: () => 42
  • En parameter: x => x * 2 or (x) => x * 2
  • Dva ali več parametrov: (x, y) => x + y

Ko v telesu potrebujete več kot en stavek, morate uporabiti zavite oklepaje in eksplicitni return. V tem primeru se puščične funkcije obnašajo kot običajne funkcije glede vrnitev: ne return, ni vrnjena nobena vrednost.

const feedCat = (status) => {
if (status === 'hungry') {
return 'Feed the cat';
} else {
return 'Do not feed the cat';
}
};

Pri vračanju literalov objektov iz puščičnih funkcij bodite previdni, saj lahko oklepaje objekta zamenjate s telesom funkcije. Da bi se izognili tej dvoumnosti, zavijte literal objekta v oklepaje, da bo JavaScript vedel, da gre za izraz, ki ga je treba vrniti:

const toObject = value => ({ result: value });

Še nekaj: puščice so vedno izrazi, nikoli deklaracije. To pomeni, da jih je treba dodeliti spremenljivki, lastnosti ali jih podati kot argument; ne morejo obstajati samostojno kot function myFunc() {}, in se ne dvignejo na enak način kot deklaracije funkcij, zato jih ne morete poklicati, preden so definirane.

Kaj točno je this v JavaScriptu?

Ključna beseda this je dinamična vezava, ki jo JavaScript ustvari, ko izvede funkcijo ali metodo razreda. Lahko si ga predstavljate kot neviden parameter, katerega vrednost je odvisna od tega, kako in kje se funkcija pokliče. Zaradi tega je zmogljiv in prilagodljiv, a hkrati tudi velik vir zmede.

V nestrogi funkciji, this vedno se razreši v nekakšen objekt; v strogem načinu je lahko dobesedno katera koli vrednost, vključno z undefined. JavaScript določi to vrednost glede na kontekst izvajanja: regularna funkcija, klic metode, klic konstruktorja, razred, globalno področje veljavnosti ali puščična funkcija.

Na najvišji ravni klasičnega skripta (ne modula), this se nanaša na globalThis, ki je običajno v brskalniku window predmet. Torej bo naslednja primerjava v brskalniku resnična:

console.log(this === window); // true

V funkcijah, ki niso puščice, this v celoti določa lokacija klica. Če pokličete obj.method(), nato pa notri method vrednost this is objČe vzamete isto funkcijo in jo poimenujete samostojna kot fn() v strogem načinu, this postane undefined; v nestrogem načinu JavaScript »nadomešča« this z globalThis.

Pomembno je, da ni pomembno, kje je funkcija definirana, temveč kako se pokliče. Metoda lahko obstaja v verigi prototipov ali pa jo je mogoče prerazporediti na drug objekt in še vedno videti this kot kateri koli objekt, ki se dejansko uporablja med klicem. Posredovanje metode pogosto spremeni njeno this razen če ga izrecno popraviš.

Obstajajo tudi orodja za nadzor this izrecno: call, apply, bindin Reflect.apply. To vam omogoča, da "vbrizgate" želeno this vrednost: fn.call(obj, arg1, arg2) bo izvršil fn z this nastavljena objIsta pravila zamenjave veljajo tudi v nestrogem načinu: če podate null or undefined as this, se nadomestijo z globalThis; primitivi so zaprti v svoje ovojne objekte.

Povratni klici dodajo še eno plast posrednosti, ker this nadzoruje tisti, ki pokliče vaš povratni klic. Metode iteracije polj, Promise konstruktor in podobni API-ji običajno kličejo povratne klice z this nastavljena undefined (ali globalni objekt v površnem načinu). Nekateri API-ji, kot so Array.prototype.forEach or Set.prototype.forEach, sprejmite ločeno thisArg parameter, ki ga lahko uporabite za nastavitev povratnega klica this.

Drugi API-ji namerno kličejo povratne klice s prilagojenimi this vrednosti. Na primer, reviver argument za JSON.parse in replacer za JSON.stringify prejeti this vezano na objekt, ki je lastnik lastnosti, ki se trenutno obdeluje. Obdelovalci dogodkov v DOM-u so vezani na element, na katerega so pritrjeni, ko so zapisani na »klasičen« način.

Osnovna ideja: puščične funkcije ne ustvarjajo svojih lastnih this

Ključna lastnost puščičnih funkcij je, da nikoli ne ustvarijo svežega this zavezujoče. Namesto tega se zaprejo (ali "zajamejo") this iz okoliškega leksikalnega okolja v trenutku, ko so ustvarjene. Ko se puščica kasneje izvede, preprosto ponovno uporabi to zajeto vrednost, ne glede na to, kako jo pokličete.

V praksi se puščična funkcija obnaša, kot da bi bila trajno samodejno vezana na this njegovega zunanjega obsega. Zato so metode, kot so call, applyin bind se ne more spremeniti this za funkcijo puščice: thisArg argument se preprosto prezre. Še vedno lahko posredujete običajne parametre skozenj, vendar this vrednost je zaklenjena.

Razmislite o tem odlomku v globalnem obsegu datoteke skripta:

const arrow = () => console.log(this);
arrow();

Ker je puščica definirana v globalni kodi, je njena this je globalno this (običajno window v skriptu brskalnika) in to se nikoli ne spremeni. Klicanje arrow kot navadna funkcija, dodelitev lastnosti ali posredovanje vedno zabeleži isti globalni objekt, ko je klicana v tem kontekstu.

Res zanimivo vedenje se pojavi, ko gnezdite puščične funkcije znotraj običajnih funkcij ali metod. Ker puščica zajema zunanjo funkcijo this, postane močno orodje za povratne klice, ki se morajo sklicevati nazaj na svoj vsebujoči objekt brez običajnega .bind(this) slovesnosti.

const counter = {
id: 42,
start() {
setTimeout(() => {
console.log(this.id); // uses counter.id
}, 1000);
},
};

If start smo uporabljali tradicionalno anonimno funkcijo znotraj setTimeout, bi morali ročno vezati this ali pa ga shranite v spremenljivko. Pri puščicah povratni klic naravno podeduje this od start, Ki je counterTako this.id printi 42 kot je predvideno.

Ta leksikalna vezava pojasnjuje tudi klasični "zakaj" this vprašanje »sprememba« pri uporabi puščic v literalih objektov. Poglejte ta dva predmeta:

const obj1 = {
speak() {
console.log(this);
}
};

const obj2 = {
speak: () => {
console.log(this);
}
};

Klicanje obj1.speak() printi obj1, Ker speak je običajna metoda in this se nastavi glede na lokacijo klica. Nasprotno pa obj2.speak() dnevniki zunanjega this (pogosto window v brskalnikih), ker puščica ne uporablja predmeta kot svoj thisObjektni literal sam po sebi ne ustvari novega this obseg; to stori samo telo funkcije, puščice pa ta korak preskočijo.

Sedaj pa si oglejmo metodo objekta, ki ustvari in takoj pokliče notranjo puščico:

const obj3 = {
speak() {
(() => {
console.log(this);
})();
}
};

obj3.speak();

V tej situaciji funkcija notranje puščice podeduje this od speak, Ki je obj3 ko se imenuje kot obj3.speak(). Čeprav je puščica vgnezdena, takoj poklicana funkcija, še vedno kaže na obj3, ne pa globalni objekt. To je bistvo leksikalnega this: sledi okoliškemu obsegu, ne pa samemu mestu klica puščice.

this med funkcijami, objekti in konstruktorji

Da bi resnično obvladali funkcije puščic in this, pomaga videti, kako this deluje v vseh večjih kontekstih: regularne funkcije, metode, konstruktorji, razredi in globalno področje uporabe. Ko so ta pravila jasna, je vedenje puščice veliko lažje razumeti.

V navadni funkciji (brez puščice), this 100% odvisno od tega, kako je funkcija poklicana. Če pokličete fn() v strogem načinu, this is undefined; v površnem načinu zamenjava naredi this postanejo globalThisČe pokličete obj.fn(), Potem this is objPremakni se fn na drug objekt ali na spremenljivko in vrednost this se bo ustrezno premaknil.

V metodi, definirani na objektnem literalu, this je objekt, na katerem se dostopa do metode, ne nujno tisti, kjer je bila metoda prvotno definirana. If obj.__proto__ vsebuje metodo in jo pokličete obj.method(), nato pa notri method, this is obj, ne prototipa.

Konstruktorji so še en poseben primer: ko pokličete funkcijo z new, this je vezan na novo ustvarjen primerek objekta. Na primer, v function User(name) { this.name = name; }, kliče new User('Alex') Kompleti this do novega User objekt. Če konstruktor eksplicitno vrne neprimitivni objekt, ta vrnjeni objekt nadomesti this kot končna vrednost new izraz.

Sintaksa razreda gradi na teh pravilih z dvema glavnima kontekstoma: instančnim in statičnim. Znotraj konstruktorja ali metode instance, this kaže na primerek razreda, s katerim delate. Znotraj statičnih metod ali statičnih inicializacijskih blokov, this se nanaša na sam razred (ali na izpeljani razred, ko je klican prek dedovanja). Polja primerka se ovrednotijo ​​z this vezano na nov primerek; statična polja glej this kot konstruktor razreda.

Konstruktorji izpeljanih razredov se obnašajo nekoliko drugače: dokler ne pokličete super(), ni uporabnega this. Pokliče super() inicializira this z delegiranjem osnovnemu konstruktorju; vrnitev pred tem v izpeljanem konstruktorju je dovoljena le, če izrecno vrnete drug objekt.

V globalnem kontekstu, this odvisno od tega, kako okolje JavaScript zavije in izvede vašo kodo. V klasičnem skriptu brskalnika, najvišja raven this je globalni objekt; v modulu ES, najvišja raven this vedno undefinedModuli CommonJS v Node.js so notranje oviti in se običajno izvajajo z this nastavljena module.exportsAtributi vgrajenega upravljalnika dogodkov v HTML-ju se izvedejo z this nastavljeni na element, na katerega so pritrjeni.

Ena subtilna, a pomembna podrobnost: objektni literali sami po sebi ne uvajajo novega this Obseg. Pisanje const obj = { value: this }; znotraj skripta bo naredil obj.value enako zunanjemu this, ne pa objekta. Samo telesa funkcij (in telesa razredov) ustvarijo namensko this vezava; puščice namerno preskočijo ta korak in podedujejo.

Zakaj so puščične funkcije odlične za povratne klice (in kdaj niso)

Ker se funkcije puščic zaprejo this, so popolnoma primerni za številne scenarije povratnih klicev, kjer želite, da se povratni klic še naprej sklicuje na okoliški objekt ali kontekst. To je še posebej priročno pri časovnikih, obljubah in metodah polj, kot so map, filterin reduce.

Predstavljajte si metodo, ki mora večkrat posodobiti neko lastnost z uporabo setInterval. Z uporabo tradicionalne funkcije, this znotraj povratnega klica bi bil privzeto globalni objekt (ali undefined v strogem načinu), torej this.count ne bi kazal na vaš primerek. Pri funkciji s puščico povratni klic naravno uporablja this zunanje metode.

function Counter() {
this.count = 0;

setInterval(() => {
this.count++;
}, 1000);
}

Zahvaljujoč puščici, this znotraj intervala se povratni klic nanaša na Counter primer, ne window. Če bi bil ta povratni klic običajna funkcija, bi potrebovali bodisi .bind(this) ali vmesna spremenljivka, kot je const self = this; da ohranim referenco.

Puščične funkcije poenostavijo tudi kodo z uporabo metod polja, kjer vam pogosto ni mar za this nasploh. Ko tradicionalno funkcijo posredujete kot povratni klic, implicitna this je običajno undefined, in to morda pozabite. Puščice vizualno jasno pokažejo, da je funkcija le čisto preslikavanje vhodov v izhode.

const numbers = [1, 2, 3];
const doubled = numbers.map(n => n * 2);

Vendar pa obstajajo pomembni primeri, ko so puščične funkcije napačna izbira, zlasti kadar potrebujete dinamično this. Dva klasična anti-vzorca uporabljata puščične funkcije kot objektne metode in kot obdelovalce dogodkov DOM, ki se zanašajo na this biti element.

Razmislite o predmetu, ki spremlja življenje mačke:

const cat = {
lives: 9,
jump: () => {
this.lives--; // bug: this is not cat
},
};

cat.jump();

Od leta jump je puščica, this se ne nanaša na cat ampak karkoli this je bil kraj, kjer je bil ustvarjen dobesedni objekt (pogosto globalni objekt). Namenjeno this.lives-- bodisi vrže (v strogem načinu) bodisi tiho mutira nekaj nepovezanega. Uporaba običajne sintakse metode je tukaj pravilna poteza.

Poslušalci dogodkov DOM so si podobni: standardni vzorec this.classList.toggle('on') znotraj dogodka se povratni klic zanaša na this biti element, ki je sprožil dogodek. S funkcijo puščice, this ne kaže več na element, zato se koda pokvari.

const button = document.getElementById('press');

button.addEventListener('click', () => {
this.classList.toggle('on'); // this is not button
});

V tej situaciji bi moral biti upravljalnik normalna funkcija, tako da this je v brskalniku vezan na element gumba. Puščične funkcije preprosto ne delujejo kot nadomestki za vstavljanje, če vaša logika pričakuje this biti cilj dinamičnega dogodka.

Druga subtilna pomanjkljivost je, da so puščične funkcije sintaktično anonimne. Običajno nimajo lastnega imena (poleg spremenljivke, ki so ji dodeljene), zaradi česar so sledi sklada nekoliko manj opisne in rekurzija nekoliko težja. V večini kode v resničnem svetu je to obvladljiv kompromis, vendar si ga je vredno zapomniti.

Posebni primeri: getterji, setterji, vezane metode in nenavadni vogali

Metode za pridobivanje in nastavljanje sledijo istemu pravilu »klica mesta«: this je objekt, na katerem se dostopa do lastnosti, ne tisti, kjer je bila prvotno definirana. Če je metoda za pridobivanje podedovana od prototipa in jo pokličete na izpeljanem objektu, this znotraj metode getter se nanaša na izpeljani objekt.

Vezane metode, ustvarjene z Function.prototype.bind vam dajo vedenje, ki je nekoliko podobno funkcijam s puščicami, vendar na ravni običajnih funkcij. Ko pokličete f.bind(obj), ustvarite novo funkcijo, katere this je trajno pritrjen na obj, ne glede na to, kako se pokliče. To je lahko uporabno v razredih, ko morate ohraniti this tudi če je metoda ločena.

class Example {
constructor() {
this.handleClick = this.handleClick.bind(this);
}

handleClick() {
console.log(this); // always the instance
}
}

Slaba stran tako vezanih metod kot puščičnih funkcij, ki se uporabljajo kot polja instance, je, da vsaka instanca dobi svojo kopijo funkcije, kar lahko poveča porabo pomnilnika. Ta kompromis je običajno sprejemljiv, če vežete le majhno število pogosto ločenih metod, vendar je to nekaj, na kar se je treba zavedati pri kodi, ki je kritična za zmogljivost.

Obstajajo tudi nekateri starejši kotni primeri, kjer this se obnaša drugače, na primer znotraj zastarelega with izjavo. Znotraj a with (obj) { ... } blok, ki kliče funkcijo, ki je lastnost obj učinkovito se obnaša, kot da bi napisali obj.method()Tako this je vezan na objSodobna koda se mora izogibati with, vendar razumevanje te izjeme pojasnjuje, da this še vedno je v osnovi odvisno od tega, kako je klic funkcije oblikovan.

V HTML-ju imajo tudi vgrajeni upravljalniki dogodkov posebno pravilo: okoliška vgrajena koda upravljalnika vidi this kot element, vendar notranje funkcije, definirane znotraj tega upravljalnika, spadajo nazaj k običajnemu this pravila. Torej bo notranja tradicionalna funkcija, ki ni vezana na nič, običajno videla this as globalThis (ali undefined v strogem načinu), ne pa element.

Nenazadnje ne pozabite, da puščične funkcije nimajo prototype lastnost in jih ni mogoče uporabiti kot konstruktorje z new. Poskusi new MyArrow() bo vrglo napako TypeError. Če potrebujete funkcijo, ki lahko deluje kot konstruktor, morate uporabiti regularno funkcijo ali razred.

Če upoštevate te podrobnosti, je izbira med puščičnimi funkcijami in tradicionalnimi funkcijami veliko lažja. Uporabite puščice tam, kjer želite leksikalno this in jedrnato sintakso ter se vedno, ko potrebujete dinamično, na lokaciji klica temelječo funkcijo, vrnite k običajnim funkcijam. this vedenje ali semantika konstruktorja.

Ko enkrat ponotranjiš, kako this je v vsaki situaciji vezan, puščice postanejo močan zaveznik namesto presenetljivega vira hroščev. Poenostavljajo običajne vzorce, kot so povratni klici in preproste transformacije, medtem ko običajne funkcije še naprej obravnavajo vloge, ki so odvisne od njihovih lastnih this vezave, kot so metode, konstruktorji in dinamični upravljalniki dogodkov.

Podobni objav: