I have been programming in JavaScript for a few months mostly using jQuery. I understand closures and I have used them, however, I still can’t understand what is the difference between function level scope and block level scope in other languages such as C#. I have been trying to teach myself with no result on that subject. Could somebody explain me with some simple examples?
Prior to ES6 (the current version of JavaScript), JavaScript had only function level scope. That is, the following:
function foo() {
console.log('before block: ' + bar); // prints 'undefined'
if(true) {
var bar = 1;
console.log('inside block: ' + bar); // prints 1
}
console.log('outisde block: ' + bar); // prints 1
}
Is exactly equivalent to:
function foo() {
var bar;
console.log('before block: ' + bar); // prints 'undefined'
if(true) {
bar = 1;
console.log('inside block: ' + bar); // prints 1
}
console.log('outisde block: ' + bar); // prints 1
}
(As a matter of fact, what I've just shown is called "hoisting", which is exactly what JavaScript does: all variable declarations are hoisted to the top of the function; assignments are left where they are.)
In contrast, languages like C# have block level scope. This would result in a compile error:
public void Foo() {
if(true) {
var foo = 1;
Console.WriteLine("inside block: " + foo);
}
Console.WriteLine("outside block: " + foo); // WILL NOT COMPILE
}
But you can have this:
public void Foo() {
var foo = 1;
if(true) {
foo = 2;
Console.WriteLine("inside block: " + foo); // prints 2
}
Console.WriteLine("outside block: " + foo); // prints 2
}
function scopeTest() {
/* consider this simple for loop
to be the "block" that we were
talking about earlier
*/
for (var i = 0; i <= 5; i++)
{
var inFor = i;
}
alert(inFor); // what happens here?
}
// call the function defined above
scopeTest( );
In the code above, we have a variable called inFor that was declared in a for loop. We then try to access the inFor variable outside the for loop in the alert statement.
If the code above does not alert anything then we know it's because Javascript uses block scope. In a block scoped language, the variable inFor will not be visible outside of the for loop. This means that if Javascript is a block scoped language, then the call to "alert(inFor);" will not recognize the inFor variable, and nothing will be output to an alert box.
But, the code above actually outputs a "5", which means that the inFor variable does exist outside of the for loop, which must mean that Javascript does NOT have block scope. And there is our answer - Javascript does not have block scope.
function scopeTest() {
var x = 2;
//this is always true:
if(x == 2)
{
var y = 15;
for (var i = 0; i <= 5; i++)
{
var inFor = i;
}
}
console.log(y); // y is defined, prints 15
console.log(i); // i is defined, prints 6
console.log(inFor); // inFor is defined, prints 5
}
You can see in the code above that the variables y, i, and inFor are declared either inside the if statement or inside the for loop. But, even though those variables are declared inside those separate "blocks", they are still visible to the rest of the function. This is because all of those variables are declared inside one function - which is what function scope is all about.
Block scope vs Function scope
So, if Javascript doesn't use block scope, then what kind of scope does it use?
Well, Javascript uses something called function scope.
Basically, the difference between function scope and block scope is that in a language that uses function scope, any variables declared within a function are visible anywhere within that same function. But with block scope, the visibility of variables is confined to any given block (whether it's an if statement, where/for loop, etc) enclosed by curly braces.
http://www.programmerinterview.com/index.php/javascript/javascript-block-scope/
http://www.programmerinterview.com/index.php/javascript/javascript-function-scope/
{
here you can't access both a and b
var a=1
here you can access only a
{
here you can access only a
var b=3
here you can access both a and b
{
here you can access both a and b
}
here too you can access both a and b
}
here you can access only a
}
here you can't access both a and b
To continue with #Ethan Brown's answer, if we use let or const instead of var, we get "referenceError" because let and const are block-scoped.
function foo() {
console.log('before block: ' + bar); // ReferenceError: bar is not defined
if (true) {
let bar = 1; // bar is not let and not var
console.log('inside block: ' + bar); // prints 1
}
console.log('outisde block: ' + bar); // ReferenceError: bar is not defined
}
Just wanted to make the answer complete.
Related
I am reading something on Variable Hoisting that I am not able understand exactly how to learn around it. I read W3C schools for the explanation. But, based on the sample code, I could not make what is hoisting.
code 1 [This is the code from w3c school]
<!DOCTYPE html>
<html>
<body>
<p id="demo"></p>
<script>
var x = 5; // Initialize x
var y; // Declare y
elem = document.getElementById("demo"); // Find an element
elem.innerHTML = x + " " + y; // Display x and y
y = 7; // Assign 7 to y
</script>
</body>
</html>
But the above code still displays 'undefined' for the variable y.
If I change the code as follows then it works fine. But, this below code is usual and not the different one to understand 'hoisting'
<script>
var x = 5; // Initialize x
var y;
y = 7;
elem = document.getElementById("demo"); // Find an element
elem.innerHTML = x + " " + y; // Display x and y
</script>
Any help on this to understand 'Variable hoisting'?
(Note: I've added a brief discussion of ES2015's let and const at the end of this answer.)
Fundamentally, what variable hoisting means is that no matter where you see var in any given scope, it's as though it were at the very beginning of the scope. So these are all identical:
function foo() {
var a = 42;
}
function foo() {
var a;
a = 42;
}
function foo() {
a = 42;
var a;
}
function foo() {
var a;
a = 42;
var a;
}
They're processed by the JavaScript engine as though they were:
function foo() {
var a;
a = 42;
}
Here's an example actually using variable hoisting, and also giving an example of what I call The Horror of Implicit Globals (that's a post on my anemic little blog):
function foo() {
a = 42;
b = 67;
console.log(a); // 42
console.log(b); // 67
var a;
}
foo();
console.log(typeof a); // undefined
console.log(typeof b); // number?!
console.log(b); // 67?!
Why does b exist outside of foo? Because inside foo, these two lines do very different things:
a = 42;
b = 67;
The first line sets the local variable a, because we declared it. Yes, we declared it later, but we declared it.
The second line creates an implicit global variable b, because we never declared b anywhere in foo.
More (on my blog):
Poor, misunderstood var
ES2015 (aka "ES6") introduced let and const. They're handled slightly differently from var:
They have block scope rather than function or global scope.
The declaration is hoisted to the top of the block, but they don't get any default value at that point; they get initialized (with undefined or the value you provide) only when the declaration is reached in the step-by-step execution of the code.
Demonstrating point #1 (block scope):
function foo() {
{
let a = 1;
console.log(a); // 1
}
console.log(a); // ReferenceError: a is not defined
}
foo();
Demonstrating point #2: This would work with var, it doesn't work with let:
function foo() {
a = 42; // ReferenceError: a is not defined
let a;
}
foo();
The time between when the identifier is reserved (declaration) and when you can use it (initialization) is called the Temporal Dead Zone within which you can't use the variable.
Javascript Engine will execute code in two phases
Pre processing phase(or instantiation phase).
Execution Phase.
Pre processing phase(or instantiation phase)-
In Preprocessing phase, the script is scanned completely for all the declarations.
var - is the identifier to declare a variable.
So when var identifier is encountered, variable will be declared in the global scope.
The value of the variable is - undefined
Execution Phase-
In Execution Phase, the script is executed line by line. All the initializations will be done in this phase.
Example-1
For Below code snippet,
In Pre processing phase, Javascript engine will scan through the code line by line, when it encounters line "var a", it will declare variable a in the global scope.
In the Execution phase, at line "a=10", variable 'a' will be initialized with value 10. when it encounters console statements, value 10 will be printed.
a=10;
console.log(a); // 10
var a;
console.log(a); // 10
This is how variable hoisting works.
In Javascript, var x = 21; is broken into 2 parts: var x; and x = 21;.
The var x; part is always hoisted to the beginning of the enclosing function. The x = 21; part is left in its original place.
The same thing happens with function () {} declarations - this would be hoisted to the top of the enclosing function scope:
function pie () {
return 21;
}
just like the var.
A variable can be used before it is declared
JavaScript Initializations are Not Hoisted
Function Hoisting
As previously mentioned, function declarations are also hoisted. However, functions that are assigned to variables are not hoisted.
See below example
Function Declaration Overrides Variable Declaration When Hoisted
When hoisting is occurring to the variable which declaring with keyword var inside an if block scope, does the ( var x;) hoisting to the top of current if block? or to the top of the global scope in this case?
Suppose we wrote the following piece of code directly in the global scope
if (true) {
some code;
var x = 1;
}
When using var (or omitting the definition key at all e.g just x = 1) as per your example, it would be hoisted to the closest scope which in your example would be the global scope (window).
If it would be wrapped in a function, then the function would be the closest scope.
function a() {
if(true){
var x=1;
}
console.log(x) // 1
console.log(window.x) // undefined
}
a()
console.log(x) // Throws error (x is not defined)
If you want the variable to be completely block scope, then you would need to use let or const.
if(true){
const x=1;
}
console.log(x) // Throws error (x is not defined)
Absolutely.
// hoisted
if( true){
x = 1;
console.log( x, typeof x );
var x;
}
// doesn't do what you thought it would, the assignment doesn't move, just the declaration.
if( true){
console.log( y, typeof y );
var y = 1;
}
The short answer is that yes, the declaration is hoisted but not to the top of the block. It is hoisted to the global level. But where it is assigned does not change.
This is tricky to test because an undeclared variable and a declared variable will both produce a typeof somevar of undefined.
var myVar;
console.log('typeof myVar');
console.log(typeof myVar);
console.log('typeof notDeclared');
console.log(typeof notDeclared);
However, if you try to use an defined variable it will throw an error, so we can use that to find out what has been declared and what has not.
var myVar;
try {
myVar;
console.log('myVar was declared');
} catch(error) {
console.log(error);
}
try {
notDeclared;
console.log('notDeclared was declared');
} catch(error) {
// Error is unfortunately captured by the sandbox,
// so we just get an empty object. :-(
console.log(error);
}
Putting it all together, we can test your code to see what happens.
// Does myVar exist in global scope?
try {
myVar;
console.log('myVar exists in global scope.');
} catch (error) {
console.log('myVar does NOT exist in global scope.');
}
if (true) {
console.log('myVar value before assignment.', myVar);
var myVar = 1;
console.log('myVar value after assignment.', myVar);
}
I have come across the following code snippet:
(function() {
bar = 5;
var bar = 10;
console.log("value of bar inside the self invoking function = " + bar);
})();
console.log("value of bar out of function scope " + bar);
When I execute the above code, I get:
"Uncaught ReferenceError"
for the second console
This is due to "variable hoisting". Variables are declared when the javascript is parsed so when it comes to execution the engine already knows all variables that will be available within a scope and can thus assign to them. After the hoisting process is done your function actually looks like this.
(function() {
var bar;
bar = 5;
bar = 10;
console.log("value of bar inside the self invoking function = " + bar);
})();
console.log("value of bar out of function scope " + bar);
You can read more about it on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/var#var_hoisting
All variables declared with var are hoisted to the top of the function in which they are declared, So if the variable is defined inside the function it will be moved to the top of the function and if it is defined in global scope, it will be moved to the top of the global context.
(function() {
bar = 5;
var bar = 10;
console.log("value of bar inside the self invoking function = " + bar);
})();
Here, in your case you have defined variable inside the anonymous function, so it will be moved to the top of this function and after hoisting it will be something like
(function() {
var bar;
bar = 5;
bar = 10;
//...rest of the code
})();
But this variable is available only in that function's local scope, it won't be available in the global scope. That's why you are getting Uncaught ReferenceError when you are trying to access it in global scope.
Here is the nice article explaining variable scope and variable hoisting in JavaScript. http://javascriptissexy.com/javascript-variable-scope-and-hoisting-explained/
One thing to note is that only the variables declared using var are hoisted. If you are using ES6 let keyword to declare a variable then it will not be hoisted. So
(function() {
bar = 5;
let bar = 10;
console.log("value of bar inside the self invoking function = " + bar);
})();
won't work and you'll get the same error. You can read more about it here
This question already has answers here:
Javascript function scoping and hoisting
(18 answers)
Closed 6 years ago.
Hi I am trying to understand the JavaScript fundamentals, and stuck in one condition.
var foo = 1;
function bar(){
foo = 10;
return;
function foo(){}
}
bar();
alert(foo);
Here alert(foo), will give me 1, and I know after return statement, function foo() will not execute. But now if change the code:
var foo = 1;
function bar(){
foo = 10;
return;
}
bar();
alert(foo);
In bar function, If I will remove function foo(). then alert(foo) will give me 10
Please help, if someone can explain me why?
This is called Javascript hoisting
I will try to explain it in details.. This is what we have
var foo = 1;
function bar(){
foo = 10;
return;
function foo(){}
}
bar();
alert(foo);
The interpreter will rewrite this as
var foo = 1;
function bar(){
function foo(){} // this is also equal to var foo = function(){};
foo = 10;
return;
}
bar();
alert(foo);
So now explaining you the hoisted code.
var foo = 1; // global variable;
function bar(){
var foo = function(){}; // foo is local variable of type function
foo = 10; // foo is changed to hold a number
return;
}
bar();
alert(foo); // you alert global variable.
As you can see if the code function foo(){} is present it is treated as a local variable within the bar() scope and any change to the foo is treated as a local variable change..
When you have function foo(){} in your bar() you are not even touching the global variable.. hence alerts 1.
When you don't have function foo(){} you are touching the global variable and hence alerts 10.
Now I hope you understand the output..
I know after return statement ,function foo() will not execute.
That's not true.
Function declarations are hoisted.
function foo(){} creates a local variable called foo (assigning the new function to it) and then foo = 10 overwrites it. You never test the value of that foo variable though.
In bar function , If I will remove function foo(). then alert(foo) will give me 10
You no longer have a local variable called foo so you are overwriting the global variable with the same name.
Compare:
(function() {
console.log("Version 1");
var foo = 1;
function bar() {
console.log("At top of bar, foo is " + foo);
foo = 10;
console.log("After assignment in bar, foo is " + foo);
return;
function foo() {}
}
bar();
console.log("Global foo is " + foo);
}());
(function() {
console.log("Version 2");
var foo = 1;
function bar() {
console.log("At top of bar, foo is " + foo);
foo = 10;
console.log("After assignment in bar, foo is " + foo);
return;
}
bar();
console.log("Global foo is " + foo);
}());
When you write this function :
function bar(){
foo = 10;
return;
function foo(){}
}
The javascript read this :
function bar(){
function foo(){}
foo = 10;
return;
}
The function foo is created into your local function bar. And when you write foo = 10,You overwrite the function foo in the local scope and not the global variable.
So your alert give you 1 because you never update the global variabe.
The problems here are hoisting and closure .
The declaration function foo(){} is hoisted, meaning in this case, even though it is written at the end of the function, it will be available everywhere within the scope, including before it's definition.
if function foo(){} IS NOT present, the statement foo = 10; overwrites the foo defined in the global scope. Therefore the global foo === 10.
If function foo(){} IS present, the statement foo = 10; just overwrites the function foo in the local scope, the global foo won't get touched hence global foo === 1
var foo = 1;
function bar(){
console.log(typeof foo) // function
return;
function foo() {}
}
bar();
alert(foo);
Opposed to:
var foo = 1;
function bar(){
console.log(typeof foo) // number
return;
// function foo() {}
}
bar();
alert(foo);
So basically what is happening is as if you have declared var foo = 10
because function declaration in javascript are hoisted up top
complier sees your code as follows .
var foo = 1;
function bar(){
var foo;
foo = 10;
return;
function foo(){}
}
bar();
alert(foo);
so in fact foo = 10 never overwrites the global foo;
it is kept local to the function .
so alert will get passed the global one .
In addition to my previous answer in the same thread I am
adding another answer to put in more details about the Hoisting
feature in JavaScript as the previous answer is already accepted by the OP for its content.
First lets get comfortable with what scoping is
Scoping in JavaScript
One of the sources of most confusion for JavaScript beginners is scoping. Actually, it’s not just beginners. I’ve met a lot of experienced JavaScript programmers who don’t fully understand scoping. The reason scoping is so confusing in JavaScript is because it looks like a C-family language. Consider the following C program:
#include <stdio.h>
int main() {
int x = 1;
printf("%d, ", x); // 1
if (1) {
int x = 2;
printf("%d, ", x); // 2
}
printf("%d\n", x); // 1
}
The output from this program will be 1, 2, 1. This is because C, and the rest of the C family, has block-level scope. When control enters a block, such as the if statement, new variables can be declared within that scope, without affecting the outer scope. This is not the case in JavaScript. Try the following in Firebug:
var x = 1;
console.log(x); // 1
if (true) {
var x = 2;
console.log(x); // 2
}
console.log(x); // 2
In this case, Firebug will show 1, 2, 2. This is because JavaScript has function-level scope. This is radically different from the C family. Blocks, such as if statements, do not create a new scope. Only functions create a new scope.
To a lot of programmers who are used to languages like C, C++, C#, or Java, this is unexpected and unwelcome. Luckily, because of the flexibility of JavaScript functions, there is a workaround. If you must create temporary scopes within a function, do the following:
function foo() {
var x = 1;
if (x) {
(function () {
var x = 2;
// some other code
}());
}
// x is still 1.
}
This method is actually quite flexible, and can be used anywhere you need a temporary scope, not just within block statements. However, I strongly recommend that you take the time to really understand and appreciate JavaScript scoping. It’s quite powerful, and one of my favorite features of the language. If you understand scoping, hoisting will make a lot more sense to you.
Declarations, Names, and Hoisting
In JavaScript, a name enters a scope in one of four basic ways:
Language-defined: All scopes are, by default, given the names this and arguments.
Formal parameters: Functions can have named formal parameters, which are scoped to the body of that function.
Function declarations: These are of the form function foo() {}.
Variable declarations: These take the form var foo;.
Function declarations and variable declarations are always moved (“hoisted”) invisibly to the top of their containing scope by the JavaScript interpreter.
Function parameters and language-defined names are, obviously, already there. This means that code like this:
Ex:
function foo() {
bar();
var x = 1;
}
is actually interpreted like this:
function foo() {
var x;
bar();
x = 1;
}
It turns out that it doesn’t matter whether the line that contains the declaration would ever be executed. The following two functions are equivalent:
function foo() {
if (false) {
var x = 1;
}
return;
var y = 1;
}
function foo() {
var x, y;
if (false) {
x = 1;
}
return;
y = 1;
}
Notice that the assignment portion of the declarations were not hoisted. Only the name is hoisted. This is not the case with function declarations, where the entire function body will be hoisted as well. But remember that there are two normal ways to declare functions. Consider the following JavaScript:
function test() {
foo(); // TypeError "foo is not a function"
bar(); // "this will run!"
var foo = function () { // function expression assigned to local variable 'foo'
alert("this won't run!");
}
function bar() { // function declaration, given the name 'bar'
alert("this will run!");
}
}
test();
In this case, only the function declaration has its body hoisted to the top. The name ‘foo’ is hoisted, but the body is left behind, to be assigned during execution.
That covers the basics of hoisting. The complete 100% credit of this answer goes to ben cherry. I didnt want to post this link in my answer because the links might break and I found this completely informative and a must read for any javascript developer.
I'm coming from an Actionscript background and (very late to the party) I am trying to learn JavaScript. I am going through this AngularJS - Video Tutorial For Beginners on YouTube (it's pretty good) and saw something really basic that I don't understand.
At line 5 the var workcount is defined. Then two anonymous functions are defined and returned in an object. The functions reference workcount but isn't workcount in a different scope? Is this like blocks in Objective-C where local vars remain accessible within the block. Is there a name for what this is?
Or if a function "knows about" vars previously defined in its scope, would the function task2 "know about" task1?
It bugs me that I can't make sense of this.
Update: Thanks for all the replies. I get it now – and while I have seen the term "closures" before, I never understood it (it seems a not very descriptive term. In reading up, I saw the term "stack-frames" and then the light bulb lit up: 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();
Output:
task1 1
task2 2
Just note that the variable and the two anonymous functions are wrapped inside the same function (let's call it a parent function). So the scope of this variable is available within this parent function.
So now this variable acts as a global variable for these two inner functions But the scope is limited to the parent function. Both the inner functions share the same variable.. Changing the value of the variable in one function will have effect in other function too..
So taking the logic in the post Let's say we execute task1 and task2 one after the other. The variable is initially set to 0. Then in your task1 it's incremented by one. Which makes the variable value 1 (0 + 1). Now in task two also its increased by one, making its value 2 (1 + 1).
This scope concept is called as closure in JavaScript.
This is called a closure in JavaScript.
The scope of a closure in JavaScript is lexical, which means that everything that is contained within the function the closure belongs to, has access to any variable that is in it
Basically createWorker is a scope and since task 1 and task 2 are declared inside createWorker they have access to all the variables declared in createWorkers scope.
But createWorker does not have access to any variables declared inside task 1 and task 2.
Yes, functions are aware of everything in their scope, including each other.
There are two parts to your question.
The second part is easy to answer first: all variables and functions in a scope are "hoisted," allowing you to use a variable before you declare it:
x = 5;
var x;
console.log(x); // Gives 5
Back to the first part of your question: in terms of scope, I won't expand too much on it since it is a widely covered topic on this and other sites. w3schools has a good guide on this.
Basically, it boils down to global and local scope. Global scope works as you might imagine, with the variable (or function) being available globally:
var x = 10;
function foo() {
console.log('Global scope! ' + x);
}
Local scope is, basically, for everything within a closure (a topic well beyond this question), which functions are:
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
}
Things get a little more complicated with var declarations. This is being greatly simplified by the ES6 let declaration. Read more.
And by the way, while your functions are anonymous, they aren't really since you are saving references to them. Functionally, the two examples below are perfectly equivalent:
// These give the exact same result
function foo() {}
var foo = function() {}
// You can use either by calling
foo();
This code illustrates how it works.
<!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>
Console output after several clicks on buttons:
task1: 1
task1 t: 0
task1: 2
task1 t: 0
task2: 3
task2 t: 0
task2: 4
task2 t: 0
It easy to see that task1 and task2 know about their parent scope and know nothing about each other and about their previous execution.
This way ball bounces.
You can write write your code as in below and javascript will interpret it the same.
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
}
};
What happens here is, variables are defined at the top of the enclosing function block. No matter in what order they are defined. So not only task2 knows about task1, task1 also knows about task2. However order of assignments in important. Consider the code:
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>
When foo1 tries to use a, it was defined but it was not assigned.
foo3 uses let instead of var. let is more intuitive for some
coming from other programming languages. But be careful as it is part
of ES6 specification and not widely supported yet.
foo4 works since b was defined before foo4 was
defined. b was assigned before foo4 was invoked.
JavaScript has some interesting variable scoping rules. Here is a quick overview:
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.)
As an added bonus, this next line of code looks like it's a variable declaration, but it's not. It defines a constant. It's part of the EcmaScript 2015 spec, AKA ES6. Here's what's new in ES6.
const x = 0; // This is a constant (locked variable) and can't be changed.
While both var & let are accessible by their immediate function & their children functions, here is where they're different: The let keyword can allow someone to make duplicates variables with the same name, from both inside of the parent & child functions! It just makes JS stranger!
Since workCount is defined inside of the parent createWorker function with the "var" keyword, then the task1 & task2 functions can change it's value, as they are children functions.
Check out the MDN specs on how the var & let keywords work.
So the answers to some of your questions are:
No, it's in the same parent "createWorker" function scope.
Unknown as I don't write ObjectiveC code. Someone else can answer that one.
Yes & No: Yes, because it can tell that task1 is a function, but No, because the code in task2's function block can't see inside of task1's function block.
task 2 would not know about variables created within task 1, task 1 and task 2 do know about workCount.