JavaScript memory

The basic data types of memory size is fixed (static memory allocation), and reference data types of dynamic memory size is not fixed (dynamic memory allocation), may change at any time. So there will be some differences in the memory allocation stage two data types.

The difference between static and dynamic memory allocation memory allocation in the following table:

Static memory allocation Dynamic memory allocation
Compilation phase to determine the size Unable to determine the size of the compile phase
At compile time Executed at runtime
Assigned to the stack Assigned to the heap
Assigned sequentially, last in, first out (LIFO) Disorderly distribution

 

Memory Allocation in JavaScript

Using basic data types and the reference data type are graphs showing memory allocation process, to be understood that the underlying details of JavaScript.

First, we start with a simple basic data types assignment, as follows:

let num = 1;

When the JavaScript engine to perform this line of code, it performs the following operations:

1 creates a variable unique identifier (identifier) --- num, and the identifier for the stack memory address A1formation mappings.

2 assign it an address on the stack memory A1.

The value 3 1is stored in the assigned address.

Example is as follows:

Usually we say that numthe value of the variable is equal 1, but in fact, strictly speaking, numthe value of the variable is equal to the stack memory stored in the memory address corresponding to the value (as shown in A1).

Next we create a new variable newNumand numassign to it:

let newNum = num;

After the above assignment, often said newNumvalue is equal to the value num 1, likewise from the strict sense of the word refers to newNumand numpoint to the same memory address A1, as shown below:

If then we do the following to see what happens:

num = num + 1 ;

We numself-growth variables, it is clear that numthe value of the variable 2. Because newNumand numpoint to the same memory address A1, then the time newNumvalue of whether to 2do, before answering this question, we first look at the current memory address changes occur:

In the figure above we can see that numthe memory address of the variable has changed from the original A1becomes A2, because in the JS in the basic data types are immutable , once modified, will assign new memory address the new value is stored and modified to the new address, so to answer that question above, newNumthe value remains the same, still is 1, because its memory address has not changed.

Look at the following example:

let str = 'ab';
str = str + " c " ;

Because the string also belongs to the basic data types, the basic data types are immutable, even if the above code simply be cspliced into the original string abback, but still it is assigned a new memory address, the variable strwill eventually point this new memory address, as shown below:

 

Understanding of the basic data types of memory allocation, then we have to understand the type of data memory allocation under reference. Similarly, we quote from a simple data type assignment start:

let arr = [];

When the JavaScript engine to perform this line of code, it performs the following operations:

1 为变量创建一个唯一标识符(identifier)---arr,该标识符用于与栈内存中的地址A3形成映射关系。

2 在栈内存中为其分配一个地址A3

3 在栈内存中存储堆中分配的内存地址的值H1

4 在堆中存储分配的值空数组[]

示例图如下:

 

在JavaScript引擎(例如Chrome和Node的V8引擎)中主要是由两个部件组成,一个叫内存堆(Memory Heap),一个叫调用堆栈(Call Stack)。其中调用堆栈除了函数调用之外,主要用于存放基本数据类型的值,而引用数据类型的值一般都存放在内存堆中,堆中存放的数据都是无序的并且可以动态地增长,所以非常适合用于存储数组和对象。

let和const的对比

在了解完以上两种数据类型的内存分配方式后,我们这里对letconst的使用方式进行一下对比,通常来说,我们建议在写代码的过程中能使用const的地方尽量减少使用let,这样可以在某种程度上避免变量被无端修改而引发的一系列问题。如下代码:

let num = 1;
num = num + 1;
let arr = [];
arr.push(1);
arr.push(2);
arr.push(3);

在上述代码中,变量num因为使用let的方式声明,所以允许其被修改,因为基本类型的值是不可变的,所以会为num变量分配新的内存地址。对于arr变量,这里同样使用let方式进行声明,表示允许其修改,但是对于push操作其实并没有修改arr变量的内存地址,只是将新的值推入了堆内存的数组中,所以此处建议修改为使用const进行声明。

如下示例:

const num = 1;
num = num + 1;

由在上边了解到的基本数据类型的内存分配方式,我们知道为变量num在栈内存中分配了一个地址来保存对应的值。

但是这里我们是使用const的方式来进行声明的,当我们重新为变量num进行赋值时,JS尝试为其分配新的内存地址,那么这里也就是抛出错误的地方,因为我们明确不允许对其进行修改。

因此在控制台中我们会看到对应的报错信息。

再看如下示例:

const arr = [];

对于引用数据类型,我们知道会在栈内存上为其分配内存地址,存储的是堆中的内存地址的值。

 

 我们做如下操作:

arr.push(1);
arr.push(2);
arr.push(3);

 

 执行push操作实际上是将新值推入堆中的数组,内存地址并没有发生改变。这也就是为什么虽然使用const声明变量,但是依旧没有报错的原因。但是如果我们使用如下方式:

arr = 1;
arr = undefined;
arr = null;
arr = [];
arr = {};

这些方式都会修改原数组的内存地址,const声明是不允许修改内存地址的,所以很明显会抛出错误。因此这里也是建议默认情况下使用const声明变量,除非需要修改内存地址,const声明的变量必须在声明时进行初始化,也方便了其他前端人员能一眼看出哪些变量是不可变的。

 

原文: https://www.cnblogs.com/tangshiwei/p/12020478.html

Guess you like

Origin www.cnblogs.com/xjy20170907/p/12021741.html