JS中的传值与传址
在 JS 中,有两种不同的方式可以操作数据的值,这两种技术分别叫做传值和传址。
数据值的操作
要知道传址跟传址,首先我们先了解下数据值的操作。
- 复制:可以把它赋值给一个新的变量
- 传递:可以将他传递给一个函数或者方法
- 比较:可以与另外一个值比较,判断是否相等
概念介绍
传值:在赋值过程中,首先对值进行了一份拷贝,而后将这份拷贝存储到一个变量、对象属性或数组元素中。拷贝的值和原始的值是完全独立、互不影响的。当一份数据通过值传递给一个函数,实际上被传递的不是数据本身,而是数据的一份拷贝。因此,如果函数修改了这个值,影响到的只是数据的那份拷贝,而并不影响数据本身。
传址:在赋值过程中,变量实际上存储的是数据的地址(对数据的引用),而不是原始数据或者是数据的拷贝。如果值通过一个地址发生了改变,这个改变也会通过原始地址表现出来。
参阅对比表
传值 | 传址 | |
---|---|---|
复制 | 实际复制的是值,存在于两个不同的独立拷贝 | 复制的只是对数值的引用,即地址,如果通过这个新的引用修改了数值,这个改变对最初的引用也是可见的 |
传递 | 传递给函数的值是一个独立的拷贝,对它的改变函数外没有影响 | 传递给函数的是对数值的一个引用。如果通过这个新的引用修改了数值,这个改变对最初的引用也是可见的 |
比较 | 比较两个独立的值,判断是否相同 | 比较的是两个的引用,判断引用是否是同一个数值。对两个不同数值的引用不相等,即使这两个数值相等 |
数据类型
根据操作数据方式的不同,我们可以把数据类型分为两类:基础类型和引用类型。
- 基础类型主要有:数字(Number)、布尔类型(Boolean);其操作方式为传值。
- 引用类型主要有:对象(Object) —— 数组(Array)、函数(Function);其操作方式为传址。
数字和布尔类型是基础类型,它们是由很小的,固定数目字节组成,所以可以通过传值来操作;而数组和函数,是对象的特殊类型,也是引用类型。由于对象没有固定大小,所以无法通过传值进行操作。
实例
传值(赋值操作)
1 | var a = 1, b = a, a = 2; |
a 先是被赋值为 1,接着把 a 的值赋给 b,这时会进行值的拷贝,因此b = 1;然后又把 a 赋值为 2。在没有执行 a = 2 之前,我们试试下列代码:
1 | console.log(a === b); // 输出为true. 可见它们在内存中是指向同一个位置的。 |
传值(基础类型)
1 | var a = 1; |
传址(引用类型)
1 | var a = ["a", "b", "c", "d"]; // 定义数组,引用类型 |
函数内的特殊引用
按值传递一个参数给函数就是制作该参数的一个独立复本,即一个只存在于该函数内的复本。即使按引用传递对象和数组时,如果直接在函数中用新值覆盖原先的值,在函数外并不反映新值。只有在对象的属性或者数组的元素改变时,在函数外才可以看出
1 | var a1 = [1, 2, 3]; |
字符串类型
前面看了这么多类型,一直都没有介绍字符串类型,它不好直接分为基础类型和引用类型,因为字符串可以是任意的长度,看上去应该是引用类型,可是他却不是对象,所以也不可作为引用类型;总结一下,字符串是按引用(即地址)复制和传递的,但是是按值来比较的。
请注意,假如有两个 String 对象(用 new String(“something”) 创建的),按引用比较它们,但是,如果其中一个或者两者都是字符串值的话,按值比较它们
类型 | 复制 | 传递 | 比较 |
---|---|---|---|
数字 | 传值 | 传值 | 传值 |
布尔 | 传值 | 传值 | 传值 |
字符串 | 不可变 | 不可变 | 传值 |
对象 | 传址 | 传址 | 传址 |
参考文章
听说赞过就能年薪百万