技术文章

JavaScript中函数都是值传递吗?

值传递在不同层面有不同的意义!

你可以认为JavaScript的函数调用参数都是值传递,也可以认为分值传递和引用传递两种!这两种情况下值传递的含义并不同,但是后者是大部分程序员最先接触的。

如果你能明白我下面说的,就不会再在这上面困惑,换到其它语言也同理。

JavaScript

语言设计层面

JavaScript的类型设计里有基本类型(值类型)和引用类型两种,基本类型分配在堆栈,或者依附于引用类型存储在堆中。看到值类型存储在堆中,估计很多人就要开始吐槽了!但是要冷静,从内存角度好好想一想引用类型的实例到底是什么?它不过是一堆值类型和内嵌其它引用类型的组合而已。这样递归想下去,你会明白,最终的数据都是靠基本的值类型来承载的。也就是堆里面除了少部分引用对应的数据结构,大部分都是值类型数据。在考虑值类型和引用类型的区别时,你考虑过这点么?

从语言层次表现上来看:函数的参数传递,值类型会被复制一份,引用类型的引用会被复制一份,此时两个引用指向同一个副本。如果你访问或修改引用类型的数据字段,实际上修改的是同一份数据。这个比较容易理解吧?

所以从这个层面上可以说分值传递和引用传递两种。这里的值传递和引用传递其实包含了语言特性在里面。

函数调用角度

假设我们不理会语言对于基本类型或者值类型的设计,单单从函数调用角度看呢?

通过上面的描述,你已经知道,值类型被复制了一份,引用也被复制了一份,从函数自身的角度出发,它只完成了复制功能,对于基本类型,它复制基本类型代表的数据,对于引用类型,它复制引用类型的引用(如果放在C语言,把引用换成指针可能更直观)。

本质上来看,函数调用在参数处理这一块,只做了复制处理,所以你可以说它是值传递。只不过这里的值其实包含了上面语言层面的两个东西:值类型的值、引用或指针。

总结

统一概念的内涵是我们程序员碰到的最大问题,这里的值传递就是典型的问题。本质只有一个,但是大家站在不同角度,不同层次,就会赋予概念不同的内涵,如果内涵都不同,就来讨论结论问题,是没有结果的。