关于值传递和引用传递,我们首先要理解 JS 不同类型的变量的存储方式。

JS 总共有 8 中数据类型,可以分为基本类型(string、number、boolean、undefined、null、symbol、bigint)和复合类型(Object)两类。

基本类型

基本类型的数据存都储在栈内存中,它们按照值传递的方式进行传递。

  1. var a = 1;
  2. var b = a;
  3. a = 2;
  4. console.log(b); // 1

值传递方式,修改了变量 a,不会影响到 b 的值,但是引用传递则不同。

复合类型

复合类型的数据是存储在堆内存中,它们按照引用传递的方式进行传递。

  1. var o = {
  2. cont: 1
  3. }
  4. var o2 = o;
  5. o.cont = 2;
  6. console.log(o2.cont); // 2

从代码中可以看出,我们修改了 o 对象中的 cont 属性,o2 的 cont 也跟着变了,这就是引用传递造成的影响。

出现这个问题的原因是:对象 o 和 对象 o2,它们指向的内存地址其实是同一个,也就是不管修改 o 还是修改 o2,最终都会作用到同一个堆地址上。

面试题

通过一道题来加深一下对值传递与引用传递的理解。

  1. // 写出输出值,并解释为什么
  2. function test(m) {
  3. m = { v: 5 }
  4. }
  5. var m = { k: 30 };
  6. test(m);
  7. alert(m.v);

这道题的结果是 undefined。

test 中的参数 m 与 外层的 m 是两个不同的变量,尽管他们的引用地址是一样的。但是 test 中的变量 m 被指向了一个新的引用地址。所以和外层的 m 就没有任何关系了。

外层的 m 并没有 v 属性,所以输出 undefined。

其实执行结果等同于下面的代码:

  1. var m = { k: 30 };
  2. var m2 = m;
  3. m2 = { v: 5 };
  4. alert(m.v);