this

Questa traduzione è incompleta. Collabora alla traduzione di questo articolo dall’originale in lingua inglese.

La keyword di funzione this si comporta in modo leggermente differente in JavaScript rispetto ad altri linguaggi. Esistono inoltre alcune differenze tra strict mode e non-strict mode.

Nella maggior parte dei casi, il valore di this è determinato da come la funzione viene invocata (chiamata). Il valore di this non può essere impostato per assegnamento durante l'esecuzione, e potrebbe essere differente ogni volta in cui la funzione viene chiamata. ES5 ha introdotto il metodo bind per impostare il valore di this indipendentemente da come la funzione è invocata. ECMAScript 2015 ha introdotto le funzione a freccia ( arrow function ), in cui la keyword this viene lessicalmente incorporata nello scope corrente ( lo scope del contesto di esecuzione relativo al blocco corrente ).

Sintassi

this

Contesto Globale

Nel contesto di esecuzione globale (fuori da qualsiasi funzione), this si riferisce all'oggetto globale, sia che ci si trovi in strict mode,  sia che ci si trovi in non-strict mode.

console.log(this.document === document); // true

// In web browsers, the window object is also the global object:
console.log(this === window); // true

this.a = 37;
console.log(window.a); // 37

Contesto di funzione

All'interno di una funzione, il valore di this dipende da come la funzione è invocata.

Chiamata semplice

function f1(){
  return this;
}

f1() === window; // global object

In questo caso, il valore di this non viene impostato dalla chiamata. Visto che il codice non è in strict mode, il valore di this deve sempre essere un oggetto quindi viene impostato di default sull'oggetto globale.

function f2(){
  "use strict"; // see strict mode
  return this;
}

f2() === undefined;

In strict mode, il valore di this rimane impostato sul valore definito al momento dell'ingresso nel contesto di esecuzione. Se non è definito, resta undefined. Può anche essere impostato a qualsiasi valore, come null42"I am not this".

Nota: Nel secondo esempio, this dovrebbe essere undefined, perchè f2 viene invocata senza specificare alcuna base (per esempio, window.f2()). Alcuni browser non hanno implementato questo orientamento, quando hanno deciso di supportare lo strict mode. Come risultato, questi browser restituivano, in modo non corretto, l'oggetto window.

Funzioni Arrow

Nelle funzioni arrow, this è assegnato lessicalmente, assume cioè il valore del contesto di esecuzione che contiene this. In codice globale punta all'oggetto globale:

var globalObject = this;
var foo = (() => this);
console.log(foo() === globalObject); // true

Non importa come foo sia invocato, this punterà all'oggetto globale. Questo è ancora valido se è chiamato come metodo di un oggetto (che solitamente punterebbe il valore di this sullo stesso) tramite chiamate dei metodi call o apply o bind

// Call as a method of an object
var obj = {foo: foo};
console.log(obj.foo() === globalObject); // true

// Attempt to set this using call
console.log(foo.call(obj) === globalObject); // true

// Attempt to set this using bind
foo = foo.bind(obj);
console.log(foo() === globalObject); // true

in ogni caso il valore di this all'interno di foo è impostato al valore di quando è stato creato (nell'esempio di sopra, l'oggetto globale). Lo stesso si applica per funzioni arrow create all'interno di altre funzioni: il loro valore di this è impostato a quello del contesto di esecuzione esterno.

// Create obj with a method bar that returns a function that
// returns its this. The returned function is created as 
// an arrow function, so its this is permanently bound to the
// this of its enclosing function. The value of bar can be set
// in the call, which in turn sets the value of the 
// returned function.
var obj = { bar : function() {
                    var x = (() => this);
                    return x;
                  }
          };

// Call bar as a method of obj, setting its this to obj
// Assign a reference to the returned function to fn
var fn = obj.bar();

// Call fn without setting this, would normally default
// to the global object or undefined in strict mode
console.log(fn() === obj); // true

Nel codice sopra, la funzione (chiamiamola funzione anonima A) assegnata a obj.bar restituisce un altra funzione (chiamiamola funzione anonima B) che viene creata come funzione arrow. Il risultato, è che this della funzione B è impostata permanentemente al valore di this di obj.bar (funzione A) quando viene chiamata. quando la funzione restituita (B) viene chiamata, il relativo this sarà sempre impostato al valore di partenza. Nel codice di esempio  il this della funzione B è impostato al valore this della funzione A che è obj, pertanto resta impostato ad obj anche quando viene chiamato in un modo che imposterebbe this come undefined od oggetto globale (o qualunque altro metodo, come nel precedente esempio, nel contesto di esecuzione globale).

