var self = this?


182

L'uso dei metodi di istanza come callback per i gestori di eventi cambia l'ambito thisda "Mia istanza" a "Qualunque cosa abbia appena chiamato il callback" . Quindi il mio codice è simile a questo

function MyObject() {
  this.doSomething = function() {
    ...
  }

  var self = this
  $('#foobar').bind('click', function(){
    self.doSomethng()
    // this.doSomething() would not work here
  })
}

Funziona, ma è questo il modo migliore per farlo? Mi sembra strano.


15
Dovresti evitare selfperché c'è un window.selfoggetto e potresti finire per usarlo accidentalmente se dimentichi di dichiarare il tuo selfvar (ad esempio quando sposti un codice). Questo può essere fastidioso da individuare / eseguire il debug. Meglio usare qualcosa del genere _this.
Alastair Maw,


3
Dal tutorial di JavaScript : "Il valore di thisè dinamico in JavaScript. Viene determinato quando viene chiamata la funzione , non quando viene dichiarata."
DavidRR,


Il fatto è, nell'ambito globale self === this. Pertanto, selfin contesti locali ha senso e segue il modello.
programmatore, 5

Risposte:


210

Questa domanda non è specifica per jQuery, ma specifica per JavaScript in generale. Il problema principale è come "canalizzare" una variabile nelle funzioni incorporate. Questo è l'esempio:

var abc = 1; // we want to use this variable in embedded functions

function xyz(){
  console.log(abc); // it is available here!
  function qwe(){
    console.log(abc); // it is available here too!
  }
  ...
};

Questa tecnica si basa sull'uso di una chiusura. Ma non funziona thisperché thisè una pseudo-variabile che può cambiare dinamicamente da un ambito all'altro:

// we want to use "this" variable in embedded functions

function xyz(){
  // "this" is different here!
  console.log(this); // not what we wanted!
  function qwe(){
    // "this" is different here too!
    console.log(this); // not what we wanted!
  }
  ...
};

Cosa possiamo fare? Assegnalo a qualche variabile e usalo attraverso l'alias:

var abc = this; // we want to use this variable in embedded functions

function xyz(){
  // "this" is different here! --- but we don't care!
  console.log(abc); // now it is the right object!
  function qwe(){
    // "this" is different here too! --- but we don't care!
    console.log(abc); // it is the right object here too!
  }
  ...
};

thisnon è unico sotto questo aspetto: argumentsè l'altra pseudo-variabile che dovrebbe essere trattata allo stesso modo - con l'aliasing.


7
Dovresti davvero associare "questo" alla chiamata di funzione e non passarlo o attraversare ambiti variabili con esso
michael

10
@michael Perché è quello?
Chris Anderson,

@michael potresti lavorare all'interno di pipe, mappe, iscrizioni ... in una funzione e non chiamare funzioni, in questo caso "questo" sta cambiando, quindi l'ambito variabile è la soluzione
Skander Jenhani

@SkanderJenhani quel commento ha 8 anni. La mia risposta sarebbe molto diversa oggi
michael il

18

Sì, questo sembra essere uno standard comune. Alcuni programmatori usano me stesso, altri usano me. È usato come riferimento all'oggetto "reale" in contrapposizione all'evento.

È qualcosa che mi ha impiegato un po 'di tempo per arrivare davvero, all'inizio sembra strano.

Di solito lo faccio proprio nella parte superiore del mio oggetto (scusa il mio codice demo - è più concettuale di ogni altra cosa e non è una lezione sull'eccellente tecnica di codifica):

function MyObject(){
  var me = this;

  //Events
  Click = onClick; //Allows user to override onClick event with their own

  //Event Handlers
  onClick = function(args){
    me.MyProperty = args; //Reference me, referencing this refers to onClick
    ...
    //Do other stuff
  }
}

12
var functionX = function() {
  var self = this;
  var functionY = function(y) {
    // If we call "this" in here, we get a reference to functionY,
    // but if we call "self" (defined earlier), we get a reference to function X.
  }
}

modifica: nonostante, le funzioni nidificate all'interno di un oggetto assumono l'oggetto finestra globale anziché l'oggetto circostante.


Sembra che tu stia descrivendo cosa var self = thisfa, ma non è questa la domanda (la domanda è se questa è la soluzione migliore al problema).
Quentin,

3
"Il problema principale è come" canalizzare "una variabile nelle funzioni integrate." Accetto questa affermazione nella risposta accettata. Oltre a ciò, non c'è nulla di sbagliato nella pratica di "quella". È abbastanza comune Quindi, come risposta alla parte "il codice mi sembra strano" ho scelto di spiegare come funziona. Credo che la ragione per cui il "codice mi sembra strano" derivi dalla confusione di come funziona.
serkan,

12

Se stai eseguendo ES2015 o scrivendo script di tipo ed ES5, puoi usare le funzioni freccia nel tuo codice e non riscontri quell'errore e questo si riferisce all'ambito desiderato nella tua istanza.

this.name = 'test'
myObject.doSomething(data => {
  console.log(this.name)  // this should print out 'test'
});

5
Come spiegazione: in ES2015 le funzioni freccia catturano thisdal loro ambito di definizione. Le definizioni delle normali funzioni non lo fanno.
defnull

@defnull Non credo sia qualcosa di speciale. Le funzioni creano un ambito di blocco. quindi l'uso della notazione a freccia invece di una funzione ti impedisce di creare un ambito, quindi questo rimarrà comunque riferito alla variabile esterna.
Nimeshka Srimal,

4

Una soluzione a questo è legare tutto il callback al tuo oggetto con il bindmetodo javascript .

Puoi farlo con un metodo denominato,

function MyNamedMethod() {
  // You can now call methods on "this" here 
}

doCallBack(MyNamedMethod.bind(this)); 

O con una richiamata anonima

doCallBack(function () {
  // You can now call methods on "this" here
}.bind(this));

Fare questo invece di ricorrere a var self = thismostra che capisci come l'associazione di thissi comporta in javascript e non si basa su un riferimento di chiusura.

Inoltre, l'operatore freccia grassa in ES6 è sostanzialmente lo stesso che chiama .bind(this)una funzione anonima:

doCallback( () => {
  // You can reference "this" here now
});

Personalmente penso che .bind (questo) stia semplicemente digitando di più, cambiando questo riferimento a me (o qualunque altra cosa) e poi semplicemente usarlo invece rende il codice più pulito. La freccia grassa è il futuro però.
davidbuttar,

3

Non ho usato jQuery, ma in una libreria come Prototype è possibile associare funzioni a un ambito specifico. Quindi tenendo presente questo, il tuo codice sarebbe simile al seguente:

 $('#foobar').ready('click', this.doSomething.bind(this));

Il metodo bind restituisce una nuova funzione che chiama il metodo originale con l'ambito specificato.


Analogo a: $('#foobar').ready('click', this.doSomething.call(this));giusto?
Muers,

Il bindmetodo non funziona nei browser più vecchi, quindi usa $.proxyinvece il metodo.
Guffa,

2

Aggiungendo semplicemente a ciò che in ES6 a causa delle funzioni freccia non dovresti aver bisogno di farlo perché catturano il thisvalore.


1

Penso che in realtà dipende da cosa hai intenzione di fare all'interno della tua doSomethingfunzione. Se si accede alle MyObjectproprietà utilizzando questa parola chiave, è necessario utilizzarla. Ma penso che il seguente frammento di codice funzionerà anche se non stai facendo nulla di speciale usando le object(MyObject)proprietà.

function doSomething(){
  .........
}

$("#foobar").ready('click', function(){

});
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.