Come accedere al `this` corretto all'interno di un callback?


1425

Ho una funzione di costruzione che registra un gestore di eventi:

function MyConstructor(data, transport) {
    this.data = data;
    transport.on('data', function () {
        alert(this.data);
    });
}

// Mock transport object
var transport = {
    on: function(event, callback) {
        setTimeout(callback, 1000);
    }
};

// called as
var obj = new MyConstructor('foo', transport);

Tuttavia, non sono in grado di accedere alla dataproprietà dell'oggetto creato all'interno del callback. Sembra che thisnon si riferisca all'oggetto creato ma a un altro.

Ho anche provato a utilizzare un metodo oggetto invece di una funzione anonima:

function MyConstructor(data, transport) {
    this.data = data;
    transport.on('data', this.alert);
}

MyConstructor.prototype.alert = function() {
    alert(this.name);
};

ma presenta gli stessi problemi.

Come posso accedere all'oggetto corretto?


95
Di tanto in tanto sono così stufo di un certo tipo di domanda, che decido di scrivere una risposta canonica. Anche se a queste domande è stata data risposta un milione di volte, non è sempre possibile trovare una buona coppia domanda + risposta che non sia "inquinata" da informazioni irrilevanti. Questo è uno di quei momenti e una di quelle domande (e sono annoiato). Se pensi che ci sia effettivamente una buona domanda / risposta canonica esistente per questo tipo di domanda, fammi sapere e cancellerò questa. Suggerimenti per miglioramenti sono benvenuti!
Felix Kling,



3
Pagina utile di TypeScript su questo , applicabile principalmente anche a JS.
Ondra Žižka,

Risposte:


1791

Cosa dovresti sapere this

this(aka "il contesto") è una parola chiave speciale all'interno di ciascuna funzione e il suo valore dipende solo da come è stata chiamata la funzione, non da come / quando / dove è stata definita. Non è influenzato da ambiti lessicali come altre variabili (ad eccezione delle funzioni freccia, vedere di seguito). Ecco alcuni esempi:

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

// normal function call
foo(); // `this` will refer to `window`

// as object method
var obj = {bar: foo};
obj.bar(); // `this` will refer to `obj`

// as constructor function
new foo(); // `this` will refer to an object that inherits from `foo.prototype`

Per saperne di più this, dai un'occhiata alla documentazione MDN .


Come fare riferimento al corretto this

Non usare this

In realtà non si desidera accedere thisin particolare, ma l'oggetto a cui si riferisce . Ecco perché una soluzione semplice è semplicemente creare una nuova variabile che si riferisce anche a quell'oggetto. La variabile può avere qualsiasi nome, ma quelli comuni sono selfe that.

function MyConstructor(data, transport) {
    this.data = data;
    var self = this;
    transport.on('data', function() {
        alert(self.data);
    });
}

Poiché selfè una variabile normale, obbedisce alle regole dell'ambito lessicale ed è accessibile all'interno del callback. Ciò ha anche il vantaggio di poter accedere al thisvalore del callback stesso.

Set esplicito thisdel callback - parte 1

Potrebbe sembrare che tu non abbia alcun controllo sul valore di thisperché il suo valore è impostato automaticamente, ma in realtà non è così.

Ogni funzione ha il metodo .bind [docs] , che restituisce una nuova funzione thisassociata a un valore. La funzione ha esattamente lo stesso comportamento di quella che hai chiamato .bind, solo che è thisstata impostata da te. Indipendentemente da come o quando viene chiamata quella funzione, thisfarà sempre riferimento al valore passato.

function MyConstructor(data, transport) {
    this.data = data;
    var boundFunction = (function() { // parenthesis are not necessary
        alert(this.data);             // but might improve readability
    }).bind(this); // <- here we are calling `.bind()` 
    transport.on('data', boundFunction);
}

In questo caso, associamo i callback thisal valore di MyConstructor's this.

Nota: quando si associa un contesto per jQuery, utilizzare invece jQuery.proxy [docs] . La ragione per fare ciò è che non è necessario memorizzare il riferimento alla funzione quando si annulla un callback di un evento. jQuery lo gestisce internamente.

