Nëse keni programuar në JavaScript për një kohë, me siguri do ta njihni fjalën kyçe Kjo të ka shkaktuar më shumë se një dhimbje kokeDhe që kur funksionet e shigjetave u shfaqën në ES6, gjërat u bënë edhe më të ndërlikuara... ose më të thjeshta, varësisht se si i shikoni.
Në këtë artikull do të shqyrtojmë më nga afër se si funksionon Kjo vlen për funksionet tradicionale dhe funksionet e shigjetave.Pse nganjëherë duket se tregon një objekt specifik dhe herë të tjera një objekt global, dhe në cilat situata ka kuptim të përdoren funksionet me shigjeta dhe në cilat situata është më mirë t'i shmangim ato?
Cfare saktesisht this në JavaScript
Fjala e rezervuar this Është një referencë për kontekstin e ekzekutimit të funksionit që është duke u ekzekutuar aktualisht. Ndryshe nga gjuhët e tjera, në JavaScript vendimi nuk bazohet në vendin ku është përcaktuar funksioni, por në ekzekutimin e funksionit. si të thirret.
Kjo do të thotë që i njëjti funksion mund të thirret në mënyra të ndryshme, dhe në secilën prej tyre, this mund të tregojë një objekt tjetërNuk është diçka që mund ta ndryshosh me një caktim të drejtpërdrejtë (nuk mund ta bësh) this = algo), por mund ta ndikoni atë me mekanizma specifikë, siç janë call, apply y bind.
Për më tepër, sjellja e tyre ndryshon midis Modaliteti i rreptë dhe modaliteti jo i rreptëNë modalitetin jo-strikt, nëse thirrni një funksion "bare" (pa një objekt përpara tij), this Zakonisht është objekti global (në shfletues, window), ndërsa në modalitetin e rreptë mund të jetë undefinedKy dallim është i rëndësishëm kur krahasohen shembujt e kodit nga burime të ndryshme.
Kjo në kontekstin global dhe në funksionet normale
Në shfletues, kur nuk ndodheni brenda ndonjë moduli ose funksioni, konteksti global është objekti. windowdhe atje this tregoni atë objektKjo do të thotë, nëse shkruani sa vijon në tastierë:
console.log(this === window); // true en un entorno de navegador no estricto
Brenda një funksioni të deklaruar në një mënyrë "klasike" (funksion normal), vlera e this Varet se si quhet ai funksion.Nëse e thirrni pa një objekt paraprak, në modalitetin jo-strikt this Zakonisht është ai global, dhe në kuptimin e ngushtë të fjalës do të jetë undefinedKjo është arsyeja pse ndonjëherë, kur zhvendosni kodin nga një faqe në tjetrën, Kjo nuk është më ajo që prisnit..
Kjo në metodat e objektit të përcaktuara me funksione normale
Kur përcaktoni një metodë në një objekt duke përdorur sintaksën tradicionale, this brenda metodës, referencë për vetë objektin nga e cila është thirrur ajo metodë.
Për shembull, nëse keni diçka si:
const obj = {
speak() {
console.log(this);
}
};
obj.speak();
Thirrja obj.speak() bën this brenda speak ji ai/ajo objKjo është sjellja që njerëzit zakonisht presin intuitivisht: metoda flet "në emër" të objektit.
Nëse përdorni një funksion klasik në vend të sintaksës së shkurtuar, efekti është i njëjtë, sepse Çelësi qëndron në mënyrën se si thirret metodaNuk ka rëndësi nëse keni përdorur shkurtesën e metodës apo fjalën kyçe function brenda objektit.
Kjo në metodat e përcaktuara me funksione shigjetash
Gjërat ndryshojnë kur përcaktoni metodën me një funksion shigjete. Diçka si:
const obj2 = {
speak: () => {
console.log(this);
}
};
obj2.speak();
Në këtë rast, gjatë ekzekutimit obj2.speak() do ta shihni this Nuk është më obj2por konteksti leksikor i jashtëm te ai objekt, i cili në një skript klasik të shfletuesit zakonisht është objekti global window.
Kjo është e çuditshme herën e parë që e shihni, sepse prisni që një metodë e objektit të tregojë vetë objektin. Megjithatë, Funksionet e shigjetave nuk krijojnë të vetat thisAta trashëgojnë vlerën e this të fushëveprimit ku janë përcaktuar. Nëse ai fushëveprim është global, ato trashëgojnë fushëveprimin global; nëse është një tjetër, ato do të trashëgojnë atë fushëveprim tjetër.
Prandaj, një rekomandim i përsëritur shpesh në dokumentacionin modern është: Mos përdorni funksione me shigjeta si metoda objekti kur të duhet this synoni atë objekt.
Shtrirja leksikore e this funksionet e shigjetave
Dallimi kryesor midis funksioneve normale dhe funksioneve me shigjetë është se kjo e fundit kanë një lidhje leksikore për thisThënë thjesht: ata nuk vendosin vetë this jo kur telefonojnë njëri-tjetrin, por kur ata krijoj.
Imagjinoni këtë shembull:
const obj3 = {
speak() {
(() => {
console.log(this);
})();
}
};
obj3.speak();
Këtu mund të duket se, si brenda speak Ne ekzekutojmë një funksion me shigjetë, Kjo duhet të "rivendoset" në gjendjen globalePor ndodh krejt e kundërta: funksioni i shigjetës kap this të funksionit që e rrethon atëe cila në këtë rast është metoda speak thirrur si obj3.speak()Prandaj, vlera e this Ai që shfaqet në tastierë është ai nga obj3.
Dua te them Funksionet e shigjetave nuk kanë të vetat thispor përkundrazi ripërdorin atë të mjedisit të tyre të afërtKjo është jashtëzakonisht e dobishme në thirrjet e ndërthurura, kohëmatësit, premtimet dhe kudo tjetër ku, me funksionet klasike, ju është dashur të përballeni me .bind ose me truke si p.sh. const that = this;.
Shembuj praktikë të humbjes dhe ruajtjes së this
Një nga problemet klasike në JavaScript është se, kur përcaktohet një funksion brenda një metode, e humb referencën për this që tregonte nga objekti dhe përfundoni me atë global ose me undefined.
Le të marrim rastin tipik të përdorimit setTimeout brenda një metode të një objekti me një funksion tradicional:
const persona = {
nombre: 'Agustin',
decirNombre: function() {
setTimeout(function() {
console.log(this.nombre);
}, 3000);
}
};
persona.decirNombre(); // Muestra undefined
Këtu kjo brenda funksionit të kaluar te setTimeout Nuk është më objekti personaFunksioni i rikthimit të thirrjes ekzekutohet në kontekstin global (në një shfletues, window), kështu që this.nombre Përpiqet të lexojë një veti në global, e cila nuk ekziston, dhe përfundon duke qenë undefined.
Përpara se të ekzistonin funksionet me shigjetë, një zgjidhje e zakonshme ishte ruajtja e vlerës së this në një variabël ndihmëse për ta "tërhequr" atë në funksion:
const persona = {
nombre: 'Agustin',
decirNombre: function() {
let that = this; // aquí this es persona
setTimeout(function() {
console.log(that.nombre);
}, 3000);
}
};
Falë kësaj variabli, ruhet referenca e saktë për objektin. Por është një truk disi i shëmtuar dhe përsëritës. Me funksionet e shigjetave, ky problem thjeshtohet shumë:
const persona = {
nombre: 'Agustin',
decirNombre: function() {
setTimeout(() => {
console.log(this.nombre);
}, 3000);
}
};
Këtu funksioni i shigjetës nuk krijon të vetin this, kështu që trashëgon this e metodës decirNombrecili është objekti personaRezultati: “Agustin” shfaqet saktë pa pasur nevojë për variabla të ndërmjetëm ose .bind.
thirrja, zbatimi dhe lidhja: kontrollimi i vlerës së this
Përveç mënyrës "natyrale" të vendosjes së kontekstit me një thirrje metode, JavaScript na jep mjete për të detyrojnë vlerën e this në funksionet normale: call, apply y bind.
Metodat call() y apply() Ata e thërrasin funksionin menjëherë, duke ju lejuar të kaloni objektin që dëshironi të përdorni si this. Dallimi është se call merr argumentet një nga një, ndërsa apply Ato pranohen në një grup. bind(), në vend të kësaj, kthen një funksion të ri me this "i bashkangjitur" vlerës që keni treguarkështu që mund ta telefononi më vonë kur t'ju përshtatet.
Megjithatë, me funksionet e shigjetave, këto metoda nuk janë të dobishme për ndryshimin this sepse vlera e saj është e lidhur leksikisht. Ju mund të përdorni call, apply o bind për të kaluar argumente, por jo për të modifikuar kontekstin e funksioneve me shigjeta, i cili është një ndryshim shumë i rëndësishëm me funksionet e rregullta.
Sintaksa bazë e funksioneve me shigjeta
Përtej sjelljes së thisFunksionet e shigjetave ofrojnë një sintaksë më kompakte dhe ekspresive për shumë situata. Forma e përgjithshme është:
(arg1, arg2, ..., argN) => expresion
Kjo formë kthen automatikisht rezultatin e shprehjes në të djathtë të shigjetës, kështu që Nuk ka nevojë të shkruash fjalën return kur ke vetëm një shprehje të thjeshtë.
Disa pika të përbashkëta të sintaksës:
- Pa parametra:
() => 42apo edhe_ => 42nëse nuk të intereson emri i argumentit. - Me një parametër të vetëm:
Kllapat janë opsionale; mund të shkruanix => x * 2o(x) => x * 2. - Me parametra të shumtë:
Kllapat janë të detyrueshme:(x, y) => x + y.
Kur keni nevojë për deklarata të shumëfishta, mund të përdorni trupi i bllokut me çelësa:
const sumar = (x, y) => {
const resultado = x + y;
return resultado;
};
Në këtë rast, meqenëse ka çelësa, Nuk ka më asnjë kthim të nënkuptuar; nëse nuk e vendosni returnfunksioni do të kthehet undefinedKjo vlen si për funksionet e shigjetave ashtu edhe për funksionet tradicionale.
Kthe objektet literale me funksione shigjetash
Ekziston një detaj sintaksor i vogël, por shumë i zakonshëm: kur një funksion me shigjetë kthen një objekt literal direktDuhet ta mbyllësh në kllapa në mënyrë që interpretuesi të mos e ngatërrojë me një bllok.
Për shembull:
x => ({ y: x })
Pa ato kllapa, JavaScript do t'i interpretonte kllapat kaçurrela si fillimin e trupit të funksionit, jo si një objekt. Është një truk i thjeshtë, por shkakton shumë gabime qesharake nëse e harroni.
Funksionet e shigjetës: anonime dhe pa prototip
Funksionet e shigjetave janë sintaksorisht anonimAta nuk kanë emra të përveçëm, gjë që mund ta ndërlikojë disi situatën. mesazhe debugimi dhe gabimisepse në gjurmë nuk e shihni identifikuesin e funksionit drejtpërdrejt, përveç nëse ia keni caktuar atë një konstante me një emër të dallueshëm.
Për më tepër, shigjeta funksionon Ata nuk zotërojnë pronë prototype dhe ato nuk mund të përdoren si kompani ndërtimiNëse përpiqeni t'i thirrni ata me newDo të shfaqet një gabim. Për të krijuar objekte duke përdorur konstruktorë ose klasa, duhet të përdorni ende funksione ose sintaksë normale. class.
Një pasojë tjetër është se Ato nuk janë të përshtatshme për modelet që kërkojnë vetë-referencim të brendshëm., siç janë disa forma të rekursionit ose trajtuesve të ngjarjeve që duhet të çregjistrohen vetë duke përdorur this ose emri i vetë funksionit.
Ku funksionet e shigjetave shkëlqejnë
Forca e madhe e funksioneve të shigjetave qëndron pikërisht në lidhje leksikore e thisAto janë ideale në situata kur dëshironi që thirrja kthyese që ia kaloni një funksioni tjetër të ruajë this të zonës përreth.
Për shembull, në një objekt me një metodë që fillon një kohëmatës dhe duhet të vazhdojë të aksesojë vetitë e vetë objektit duke përdorur this:
const contador = {
id: 42,
iniciar() {
setTimeout(() => {
console.log(this.id); // this es contador
}, 1000);
}
};
Në ES5 ishte e zakonshme të duhej të vendosje .bind(this) te rikthimi i thirrjes ose ruaj this në një ndryshore tjetër. Me funksione shigjetash, Kodi bëhet më i pastër dhe më afër qëllimit të vërtetë..
Ato janë gjithashtu shumë praktike me metodat e vargjeve të tilla si map, filter, reduce dhe kompania, sepse zvogëlon zhurmën sintaksore kur logjika e funksionit është e shkurtër:
const numeros = [1, 2, 3];
const dobles = numeros.map(n => n * 2);
Kur përdoren me kursim, këto forma kompakte e bëjnë rrjedhën e të dhënave më të lehtë për t'u ndjekur me një shikim.
Kur duhet të shmangni funksionet e shigjetave
Edhe pse funksionet e shigjetave janë shumë të dobishme, ato nuk zëvendësojnë funksionet e rregullta. Ka disa raste të qarta ku Është më mirë të mos i përdorni ato.:
- Metodat e objekteve që varen nga
this:
Nëse përcaktoni një metodë sisaltos: () => { this.vidas--; }brenda një objektigato,thisNuk do të tregojë nga macja, por nga mjedisi i jashtëm, dhe prona nuk do të përditësohet siç prisni. - Thirrjet e ngjarjeve DOM që kanë nevojë për një
thisdinamik:
Në një trajtues siboton.addEventListener('click', () => { this.classList.toggle('on'); });,thisNuk do të jetë butoni i shtypur, por konteksti më i lartë që ndoshta do t'ju japë një gabim shtypi. - Ndërtuesit ose funksionet që kanë nevojë
prototype:
Meqenëse nuk mund të përdoret menewFunksionet me shigjeta nuk janë të përshtatshme për krijimin e instancave ose për modelet e bazuara në prototip.
Në të gjitha këto raste, një Funksioni normal mbetet mjeti i duhur sepse e lejon këtë this Është i lidhur dinamikisht me mënyrën se si e thirrni funksionin.
Nëse mësoheni të zgjidhni me vetëdije midis funksionit normal dhe funksionit të shigjetës në varësi të asaj që ju nevojitet this dhe nga konteksti, Kodi juaj do të jetë më i parashikueshëm dhe i lexueshëm. për këdo që e ruan më pas.
Në fund të fundit, të kuptuarit se si vlera e this në JavaScript, dhe si funksionet e shigjetave e trashëgojnë atë vlerë Çelësi për të ndaluar së përballuari rezultate të papritura, duke përfituar nga sheqeri sintaksor i ES6 dhe metodat e shkrimit, thirrjet kthyese dhe trajtuesit e ngjarjeve që bëjnë pikërisht atë që keni pasur në mendje, është të kuptoni fushëveprimin leksikor ku ato krijohen.