Note: This article is chapter 4 of the Relearning JavaScript advanced Programming series on Variables, scopes, and Memory Issues. About “relearning JavaScript advanced programming” is a review of the basics of JS learning.

1. Values for base and reference types

The ES variable contains values of two different data types: base type values and reference type values.

When assigning a value to a variable, the parser must determine whether the value is of a primitive or reference type

1.1 Basic Type Values

This refers to simple data that is stored in stack memory, i.e. the value is kept entirely in one location in memory. The following five basic values occupy a fixed amount of memory, so their values can be stored in stack memory. This can also speed up the query of variables. For variables that hold values of primitive types, they are accessed by value, and we operate on their actual values.

  • Undefined
  • Null
  • Boolean
  • Number
  • String

1.2 Reference Type values

The object stored in the heap is actually just a pointer to another location in memory where the object is stored.

Therefore, if you want to assign a value of reference type to a variable, you must allocate space in the heap memory for that value. Since the size of this value is not fixed, it cannot be stored in the stack memory, but the size of the memory address is fixed, so the memory address can be stored in the stack memory. In this way, when querying for variables of reference type, the memory address can be read from the stack first, and the value held in heap memory can be found. This type of access is called reference access because we are not the actual value of the operation, but the object referenced by that value.

1.3 Dynamic Properties

The way to define a base type value and a reference type value is similar: create a variable and assign a value to it. However, once the value is stored in a variable, the operations that can be performed on different types of values are quite different. For a value of a reference type, we can add attributes and methods. You can also change and delete its properties and methods.

var p = new Object()
p.name = 'vue'
alert(p.name)   // vue
Copy the code

1.4 Copying Variable Values

In addition to the way they are saved, there are also differences in copying primitive and reference type values from one variable to another. If a value of a primitive type is copied from one variable to another, a new value is created on the stack and then copied to the location allocated for the new variable:

Var n = 5 var n2 = n // Note that n and n2 are independent. Changing n does not change n2Copy the code

When a variable copies a value of a reference type to another variable, a copy of the value stored on the stack is also made into the space allocated for the new variable. The difference is that a copy of this value is actually a pointer that points to an object stored in the heap. After the copy operation, the two variables are actually the same object referenced. So changing one will change the other.

var obj = new Object()
var obj2 = obj1
obj1.name = 'vue'
alert(obj2.name)    // vue
Copy the code

1.5 Transfer Parameters

Arguments to all functions in ES are passed by value, that is, values outside the function are copied to arguments inside the function.

To the parameter values of basic types, is passed values will be copied to a local variable (or named parameters, or is one of the arguments object element), to the parameter passing in the value of a reference type, will copy the value in memory address to a local variable, so the change of the local variable will be reflected in the function of external.

function addTen(num){
    num += 10
    return num
}

var count = 20
var result = addTen(count)
console.log(count) // 20
console.log(result) // 30
Copy the code

1.6 Detection Types

It can be detected by the Typeof operator, as described in Chapter 3. Typeof is fine for primitive data types, but it’s a bit more difficult for reference types, so instanceof can be used instead

result = variable instanceof constructor
Copy the code

The instanceof operator returns true if the variable is an instanceof a given reference type, as follows:

Person instanceof ObjectCopy the code

By convention, all values of a reference type are instances of Object, so the instanceof operator always returns true when checking for a reference type value and the Object constructor. If the instanceof operator is used to check for a primitive type value, it always returns false. Because base types are not objects.

Note: When the typeof operator is used to detect a function, it returns function. When typeof is used to detect regular expressions in Safari and Chrome, this operator incorrectly returns function

1.7 Execution environment and scope

Execution environment is one of the most important concepts in JS. Execution environments define other data that variables or functions have access to and determine their respective behavior, and each execution environment has a variable object associated with it. All variables and functions defined in the environment are stored in this object.

The global execution environment is the most peripheral execution environment. According to the host environment where ES is implemented, the object representing the execution environment is different. In the browser, the global execution environment is the Window object. So all global variables and functions are created as properties and methods of the Window object, and when all code in an execution environment is executed, that environment is destroyed, along with all variables and function definitions stored in it.

Each function creates its own execution environment when it is called. When the flow of execution enters a function, the environment of the function is pushed into an environment stack, and after the function is executed, the stack ejects its environment, returning control to the previous execution environment.

