2016-04-21 17 views
14

Vengo da uno sfondo di Actionscript e (molto tardi alla festa) Sto cercando di imparare JavaScript. Sto passando per questo AngularJS - Video Tutorial For Beginners su YouTube (è abbastanza buono) e ho visto qualcosa di veramente semplice che non capisco.Ambito all'interno di una funzione anonima?

Alla riga 5 è definito lo var workcount. Quindi due funzioni anonime sono definite e restituite in un oggetto. Le funzioni si riferiscono a workcount ma non sono workcount in un ambito diverso? È simile a blocks in Objective-C in cui le vars locali rimangono accessibili all'interno del blocco. C'è un nome per quello che è?

O se una funzione "conosce" Vars precedentemente definito nel suo campo di applicazione, avrebbe la funzione task2 "sapere" task1?

Mi dà fastidio che non riesca a dare un senso a questo.

Aggiornamento: Grazie per tutte le risposte. Ora capisco - e anche se ho visto il termine "chiusure" prima, non l'ho mai capito (sembra un termine non molto descrittivo. Nel leggere, ho visto il termine "stack-frame" e poi la lampadina accesa : stack ... frame of reference);


var createWorker = function(){ 

    var workCount = 0; 

    var task1 = function(){ 
    workCount += 1; 
    console.log("task1" , workCount); 
    }; 

    var task2 = function(){ 
    workCount += 1; 
    console.log("task2" , workCount); 
    }; 

    return { 
    job1: task1, 
    job2:task2 
    } 
}; 

worker=createWorker(); 

worker.job1(); 

worker.job2(); 

uscita:

task1 1 
task2 2 
+3