ECMAScript 6: utilizzare le funzioni freccia

ECMAScript 6 introduce funzioni freccia , che possono essere pensate come funzioni lambda. Non hanno il loro thislegame. Invece, thisè cercato nell'ambito proprio come una normale variabile. Ciò significa che non devi chiamare .bind. Non è l'unico comportamento speciale che hanno, fare riferimento alla documentazione MDN per ulteriori informazioni.

function MyConstructor(data, transport) {
    this.data = data;
    transport.on('data', () => alert(this.data));
}

Set thisdi callback - parte 2

Alcune funzioni / metodi che accettano i callback accettano anche un valore a cui thisdovrebbero fare riferimento i callback . Questo è fondamentalmente lo stesso che associarlo tu stesso, ma la funzione / metodo lo fa per te. Array#map [docs] è un tale metodo. La sua firma è:

array.map(callback[, thisArg])

Il primo argomento è il callback e il secondo argomento è il valore a cui thisdovrebbe fare riferimento. Ecco un esempio inventato:

var arr = [1, 2, 3];
var obj = {multiplier: 42};

var new_arr = arr.map(function(v) {
    return v * this.multiplier;
}, obj); // <- here we are passing `obj` as second argument

Nota: la possibilità o meno di trasmettere un valore thisè di solito menzionata nella documentazione di tale funzione / metodo. Ad esempio, il $.ajaxmetodo [docs] di jQuery descrive un'opzione chiamata context:

Questo oggetto verrà inserito nel contesto di tutti i callback relativi ad Ajax.


Problema comune: utilizzo dei metodi oggetto come callback / gestori di eventi

Un'altra manifestazione comune di questo problema è quando un metodo oggetto viene utilizzato come gestore di callback / evento. Le funzioni sono cittadini di prima classe in JavaScript e il termine "metodo" è solo un termine colloquiale per una funzione che è un valore di una proprietà dell'oggetto. Ma quella funzione non ha un collegamento specifico al suo oggetto "contenente".

Considera il seguente esempio:

function Foo() {
    this.data = 42,
    document.body.onclick = this.method;
}

Foo.prototype.method = function() {
    console.log(this.data);
};

La funzione this.methodè assegnata come gestore eventi click, ma se si document.bodyfa clic, il valore registrato sarà undefined, perché all'interno del gestore eventi, si thisriferisce a document.body, non all'istanza di Foo.
Come già accennato all'inizio, ciò che si thisriferisce dipende da come viene chiamata la funzione , non da come viene definita .
Se il codice fosse simile al seguente, potrebbe essere più ovvio che la funzione non ha un riferimento implicito all'oggetto:

function method() {
    console.log(this.data);
}


function Foo() {
    this.data = 42,
    document.body.onclick = this.method;
}

Foo.prototype.method = method;

La soluzione è la stessa di cui sopra: se disponibile, utilizzare .bindper associare esplicitamente thisa un valore specifico

document.body.onclick = this.method.bind(this);

o chiama esplicitamente la funzione come "metodo" dell'oggetto, usando una funzione anonima come gestore di callback / evento e assegna l'oggetto ( this) a un'altra variabile:

var self = this;
document.body.onclick = function() {
    self.method();
};

o usa una funzione freccia:

document.body.onclick = () => this.method();

39
Felix, ho letto prima questa risposta ma non ho mai risposto. Mi preoccupo che le persone usino selfe thatche facciano riferimento this. Mi sento così perché thisè una variabile sovraccarica utilizzata in contesti diversi; mentre di selfsolito corrisponde all'istanza locale e di thatsolito si riferisce a un altro oggetto. So che non hai impostato questa regola, poiché l'ho vista apparire in molti altri posti, ma è anche il motivo per cui ho iniziato a usare _this, ma non sono sicuro di come si sentano gli altri, fatta eccezione per la pratica non uniforme quello è risultato.
vol7ron,