In the above, the function(call it anonymous function A) assigned to obj.bar returns another function(call it anonymous function B) that is created as an arrow function. As a result, function B's  this is permanently set to the this of obj.bar (function A)when called. When the returned function(function B) is called, its this will always be what it was set to initially. In the above code example, function B's this is set to function A's this which is obj, so it remains set to obj even when called in a manner that would normally set its this to undefined or the global object (or any other method as in the previous example in the global execution context).

Come metodo di un oggetto

Quando una funzione viene invocata come metodo di un oggetto, il this, all'interno della funzione, viene impostato sull'oggetto di cui la funzione è metodo.

Nell'esempio seguente, quando o.f() viene invocata, all'interno della funzione this è associato all'oggetto o.

var o = {
  prop: 37,
  f: function() {
    return this.prop;
  }
};

console.log(o.f()); // logs 37

Da notare che questo comportamento non è per nulla influenzato dal come e dal dove la funzione sia stata definita. Nell'esempio precedente, abbiamo definito la funzione inline, come membro f, nel corso della definizione di o. Tuttavia, avremmo potuto facilmente definire la funzione prima, per poi associarla a o.f. Il risultato sarebbe stato lo stesso:

var o = {prop: 37};

function independent() {
  return this.prop;
}

o.f = independent;

console.log(o.f()); // logs 37

Questo dimostra che la cosa più importante è che la funzione venga invocata dal membro f di o.

In modo analogo, l'associazione di this è influenzata solo dal membro più vicino. Nell'esempio seguente, quando invochiamo la funzione, la invochiamo come metodo g dell'oggetto o.b. Questa volta, durante l'esecuzione, this, all'interno della funzione, sarà associata ad o.b. Il fatto che l'oggetto sia, esso stesso, un membro di o non ha alcuna conseguenza; la sola cosa che conti è il riferimento più immediato.

o.b = {g: independent, prop: 42};
console.log(o.b.g()); // logs 42

this nella prototype chain dell'oggetto

La stessa notazione è valida per i metodi definiti altrove nella prototype chain dell'oggetto. Se il metodo è sulla prototype chain di un oggetto, this si riferisce all'oggetto su cui il metodo è stato chiamato, come se il metodo appartenesse all'oggetto.

var o = {f:function(){ return this.a + this.b; }};
var p = Object.create(o);
p.a = 1;
p.b = 4;

console.log(p.f()); // 5

in questo esempio, l'oggetto assegnato alla variabile p non ha definita una proprietà f, la eredita dal suo prototipo. Non ha importanza che il controllo per f trovi eventualmente un membro con quel nome in o; il controllo è cominciato con un riferimento a p.f, quindi this all'interno della funzione assume il valore dell'oggetto a cui p si riferisce. Cioè, dal momento che f è chiamata come metodo di p, la parola chiave this al suo interno si riferisce a p. Questa è una interessante caratteristica dell'ereditarietà dei prototipi di javascript.

this all'interno di metodi getter o setter

Ancora, la stessa notazione è valida quando una funzione è invocata all'interno di metodi get o set. In una funzione usata come getter o setter this viene collegata all'oggetto dal quale la proprietà è settata o ricavata.

function modulus(){
  return Math.sqrt(this.re * this.re + this.im * this.im);
}

var o = {
  re: 1,
  im: -1,
  get phase(){
    return Math.atan2(this.im, this.re);
  }
};

Object.defineProperty(o, 'modulus', {
    get: modulus, enumerable:true, configurable:true});

console.log(o.phase, o.modulus); // logs -0.78 1.4142

Come costruttore

Quando una funzione è usata come un costruttore (tramite la parola chiave new), this è collegata al nuovo oggetto che viene costruito.

Nota: mentre di default un costruttore restituisce l'oggetto riferenziato da this, può invece restituire qualche altro oggetto (se il valore di ritorno non è un oggetto, allora viene restituito l'oggetto this).

/*
 * Constructors work like this:
 *
 * function MyConstructor(){
 *   // Actual function body code goes here.  
 *   // Create properties on |this| as
 *   // desired by assigning to them.  E.g.,
 *   this.fum = "nom";
 *   // et cetera...
 *
 *   // If the function has a return statement that
 *   // returns an object, that object will be the
 *   // result of the |new| expression.  Otherwise,
 *   // the result of the expression is the object
 *   // currently bound to |this|
 *   // (i.e., the common case most usually seen).
 * }
 */

function C(){
  this.a = 37;
}

var o = new C();
console.log(o.a); // logs 37


function C2(){
  this.a = 37;
  return {a:38};
}

o = new C2();
console.log(o.a); // logs 38

Nell'ultimo esempio (C2), dal momento che è stato restituito un oggetto durante la costruzione, il nuovo oggetto a cui this era collegato viene semplicemente scartato. (Questo rende essenzialmente l'assegnazione "this.a = 37;" codice inutile. Non lo è in senso stretto, in quanto viene eseguito, ma può essere eliminato senza conseguenze).

