MySQL Java JavaScript PHP Python HTML-CSS C-sharp

Cuvântul cheie "this"

Comportamentul cuvântului cheie "this" depinde de contextul în care este utilizat și de modul în care este utilizat - strict sau non-strict.

Contextul global și obiectul globalThis

În contextul global, "this" se referă la obiectul global. Ce reprezintă "obiectul global" în JavaScript? Acest lucru depinde de mediul în care se execută codul.

Astfel, într-un browser web, "this" reprezintă obiectul window - obiectul care reprezintă fereastra browserului. În mediul Node.js, "this" reprezintă obiectul global. În cazul lucrătorilor web, "this" reprezintă obiectul self.

De exemplu, într-un browser web, la executarea următorului cod:

console.log(this);

vom obține o ieșire în consolă similară cu următoarea:

Window {window: Window, self: Window, document: document, name: "", location: Location, …}

În standardul ES2020, a fost adăugată definiția obiectului globalThis, care permite referirea la contextul global indiferent de mediu sau situație în care se execută codul:

console.log(globalThis);

Contextul funcției

În cadrul unei funcții, "this" se referă la contextul extern. Pentru funcțiile definite în contextul global, acesta este obiectul globalThis. De exemplu:

function foo(){
   var bar = "local";
   console.log(this.bar);
}

var bar = "global";

foo();  // global

Dacă nu am folosi "this", atunci referirea ar merge către o variabilă locală definită în interiorul funcției.

function foo(){
   var bar = "local";
   console.log(bar);
}

var bar = "global";

foo();  // local

Dar dacă am folosi modul strict (strict mode), atunci "this" în acest caz ar avea valoarea "undefined":

"use strict";
function foo(){
   var bar = "local";
   console.log(this.bar);
}

var bar = "global";

foo();  // eroare- this - undefined

Contextul obiectului

În contextul unui obiect, inclusiv în metodele sale, cuvântul cheie "this" se referă la același obiect:

const obj = {
   bar: "object",
   foo: function(){
       console.log(this.bar);
   }
}
var bar = "global";
obj.foo();  // object

Determinarea dinamică a contextului

Codul unei funcții întotdeauna folosește ca "this" contextul extern în care este apelat acest cod (exact apelat, nu definit). Să analizăm un exemplu mai complex:

function foo(){
   var bar = "foo_bar";
   console.log(this.bar);
}
 
const obj1 = {bar:"obj1_bar", foo: foo};
const obj2 = {bar:"obj2_bar", foo: foo};
 
var bar = "global_bar";
 
foo();  // global_bar
obj1.foo();   // obj1_bar
obj2.foo();   // obj2_bar

Aici este definită variabila globală bar ("global_bar"). De asemenea, în funcția foo este definită variabila locală bar ("foo_bar"). Care va fi valoarea afișată în funcția foo? Funcția foo utilizează definiția variabilei stabilită în contextul extern. Pentru funcția foo, acesta este implicit contextul global, așadar afișează valoarea variabilei globale (deoarece acest script rulează în modul non-strict, iar cuvântul cheie "this" în funcția foo se referă la contextul extern).

Cu obiectele, situația este diferită. Ele definesc propriul lor context în care există proprietatea lor bar. La apelul metodei foo, contextul extern față de funcție va fi contextul obiectelor obj1 și obj2.

Un astfel de comportament poate duce la unele neînțelegeri în anumite situații. Spre exemplu, să examinăm o altă situație:

var bar = "global_bar";

const obj1 = {
   bar: "obj1_bar",
   foo: function(){
       console.log(this.bar);  // bar = "obj1_bar"
   }
}
const obj2 = {bar: "obj2_bar", foo: obj1.foo}; // bar = "obj2_bar"

const foo = obj1.foo;   // bar = "global_bar"

obj1.foo(); // obj1_bar
obj2.foo(); // obj2_bar
foo();      // global_bar

În acest exemplu, în obiectul obj1 este definită funcția foo:

const obj1 = {
   bar: "obj1_bar",
   foo: function(){
       console.log(this.bar);  // bar = "obj1_bar"
   }
}

Această funcție foo va prelua valoarea pentru "this.bar" din contextul extern - din obiectul obj1, prin urmare, "this.bar = "obj1_bar"".

Obiectul obj2 folosește funcția foo din obiectul obj1:

const obj2 = {bar: "obj2_bar", foo: obj1.foo};

Cu toate acestea, funcția obj1.foo va căuta, de asemenea, valoarea pentru this.bar din nou în contextul extern, iar în acest caz, acesta este obiectul obj2. În obiectul obj2, această valoare este "obj2_bar".

Același lucru este valabil și pentru variabila globală foo, care face referire la aceeași funcție ca și metoda obj1.foo:

const foo = obj1.foo;

