深入解析 JavaScript 变量赋值机制:直接量与引用类型

作者:半夏

时间:2026-10-22

浏览:235

本文深入解析 JavaScript 中变量赋值的底层机制,重点区分字符串(直接量)与对象/数组(引用类型)在赋值时的行为差异。通过具体代码示例,阐明变量重赋值时内存空间的变化,并对比字符串拼接与数组 Join 的性能差异,帮助开发者优化代码效率。

文章目录

JavaScript 变量赋值基础

JavaScript 属于弱类型语言,声明变量时无需指定具体类型,例如 var x 可以赋予任意类型的值。


例如:



var str = "string....";


var arr = ["this","is","array"];


var obj = {name:"caizhongqi",age:26,sex:"male"};


上述写法均正确,看似简单便捷,但这种便捷性也可能引发难以预料的意外,请看下面的例子(例1):



字符串赋值:直接量机制

<script> var x = "this is string";


var y = x;


x="ni hao";


alert(y)


</script>



你可能认为 alert 输出的结果是 “this is string”,这是正确的。但对于熟悉 Java 的程序员而言,var y=x 通常意味着将 x 在内存中的地址(指针)赋给 y,因此他们预期 alert 输出 “ni hao” 才符合 Java 的习惯。然而 JavaScript 并非如此,字符串赋值属于直接量操作,即将数据副本直接存入 y 的存储空间。



数组赋值:引用类型机制

再看下面的例子(例2):



<script>


var x = ["hello"] // 这是一个数组,只有一个元素,并且该元素为字符串类型


var y = x;


x[0] = "world";


alert(y[0]);


</script>



如果你认为 alert 输出的是 “hello”,那就错了。当执行 var y = x 时,x 传递的是其在内存中的地址(指针)!x[0]="world" 修改了原存储位置的数据,因此 alert(y[0]) 获取的是 x 修改后的新值。这是否让人感到困惑?为什么有时是直接量,有时又是引用量呢?


变量重赋值与内存空间变化

别急,下面的例子(例3)可能会让你更加困惑:



<script>


var x = ["hello"] // 这是一个数组,只有一个元素,并且该元素为字符串类型


var y = x;


x = ["ni","hao"]; // x 将变成一个新的数组了。


alert(y[0]);


</script>



结果显示 alert 输出的是 “hello”!这种看似“古灵精怪”的 JavaScript 行为确实让人捉摸不透。



周星驰的《国产零零漆》中有类似的一幕:


当星爷刚从深圳到香港执行任务时,袁咏仪从他的行李中发现一个吹头发的风筒,星爷说这其实是个须刨,把皮鞋拿出来一看却是一个风筒,一个貌似大哥大电话的玩意其实又是一个须刨。须刨与风筒把袁咏仪与观众都搞混乱了,哈哈哈哈,这是我很喜欢的一部片,第一次看时肚子都笑痛了。



回过头来再看看刚才的变量赋值,直接量与引用量的使用,就好像须刨与风筒换来换去,把我们都搞晕了。


其实问题出在对 x 的第二次赋值 x = ["ni","hao"] 上,我们看看变量在存储器上变化以及 JavaScript 在对待字符串类型与对象类型的不同:



我们观察下面两种情况:


var x = "this is string...";


var y = ["this","is","string"];



x 与 y 的不同之处在于类型。JavaScript 解析器将字符串直接赋值(即 copy)给 x(直接量),却将数组的指针赋给 y(引用量),这一切都是瞬间全自动完成的!结合下面的图,可能会更好地理解:





图中 p1、p2... 就是变量的指针,上面的 var y 中的 y 存的就是 Object 类型变量的指针 p1(假设),而 x 存放的就是字符串本身。再分析一下例3,执行 var x = ["hello"] 时,解析器就在内存上开辟一块存储空间放这个数组,而 x 就拿到了这个空间的地址(指针),再执行 x = ["ni","hao"] 时,解析器又新开辟一块存储空间放这个新数组,而 x 就是这个新存储空间的指针,这也就是说,JavaScript 里变量的重定义(或重新赋值)将会新开辟一块存储空间,而没有销毁原来的空间;回过头来再看例2,x[0] = "world",这句没有给 x 新定义值,没有新开辟存储空间,只是修改了它存储空间里面的数据,因此例2最后 alert 出来的就是 “world”;例1是字符串赋值,全过程是直接量操作。



从上面的分析可以看出,JavaScript 的变量可以存储直接量也可以存储指针,这是没办法被人工干扰的,因此,在日常的编码中,就需要注意这些问题,比如大字符串连接,循环里面赋值等细节就能直接影响到程序的执行效率。



性能优化:字符串拼接与数组 Join

看看两个例子:



var _tmpStr="";


var str = "this is big string...";


for (i=0; i<100; i++){


_tmpStr += a;


}

a = _tmpStr;



因为是字符串操作,使用直接量,每次循环都要操作大字符串,非常笨重,效率低下。如果改用引用量操作,即通过数组:



var str = "this is big string...";


var _tmpArray = [];


for (i=0; i<100; i++){


_tmpArray[i]=str;


}

str = _tmpArray.join("");



做个测试,假如有个 100k 的字符串,用直接量连接操作,我的机器上需要约 2600 毫秒,如果用数组连接,则需要 150 毫秒,效率相差十几倍。



好久没写这么长的文章了,花了我大半天的时间。



实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章