2013-02-23 18 views
9

Non riesco a capirmi un caso specifico di scoping per le variabili JavaScript. Diverso da altri esempi e domande che ho trovato, mi interessa l'ambito per le funzioni annidate.Ambito locale JavaScript: var rispetto a questo

Ho impostato un esempio su this JSFiddle. La parte rilevante è la seguente:

function MyObject() { 
    var self = this; 

    var a = 1; 
    this.b = 2; 

    var innerMethod = function() { 
     //1 and 2: direct reference 
     logMessage("a = " + a); // a = 1 
     //logMessage("b = " + b); // Error: b is not defined 

     //3 and 4: using this 
     logMessage("this.a = " + this.a); // this.a = undefined 
     logMessage("this.b = " + this.b); // this.b = undefined 

     //5 and 6: using self 
     logMessage("self.a = " + self.a); // self.a = undefined 
     logMessage("self.b = " + self.b); // self.b = 2 
    } 
} 

Ora, capisco che un riferimento alla a lavora direttamente. Capisco anche che i messaggi 3 e 4 (this.a e this.b) non riusciranno perché this si riferisce alla funzione interna. Capisco anche che la linea 6 funziona perché salvo il riferimento all'oggetto originale.

Quello che non capisco è:

  • perché non sono i messaggi 1 e 2 lavorano allo stesso modo?
  • perché i messaggi 5 e 6 non funzionano allo stesso modo?
+5

Perché dovrebbero lavorare allo stesso modo? Sembra che tu stia analizzando con Java o qualche altro linguaggio in cui il namespace 'this' è implicito, il che non è il caso di JS. –

+0

@ FabrícioMatté Potrei essere inconscio a fare questo (gioco di parole). Non riesco a capire se l'ambito debba rendere le variabili/membri automaticamente esposti ai membri interni. Sembra che non sia così, perché non è coerente. – Alpha

+3

@Alpha Stai confrontando le variabili ('var a = 5;') con le cose che non sono variabili ma le proprietà degli oggetti ('this.b = 10;' imposta la proprietà 'b' dell'oggetto che' this' fa riferimento a '10'). Queste cose non sono le stesse e quindi non si comportano in modo identico. – Niko

risposta

4

La variabile a è proprio quella, una variabile. È visibile nell'ambito di innerMethod (che è solo una funzione annidata), come a, che è come è stato dichiarato (cioè JavaScript ha regole di scoping lessicale, le funzioni interne possono vedere le variabili delle funzioni che sono definite all'interno di).

this non corrisponde all'ambito locale del costruttore MyObject.

Hai visto che self è un alias per this di MyObject, e che innerMethod ha sovrascritto this nel proprio ambito. Tuttavia, poiché this non è un alias per l'ambito delle funzioni, né self.athis.a funzioneranno mai qui.

Per una spiegazione più rigorosa dello scope lessicale è possibile ad es. inizio alle wikipedia: http://en.wikipedia.org/wiki/Scope_(computer_science)

È possibile leggere i contesti di esecuzione e le regole di risoluzione identificatore nel ECMA standard, http://es5.github.com/#x10.3

+0

Ben spiegato. :) – Kaeros

+0

Preferirei il termine ['VariableEnvironment'] (http://es5.github.com/#x10.3) invece di' function scope' nel tuo terzo paragrafo e dichiaro che il motivo dietro al primo paragrafo è che JS ha [scope lessicale] (http://stackoverflow.com/questions/1047454/what-is-lexical-scope). Ma molto ben spiegato. –

+0

Ho incorporato alcune delle tue modifiche, ma sono titubante nello scambiare VariableEnvironment per l'ambito delle funzioni. Anche se è tecnicamente più corretto, credo che l'ambito della funzione sia un concetto più noto per i programmatori che provengono da altre lingue. Ho aggiunto il tuo link allo standard ECMA. – thebjorn

1

È un problema con l'ambito, quando le funzioni vengono create salvano l'ambiente (comprese le variabili).

Quindi, quando viene creato innerMethod, è possibile visualizzare le variabili self e a.

Un concetto importante è che l'ambito viene creato quando la funzione viene dichiarata, anziché quando viene chiamata.

Nel tuo caso 1, b non viene dichiarato (l'oggetto non è lo stesso).

Nei casi 5 e 6, non è stato creato self.a.

0

La ragione principale è che self non è uguale a this area di innerMethod. this è una parola chiave per fare riferimento al proprietario della funzione.Per innerMethod, NON è un metodo di istanza, appartiene alla finestra.

function MyObject() { 
    var self = this; 

    var innerMethod = function() { 
     alert("inner method, self == this?: " + self == this); // false 
     alert("inner method: " + this); // [object Window] 
     alert("closest constructor name of in prototype chain ?: "+ this.__proto__.constructor.name); // Window 
    } 

    this.outerMethod = function(){ 
     innerMethod(); 
     alert("outer method: " + this); // [object MyObject] 
     alert("closest constructor name in prototype chain?: "+ this.__proto__.constructor.name); // MyObject 
    } 
} 

var o = new MyObject(); 
o.outerMethod(); 

Puoi giocare a here

Problemi correlati