When code executes in an environment, it creates a scope chain of variable objects. The purpose of the scope chain is to ensure orderly access to all variables and functions that the execution environment has access to. The front end of a scope is always the variable object of the environment in which the code is currently executing. If the environment is a function, treat its active object as a variable object. The active object child starts out with a single variable, the Arguments object. The next variable object in the scope chain comes from the containing environment, and the next variable object comes from the next containing environment. This continues to the global execution environment, where the variable object is always the last object in the scope chain.

Identifier resolution Is the process of searching for identifiers, level by level, along the scope chain, always starting at the front of the scope chain and working backwards until the identifier location is found, failing which an error is reported.

Important: In a particular execution environment, the internal environment can access all the external environment through the scope chain, but the external environment cannot access any variables and functions in the internal environment. The relationship between these environments is linear and orderly, and each environment can search up the scope chain to query variable and function names; But no environment can enter another execution environment by searching down the scope chain. Arguments to a function are also treated as variables, so their access rules are the same as any other variable in the execution environment.

1.7.1 Extending the scope chain

Although there are only two types of execution environment altogether – global and local (functions), there are other ways to extend the scope chain. The idea is to temporarily add a variable object to the front of the scope chain. The variable object is removed after the code executes. This can be done in the following two ways:

The catch block of a try-catch statement is the with statementCopy the code

Both statements add a variable object to the front of the scope chain, which in the case of the with statement contains declarations of variables for all properties and methods of the specified object. For a catch statement, the variable object contains a declaration of the error object that was thrown. These variables are read-only, so variables declared in the with and catch statements are added to variable objects in the execution environment.

Note: In the JavaScript implementation of IE, there is an inconsistency with the standard in that the error object caught in the catch statement is added to the variable object in the execution environment. That is, the error object can be accessed even outside the catch block.

1.8 Has no block-level scope

JavaScript has no block-level scope. At least not in the current version

If (true) {var color = 'blue'} console.log(color) // blue // If the definition of other languages inside {} is not available outside {}Copy the code

1.8.1 Declaring variables

When you declare a variable using the var keyword, the variable is automatically added to the nearest available environment, which in the case of a function is the local environment of the function and, in the case of the with statement in the previous example, is the environment of the function. If a variable is initialized undeclared, it is automatically added to the global environment.

Note: It is a common mistake when writing JavaScript code to initialize variables without declaring them, because this can lead to accidents. We recommend that variables be declared before they are initialized.

1.8.2 Querying An Identifier

When an identifier is referenced for reading and writing in an environment, you must determine what the identifier actually represents through a search that starts at the front of the scope chain and moves up the list of identifiers that match the given name. If the identifier is found in the local environment, the search process stops and the variable is ready. If the variable name is not found in the local environment, continue searching up the scope. The search process traces all the way back to variable objects in the global environment. If this identifier is not found in the global environment either, it means that the variable is undeclared.

var color = 'blue'
function getColor () {
    return color
}

alert(getColor()) // 'blue'
Copy the code

In the example above, the variable color is referenced when the function getColor() is called, and a two-step search process begins to determine the value of the variable color. First, the variable object of getColor() is searched, 19 to see if it contains an identifier named color, and if not, the search continues to the next variable object (the variable object of the global environment), where the identifier named color is found. The search ends because the variable object that defines the variable is found.

Note: If there is a local variable definition during the search, the search automatically stops and does not enter another variable object. In other words, if there is an identifier of the same name in the local environment, the identifier in the parent environment is not used.

Note: Variable queries also come at a cost. Accessing local variables is faster than accessing global variables because you don’t have to search up the scope chain.

1.9 Garbage Collection

JavaScript has automatic garbage collection, which means that the execution environment is responsible for managing the memory used during code execution. It works by finding variables that are no longer in use and freeing up memory. The garbage collector does this periodically at regular intervals.

1.9.1 Flag clearing

JavaScript is the most common way of garbage collection is to mark clear, when the variables into the environment, for the variable tag a “into the environment”, logically, can never be released into the environment variables of the memory, as long as the entered the environment, then represent might need it, when the variable from the environment, Will be marked “out of the environment.” When the garbage collector runs, it marks all variables stored in memory, then removes the tags of variables in the environment that have already been referenced by variables in the environment, leaving the variables to be deleted. Finally, the garbage collector completes the memory cleanup.