Se pubblichi immagini, assicurati che lo stesso contenuto sia disponibile come testo (che ovvi all'uso delle immagini). Non tutti possono vedere immagini allegate. – RobG

+6

Questo sembra essere un semplice caso di non comprensione delle chiusure, vedere [* MDN: Chiusure *] (https://developer.mozilla.org/en/docs/Web/JavaScript/Closures) e [* SO: Come fare JavaScript chiusure funzionano? *] (http://stackoverflow.com/questions/111102/how-do-javascript-closures-work?rq=1). – RobG

risposta

12

Basta notare che la variabile e le due funzioni anonime sono avvolti all'interno della stessa funzione (chiamiamola una funzione genitore). Quindi l'ambito di questa variabile è disponibile all'interno di questa funzione genitore.

Così ora questa variabile agisce come una variabile globale per queste due funzioni interne Ma l'ambito è limitato alla funzione genitore. Entrambe le funzioni interne condividono la stessa variabile .. Cambiare il valore della variabile in una funzione avrà effetto anche in altre funzioni.

Quindi prendere la logica nel post Diciamo che eseguiamo task1 e task2 uno dopo l'altro . La variabile è inizialmente impostata su 0. Quindi nel task1 è incrementata di uno. Il che rende il valore della variabile 1 (0 + 1). Ora nel compito due è anche aumentato di uno, rendendo il suo valore 2 (1 + 1).

Questo concetto di ambito è denominato chiusura in JavaScript.

9

Si chiama chiusura in JavaScript.

L'ambito di una chiusura in JavaScript è lessicale, il che significa che tutto ciò che è contenuto all'interno della funzione di chiusura appartiene, ha accesso a qualsiasi variabile che è in essa

Fondamentalmente createWorker è un campo di applicazione e dal compito 1 e il task 2 sono dichiarati all'interno di createWorker che hanno accesso a tutte le variabili dichiarate nell'ambito di createWorkers.

Ma createWorker non hanno accesso a tutte le variabili dichiarate all'interno task 1 e 2. compito

+2

Q: "C'è un nome per quello che è?". A: "Questo in javascript è chiamato chiusura". Nuff ha detto +1 –

0

task 2 non saprebbe su variabili create all'interno di funzione 1, funzione 1 e 2 compito lo so workCount.

2

Sì, le funzioni sono a conoscenza di tutto ciò che è compreso, compreso l'un l'altro.

Ci sono due parti alla tua domanda.

La seconda parte è facile rispondere prima: tutte le variabili e le funzioni in un ambito sono "hoisted", che consente di utilizzare una variabile prima di dichiarare che:

x = 5; 
var x; 
console.log(x); // Gives 5 

Torna alla prima parte del tuo domanda: in termini di ambito, non mi dilungherò troppo su di esso poiché è un argomento ampiamente trattato su questo e altri siti. w3schools has a good guide on this.

Fondamentalmente, si riduce all'ambito globale e locale. portata globale funziona come si potrebbe immaginare, con la variabile (o funzione) di essere disponibile a livello globale:

var x = 10; 
function foo() { 
    console.log('Global scope! ' + x); 
} 

ambito locale è, in fondo, per tutto ciò all'interno di una chiusura (un argomento ben oltre questa domanda), quali funzioni sono:

function foo() { 
    bar(); // This will work, since foo and bar share scope 
    foobar(); // This will not work: foobar is only in scope within bar 
} 

function bar() { 
    function foobar() { 
    console.log('foobar'); 
    }; 

    console.log('bar'); 
    foobar(); // This will work, since foobar is defined within bar's local scope 
} 

Le cose diventano un po 'più complicato con var dichiarazioni. Questo è stato notevolmente semplificato dalla dichiarazione ES6 let. Read more.

E a proposito, mentre le tue funzioni sono anonime, non lo sono davvero da quando stai salvando dei riferimenti ad esse. Funzionalmente, i due esempi di seguito sono perfettamente equivalenti:

// These give the exact same result 
function foo() {} 
var foo = function() {} 

// You can use either by calling 
foo(); 
1

JavaScript ha alcune regole interessanti per l'ambito delle variabili. Ecco una rapida panoramica:

x = 0; // Global, as no "var" keyword preceeds it. Btw: var is optional! 
var x = 0; // This is scoped to it's parent fn. Child fn's can use it. 
let x = 0; // This is similar to var, but has a special use case. (See below.) 

Come bonus aggiuntivo, questa riga di codice successiva sembra che sia una dichiarazione di variabile, ma non lo è. Definisce una costante. Fa parte della specifica EcmaScript 2015, AKA ES6. Ecco what's new in ES6.

const x = 0; // This is a constant (locked variable) and can't be changed. 

Mentre entrambi var & let sono accessibili dalla loro funzione immediata & funzioni loro figli, qui è dove sono diversi: Il let parola chiave può permettere a qualcuno di fare le variabili duplicati con lo stesso nome, sia dall'interno della le funzioni figlio genitore &! Semplicemente rende JS estraneo!

Dal workCount è definito all'interno della funzione genitore createWorker con la parola chiave "var", allora i task1 & task2 funzioni possono cambiare il suo valore, in quanto sono le funzioni bambini.

Controlla le specifiche MDN su come funzionano le parole chiave var & let.

Quindi le risposte ad alcune delle vostre domande sono:

  1. No, è nel genitore stesso "createWorker" ambito delle funzioni.
  2. Sconosciuto perché non scrivo codice ObjectiveC. Qualcun altro può rispondere a quello.
  3. Sì & No: Sì, perché può indicare che task1 è una funzione, ma No, perché il codice nel blocco funzione di task2 non può vedere all'interno del blocco funzione di task1.
2

Questo codice illustra come funziona.

<!DOCTYPE html> 
<html xmlns="http://www.w3.org/1999/xhtml"> 
<head> 
    <title>Closure JS</title> 
    <script type="text/javascript"> 
     var createWorker = function() { 
      var workCount = 0; 
      var task1 = function() { 
       var t = t || 0; 
       workCount += 1; 
       console.log("task1: " + workCount); 
       console.log("task1 t: " + (t++)); 
      } 
      var task2 = function() { 
       var t = t || 0; 
       workCount += 1; 
       console.log("task2: " + workCount); 
       console.log("task2 t: " + (t++)); 
      } 
      return { 
       job1: task1, 
       job2: task2 
      }; 
     } 
     var app = new createWorker(); 
    </script> 
</head> 
<body> 
<div> 
    <input type="button" value="task1" onclick="app.job1()" /> 
    <input type="button" value="task2" onclick="app.job2()" /> 
</div> 
</body> 
</html> 

uscita della console dopo alcuni clic sui pulsanti:

task1: 1 
task1 t: 0 
task1: 2 
task1 t: 0 
task2: 3 
task2 t: 0 
task2: 4 
task2 t: 0 

E 'facile vedere che task1 e Task2 conoscere la loro portata genitore e non sanno nulla gli uni degli altri e sulla loro esecuzione precedente.
In questo modo la palla rimbalza.

2

Puoi scrivere il tuo codice come in seguito e javascript lo interpreterà allo stesso modo.

var createWorker = function(){ 
    var workCount, task1, task2; 

    workCount = 0; 

    task1 = function(){ 
    workCount += 1; 
    console.log("task1" , workCount); 
    }; 

    task2 = function(){ 
    workCount += 1; 
    console.log("task2" , workCount); 
    }; 

    return { 
    job1: task1, 
    job2:task2 
    } 
}; 

Quello che succede qui è che le variabili sono definite nella parte superiore del blocco funzione che lo racchiude. Non importa in quale ordine sono definiti. Quindi, non solo task2 sa di task1, task1 sa anche di task2. Tuttavia, l'ordine degli incarichi è importante. Si consideri il codice:

function foo1() { 
 
    console.log("foo1: " + a); 
 
    var a = "Hello"; 
 
} 
 

 
function foo2() { 
 
    var a = "Hello"; 
 
    console.log("foo2: " + a); 
 
} 
 

 
function foo3() { 
 
    console.log("foo3: " + a); 
 
    let a = "Hello"; 
 
} 
 

 
function foo4() { 
 
    console.log("foo4: " + b); 
 
} 
 
var b = 5; 
 

 
foo1(); // undefined 
 
foo2(); // Hello 
 

 
try { 
 
    foo3(); // Throws ReferenceError 
 
} catch (e) { 
 
    console.log("foo3: " + e.message); 
 
} 
 
foo4(); // 5
<script src="http://gh-canon.github.io/stack-snippet-console/console.min.js"></script>

  • Quando foo1 tenta di utilizzare a, è stato definito, ma non è stato assegnato.
  • foo3 utilizza let anziché var. let è più intuitivo per alcuni provenienti da altri linguaggi di programmazione. Ma fai attenzione poiché è la parte delle specifiche ES6 e non ancora ampiamente supportata.
  • foo4 funziona dal b è stato definito prima foo4 è stato definito . b è stato assegnato prima dell'invocazione di foo4.
Problemi correlati