深入理解 JS 参数传递

发布于: 2020 年 07 月 22 日
深入理解 JS 参数传递

由于在 JavaScript 中访问变量的方式有两种:按值访问及按引用访问,那么参数传递是以是什么方式传递的呢?



在《JavaScript 高级程序设计》一书中有写到:

ECMAScript 中所有函数的参数都是按值传递的。也就是说,把函数外部的值复制给函数内部的参数,就和把值从一个变量复制到另一个变量一样。基本类型值的传递如同基本类型变量的复制一样,而引用类型值的传递,则如同引用类型变量的复制一样。

(P70页)



那么我们就通过几个例子来分析看一下。



传入基本类型



function add(num) {
num = num + 1;
return num;
}
var count = 0;
console.log(add(count)) // 1
console.log(count) // 0



这里我们声明了一个变量 count,然后调用 add 函数,传入 count,此时相当于把 count 复制了一份,赋值给 num,各自占用单独的空间:





因此在 add 函数内部对 num 的修改,并不会影响到原来的 count:





上面演示的是一个基本类型,那么如果传入的是一个引用类型呢?



传入引用类型



首先来看第一个例子:



function foo(o) {
o = {b: 1};
return o;
}
var obj = {a: 1};
console.log(foo(obj)); // {b: 1}
console.log(obj); // {a: 1}



通过运行结果,看起来传入引用类型貌似也是复制了一份,对原来的并未有影响?



首先看一下引用类型的存储方式:





引用类型在栈空间中存储的实际上是一个指针,指向堆内存中实际存储的位置。



当 obj 传入 foo 函数内部,对于值也是复制了一份,只不过是指向同样的堆空间,他们的引用还是一样的。



但是在 foo 函数内部,对于 o 的修改实际上是赋值操作,直接覆盖,指向了新的地址,因此对于 obj 并没有影响,如图所示:





然后再来看下一个例子:



function foo(o) {
o.a = 2;
return o;
}
var obj = {a: 1};
console.log(foo(obj)); // {a: 2}
console.log(obj); // {a: 2}



由于在函数 foo 内部执行 o.a = 2,修改的是堆空间中的对象,而这个对象和 obj 共享,因此也影响到了 obj 的变化:





总结

通过以上分析,我们可以知道 JavaScript 中的所有参数传递均为值传递,存在一个值复制的过程,基本类型直接复制出新的值,而引用类型复制的是指针,指向堆空间中的实际存储对象。



思考:可以分析下如下代码中各个 console.log 的输出结果



var obj = {n:1};
(function(obj){
console.log(obj.n)
obj.n=3;
var obj = {n:2};
console.log(obj.n)
})(obj);
console.log(obj.n)



Ok, 以上就是关于 JS 中参数传递的一些总结😯。



Photo by Brooke Cagle on Unsplash

发布于: 2020 年 07 月 22 日 阅读数: 3
用户头像

蓝调达里

关注

一个前端工程师 2018.01.01 加入

每天进步一点点ヽ(•̀ω•́ )ゝ,公众号:前端柠檬

评论

发布
暂无评论
深入理解 JS 参数传递