3
@FelixKling sarebbe sicuro supporre che l'utilizzo di queste funzioni prototipo interne avrà sempre il comportamento previsto, indipendentemente da come vengono (tipicamente) chiamate? Quando si usano i callback all'interno delle funzioni del prototipo, esiste un'alternativa a bind (), self o that?
andig

5
@FelixKling Può essere utile a volte fare affidamento su Function.prototype.call ()e Function.prototype.apply (). In particolare con apply ()ho ottenuto un sacco di chilometraggio. Sono meno propenso a usare bind ()forse solo per abitudine sebbene sia consapevole (ma non certo) che potrebbero esserci lievi vantaggi generali nell'uso del bind rispetto alle altre opzioni.
Nolo,

5
Ottima risposta ma considera l'aggiunta di una soluzione opzionale aggiuntiva che è solo quella di non utilizzare classi, nuove o affatto.
Aluan Haddad,

4
re funzioni freccia "Invece, questo è cercato nell'ambito come una normale variabile." totalmente fatto questo clic per me, grazie! () => this.clicked();)
alfanumerico0101

211

Ecco alcuni modi per accedere al contesto principale all'interno del contesto secondario:

  1. Puoi usare la bind()funzione.
  2. Memorizza il riferimento al contesto / questo all'interno di un'altra variabile (vedi esempio sotto).
  3. Utilizzare le funzioni della freccia ES6 .
  4. Modifica codice / funzione design / architettura - per questo dovresti avere il comando sui modelli di progettazione in JavaScript.

1. Utilizzare la bind()funzione

function MyConstructor(data, transport) {
    this.data = data;
    transport.on('data', ( function () {
        alert(this.data);
    }).bind(this) );
}
// Mock transport object
var transport = {
    on: function(event, callback) {
        setTimeout(callback, 1000);
    }
};
// called as
var obj = new MyConstructor('foo', transport);

Se si utilizza underscore.js- http://underscorejs.org/#bind

transport.on('data', _.bind(function () {
    alert(this.data);
}, this));

2 Memorizza il riferimento al contesto / questo all'interno di un'altra variabile

function MyConstructor(data, transport) {
  var self = this;
  this.data = data;
  transport.on('data', function() {
    alert(self.data);
  });
}

3 Funzione freccia

function MyConstructor(data, transport) {
  this.data = data;
  transport.on('data', () => {
    alert(this.data);
  });
}

1
L'opzione bind () è sorprendente è solo passare il puntatore di questo oggetto per essere questo sull'altro oggetto (: Grazie!
Stav Bodik

Il bind () funziona come un fascino. Grazie mille +1 da parte mia :)
Anjana Silva,

56

È tutto nella sintassi "magica" di chiamare un metodo:

object.property();

Quando si ottiene la proprietà dall'oggetto e la si chiama in una volta sola, l'oggetto sarà il contesto per il metodo. Se si chiama lo stesso metodo, ma in passaggi separati, il contesto è invece l'ambito globale (finestra):

var f = object.property;
f();

Quando si ottiene il riferimento di un metodo, non è più associato all'oggetto, è solo un riferimento a una funzione semplice. Lo stesso accade quando si ottiene il riferimento da utilizzare come callback:

this.saveNextLevelData(this.setAll);

Ecco dove assoceresti il ​​contesto alla funzione:

this.saveNextLevelData(this.setAll.bind(this));

Se stai usando jQuery dovresti invece usare il $.proxymetodo, poiché bindnon è supportato in tutti i browser:

this.saveNextLevelData($.proxy(this.setAll, this));

33

Il problema con "contesto"

Il termine "contesto" è talvolta usato per riferirsi all'oggetto a cui fa riferimento questo . Il suo utilizzo è inappropriato perché non si adatta né semanticamente o tecnicamente con ECMAScript di questo .

"Contesto" indica le circostanze che circondano qualcosa che aggiunge significato, o alcune informazioni precedenti e seguenti che danno un significato extra. Il termine "contesto" è usato in ECMAScript per riferirsi al contesto di esecuzione , che è tutti i parametri, l'ambito e questo nell'ambito di alcuni codici di esecuzione.