I metodi call e apply

Dove una funzione usa la parola chiave this, il suo valore può essere collegato ad un qualsivoglia oggetto nella chiamata usando i metodi call o apply che tutte le funzioni ereditano da Function.prototype. 

function add(c, d){
  return this.a + this.b + c + d;
}

var o = {a:1, b:3};

// The first parameter is the object to use as
// 'this', subsequent parameters are passed as 
// arguments in the function call
add.call(o, 5, 7); // 1 + 3 + 5 + 7 = 16

// The first parameter is the object to use as
// 'this', the second is an array whose
// members are used as the arguments in the function call
add.apply(o, [10, 20]); // 1 + 3 + 10 + 20 = 34

Notare che con call e apply, se il valore passato tramite this non è un oggetto, viene eseguito un tentativo di convertire tale valore in oggetto usando l'operazione interna ToObject. pertanto, se il valore passato è un primitivo come 7 o 'foo', questo verrà convertito ad Object usando il relativo costruttore, quindi il valore primitivo 7 viene convertito  come new Number(7) e la stringa 'foo' viene convertita come new String('foo'), per esempio:

function bar() {
  console.log(Object.prototype.toString.call(this));
}

bar.call(7); // [object Number]

Il metodo bind

ECMAScript 5 ha introdotto Function.prototype.bind. Chiamare f.bind(someObject) crea una nuova funzione con lo stesso corpo e visibità di f, ma nella funzione originale si trova la parola chiave this, nella nuova funzione viene permanentemente collegato al primo argomento passato alla chiamata del metodo bind, ignorando come la funzione stessa venga usata. 

function f(){
  return this.a;
}

var g = f.bind({a:"azerty"});
console.log(g()); // azerty

var o = {a:37, f:f, g:g};
console.log(o.f(), o.g()); // 37, azerty

Come handler degli eventi del DOM

Quando una funzione viene usata come handler di eventi, i suoi riferimenti this sono puntati all'elemento che ha originato l'evento (alcuni Browser non seguono queste convenzioni per i listeners agguinti dinamicamente tramite metodi diversi da addEventListener).

// When called as a listener, turns the related element blue
function bluify(e){
  // Always true
  console.log(this === e.currentTarget); 
  // true when currentTarget and target are the same object
  console.log(this === e.target);
  this.style.backgroundColor = '#A5D9F3';
}

// Get a list of every element in the document
var elements = document.getElementsByTagName('*');

// Add bluify as a click listener so when the
// element is clicked on, it turns blue
for(var i=0 ; i<elements.length ; i++){
  elements[i].addEventListener('click', bluify, false);
}

In un handler di eventi "in-line"

quando il codice è chiamato da un handler in-line, this punta all'elemento DOM sul quale il listener è posizionato:

When code is called from an in–line handler, its this is set to the DOM element on which the listener is placed:

<button onclick="alert(this.tagName.toLowerCase());">
  Show this
</button>

Sopra, alert mostra 'button'. Notare comunque che this assume tale valore solo al di fuori di una funzione:

 

<button onclick="alert((function(){return this}()));">
  Show inner this
</button>

 

in questo caso, nella funzione interna, this non punta all'elemento DOM quindi restituisce l'oggetto globale/window (cioè l'oggetto di default in modalità non-strict, in cui this non viene impostato dalla chiamata)

Specifiche

Specification Status Comment
ECMAScript 2017 Draft (ECMA-262)
The definition of 'The this keyword' in that specification.
Draft  
ECMAScript 2015 (6th Edition, ECMA-262)
The definition of 'The this keyword' in that specification.
Standard  
ECMAScript 5.1 (ECMA-262)
The definition of 'The this keyword' in that specification.
Standard  
ECMAScript 3rd Edition (ECMA-262)
The definition of 'The this keyword' in that specification.
Standard  
ECMAScript 1st Edition (ECMA-262)
The definition of 'The this keyword' in that specification.
Standard Initial definition. Implemented in JavaScript 1.0.

 

Compatibilità dei browser

Feature Chrome Firefox (Gecko) Internet Explorer Opera Safari
Basic support (Yes) (Yes) (Yes) (Yes) (Yes)
Feature Android Chrome for Android Firefox Mobile (Gecko) IE Mobile Opera Mobile Safari Mobile
Basic support (Yes) (Yes) (Yes) (Yes) (Yes) (Yes)

 

Vedere Anche

Tag del documento e collaboratori

 Hanno collaborato alla realizzazione di questa pagina: ILTORU, dr-astico, lvzndr, scurtoni
 Ultima modifica di: ILTORU,