关于值传递和引用传递,我们首先要理解 JS 不同类型的变量的存储方式。
JS 总共有 8 中数据类型,可以分为基本类型(string、number、boolean、undefined、null、symbol、bigint)和复合类型(Object)两类。
基本类型
基本类型的数据存都储在栈内存中,它们按照值传递的方式进行传递。
var a = 1;var b = a;a = 2;console.log(b); // 1
值传递方式,修改了变量 a,不会影响到 b 的值,但是引用传递则不同。
复合类型
复合类型的数据是存储在堆内存中,它们按照引用传递的方式进行传递。
var o = {cont: 1}var o2 = o;o.cont = 2;console.log(o2.cont); // 2
从代码中可以看出,我们修改了 o 对象中的 cont 属性,o2 的 cont 也跟着变了,这就是引用传递造成的影响。
出现这个问题的原因是:对象 o 和 对象 o2,它们指向的内存地址其实是同一个,也就是不管修改 o 还是修改 o2,最终都会作用到同一个堆地址上。
面试题
通过一道题来加深一下对值传递与引用传递的理解。
// 写出输出值,并解释为什么function test(m) {m = { v: 5 }}var m = { k: 30 };test(m);alert(m.v);
这道题的结果是 undefined。
test 中的参数 m 与 外层的 m 是两个不同的变量,尽管他们的引用地址是一样的。但是 test 中的变量 m 被指向了一个新的引用地址。所以和外层的 m 就没有任何关系了。
外层的 m 并没有 v 属性,所以输出 undefined。
其实执行结果等同于下面的代码:
var m = { k: 30 };var m2 = m;m2 = { v: 5 };alert(m.v);