În acest caz, va avea loc căutarea valorii pentru this.bar, dar acum în contextul funcției foo. Acesta este contextul global, unde este definită variabila var bar = "global_bar".

Contextul în funcții înglobate

Dacă apelăm o funcție dintr-o altă funcție, funcția apelată va folosi, de asemenea, contextul extern:

var bar = "global bar";
 
function foo(){
   var bar = "foo bar";
   function moo(){
         
       console.log(this.bar);
   }
   moo();
}
foo();  // global bar

Aici, funcția foo() utilizează valoarea variabilei bar din contextul extern ca this.bar, adică valoarea variabilei globale bar. Funcția moo() de asemenea, utilizează valoarea variabilei bar din contextul extern, adică this.bar pentru funcția externă foo, care la rândul său reprezintă valoarea variabilei globale bar. Prin urmare, consola va afișa în final "global bar", nu "foo bar".

Legarea explicită

Cu ajutorul metodelor call() și apply(), putem specifica o legare explicită a funcției la un anumit context:

function foo(){
   console.log(this.bar);
}

var obj = {bar: "obj_bar"}
var bar = "global_bar";
foo();              // global_bar
foo.apply(obj);     // obj_bar
// или
// foo.call(obj);

În al doilea caz, funcția foo este legată la obiectul obj, care determină contextul său. Prin urmare, în al doilea caz, consola va afișa "obj_bar".

Metoda bind

Metoda bind() permite crearea unei noi funcții cu același corp și domeniu de vizibilitate ca și funcția f, dar cu o legare la obiectul o:

function foo(){
   console.log(this.bar);
}

const obj = {bar: "object"}
var bar = "global";
foo();  // global
const func = foo.bind(obj);
func(); // object

this și funcțiile săgeată

În funcțiile săgeată, this folosește contextul de mediu, nu mediul în care este definită funcția săgeată. Să analizăm următorul exemplu:

const person = {
   name: "Tom",
   say:()=> console.log(`Mă numesc ${this.name}`)
}
person.say();   // Mă numesc

Aici, funcția săgeată say() accesează o proprietate this.name, dar ce reprezintă aici this? Pentru contextul extern în care este definită funcția săgeată - adică pentru contextul obiectului person, this reprezintă obiectul global (obiectul fereastră a browserului). Cu toate acestea, variabila globală name nu este definită, așa că va fi afișat în consolă:

Mă numesc

Acum să modificăm puțin exemplul:

const person = {
   name: "Tom",
   hello(){
       console.log("Salut");
       let say = ()=> console.log(`Mă numesc ${this.name}`);
       say();
   }
}
person.hello();

Acum, funcția săgeată este definită în metoda hello(). Pentru această metodă, this reprezintă obiectul person în care este definită această metodă. Prin urmare, în funcția săgeată, this va reprezenta obiectul person, iar this.name va fi proprietatea name a acestui obiect. Astfel, la executarea programului vom obține:

Salut! Mă numesc Tom

Deși funcțiile săgeată pot adăuga complexitate atunci când vine vorba de gestionarea this, totuși, ele pot rezolva anumite probleme. De exemplu, la lucrul cu mai multe contexte, trebuie să fim atenți la modul în care este definită variabila în respectivul context. Spre exemplu, să luăm în considerare următorul cod:

const school ={
   title: "Oxford",
   courses: ["JavaScript", "TypeScript", "Java", "Go"],
   printCourses(){
       this.courses.forEach(function(course){
           console.log(this.title, course);
       })
   }
}
school.printCourses();

Funcția printCourses parcurge toate cursurile din array și, la afișarea lor, le precede cu valoarea proprietății title. Cu toate acestea, pe consolă, la rularea programului, vom vedea următoarele:

undefined "JavaScript" undefined "TypeScript" undefined "Java" undefined "Go"

Observăm că valoarea this.title nu este definită, deoarece this ca context al obiectului este înlocuit cu contextul global. În acest caz, trebuie să transmitem o astfel de valoare this.title sau întregul context al obiectului.

const school ={
   title: "Oxford",
   courses: ["JavaScript", "TypeScript", "Java", "Go"],
   printCourses(){
       const that = this;
       this.courses.forEach(function(course){
           console.log(that.title, course);
       })
   }
}
school.printCourses();

Funcțiile săgeată, de asemenea, permit rezolvarea acestei probleme:

const school ={
   title: "Oxford",
   courses: ["JavaScript", "TypeScript", "Java", "Go"],
   printCourses(){
       this.courses.forEach((course)=>console.log(this.title, course))
   }
}
school.printCourses();

Contextul pentru funcția săgeată în acest caz va fi contextul obiectului school. Prin urmare, nu este necesar să definim variabile suplimentare pentru a transmite date către funcție.

← Lecția anterioară Lecția următoare →