基本数据类型
var a = 1; // 假设栈中开辟内存空间,地址为0x0202,存放值为1,a指向0x0202这个地址
a = 2; // 栈中开辟内存空间,地址0x0203,存放值为2,a指向0x0203这个地址,0x0202没有被指向
对于基本数据类型(number、string、boolean、undefined、null)其值是“不可变”的,每次值被修改,都会在栈中开辟新的内存空间,写入修改值后,改变标识符的指向。
那么,对于堆中的变量也符合这种规则吗?
引用数据类型
var obj = {a:1}; // 假设堆中开辟内存空间,地址为0x1020,其值为1,obj.a指向0x1020这个地址
obj.a = 2; // 请问:是直接在堆中地址为0x1020内存上重写值为 2?
// 还是像上面一样开辟新的内存空间,地址为0x1030,存放值为2,修改obj.a的指向为 0x1030?
请问:是直接在堆中地址为0x1020内存上重写值为 2?还是像上面一样开辟新的内存空间,地址为0x1030(假设),存放值为2,修改obj.a的指向为 0x1030?
这是你说的吧?
基本数据类型是指内存中存放的数据的类型是基本类型,而不是内存地址。但是“每次值被修改都会开辟新的内存空间写入,再改变标识符指向”这件事和数据类型无关,是更底层的逻辑,而且这个逻辑甚至和JS无关。
你想想看,
var a = {}
,然后a.t = 5
,此时a的值变了吗?或者说a的标识符指向的地址中存储的内容变了吗?当然没变,所以我们必须用var a = {}; a = {t: 5}
的方式才能让侦听发现a变了。同理,任何语言中只要支持“引用”的,是不是都是一样的结果?这样总结吧,值是存放到某个内存地址,标记使用,然后改变指向标识,再将原始地址标记为未使用。但是通常开发者并不需要关注这个事情。
至于为什么这样搞,就是@xdsnet 说的那样了,原始地址放不开新数据怎么办?把别人都挪一下地方?那不累死了。
注意细节:
var a = 1; // 假设栈中开辟内存空间,地址为0x0202,存放值为1,a指向0x0202这个地址
这个描述是不完整的,因为1是整型,所以需要先开辟一个4字节空间,再把1放进去,然后a指向0x0202,l=4。所以当a = 1.5
时,需要先开辟一个8字节空间才行。这个空间必须是连续的。