JavaScript变量传值与传址机制详解

作者:异步漫步

时间:2026-10-24

浏览:435

本文解析JavaScript中变量赋值与函数传参的底层机制。通过区分不可变类型(如字符串)与可变类型(如对象),阐明前者传递内存中的值本身,后者传递内存引用(地址)。理解这一区别对于掌握浅拷贝、深拷贝及避免意外修改原始数据至关重要。

文章目录

JavaScript变量传值与传址机制详解

这个标题虽然读起来略显拗口,但它触及了理解数据结构的核心概念。标题中涉及的四个关键术语,其对应的英文表达分别是:shallow copy(注意并非shadow copy)、deep copy、pass by value以及pass by reference(或pass by address)。其中,传址和传引用在概念上是一致的。



不可变类型与可变类型的内存分配

一门编程语言的核心在于数据结构,粗略分类可将数据结构划分为不可变类型(immutable)和可变类型(mutable)。如此划分的原因涉及内存分配策略:对于不可变类型,只需分配有限的内存空间;而对于可变类型,理论上则需要分配大小无上限的空间。因此,这种分类旨在合理利用系统资源。实际上,栈内存(stack)通常用于保存不可变类型的值,而堆内存(heap)则用于存储可变类型的值。



不可变类型的赋值行为

所谓不可变类型,是指该值一旦赋予某个变量,便仅属于该变量,无法被其他变量共享。例如:


代码如下:

 
window.onload=function(){
{ 
var stringValue = "淡淡的";
var anotherStringValue = stringValue;
stringValue = "I have changed";
alert(stringValue);// 输出 I have changed
alert(anotherStringValue);// 输出 淡淡的

此时,anotherStringValue中保存的值是否也会变为“I have changed”?答案是否定的。因为



var anotherStringValue = stringValue;



这行代码会按照stringValue中保存的字符串原样,复制一个字符串(同时在内存中分配一块新的空间),并将该副本赋值给anotherStringValue。换句话说,尽管这两个变量保存的值相同,但它们并不共享同一块内存区域。因此,修改其中任何一个变量的值,都不会影响另一个变量。即



stringValue = “I have changed”;



这一操作只会影响stringValue的值。但确切地说,执行stringValue = “I have changed”;并非直接修改原字符串,而是创建了一个新字符串(并在内存中分配新空间),然后让stringValue指向这个新字符串——这更像是替换变量的引用;原来的字符串由于没有变量再引用它,便成为了垃圾(当然,其所占用的内存最终会被垃圾回收机制回收)。



可变类型的引用传递

由此可见,对于不可变类型,赋值操作传递的是内存中值本身的副本。那么,对于可变类型呢?答案是传递内存中值的引用(或称地址)。无论传递多少次,内存中始终只保留一份原始值——毕竟可变类型的大小难以预测,只保存一份原始值能最大限度地节省内存空间。例如:


代码如下:

 
window.onload=function(){
{ 
var objectValue = {1:1,'s':'string','innerObject':{'innerArray' : [1,2,3]}};
var anotherObjectValue = objectValue;
objectValue[1] = 100;
alert(anotherObjectValue[1]); //输出 100
} 

显而易见,这里的anotherObjectValue通过赋值操作,从objectValue那里仅获得了对原始对象({1:1,'s':'string','innerObject':{'innerArray' : [1,2,3]}})的引用,即该对象在内存中的地址,或者说是“门牌号码”。因此,通过objectValue修改原始对象的第一个元素(objectValue[1] = 100;),anotherObjectValue[1]也会反映出同样的变化——因为这两个变量共享同一份原始数据。



函数参数的传递规则

在JavaScript中,向函数传递参数遵循上述默认约定:对不可变类型传值,对可变类型传址。例如:



function example(str, obj){


……
}

example(stringValue,objectValue);



调用example函数时,第一个参数传递的是实际的字符串值,而第二个参数传递的是对象的引用(内存地址)。

实用工具推荐

电子包浆

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

使用 ›
图片压缩

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

使用 ›
相关文章