Questo è mostrato nella sezione 10.4.2 dell'ECMA-262 :

Impostare ThisBinding sullo stesso valore di ThisBinding del contesto di esecuzione della chiamata

che indica chiaramente che questo fa parte di un contesto di esecuzione.

Un contesto di esecuzione fornisce le informazioni circostanti che aggiungono significato al codice che viene eseguito. Include molte più informazioni rispetto a thisBinding .

Quindi il valore di questo non è "contesto", è solo una parte di un contesto di esecuzione. È essenzialmente una variabile locale che può essere impostata dalla chiamata a qualsiasi oggetto e in modalità rigorosa, a qualsiasi valore.


Non posso essere d'accordo con questa risposta. L'esistenza del termine "contesto di esecuzione" non vieta altri usi del "contesto" più di quanto non vieti altri usi di "esecuzione". Forse c'è un termine migliore da descrivere, thisma nessuno è offerto qui, ed è probabilmente troppo tardi per chiudere la porta al "contesto".
Roamer-1888,

@ Roamer-1888 — grazie per la modifica. Hai ragione, ma il mio argomento non si basa sull'esistenza di "contesto di esecuzione" che preclude il "contesto" per qualche altro scopo. Piuttosto, si basa sul fatto che il "contesto" sia inappropriato dal punto di vista sia tecnico sia semantico. Penso anche che l'uso del "contesto" invece di "questo" si stia estinguendo. Non vedo alcun motivo per trovare un termine alternativo a questo o questo Legame , semplicemente offusca e significa che ad un certo punto devi spiegare che "contesto" è in realtà questo , e che non è in alcun "contesto". :-)
RobG

Non credo che si possa dire che questo non è in alcun modo "contesto", quando hai già ammesso che fa parte di un contesto di esecuzione, in cui "esecuzione" è semplicemente aggettivale.
Roamer-1888,

@ Roamer-1888 — Non continuerò questa conversazione oltre questo punto. Sì, questo è parte di un contesto di esecuzione. Dire che è il contesto è come dire che un giocatore di una squadra è la squadra.
RobG

RobG, peccato che non vuoi continuare. È un dibattito interessante. Grazie per avermi concesso il tuo tempo.
Roamer-1888,

31

Dovresti conoscere la parola chiave "questa".

Secondo il mio punto di vista è possibile implementare "questo" in tre modi (funzione Auto / Freccia / Metodo di associazione)

Una funzione di questa parola chiave si comporta in modo leggermente diverso in JavaScript rispetto ad altre lingue.

Ha anche alcune differenze tra la modalità rigorosa e la modalità non rigorosa.

Nella maggior parte dei casi, il valore di questo è determinato da come viene chiamata una funzione.

Non può essere impostato per assegnazione durante l'esecuzione e può essere diverso ogni volta che viene chiamata la funzione.

ES5 ha introdotto il metodo bind () per impostare il valore di una funzione indipendentemente da come viene chiamato,

e ES2015 hanno introdotto funzioni freccia che non forniscono questo legame (mantiene questo valore del contesto lessicale accluso).

Metodo 1: Sé - Il Sé viene utilizzato per mantenere un riferimento all'originale anche se il contesto sta cambiando. È una tecnica spesso usata nei gestori di eventi (specialmente nelle chiusure).

Riferimento : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this

function MyConstructor(data, transport) {
    this.data = data;
    var self = this;
    transport.on('data', function () {
        alert(self.data);
    });
}

Metodo2 : Funzione freccia: un'espressione della funzione freccia è un'alternativa sintatticamente compatta a un'espressione di funzione regolare,

sebbene senza i propri vincoli a questo, argomenti, parole chiave super o new.target.

Le espressioni delle funzioni freccia non sono adatte come metodi e non possono essere utilizzate come costruttori.

Riferimento : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions

  function MyConstructor(data, transport) {
    this.data = data;
    transport.on('data',()=> {
        alert(this.data);
    });
}

Method3 : Bind : il metodo bind () crea una nuova funzione che,

quando chiamato, ha questa parola chiave impostata sul valore fornito,

