最近在学习数据结构和算法的时候,常常会遇到需要交换两个数值的情况,使用解构赋值虽然简单快速,但如果能把代码封装成一个
swap
函数,可以使代码更加简洁,也更具可读性,但是在写出来后才发现其中的问题所在。
众所周知,JavaScript 中的变量分为原始值
和引用值
两种数据类型,其中原始值对应 Undefined、null、Boolean、Number、String 和 Symbol 六种类型,而引用值对应 Object、Array 等。访问原始值是按值访问
的,而引用值则是按引用访问
的。在复制变量和传参的时候,两种访问方式存在根本上的不同。
按值访问的类型,在复制和传递变量时,会生成一个独立的新变量,互不影响,变量独立地储存于栈内存中。
按引用访问的类型,复制和传递变量时,实际上传递的是同一个指针,指向同一个堆内存中的对象。
正因此,如果想要编写一个swap
函数,如下
|
|
在外部调用时会发现毫无效果
|
|
这是因为调用函数传参时,实际上复制了一份新的 a 和 b 作为变量进入函数,在函数结束的时候这两个变量便被清除,因此对函数外部的变量无法造成影响。
但是对于对象而言,在传参的时候实际上传入的是指向该对象的指针,所以在函数内部对该对象的修改会反映到全局中,如下
|
|
所以对于按值访问的对象,从根本上就不可能通过函数传参进行改变,这是因为传入的参数实际上是独立于外部变量的一个新变量,其只存在于该函数的生命周期内,函数执行完毕后就会清除自身作用域内的局部变量,所以 swap 函数对原始值是无法生效的。
但是对于对象而言,在任何地方对其进行的修改都会导致该对象本身值的变化,这也是为什么Vue
的ref
函数调用时需要把数据封装成对象的原因。
“在任何值周围都有一个封装对象,这样我们就可以在整个应用中安全地传递它,而不必担心在某个地方失去它的响应性”
——Vue 官方文档