Scope in JavaScript
Tags: javascript, codenewbie, es6
Published: 2020-07-17 16:49:10

## Scope

This one is definitely important to having your code run properly or as expected. If you're accessing a variable that's in a separate closure than the one you're trying to access from you won't get the result you need.

## What is Scope?

In my own simple words, **scope** can be thought of as a 'field of view'.

#### Pirate Ship Analogy

Think of an old Pirate ship. HOLD ON - just stay with me.

Let's say we have 3 Pirates named **Jack**, **Anne** and **Bill**.

**Anne** positioned on the Main Deck has a specific field of view. **Jack** in the brig below looking through the open grate has his own view as well. **Bill** way up in the Crow's Nest looking out for other ships has a different field of view.

Now we could say that **Jack** in the brig below has the most limited view. 

**Anne** on the deck can see what **Jack** sees and even more.

Then **Bill** in the crow's nest can see all of what **Anne** and **Jack** can see.

Lastly, _they all can see_ the open sea - which for our purposes will be the **global scope**.

---

**Field of view**: _Global_ > Bill > Anne > Jack

#### Pirate Ship Scenario #1

Let's say the Captain is on the Upper Deck - which is above the Main Deck and below the Crow's Nest.

What if **Jack** wanted to know where the Captain of the ship was? He most certainly can't see him inside the brig - so he asks **Anne**.

**Anne** on the Main Deck can't really see the Upper Deck from her field of view. So she's not sure either.

Now they ask **Bill** all the way up in the Crow's Nest can see the Captain on the Upper Deck so he passes that information down to **Anne** and down to **Jack**.

Must be some nice Pirates to even pay attention to **Jack** in the brig... Anyway, lets see what that could look like in code.

```js
function Bill() {
  let CaptainLocation = 'Upper Deck'

  function Anne() {
    function Jack() {
      console.log(CaptainLocation)
    }
    Jack()
  }
  Anne()
}
Bill()
```

`Jack()` is trying to log the Captain's Location but it's not within his scope or, in other words, his `{}`. It's not it `Anne()` either so that one `console.log()` reaches all the way up to `Bill()` to find the value.

#### Pirate Ship Scenario #2

Now if any one of our friendly Pirates wanted to know if it's storming. They could easily determine that looking to the open sea or the **global scope**.

```js
let isStorming = true
function Bill() {
  console.log(isStorming)
  function Anne() {
    console.log(isStorming)
    function Jack() {
      console.log(isStorming)
    }
    Jack()
  }
  Anne()
}
Bill()
```
The **global scope** gives access to its information to all things in our code because each line of our code is _enclosed_ inside it.

When we create closures, most commonly through declaring a function, we put a set of blinders on _whatever goes inside_ the `{}`.

Now let's return to a way more basic, less ridiculous set of examples.

## Some basic examples

Let's roll through a couple scenarios to see how these closures affect what our super complex variable `x` resolves to in each `console.log()`.

```js
  const x = 0
  console.log(x) // Global scope : x = 0

  function func1 () {
    const x = 5
    console.log(x) // func1() scope : x = 5
    func2()
  }

  function func2 () {
    const x = 8
    console.log(x) // func2() scope : x = 8
  }

  func1()
  /* output : 0
              5
              8
  */
```

This is because each `console.log(x)` has its own scope and as such will have a different value when accessed. 

---

If we modify that slightly to remove the `x` declaration from `func2()` then you'll see it goes to the **global scope** and finds `x` and therefore logs `0`. 

```js
  const x = 0
  console.log(x) // x = 0

  function func1 () {
    const x = 5
    console.log(x) // x = 5
    func2()
  }

  function func2 () {
    /* x no longer declared here! */
    console.log(x) // x = 0
  }
  func1()
  /* output : 0
              5
              0
  */
```
Why did `x` resolve to `0` instead of `5`? `func2()` called `func1()`, right?!

Even though `func2()` is called _inside_ of `func1()` it **is not ENCLOSED** by `func1()`. So `func2()` tries to find x in _its own scope first_, doesn't find it so it moves to its _enclosing scope_ which is the **global scope**.

---

Now if we move the declaration of `func2()` inside of `func1()` it will go like this:
  - Try to find `x` in local scope (or `func2()` scope basically)
    - `x` _not found_ -> move up in scope
  - Try to find `x` in the enclosing scope (or `func1()` scope)
    - `x` **found** -> `x = 5`

```js
  const x = 0
  console.log(x) // Global scope : x = 0

  function func1 () {
    const x = 5
    console.log(x) // func1() scope : x = 5

    function func2 () {
      console.log(x) // func2() scope : x = 5
    }
    
    func2()
  }
  func1()
  /* output : 0
              5
              5
  */
```
Lastly, if we were to remove the `x` declaration from `func2()` then no matter if `func1()` is declared _inside or outside_ of `func2()` we will see `x = 0` because both functions do not find `x` in their respective scopes and must eventually move to the global scope to find an `x` value.

---

This can most definitely be a point of confusion. I know it was for me and I had to double check all of these outputs! 

What I recommend, simply because it helped me become more familiar and ensure I'm getting the right value, is to do what you've seen in these examples.

`console.log()` the heck out of your values if something doesn't seem right _or_ just to be safe.

`console.log()` is your friend! So is **scope** but it's that one friend who can definitely get on your nerves sometimes.