con una determinata sequenza di argomenti che precede quella fornita quando viene chiamata la nuova funzione.

Riferimento: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_objects/Function/bind

  function MyConstructor(data, transport) {
    this.data = data;
    transport.on('data',(function() {
        alert(this.data);
    }).bind(this);

25

Innanzitutto, devi avere una chiara comprensione scopee il comportamento della thisparola chiave nel contesto di scope.

this& scope:


there are two types of scope in javascript. They are :

   1) Global Scope

   2) Function Scope

in breve, l'ambito globale si riferisce all'oggetto finestra. Le variabili dichiarate in un ambito globale sono accessibili da qualsiasi luogo. D'altra parte l'ambito della funzione risiede all'interno di una funzione. Le variabili dichiarate all'interno di una funzione non sono accessibili normalmente dal mondo esterno. thisla parola chiave nell'ambito globale si riferisce all'oggetto finestra. thisLa funzione inside si riferisce anche all'oggetto window, quindi thisfarà sempre riferimento alla finestra fino a quando non troveremo un modo di manipolare thisper indicare un contesto di nostra scelta.

--------------------------------------------------------------------------------
-                                                                              -
-   Global Scope                                                               -
-   ( globally "this" refers to window object)                                 -     
-                                                                              -
-         function outer_function(callback){                                   -
-                                                                              -
-               // outer function scope                                        -
-               // inside outer function"this" keyword refers to window object -                                                                              -
-              callback() // "this" inside callback also refers window object  -

-         }                                                                    -
-                                                                              -
-         function callback_function(){                                        -
-                                                                              -
-                //  function to be passed as callback                         -
-                                                                              -
-                // here "THIS" refers to window object also                   -
-                                                                              -
-         }                                                                    -
-                                                                              -
-         outer_function(callback_function)                                    -
-         // invoke with callback                                              -
--------------------------------------------------------------------------------

Diversi modi per manipolare le thisfunzioni di callback interne:

Qui ho una funzione di costruzione chiamata Person. Ha una proprietà chiamata namee quattro metodo chiamato sayNameVersion1, sayNameVersion2, sayNameVersion3, sayNameVersion4. Tutti e quattro hanno un compito specifico: accettare un callback e richiamarlo. Il callback ha un compito specifico che è quello di registrare la proprietà name di un'istanza della funzione di costruzione Person.

function Person(name){

    this.name = name

    this.sayNameVersion1 = function(callback){
        callback.bind(this)()
    }
    this.sayNameVersion2 = function(callback){
        callback()
    }

    this.sayNameVersion3 = function(callback){
        callback.call(this)
    }

    this.sayNameVersion4 = function(callback){
        callback.apply(this)
    }

}

function niceCallback(){

    // function to be used as callback

    var parentObject = this

    console.log(parentObject)

}

Ora creiamo un'istanza dal costruttore della persona e invociamo diverse versioni del sayNameVersionXmetodo (X si riferisce a 1,2,3,4) niceCallbackper vedere in quanti modi possiamo manipolare il thiscallback interno per fare riferimento personall'istanza.

var p1 = new Person('zami') // create an instance of Person constructor

legare:

Quello che fa il bind è creare una nuova funzione con la thisparola chiave impostata sul valore fornito.

sayNameVersion1e sayNameVersion2usa bind per manipolare thisla funzione di callback.

this.sayNameVersion1 = function(callback){
    callback.bind(this)()
}
this.sayNameVersion2 = function(callback){
    callback()
}

il primo si associa thisal callback all'interno del metodo stesso e per il secondo il callback viene passato con l'oggetto associato ad esso.

p1.sayNameVersion1(niceCallback) // pass simply the callback and bind happens inside the sayNameVersion1 method

p1.sayNameVersion2(niceCallback.bind(p1)) // uses bind before passing callback

chiama:

La first argumentdel callmetodo viene utilizzato come thisall'interno della funzione che viene richiamata con callcollegato ad esso.

sayNameVersion3utilizza callper manipolare il thisriferimento all'oggetto persona che abbiamo creato, anziché all'oggetto finestra.

