JavaScript变量、传值与传址机制详解
本文深入解析JavaScript中变量、传值与传址的核心机制。详细区分基本类型(如number、string)与引用类型(如Array、Object)在内存中的存储差异。通过四个典型代码案例,阐明函数参数传递时“复制变量值”的行为:基本类型复制数值,引用类型复制指针。重点解释为何直接赋值参数会切断外部引用,而修改对象属性仍会影响原对象,帮助开发者准确理解JS内存模型与变量作用域。
JavaScript变量类型与参数传递机制概述
首先梳理核心结论:
1. JavaScript中的变量包含两种类型的值:引用类型和基本类型。引用类型涵盖Array、Object和Function(可理解为非基本类型均属此类);五种基本类型分别为undefined、null、string、boolean和number。
2. 函数参数的传递机制本质上是复制变量值。
教材指出:“将函数外部的值复制给函数内部参数,等同于将一个变量赋值给另一个变量。基本类型的传递与基本类型变量的复制一致,而引用类型的传递则与引用类型变量的复制一致。”
“当变量复制引用类型的值时,系统会将存储在变量对象中的值复制一份到新变量的空间中。不同之处在于,这个副本实际上是一个指针,指向堆内存中的一个对象。复制操作完成后,两个变量引用同一个对象。因此,修改其中一个变量会影响另一个变量。”
【注意:只有复制引用类型的值时,才涉及传址概念】
3. 参数本质上是函数的局部变量。
----------------------------------------------------------------------------
传值与传址的基本概念与内存分布
基本概念解释:
传值:将A的数值传递给B,修改B时A不受影响,因为B存储的是与A相同的值; 传址:将A的地址传递给B,修改B时A随之改变,因为B存储的是A的地址(类似于电脑中的快捷方式)。
值类型(value type)数据存储在栈内存的变量中。即在栈中分配内存空间,直接存储所包含的值,该值即代表数据本身。值类型数据具有较快的存取速度。
引用类型(reference type)数据不驻留在栈中,而是存储于堆内存。即在堆中分配内存空间,不直接存储所包含的值,而是指向所存储的值,该值代表指向的地址。访问引用类型数据时,需先在栈中检查变量内容,该变量引用堆中的实际数据。引用类型数据比值类型数据占用更大的存储规模,且访问速度较低。
----------------------------------------------------------------------------
函数参数传递的四个典型案例分析
以下是三个典型问题。
【问题1】:为什么执行change(a)函数后,外部的a没有受到影响?
<script>
var a = [1, 2, 3];
function change(a) {
console.log(a);//[1,2,3]
a = 2; //传值
console.log(a);//2
}
change(a);
console.log(a); //[1,2,3]
</script>
问题1解答:change(a)的执行过程如下:首先将对象a(数组)传入change函数,并复制给change的参数a。随后执行a=2赋值语句,此时变为传值操作。由于a=2是值类型,不涉及引用地址问题,因此并未影响外部的a。
【问题2】:为什么执行change(a)函数后,外部的a受到了影响?
<script>
var a = [1, 2, 3];
function change() {
a = 2;//传值
}
change();
console.log(a); //2
</script>
问题2解答:执行change()时,函数在其执行环境中查找作用域链。活动对象(activation object)不包含变量a,于是沿作用域链向上查找,直到全局执行环境找到变量a。此时函数内部的a和外部的a在内存上指向同一地址,因此函数内部a发生变化时,外部a也会随之改变。
解析:问题2与问题1的区别在于,问题2并未引入参数,因此不涉及复制变量的操作。
【问题3】:为什么执行change(a)函数后,外部的a受到了影响?
<script>
var a = [1, 2, 3];
function change(b) {
b[0] = 2;
}
change(a);
console.log(a); //[2,2,3]
</script>
问题3解答:此问题与问题1非常相似,唯一区别在于a=2换成了b[0]=2。起初令人困惑的是:既然说是复制,参数b应该是复制值,为何会影响外部的a?
确实,change函数执行时,参数b是a的复制值。因为a是引用类型,所以在函数内部b和a按引用访问的是同一个地址的对象。b[0]=2的出现,并不影响函数内部b和a引用的是同一个对象这一事实。
【问题4】:为什么执行change(a)函数后,外部的a没有受到影响?
var a = [1, 2, 3];
function change(b) {
console.log(b);//[1,2,3]
b=2;
b[0] = 2;
}
change(a);
console.log(a); //[1,2,3]
问题4解答:change(b)的执行过程如下:a对象传入change函数,将值和地址复制给b。执行b=2后,b变为值类型,不再涉及地址引用问题。此后b[0]=2实际上毫无意义,因为此时b已不是数组,自然不具备b[0]这样的索引方式。因此,b与a的地址引用关系在b=2执行后即已消失。此时外界的a仍然是[1,2,3]。
以上即为本文的全部内容,希望对大家有所帮助。
什么时候该用JS构造器:与工厂模式、字面量的选择对比
2026-11-05 16:18:22
推荐几款轻量级JS照片墙开源库及对比
2026-11-05 15:56:19
JavaScript递归写法有哪些常见陷阱及避免方法
2026-11-05 14:53:38
JS数组浅拷贝与深拷贝怎么选?场景与方法总结
2026-11-05 14:41:02
p5.js 中 setup() 和 draw() 函数的执行机制详解
2026-11-05 12:32:38
