În JavaScript, fiecare funcție are o this
referință creată automat atunci când o declarați.
JavaScript this
este destul de similar cu o this
referință în alte limbaje bazate pe clase, cum ar fi Java sau C # (JavaScript este un limbaj bazat pe prototip și nu are concept de „clasă”): indică obiectul care apelează la funcție (acest obiect numit uneori ca context ). Cu toate acestea, înthis
JavaScript, referința din interiorul funcțiilor poate fi legată de diferite obiecte, în funcție de locul în care funcția este apelată .
Iată 5 reguli de bază pentru this
legarea în JavaScript:
Regula 1
Când se apelează o funcție în domeniul global, this
referința este legată implicit de obiectul global ( window
în browser sau global
în Node.js). De exemplu:
function foo() { this.a = 2; } foo(); console.log(a); // 2
Notă: Dacă declarați foo()
funcția de mai sus în modul strict, atunci apelați această funcție în domeniul global, this
va fi undefined
și atribuirea this.a = 2
va arunca o Uncaught TypeError
excepție.
Regula 2
Să examinăm exemplul de mai jos:
function foo() { this.a = 2; } const obj = { foo: foo }; obj.foo(); console.log(obj.a); // 2
În mod clar, în fragmentul de mai sus, foo()
funcția este apelată cu contextul este obj
obiect și this
referința acum este legată obj
. Deci, atunci când o funcție este apelată cu un obiect context, this
referința va fi legată de acest obiect.
Regula 3
.call
, .apply
și .bind
pot fi folosite toate pe site-ul apelului pentru a lega în mod explicit this
. Utilizarea .bind(this)
este ceva ce puteți vedea în destul de multe componente React.
const foo = function() { console.log(this.bar) } foo.call({ bar: 1 }) // 1
Iată un exemplu rapid despre modul în care fiecare este folosit pentru a lega this
:
.call()
:fn.call(thisObj, fnParam1, fnParam2)
.apply()
:fn.apply(thisObj, [fnParam1, fnParam2])
.bind()
:const newFn = fn.bind(thisObj, fnParam1, fnParam2)
Regula 4
function Point2D(x, y) { this.x = x; this.y = y; } const p1 = new Point2D(1, 2); console.log(p1.x); // 1 console.log(p1.y); // 2
Lucrul pe care trebuie să-l observați este Point2D
funcția numită cu new
cuvânt cheie, iar this
referința este obligată să p1
obiecteze. Deci, atunci când o funcție este apelată cu new
cuvânt cheie, va crea un obiect nou și this
referința va fi legată de acest obiect.
Notă: pe măsură ce numiți o funcție cu new
cuvânt cheie, o numim și funcție de constructor .
Regula 5
JavaScript determină valoarea de this
la runtime, pe baza contextului curent. Deci, this
uneori, poate indica altceva decât ceea ce vă așteptați.
Luați în considerare acest exemplu de clasă Cat cu o metodă numită makeSound()
, urmând modelul din regula 4 (de mai sus) cu o funcție constructor și new
cuvântul cheie.
const Cat = function(name, sound) { this.name = name; this.sound = sound; this.makeSound = function() { console.log( this.name + ' says: ' + this.sound ); }; } const kitty = new Cat('Fat Daddy', 'Mrrooowww'); kitty.makeSound(); // Fat Daddy says: Mrrooowww
Acum, să încercăm să oferim pisicii o cale către annoy()
oameni prin repetarea sunetului său de 100 de ori, o dată la jumătate de secundă.
const Cat = function(name, sound) { this.name = name; this.sound = sound; this.makeSound = function() { console.log( this.name + ' says: ' + this.sound ); }; this.annoy = function() { let count = 0, max = 100; const t = setInterval(function() { this.makeSound(); // <-- this line fails with `this.makeSound is not a function` count++; if (count === max) { clearTimeout(t); } }, 500); }; } const kitty = new Cat('Fat Daddy', 'Mrrooowww'); kitty.annoy();
Asta nu funcționează, deoarece în setInterval
callback am creat un nou context cu scop global, deci this
nu mai indică instanța noastră de pisică. Într-un browser web, this
va indica în schimb obiectul Window, care nu are o makeSound()
metodă.
Câteva moduri de a-l face să funcționeze:
- Înainte de a crea noul context, atribuiți
this
unei variabile locale numiteme
sauself
sau oricum doriți să o numiți și utilizați acea variabilă în interiorul apelului invers.
const Cat = function(name, sound) { this.name = name; this.sound = sound; this.makeSound = function() { console.log( this.name + ' says: ' + this.sound ); }; this.annoy = function() { let count = 0, max = 100; const self = this; const t = setInterval(function() { self.makeSound(); count++; if (count === max) { clearTimeout(t); } }, 500); }; } const kitty = new Cat('Fat Daddy', 'Mrrooowww'); kitty.annoy();
- Cu ES6 puteți evita atribuirea
this
unei variabile locale utilizând o funcție săgeată, care se leagăthis
de contextul codului înconjurător unde este definit.
const Cat = function(name, sound) { this.name = name; this.sound = sound; this.makeSound = function() { console.log( this.name + ' says: ' + this.sound ); }; this.annoy = function() { let count = 0, max = 100; const t = setInterval(() => { this.makeSound(); count++; if (count === max) { clearTimeout(t); } }, 500); }; } const kitty = new Cat('Fat Daddy', 'Mrrooowww'); kitty.annoy();