JavaScript >> Javascript tutorial >  >> Tags >> this

Forstå 'dette' i Javascript

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:

  1. adgangsvariabler defineret i dette omfang
  2. 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