JavaScript中函数的参数传递方式都是按值传递

黑色杜克
  • 412

函数传递方式

JavaScript中函数的参数传递方式都是按值传递,没有按引用传递,应该怎么理解??

“能不能举个例子”

补充:保存引用的对象(比如数组,它是按照引用传递的又该怎么理解)

function add(arr,num){
    for(var i=0; i<arr.length; i++){
        arr[i]+= num;
    }
}
var arr1 =[1,2,3,4,5];
add(arr1,5);
console.log(arr1);//[6, 7, 8, 9, 10]
回复
阅读 6.5k
8 个回答

楼上的回答中,@kikong 的回答是最靠谱的。

当传递原始类型值给形参时,传递的就是原始值本身。
当传递引用类型值给形参时,传递的是一个指针(一个特殊的值)。

这就是所谓的 JS 中的按值传递

其实吧,JavaScript 的参数传递涉及两组核心概念:

  1. 按值传递和按共享传递(call by value VS call by sharing

  2. 重新绑定和变异 (rebinding VS mutation

参数传递的本质其实是一个隐式赋值,赋值运算(=)发生了什么,参数传递就发生了什么。

var num1 = 5
var num = num1

num1 保存着数字类型值 5,将 num 赋值为 num1num就保存了数字 5。这是按值传递。
call by value

var arr1 = [1, 2, 3, 4, 5]
var arr = arr1

arr1 保存一个引用类型值,也可以理解为 arr1 指向数组 [1, 2, 3, 4, 5]的内存地址。将 arr 赋值为 arr1arr 也就指向了该数组的内存地址。这是按共享传递(两个变量共享该对象的内存地址)。
call by sharing

var arr1 = [1, 2, 3, 4, 5]
var arr = arr1
arr = [2, 3, 4, 5, 6]

arr 原本与 arr1 一起指向数组 [1, 2, 3, 4, 5] 的内存地址,但通过另一个赋值语句,使 arr 重新指向了数组 [2, 3, 4, 5, 6] 的内存地址。这是重新绑定。
rebinding

var arr1 = [1, 2, 3, 4, 5]
var arr = arr1
arr1.push(6)
console.log(arr1.length) // => 6
console.log(arr.length)  // => 6

任何对 arr1arr 的修改都是对其所指向对象的修改。这是 mutation。
mutation

这里尤其需要注意的是 rebinding。对 arr 重新赋值之后,arr1arr 已经指向了不同的内存地址,两者已经断开联系。

在你的例子中,

function add(arr,num){
    for(var i=0; i<arr.length; i++){
        arr[i]+= num;
    }
}
var arr1 =[1,2,3,4,5];
add(arr1,5);
console.log(arr1);//[6, 7, 8, 9, 10]

在执行 add(arr1, 5) 时,传参完成的是隐式的赋值操作(即,arr = arr1, num = 5),其中传参给 arr 是 按共享传递,传参给 num 是按值传递

在函数体内修改 arr (arr[i] += num),是 mutation 操作,所以即便 arr 在随后被销毁了,通过 arr1 也能观察到变更。

javascript中的参数传递都采用 按值传递的方式
对于对象来说,这个值是指对象的内存地址
对基本类型,这个值是原始值

=======

function add(arr,num){
    console.log(arr);//[1,2,3,4,5];
    //arr被重新赋值前和arr1的相同
    arr=[5,6,7,8,9];//arr被重新赋值,指向的地址不同,但不会影响arr1的指向,也就是其地址信息
    for(var i=0; i<arr.length; i++){
        arr[i]+= num;
    }
    console.log(arr);//[10, 11, 12, 13, 14]
}
var arr1 =[1,2,3,4,5];
add(arr1,5);
console.log(arr1);//[1, 2, 3, 4, 5]

1、按值传递:
按值传递就是将变量先复制一份,然后将复制的变量传入函数,如下面函数,先将num复制,然后再将复制的值传入add函数,执行下面函数就很明了了。
var num=10;
function add(num){
num+=10;
return num;
}
console.log("这是add方法返回的值 "+add(num));//这是add方法返回的值 20
console.log("这是原始的num "+num);//这是原始的num 10
2、按引用传递
按引用传递思想和按值传递一样,先将对象的引用复制一份,然后再将所复制的引用传入函数;不同的是,这两个引用都指向同一个对象。来看一下面的一段代码:
function person(){
this.name="小明";
this.age=23;
}
p1=new person();
p2=new person();
function editName(person){
person.name="小红";
}
console.log(p1.name);//小明
editName(p1);
console.log(p1.name);//小红
注意:不是说可以改变对象的值就是说明是按引用传递,例如以下代码:
function chengeName(p){
p=new person();
p.name="小小";
}
p2=new person();
console.log(p2.name);//小明
chengeName(p2);
console.log(p2.name);//小明
这里p2的name虽然没有改变,但它也是属于按引用传递的

js中函数参数都是按值传递的,即使函数局部改变引起了全局的改变。javascript高级程序设计里是这么说的,可是js里对象哪里有值传递啊。。。
直接传值的话,又哪来的深复制浅复制啊。搞不懂了
function setName(obj) {
obj.name = 'obj';
obj = new Object();
obj.name = 'obj2';
}

var person = new Object();
setName(person);
console.log(person.name);//obj

传递参数:所有函数的参数都是按值传递的。基本类型值的传递如同基本类型变量的复制,而引用类型值的传递,如同引用类型变量的复制。

复制变量值:基础类型会创建一个新值,把值复制到新位置,之后彼此独立。引用类型会复制指针,新老变量(复制和被复制的变量)引用同一个对象,改变其中一个,就会影响另一个。

例子可以参考js高级程序设计第三版4.1.3

clipboard.png

把引用类型的变量想成一堆指针,就是全按值传递。

    var foo = {
        bar: function() { return this.baz; },
        baz: 1
    };

    (function(){
        return typeof arguments[0]();//"undefined"
    })(foo.bar);

你看这个例子,如果是传递引用,那么foo.bar应该会被当作函数传进去,后面的typeof就不会是undefined了。对吧。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
你知道吗?

宣传栏