JavaScript函数参数传递机制详解:值类型与引用类型的区别

作者:半夏

时间:2026-10-24

浏览:334

本文深入解析JavaScript中函数参数的传递机制。通过对比基本类型(如Number、String)与引用类型(如Object、Array)的传递行为,阐明JS参数始终按值传递的核心原理。文章结合具体代码实例,分析变量赋值、对象属性修改及重新赋值对原变量的影响,帮助开发者避免常见误区,掌握正确的参数使用方式。

文章目录

JavaScript函数参数传递机制详解:值类型与引用类型的区别

首先分析一道JavaScript笔试题:


var setObj=function(o){
o.name="xiaoming";
o={};
o.name="xiaohong";
}
var p={name:"xixi",age:24};
setObj(p);
console.log(p);

输出结果为{name:xiaoming,age24};

在JavaScript语言中,函数参数默认采用引用传递机制。

值类型与引用类型的传递行为

一.值类型参数传递:

代码示例如下:


function addNum(num){
 num+=10;
 return num;
}
var num=10;
var result=addNum(num);
console.log(num);
console.log(result);

上述代码执行后弹出的数值分别为10和20,具体解析如下:

定义变量num并赋值为10,该变量属于值类型。当作为参数传递给函数时,系统会将该值复制一份传入函数内部。因此,函数执行完毕后,原始变量num的值保持不变,函数内部修改的仅是副本。

二.引用类型参数传递:


 function setName(obj){ 
obj.name="青岛新锐"; 
} 
var web=new Object(); 
web.name="蚂蚁部落";
 setName(web); 
console.log(web.name);

上述代码弹出的结果为“青岛新锐”,具体解析如下:

定义一个对象web,其属于引用类型。当作为参数传递给函数时,传递的是该对象的引用(即内存地址)。因此,在函数内部修改属性时,实际修改的是外部创建的对象本身。

三.深入理解:


function setName(obj){ 
 obj.name="青岛新锐"; 
 obj=new Object(); 
 obj.name="蚂蚁部落"; 
 } 
 var web=new Object(); 
setName(web); 
console.log(web.name);

上述代码弹出的结果为青岛新锐。许多人可能误以为会弹出“蚂蚁部落”,具体解析如下:

在函数外部创建对象,并将该对象的引用赋值给变量web,此时web存储的是对象在内存中的地址。当传递参数时,传递的是外部创建对象的地址。在函数内部,为外部创建的对象添加自定义属性name并赋值为“青岛新锐”,随后创建新对象并将新对象的地址赋值给obj。此时,obj指向新对象而非外部对象,因此外部对象的name属性不会改变。

这种写法对于其他语言程序员而言难以接受,实际开发中应避免此类写法,以免导致全局作用域污染。近期研读《javascript高级程序设计》时遇到js传递方式问题,经耗时研究终获理解。

数据类型与变量复制原理

数据类型

在javascript中,数据类型主要分为两类:

  • 基本类型值(primitive type),例如Undefined、Null、Boolean、Number、String。
  • 引用类型值,即对象类型(Object type),例如Object、Array、Function、Date等。

变量复制机制

众所周知,js中基本类型和引用类型的变量保存方式不同,导致变量复制行为存在差异。若将一个变量向另一个变量复制基本类型的值,系统会将前者的值克隆一份,并将克隆值赋值给后者。因此,这两个值完全独立,仅value相同。


var num1 = 10;
var num2 = num1;
console.log(num2);//10

上述num1中保存的值为10,当把num1的值赋值给num2时,num2的值也为10。但这两个10完全独立,num2中的10仅为克隆值。这好比编写一个word文档,将其放入num1的文件夹,再复制该word文档(称为word副本)放入num2的文件夹。这两个word文档完全一致,修改其中任何一个均不影响另一个。


num2 += 1;
console.log(num1); //10
console.log(num2); //11