this.sayNameVersion3 = function(callback){
    callback.call(this)
}

e si chiama come il seguente:

p1.sayNameVersion3(niceCallback)

applicare :

Simile al callprimo argomento di si applyriferisce all'oggetto che verrà indicato dalla thisparola chiave.

sayNameVersion4usa applyper manipolare thisper riferirsi all'oggetto persona

this.sayNameVersion4 = function(callback){
    callback.apply(this)
}

e si chiama come il seguente. Semplicemente il callback è passato,

p1.sayNameVersion4(niceCallback)

1
qualsiasi critica costruttiva riguardo alla risposta sarà apprezzata!
AL-zami,

1
Questa parola chiave nell'ambito globale non si riferisce necessariamente all'oggetto finestra . Questo è vero solo in un browser.
Randall Flagg,

1
@RandallFlagg ho scritto questa risposta dal punto di vista del browser. Mi sono sentita libera di modificare questa risposta se necessario :)
AL-zami,

19

Non possiamo associarlo a setTimeout(), poiché viene sempre eseguito con l'oggetto globale (Window) , se si desidera accedere al thiscontesto nella funzione di callback, utilizzando bind()la funzione di callback possiamo ottenere come:

setTimeout(function(){
    this.methodName();
}.bind(this), 2000);

9
In che modo differisce da una qualsiasi delle risposte esistenti?
Felix Kling,

13

