What variables are stored in the heap/stack?

When you look at this problem, the first response is simple: the base types are kept on the stack and the reference types are kept on the heap ✌️✌️✌️, but is that all? Let’s take a closer look

JS data types

As we know, JS is a dynamic language, because there is no need to confirm the data type of variables before declaring them, so JS variables have no data type, and only values have data type. Variables can hold data of any type at any time.

There are eight data types for JS values:

  • Boolean:truefalse
  • Undefined: a default value for an unassigned variable or for a promoted variableundefined
  • Null: Only one valuenull
  • Number: Indicates the Number type
  • BigInt (ES10) : indicates greater than253-1The integer
  • String: indicates the character type
  • Symbol (ES6)
  • Object: Indicates the Object type

The first seven data types are called basic types, and the last object type is called a reference type

JS variable storage mechanism

JS memory space is divided into stack space, heap space and code space. The code space is used to store executable code.

Stack space

A stack is a linear structure In memory that stores local variables and function parameters, following the LIFO/Last In First Out principle. The stack occupies a continuous storage space in memory, and the stack and the stack are just Pointers moving up and down in memory.

The stack space of JS is what we call the call stack. It is used to store the execution context, including variable space and lexical environment. Var and function are stored in the variable environment, and variables declared by let and const are stored in the lexical environment.

var a = 1
function add(a) {
  var b = 2
  let c = 3
  return a + b + c
}

// Call the function
add(a)
Copy the code

This code simply creates an add function and then calls it.

Let’s take a step by step look at the process of executing a function call.

Before executing this code, the JavaScript engine creates a global execution context that contains all declared functions and variables:

As you can see from the figure, the global variable A and the function add in the code are stored in the variable environment.

When the execution context is ready, the global code is executed by first performing an assignment of a = 1,

After the assignment, the value of a changes from undefined to 1, and then the add function is executed. JavaScript determines that this is a function call, and then does the following:

  • First, pull out the add function code from the global execution context
  • Next, compile this code for the add function, create the execution context and executable code for the function, and push the execution context onto the stack

  • The code then executes, returns the result, and the execution context for add pops off the top of the stack, leaving only the global context on the call stack.

At this point, the entire function call execution is complete.

In other words, the variables in the stack will be automatically collected after the function call ends.

So, in general, the stack space is not set too large, whereas basic types occupy a fixed amount of memory, so their values are stored in the stack space, which we access by value. They also do not need to be managed manually; they are created when a function is called and disappear when the call is over.

The heap

The heap data structure is a tree-like structure. It accesses data in much the same way as bookshelves and books. We just need to know the name of the book and we can take out the book, we don’t need to take out the book on top.

Data that can’t be stored on the stack like objects are stored on the heap, and the stack just keeps the address of the object in the heap, which is a reference to the object, and for this, we call it access by reference.

Here’s an example to help you understand:

var a = 1
function foo() {
  var b = 2
  var c = { name: 'an' } // Reference type
}

// Call the function
foo()
Copy the code

As a result, the heap space is usually large enough to hold a lot of large data, but the downside is that it takes time to allocate and reclaim memory

JS variable storage mechanism and closures

To sum up the above, JS memory space is divided into stack space, heap space, code space. The code space is used to store executable code

  • Basic types: Stored in stack memory because these types each occupy a fixed amount of space in memory and are accessed by value.
  • Reference types: stored in heap memory, because the size of such values is not fixed, so they cannot be stored in stack memory, but the size of memory address is fixed, so stored in heap memory, in stack memory is stored only the access address of the object. When querying variables of reference types, the memory address is read from the stack and then the value in the heap is found from the address. For this, we call it access by reference.

closure

So closures? Given that basic variables are stored on the stack, and that data on the stack is automatically destroyed after the function is executed, why can closures refer to variables in the function after the function is executed?

function foo() {
  let num = 1 // Create local variable num and local function bar
  function bar() { // bar() is an internal function method, which is a closure
      num++
      console.log(num) // Use variables declared by an external function. Internal functions can access variables from an external function
  }
  return bar // Bar is returned by the external function as a return value, which returns a closure
}

/ / test
let test = foo()
test() / / 2
test() / / 3
Copy the code

After executing the function foo, the variable num in foo should be ejected for destruction. Why should the use of nan continue?

This indicates that the variables in the closure are not stored on the stack, but on the heap:

console.dir(test)
Copy the code

So when the JS engine determines that it is currently a closure, it creates a “closure(foo)” object in the heap space (which is an internal object that is not accessible to JS) to hold the num variable

Note that even if the function is not returned (the closure is not returned) :

function foo() {
  let num = 1 // Create local variable num and local function bar
  function bar() { // bar() is an internal function method, which is a closure
      num++ 
      console.log(num) // Use variables declared by an external function. Internal functions can access variables from an external function
  }
  bar() / / 2
  bar() / / 3
  console.dir(bar)
}

foo()
Copy the code

conclusion

JS is a dynamic language, because there is no need to confirm its data type before declaring a variable, so THE variable of JS has no data type, only the value has data type, variables can hold any type of data at any time, JS value has 8 data types, they can be divided into two categories — basic type and reference type. The basic type of data is stored in the stack, and the reference type of data is stored in the heap. The data in the heap is associated by reference and variables.

With the exception of closures, variable values in JS closures are not held in stack memory, but in heap memory.

Three minutes a day, advance one