由上可知,修改num2的值,num1的值未发生变化。接下来考察引用类型的复制。当从一个变量向另一个变量复制引用类型的值时,同样会将存储在变量对象中的值复制一份放入新变量分配的空间中。


var obj1 = {
name : "111"
};
var obj2 = obj1;
console.log(obj2.name); //111
obj2.name = "222";
console.log(obj1.name); //222

第一次打印结果为“111”,这易于理解;但第二次打印结果为“222”,略显突兀。这正是引用类型与基本类型的区别所在。复制对象时,并不会在堆内存中新生成一个一模一样的对象,而是多了一个保存指向该对象指针的变量。将obj1的值复制给obj2时,该值的副本实际上是一个指针,指向存储在堆中的一个对象。这意味着创建了一个新的内存地址传给了obj2,obj1和obj2两个变量同时指向同一个Object。当改变该对象时,它们的值都会改变,即其中任何一个作出的改变都会反映在另一个身上。下方的简易图示可能更为直观。

JavaScript函数参数传递机制详解:值类型与引用类型的区别

函数参数传递的核心结论

函数参数的传递机制

《js高级程序设计》对此的叙述如下:所有函数的参数都是按值传递的。也就是说,把函数外部的值复制给函数内部的参数,这与把值从一个变量复制到另一个变量相同。因此,若能理解变量的复制,那么参数的传递也就很简单了。首先从基本类型举例说明。


var count = 10;
function num(num1){
num1 = 1;
return num1;
}
var result = num(count1);
console.log(result);//1
console.log(count);//10,并未变成1

此例易于理解,实际就是创建了一个count的副本,然后将count的值传入参数中。因为函数中定义了参数的值,所以1将10覆盖,最终result返回1,而count并未发生变化。再看一个有关传递对象的例子。


var person = {
name : "Tom"
};
function obj(peo){
peo.name = "Jerry";
return peo;
}
var result = obj(person);
console.log(result.name);// Jerry
console.log(person.name);// Jerry

在上述例子中,把person复制传入obj()中,peo和person指向了同一个对象。在peo中修改了name属性,实则修改了它们共同指向的对象的name属性。相对应地,外部person所引用的name属性也随之改变,因此打印结果为Jerry。乍看之下,感觉引用类型的参数是按照引用传递的,这是我最初犯下的错误。再来看一个例子。


var person = {
name : "Tom"
}; 
function obj(peo){
peo = {
name : "Jerry"
};
return peo;
}
var result = obj(person);
console.log(result.name);// Jerry
console.log(person.name);// Tom

在上述例子中,在函数中重新定义了一个对象,此时堆内存中存在两个对象。外部的person指向的是老的对象,被传入参数后指向的是新定义的对象,因此调用后返回的值是新定义对象的值。如果是参数按引用传递,那么person.name打印出来的结果应为Jerry。从这点可以得出参数是按值传递的(部分资料称为按共享传递)。

我们借用老罗推荐的《人类简史》进行形象化描述,尽管描述可能不够完美。简史的第一章标题为“认知革命”,我们将此名字改为“person”,根据后面的页码数可直接找到“认知革命”的内容(即peoson所指向的对象)。第二章为“农业革命”,我们将其命名为“result”,其分目录有一节“记忆过载”(改名为“peo”),同样可直接根据页码找到这一节内容。

现在我们将“person”复制到“peo”中,第二章中的“peo”这一节就变成了“person”。而我们根据第一章中的“peoson”找到的仍是第一章的内容,这是因为它们指向了不同的内容板块,互不干扰。在此,堆内存即为每章的内容,而第一章和第二章内容是2个不同的对象,且这两者互不相干。因此,打印外部person.name时,结果仍为以前对象的属性值。

结论

总而言之,在js中参数都是按值传递的。我编写的例子较为粗糙,《javascript高级程序设计》中的例子描述更为清晰,更易理解。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持本站。

实用工具推荐

电子包浆

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

使用 ›
图片压缩

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

使用 ›
相关文章