1

I'm quite new to coding and am confused about the differences between a local scope with a function scope and block scope.

I understand that global scope is when a variable is declared outside of a function so it can be accessed anywhere. A function scope is when a variable can be accessed anywhere within the function and a block scope is when a variable can be accessed within a set of braces e.g. {let a = block scope},

However, I'm confused. What is a local scope? Is local scope the same thing as function scope?

Any help will be much appreciated

Bigboybob
  • 75
  • 2
  • 10
  • 3
    We were all beginners at one point. There are no stupid questions, and no apology is needed. –  Sep 04 '19 at 13:59
  • Possible duplicate of [What is the scope of variables in JavaScript?](https://stackoverflow.com/questions/500431/what-is-the-scope-of-variables-in-javascript) – Heretic Monkey Sep 04 '19 at 14:00

2 Answers2

7

"Local scope" is a catch-all term for any scope that isn't global, so it includes both function scope and block scope (and module scope).

It used to be that JavaScript had only function scope and global scope. As of ES2015, it also has block scope for let, const, and class declarations, as well as "module scope" (the top-level scope for a module) and for scope (details below).

Here's an example:

// Assume this code is not in a module and is at the top level

let a; // Global scope

function example() {
    let b; // function scope (a kind of local scope)

    for (let n = 0; n < 2; ++n) { // `n` is in local scope for the `for` (a kind of local scope)
        let c = n * 2; // block scope (a kind of local scope)
    }

    // This is a freestanding block, they don't *have* to be attached to anything
    {
        let d; // block scope (a kind of local scope)
    }
}

It would be just the same if that were in a module except that the let a wouldn't be at global scope, it would be at module scope.

It's probably worth calling out the scope containing a let declaration within a for loop initializer isn't quite the same as the scope attached to any block that the for has; the former is the parent scope of the latter, and sometimes a for doesn't have a block attached to it:

for (let n = 0; n < 0; ++n)
    console.log(n);

The scope of n above is non-obvious. It's scoped to the for loop, but in a very interesting way: A new n is created for each loop iteration. So for the first interation, there's an n whose value is 0. Then, a new n is created, gets a copy of the old n's value, and is then incremented; then that new n is used for the next loop iteration. This is handy for closures in loops.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • 1
    ahhh I see, so local scope includes both function scope and block scope. I thought it was something completely different. Thanks for clarifying! – Bigboybob Sep 04 '19 at 14:04
  • I just saw your edits, this explains it perfectly, thank you! – Bigboybob Sep 04 '19 at 14:36
1

It's a good question. Under most of circumstances, function scope is local scope.

However, consider the following code:

function foo(){
  const sum = 0
  someArray.forEach(function(item){
     var plusOne = item + 1
     sum = sum + 1
  })
}

This function contains an inner function (called a closure) that defines its own scope. While the inner function is being executed, plusOne is in the local scope. sum is not in the local scope, but it's not really in the "global" scope either; it's in the scope of its parent. (You'll see this described in Chrome Dev Tools as the "closure" scope.) Scopes are nested, so your inner function/closure can see and modify variables in the parent scope (sum in this case).

There's another possibility if you're using CommonJS/ES6 modules. This might be a file:

var foo = 1
export function bar() {
  return foo
}

You can write this (ES6) code to access bar:

import {bar} from "thefile"
console.log(bar())

You can't write this code:

import {foo} from "thefile"

foo looks "global"-ish, but it's really local to the module, and thus is in scope only for that module. It's not exported, so it isn't accessible outside that module.

(Aside: A "transpiler" will take JavaScript written for one platform/version and translate it to another. So, for example, it's common to transpile modern ES6 like I've written above to the lowest-common-denominator such as a web browser. Browsers don't generally support modules, so a transpiler will wrap the original module code in a function, thus converting "module scope" to "function scope".)

Craig Walker
  • 49,871
  • 54
  • 152
  • 212
  • Ahh I see, so if I'm understanding this correctly, foo looks like its declared with global scope but its actually module scope because only the function is exported and not the variable – Bigboybob Sep 04 '19 at 14:27
  • 1
    Sort of. Both `foo` and `bar` are *declared* with module scope. But because it has `export` in front of it, `bar` is also *exported* from the module, and so can escape the module scope. (`foo` cannot do this.) Neither are declared with global scope, so you can't just access them as-is. You have to explicitly import `bar`, and `foo` is just completely unaccessible. – Craig Walker Sep 04 '19 at 20:23
  • 1
    BTW: Don't worry *too* much about all this module stuff if you're just starting out with JavaScript. JS has had a messy history, with several competing attempts at modularization. My answer just shows one as an example; you'll see `require`/`module.exports` a lot too. These aren't specific to a conversation about "scope" except to show that "not all scope is function or global". – Craig Walker Sep 04 '19 at 20:27
  • 1
    Abit late but just saw these comments now, I think I understand what you mean, thanks for explaining this in more detail! – Bigboybob Sep 09 '19 at 23:12