JS参数都是按值传递的

在高程中是这样描述的:

ECMAScript中所有函数的参数都是按值传递的

我们怎么理解这句话呢?

几个例子 :chestnut:

var i = 1;
function test(k) {
    k = 2
    console.log(k)
}
test(i)  //2
console.log(i) //1
var o = {
    value: 1
}
function test(o) {
    o.value = 2
    console.log(o.value)
}
test(o) //2
console.log(o.value) //2
var o = {
    value: 1
}
function test(o) {
    o = 2
    console.log(o)
}
test(o) //2
console.log(o.value) //1
  1. 我们先看第一个例子,很好理解,按值传递,当 i 被传进 test 方法,相当于拷贝了一份 i ,
    设这个值为 _i ,我们后续修改的都是 _i ,而不会影响原值

  2. 再看第二个例子,把 o 传进 test 方法,传递的是地址值(即引用),所以当改变 o
    value 的时候,源对象也会被影响,因为两者是引用的同一个地址

  3. 按照上面的说法,此处修改了 o 的值,源对象也应该被修改啊,然而源对象并没有变,是哪
    里出错了吗?难道说 js 并不是按值传递吗?

进一步思考

我们知道, js 数据类型分为两种:值类型和引用类型,值类型存储在栈中,引用类型存储在堆中,
同时维护一个地址在栈中。而参数传递方式就是指实参传递给形参的一个过程。值传递就是将实参在
栈中的值传给

从这个角度来看三个例子:

  1. 在栈中申请一个地址 001 ,给它一个值 1,将这个值传递到 test 方法,为形参 o在栈
    中申请一个地址 002, 将 1赋给 002,所以修改该值的时候,修改的是 002 地址的
    值,001 的值并没有发生改变。所以再次打印,依然是 1

  2. o 是引用类型,所以需要在堆中申请一个地址 011,保存一个对象(属性 value 为 1),
    然后在栈中申请一个地址 001 ,这个地址保存了 011 这个内存地址值,然后为 test 方法
    的形参 o 在栈中申请一个地址 002 ,它保存了 011 这个内存地址值,所以当修改它的值
    的时候,会去找 011 这个地址的对象。所以再次打印 o 的时候,它的值已经发生了变化

  3. o 是引用类型,在堆中申请一个地址 011 ,保存一个对象(属性 value 为 1),然后
    在栈中申请一个地址 001 ,这个地址保存了 011 这个内存地址值,然后 test 方法的形参
    o 在栈中申请一个地址 002,它保存了 011这个内存地址值,到目前为止跟第二个例子
    都是一样的,接下来不同的地方来了,它给形参 o 赋值为 2,由于 2 是 Number 类型,
    所以直接给 002 这个地址赋值为 2,但是源对象在堆中的值并没有改变,所以第一次打印
    2,第二次打印仍然为 1

结论

大家不要纠结于是值传递还是引用传递或者是 call by sharing。只要搞懂上面的几个概念,
就能清楚了解js参数的传递方式