特别是在 v8 / Node.js 中,当您将原始类型(字符串、数字、布尔值)推入数组时,它会克隆字符串,还是存储引用?
我知道你不能这样做并更改字符串:
let array = []
let x = 'foo'
array.push(x)
x = 'bar'
console.log(array) //=> ['foo']
但是如果我这样做,是否会多次复制字符串(从而增加内存占用)?
let array = []
let x = 'foo'
array.push(x)
array.push(x)
array.push(x)
...
对象键有同样的问题,如果我这样做,它会克隆字符串吗?
let object = {}
let x = 'foo'
object.a = x
object.b = x
object.c = x
我搜索了一下,但没有找到这个问题的直接答案。
这篇博文说:
对象和数组作为指向原始对象的指针推送。 数字或布尔值等内置基本类型被作为副本推送。
但我不确定这是否正确(没有备份)。我必须运行一系列彻底的测试来真正检查并查看当我推入数组时内存是否会增长。我不太确定实现这一点的最简单方法,所以也许 v8 工程师或其他精通编译器理论的人知道这是如何实现的。
我想使用
Buffer.byteLength(text, 'utf8')
来计算我添加到特里树中的每个字符串的大小,然后跟踪特里树的粗略大小(将其中使用的字符串大小相加,并粗略估计用于存储的字节) n 个对象属性和 x 长度的数组)。所以第一步是理解,当我将字符串推入多个位置时,它会被复制吗?还是会在每个地方携带相同的引用?
我希望博客是不正确的,并且它推送了一个引用,只是一旦将变量发送到另一个函数,你就无法修改它。但字符串仍然是一个引用,直到您尝试更改变量,类似的事情。
我已经构建了一个测试框架
当您运行此命令时,您将看到 a 和 c 通过引用传递(浅拷贝),而 b 通过值传递
var a = {'a' : 0}
var b = 0;
var c = [0];
function foo(x) {
return ++x.a;
}
function foo2(x) {
return ++x;
}
function foo3(x) {
x.push(1);
return x;
}
console.log(a);
foo(a);
console.log(a);
console.log(b);
foo2(b);
console.log(b);
console.log(c);
foo3(c);
console.log(c);