Hvordan gik this
begynder alt?
Den ene ting, der synes at forene begyndere javascript-programmører mere end noget andet, er deres fælles forvirring om konceptet this
.
Måske er det fordi this
eller self
på andre sprog opfører sig anderledes end i javascript.
Se, sproget blev skabt på ti dage. Nogle mindre end ideelle beslutninger blev sandsynligvis truffet. Det er, hvad det er.
This
eksisterer
Jeg mener det. Du kan få adgang til this
hvor som helst i et javascript-program. På det yderste niveau? Jo da!
console.log(this);
Inde i en funktion? Også, ja.
function foo() {
console.log(this);
}
Hvad med konstruktører? Selvfølgelig!
function Bar(x, y) {
this.x = x;
this.y = y;
}
Men se, her ligger forvirringen . Det føles bestemt fornuftigt at tale om this
som egenskab på funktioner, konstruktører og metoder. Men det er forkert.
This
eksisterer af sig selv! Det er en egenskab på funktionsomfang!
Hvad er this
omfang ting?
Du kan tænke på funktionsomfang (eller Function Environment Records at være korrekt) som beholdere for variabler. Hvert omfang vil indeholde en masse navne på variabler (og tilknyttede værdier).
Fra ethvert funktionsområde kan du:
- adgangsvariabler defineret i dette omfang
- adgangsvariable defineret i ethvert forfaderfunktionsomfang
På det yderste niveau er det globale omfang, hvor der bor så berømte indbygninger som:Math
og console
og Number
blandt andre.
Læg mærke til, hvordan de er mærket foo() scope eller bar()-omfang i diagrammet og ikke foo scope , bjælkeomfang osv.
Det er fordi et omfang er forbundet med funktionskald, ikke funktionerne i sig selv. Der oprettes et nyt funktionsområde for hvert funktionskald. Derfor kunne du gøre:
function foo(x) {
let bar = x;
}
foo(7);
foo(42);
og bar
oprettes to forskellige tidspunkter med to forskellige værdier tildelt.
Se nu på billedet igen. Du vil se this
findes på hvert funktionsområde. Du behøver ikke at erklære det, det føjes automatisk til omfanget.
This
endnu en gang
Her er en opsummering af, hvad jeg lige sagde:
Opkald skaber funktionsomfang. Disse scopes skaber this
. Ergo, ved transitivitet, this
er knyttet til funktionskald .
Ikke funktioner. Ikke konstruktører. Opkald!
Reglerne for this
sprog
I javascript er der kun to typer opkald. Værdien af this
afhænger af den type opkald, du foretager.
1. Funktionsopkald
Bare almindelige gamle vaniljefunktionskald.
function foo() {
console.log(this);
}
foo(); // Window
This
indstilles til den globale Window
objekt for disse.
2. Metodekald
Metodekald er ikke noget særligt, kun kald som har formen <object>.<attribute>()
. For eksempel:
const foo = {
bar: function () {
console.log(this);
}
};
foo.bar();
For metodekald, this
indstilles til det objekt, hvorfra metoden blev kaldt. Igen, funktioner er ligegyldige* for this
, kun opkaldene.
function foo() {
console.log(this);
}
let x = { bar: foo };
foo(); // Window
x.bar(); // x
let baz = x.bar;
baz(); // Window
Selv baz
vil udskrive Window
. Det er ikke et metodekald, det følger ikke metodekaldsformatet!
Det er stort set alt, hvad der skal til.........
........eller er det?!
Jeg undskylder for this
Husk, hvordan jeg fortalte dig this
handler det om funktionskald, ikke selve funktionerne? Nå, jeg løj.
Ok se, lad mig minde dig om endnu en gang:De lavede javascript på 10 dage!
this
regler, vi har diskuteret ovenfor, de er en smule begrænsende. Så der er tre * måder du kan tilsidesætte disse regler på.
* tør du ikke engang nævne ansøg
1. call
Den særlige call
metode på funktioner giver dig mulighed for at videregive din egen brugerdefinerede værdi på this
til et funktionskald (eller opkaldets omfang skulle jeg sige).
function foo() {
console.log(this);
}
foo.call({ a: 42 }); // { a: 42 }
2. bind
bind
er en anden indbygget metode på funktioner. Meget gerne call
det giver dig også mulighed for at sende en brugerdefineret værdi for this
til funktionsopkaldet. Undtagen i modsætning til call
, bind
kalder ikke funktionen med det samme. Det returnerer i stedet en speciel 'bundet' funktion.
function foo() {
console.log(this);
}
let bar = foo.bind({ a: 42 });
foo(); // Window
bar(); // { a: 42 }
3. Pilefunktioner
Pilefunktioner er den tredje måde at tilsidesætte opkaldsreglerne for this
beskrevet tidligere. Pilefunktioner fanger this
fra det funktionsomfang, de er oprettet i.
function foo() {
const bar = () => {
console.log(this);
};
return bar;
}
let bar = foo.call({ a: 42 });
bar(); // { a: 42 }
Så de er i bund og grund det samme som at definere en normal funktion, men så også binde den.
// achieves the same effect
function foo() {
const bar = (function () {
console.log(this);
}).bind(this);
return bar;
}
let bar = foo.call({ a: 42 });
bar(); // { a: 42 }
Sammenfattende
Ja, ingen ordspil i overskriften this
tid (ups). De vigtigste ting er dette:
I JS this
er knyttet til det aktuelle funktionsomfang, og da funktionsomfang er knyttet til funktionskald -- this
er forbundet med opkald. Det er reglerne, men de kan tilsidesættes.
Det er grunden til, at folk ofte er forvirrede, når de videregiver funktioner, der henviser til this
til tilbagekald. Det er også grunden til, at du fik besked på at bruge pilefunktioner, hvis du har brug for at videregive dem til tilbagekald.
Jeg var også forvirret over this
i lang tid. I stedet for at tage den mere fornuftige tilgang at læse en artikel som denne, besluttede jeg i stedet at implementere mit eget javascript.
Jeg skrev en delmængde af javascript. I den delmængde af javascript. Hvis du vil ned i det kaninhul, så tjek repoen:
https://github.com/BlueBlazin/thislang
Hvis du vil have flere indlæg om andre javascript- eller computerrelaterede emner, så lad mig det vide på twitter:
https://twitter.com/suicuneblue