La domanda ruota attorno al thiscomportamento delle parole chiave in JavaScript. thissi comporta diversamente come di seguito,

  1. Il valore di this è solitamente determinato da un contesto di esecuzione delle funzioni.
  2. Nell'ambito globale, si thisriferisce all'oggetto globale (l' windowoggetto).
  3. Se la modalità rigorosa è abilitata per qualsiasi funzione, il valore di thissarà undefinedcome nella modalità rigorosa, l'oggetto globale si riferisce al undefinedposto windowdell'oggetto.
  4. L'oggetto che si trova davanti al punto è ciò a cui sarà legata questa parola chiave.
  5. Siamo in grado di impostare il valore di questo esplicitamente call(), bind()eapply()
  6. Quando newviene utilizzata la parola chiave (un costruttore), questo è associato al nuovo oggetto che viene creato.
  7. Le funzioni freccia non si legano this , invece thissono legate in modo lessicale (ovvero in base al contesto originale)

Come la maggior parte delle risposte suggerisce, possiamo usare la funzione Freccia o bind()Metodo o Auto var. Vorrei citare un punto su lambdas (funzione Freccia) dalla Guida allo stile di Google JavaScript

Preferisci usare le funzioni freccia su f.bind (questo), e specialmente su goog.bind (f, questo). Evita di scrivere const self = this. Le funzioni freccia sono particolarmente utili per i callback, che a volte trasmettono argomenti aggiuntivi imprevisti.

Google consiglia chiaramente di utilizzare lambdas anziché legare o const self = this

Quindi la soluzione migliore sarebbe usare lambda come di seguito,

function MyConstructor(data, transport) {
  this.data = data;
  transport.on('data', () => {
    alert(this.data);
  });
}

Riferimenti:

  1. https://medium.com/tech-tajawal/javascript-this-4-rules-7354abdb274c
  2. Arrow-funzioni-vs-bind

Questa domanda riguarda specificamente l'utilizzo di funzioni / metodi come callback. La tua risposta potrebbe adattarsi meglio a stackoverflow.com/q/3127429/218196 .
Felix Kling,

@FelixKling Sì, la domanda riguarda l'uso di funzioni / metodi come callback in quel problema principale era dovuto alla gestione della thisparola chiave, ecco perché ho diviso la mia risposta in due parti, una circa thise una seconda sull'uso di funzioni / metodi come callback. Sentiti libero di modificare la risposta.
Code_Mode

Trovo il tuo quarto punto formulato in modo ambiguo. Si consideri l' esempio "Problema quando si utilizzano metodi con The this Object come Callbacks" , in cui l'oggetto giusto si trova prima del punto, ma il contesto non è ancora quell'oggetto.
bleistift2,

7

Attualmente esiste un altro approccio possibile se le classi sono utilizzate nel codice.

Con il supporto dei campi di classe è possibile farlo nel modo seguente:

class someView {
    onSomeInputKeyUp = (event) => {
        console.log(this); // this refers to correct value
    // ....
    someInitMethod() {
        //...
        someInput.addEventListener('input', this.onSomeInputKeyUp)

Sicuramente sotto il cofano è tutta una vecchia funzione di freccia che lega il contesto, ma in questa forma sembra molto più chiaro quel legame esplicito.

Dal momento che si tratta della proposta della fase 3, avrai bisogno di babel e del plugin babel appropriato per elaborarlo come per ora (08/2018).


2
Questo è esattamente il modo in cui l'ho fatto funzionare in Typescript: public methodName = (params) => { body }all'interno di una classe.
yeyeyerman,

5

Un altro approccio, che è il modo standard da DOM2 di legarsi thisall'interno del listener di eventi, che consente di rimuovere sempre il listener (tra gli altri vantaggi), è il handleEvent(evt)metodo EventListenerdall'interfaccia:

var obj = {
  handleEvent(e) {
    // always true
    console.log(this === obj);
  }
};

document.body.addEventListener('click', obj);

Informazioni dettagliate sull'uso handleEventsono disponibili qui: https://medium.com/@WebReflection/dom-handleevent-a-cross-platform-standard-since-year-2000-5bf17287fd38


0

this in JS:

Il valore di thisin JS è determinato al 100% da come viene chiamata una funzione e non da come viene definita. Siamo in grado di relativamente facile trovare il valore della thisdalla 'sinistra della regola dot' :

  1. Quando la funzione viene creata utilizzando la parola chiave funzione il valore di this è l'oggetto a sinistra del punto della funzione che viene chiamata
  2. Se non è rimasto alcun oggetto del punto, il valore thisall'interno di una funzione è spesso l'oggetto globale ( globalnel nodo, windownel browser). Non consiglierei di usare la thisparola chiave qui perché è meno esplicita dell'uso di qualcosa di similewindow !
  3. Esistono alcuni costrutti come le funzioni freccia e le funzioni create usando la Function.prototype.bind()funzione che può fissare il valore di this. Queste sono eccezioni alla regola ma sono davvero utili per fissare il valore di this.

Esempio in nodeJS

module.exports.data = 'module data';
// This outside a function in node refers to module.exports object
console.log(this);

const obj1 = {
    data: "obj1 data",
    met1: function () {
        console.log(this.data);
    },
    met2: () => {
        console.log(this.data);
    },
};

const obj2 = {
    data: "obj2 data",
    test1: function () {
        console.log(this.data);
    },
    test2: function () {
        console.log(this.data);
    }.bind(obj1),
    test3: obj1.met1,
    test4: obj1.met2,
};

obj2.test1();
obj2.test2();
obj2.test3();
obj2.test4();
obj1.met1.call(obj2);

Produzione:

inserisci qui la descrizione dell'immagine

Lascia che ti guidi attraverso le uscite 1 per 1 (ignorando il primo registro a partire dal secondo):

  1. thisè a obj2causa della sinistra della regola punto, possiamo vedere come test1viene chiamato obj2.test1();. obj2è a sinistra del punto e quindi il thisvalore.
  2. Anche se obj2è a sinistra del punto, test2è vincolato obj1tramite il bind()metodo. Quindi il thisvalore è obj1.
  3. obj2che resta del punto dalla funzione che si chiama: obj2.test3(). Pertanto obj2sarà il valore di this.
  4. In questo caso: obj2.test4() obj2è a sinistra del punto. Tuttavia, la funzione freccia non ha il proprio thisbinding. Pertanto si legherà al thisvalore dell'ambito esterno che è ilmodule.exports oggetto che è stato registrato all'inizio.
  5. Possiamo anche specificare il valore di thisusando la callfunzione. Qui possiamo passare il thisvalore desiderato come argomento, che è obj2in questo caso.
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.