Open ChuChencheng opened 4 years ago
当我们在 JavaScript 中声明一个原始值,例如
let myNumber = 123
JS 会做以下事情:
myNumber
123
这时候,我们口头上会说 “myNumber 等于 123” ,但实际上, myNumber 是指向了一个地址,而地址存的值是 123 。
当我们重新给 myNumber 赋值时:
myNumber = 456
原来的 123 并没有消失或改变,而是重新分配了一个地址,把 myNumber 指向新的地址,并把 456 存入新地址的值。
456
JavaScript 的内存模型可以理解为,存在两个区域: 调用栈 和 堆
调用栈
堆
其中, 调用栈 中存着原始值的值与函数; 堆 中存储引用类型的值。
那么引用类型的值是怎么存储的?
当我们声明一个数组:
const arr = []
发生了什么:
arr
[]
let
const
我们都知道, let 与 const 的区别是, let 允许开发者重新给变量赋值,而 const 反之。
实际上,这个行为限制的是能否修改标识符所指向的内存地址,例如:
const myNumber = 123 myNumber = 456 // TypeError: Assignment to constant variable. const arr = [] arr.push(1) arr[1] = 2 console.log(arr) // [1, 2] arr = [3, 4] // TypeError: Assignment to constant variable.
在上述例子中可以看到,对于原始值标识符 myNumber 的重新赋值报错了,这是符合预期的。 但对于引用类型 arr ,可以修改值 [] 而不报错,但整个数组重新赋值,一样会报错。
这是因为,当我们修改 [] 的时候,我们修改的是 堆 里面的值,而 调用栈 中, arr 标识符指向的地址没有被修改,因此不会报错;当我们重新赋值 arr 时, 调用栈 里面会重新分配地址, arr 标识符指向的地址改变了,因此报错。
JavaScript’s Memory Model - Medium
变量声明与赋值
当我们在 JavaScript 中声明一个原始值,例如
JS 会做以下事情:
myNumber
123
存入分配的地址这时候,我们口头上会说 “myNumber 等于 123” ,但实际上,
myNumber
是指向了一个地址,而地址存的值是123
。当我们重新给
myNumber
赋值时:原来的
123
并没有消失或改变,而是重新分配了一个地址,把myNumber
指向新的地址,并把456
存入新地址的值。内存模型
JavaScript 的内存模型可以理解为,存在两个区域:
调用栈
和堆
其中,
调用栈
中存着原始值的值与函数;堆
中存储引用类型的值。那么引用类型的值是怎么存储的?
当我们声明一个数组:
发生了什么:
arr
调用栈
中分配一个地址,标识符指向这个地址堆
中分配一个地址,把地址存入步骤 2 中创建的地址对应的值中[]
存入堆
中步骤 3 分配的地址的值中let
与const
我们都知道,
let
与const
的区别是,let
允许开发者重新给变量赋值,而const
反之。实际上,这个行为限制的是能否修改标识符所指向的内存地址,例如:
在上述例子中可以看到,对于原始值标识符
myNumber
的重新赋值报错了,这是符合预期的。 但对于引用类型arr
,可以修改值[]
而不报错,但整个数组重新赋值,一样会报错。这是因为,当我们修改
[]
的时候,我们修改的是堆
里面的值,而调用栈
中,arr
标识符指向的地址没有被修改,因此不会报错;当我们重新赋值arr
时,调用栈
里面会重新分配地址,arr
标识符指向的地址改变了,因此报错。参考
JavaScript’s Memory Model - Medium