1.9.2 Reference Counting

Another garbage collection strategy is reference counting, which keeps track of how many times each value is referenced. When a variable is declared and a reference type value is assigned to that variable, the number of references to that value is 1. If the same value is assigned to another variable, the number of references to that value is increased by 1. Conversely, if a variable containing a reference to that value obtains another value, the number of references to that value is reduced by one. When the number of references to this value becomes zero. There is no way to access the value again, so you can reclaim the memory it occupies.

1.9.3 Performance Problems

Garbage collectors run periodically, and if the amount of memory allocated for variables is significant, the amount of collection can be considerable. All this leads to performance problems.

1.9.4 Managing Memory

Since JavaScript typically allocates less free memory to web browsers than it does to desktop applications, this is done for security reasons. The goal is to prevent a web page running JavaScript from using up all the system memory and causing the system to crash. Memory limitations affect not only the allocation of memory to variables, but also the call stack and the number of statements that can be executed simultaneously in a thread.

Therefore, making sure that you use the least amount of memory is the best way to make your pages look good, and the best way to optimize your memory footprint is to save only the necessary data for executing code. Once data is no longer useful, it is best to release references to it by setting its value to null —-, a practice called dereferencing. This method applies to most global variables and properties of global objects. Local variables are automatically removed when they leave the execution environment.

Note: Dereferencing a value does not automatically reclaim the memory occupied by that value. The real purpose of dereferencing is to take the value out of the execution environment so that the garbage collector can reclaim it the next time it runs.

conclusion

JavaScript variables can be used to hold values of two types: base and reference types. The basic types are Undefined, Null, Boolean, Number, and String. They have the following characteristics.

  1. Base type values take up a fixed amount of memory and are therefore kept in stack memory.
  2. Assigning a value of a primitive type from one variable to another creates a copy of that value.
  3. A variable that contains a reference type value does not actually contain the object itself, but rather a pointer to that object.
  4. Copying a reference type value from one variable to another is actually copying a pointer, so both variables end up pointing to the same object.
  5. The Typeof operator can be used to determine what base type a value is, and the instanceof operator can be used to determine what reference type a value is.

All variables live in an execution environment that determines the lifetime of the variables and which parts of the code can access them. As follows:

  1. Execution environment can be divided into global execution environment and function execution environment.
  2. Each time you enter a new execution environment, a chain of scopes is created to search for variables and functions.
  3. The local environment of a function has access not only to variables in the function scope, but also to its containing (parent) environment and even to the global environment.
  4. The global environment can only access variables and functions defined in the global environment, and cannot directly access any data in the local environment
  5. The execution environment of a variable helps determine when memory should be freed

JavaScript is a programming language with automatic garbage collection, so developers don’t have to worry about memory allocation and collection, as follows:

  1. Values that leave scope are automatically marked as recyclable and therefore deleted during garbage collection.
  2. “Tag cleanup” is the prevailing garbage collection algorithm. The idea is to tag values that are not currently in use and then reclaim their memory.
  3. Another garbage collection algorithm is “reference counting,” the idea of which is to keep track of how many times all values are referenced. JavaScript engines no longer use this algorithm, but it can still cause problems when accessing non-native JavaScript objects in IE.
  4. The “reference counting” algorithm can cause problems when there are circular references in your code.
  5. Dereferencing variables not only helps eliminate circular references, but also benefits garbage collection. To ensure efficient memory reclamation, unreference global objects, global object properties, and circular reference variables that are no longer used in a timely manner.

Welcome to pay attention to the public account [Xiaoyao students]

Re-learn js series

Relearn JS JavaScript introduction

Relearn JS to use JavaScript in HTML

Data types => Data types

Relearn the basic JavaScript concepts of JS (middle) => operator

Relearn the basic JavaScript concepts of JS (part 2) => operator

ES6 Introduction series

ES6 Introduction to let and cont

ES6 introduction to variable deconstruction assignment

ES6 starter string extension

ES6 – An extension to get started with re

ES6 introduction to numerical extension

Extension of ES6 introductory functions

ES6 introduction to the array extension

Extensions to ES6 starter objects

ES6 Symbol for beginners

Git tutorial

Front-end Git basics tutorial