logo头像

叩首问路,码梦为生

JS中的传值与传址

在 JS 中,有两种不同的方式可以操作数据的值,这两种技术分别叫做传值传址

数据值的操作

要知道传址跟传址,首先我们先了解下数据值的操作。

  1. 复制:可以把它赋值给一个新的变量
  2. 传递:可以将他传递给一个函数或者方法
  3. 比较:可以与另外一个值比较,判断是否相等

概念介绍

传值:在赋值过程中,首先对值进行了一份拷贝,而后将这份拷贝存储到一个变量、对象属性或数组元素中。拷贝的值和原始的值是完全独立、互不影响的。当一份数据通过值传递给一个函数,实际上被传递的不是数据本身,而是数据的一份拷贝。因此,如果函数修改了这个值,影响到的只是数据的那份拷贝,而并不影响数据本身。

传址:在赋值过程中,变量实际上存储的是数据的地址(对数据的引用),而不是原始数据或者是数据的拷贝。如果值通过一个地址发生了改变,这个改变也会通过原始地址表现出来。

参阅对比表

传值传址
复制实际复制的是值,存在于两个不同的独立拷贝复制的只是对数值的引用,即地址,如果通过这个新的引用修改了数值,这个改变对最初的引用也是可见的
传递传递给函数的值是一个独立的拷贝,对它的改变函数外没有影响传递给函数的是对数值的一个引用。如果通过这个新的引用修改了数值,这个改变对最初的引用也是可见的
比较比较两个独立的值,判断是否相同比较的是两个的引用,判断引用是否是同一个数值。对两个不同数值的引用不相等,即使这两个数值相等

数据类型

根据操作数据方式的不同,我们可以把数据类型分为两类:基础类型引用类型

  • 基础类型主要有:数字(Number)、布尔类型(Boolean);其操作方式为传值。
  • 引用类型主要有:对象(Object) —— 数组(Array)、函数(Function);其操作方式为传址。

数字和布尔类型是基础类型,它们是由很小的,固定数目字节组成,所以可以通过传值来操作;而数组和函数,是对象的特殊类型,也是引用类型。由于对象没有固定大小,所以无法通过传值进行操作。

实例

传值(赋值操作)

1
2
var a = 1, b = a, a = 2;
console.log("a=" + a + ",b=" + b);

a 先是被赋值为 1,接着把 a 的值赋给 b,这时会进行值的拷贝,因此b = 1;然后又把 a 赋值为 2。在没有执行 a = 2 之前,我们试试下列代码:

1
console.log(a === b);  // 输出为true. 可见它们在内存中是指向同一个位置的。

传值(基础类型)

1
2
3
4
5
6
7
8
9
10
var a = 1;
var b = a; // 将a复制给b
function add1(x,y) { // 函数修改参数的值
x = x + y; // 虽然这个里面将值进行相加,但是仅仅是值的独立拷贝,进行相加,在函数外面没有影响
}
add1(a,b); // 数字类型为传值

alert("a:" + a + "n" + "b:" + b); // a为1,b为1
(a == b) ? c = "true" : c = "false";
alert(c); // c = "true"

传址(引用类型)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var a = ["a", "b", "c", "d"];      // 定义数组,引用类型
var b = a; // 将a复制给b
function add(x) { // 函数修改参数的值
x[0] = "tt";
}
add(b); // 数组对象为传址
alert("a:" + a[0] + a[1] + a[2] + a[3] + "n" + "b:" + b[0] + b[1] + b[2] + b[3]); // b对象修改,则a也会修改,传址
(a == b) ? q = "true" : q = "false"; // 判断 a=b ,返回true
alert(q);

var a = ["a", "b", "c", "d"];
var b = ["a", "b", "c", "d"];
(a == b) ? q = "true" : q = "false"; // 这里定义了两个对象,虽然值一样,但是不是同样的地址,所以为false
alert(q); // 输出"false"

函数内的特殊引用

按值传递一个参数给函数就是制作该参数的一个独立复本,即一个只存在于该函数内的复本。即使按引用传递对象和数组时,如果直接在函数中用新值覆盖原先的值,在函数外并不反映新值。只有在对象的属性或者数组的元素改变时,在函数外才可以看出

1
2
3
4
5
6
7
8
9
10
11
var a1 = [1, 2, 3];
function add(a, b) {
var newa = Array();
newa[0] = a[0] + b;
newa[1] = a[1] + b;
newa[2] = a[2] + b;
a = newa; // 重新覆盖了引用,所以外部是不可见的
alert(a[0]); // 11
}
add(a1, 10);
alert(a1[0]); // 1

字符串类型

前面看了这么多类型,一直都没有介绍字符串类型,它不好直接分为基础类型和引用类型,因为字符串可以是任意的长度,看上去应该是引用类型,可是他却不是对象,所以也不可作为引用类型;总结一下,字符串是按引用(即地址)复制和传递的,但是是按值来比较的。

请注意,假如有两个 String 对象(用 new String(“something”) 创建的),按引用比较它们,但是,如果其中一个或者两者都是字符串值的话,按值比较它们

类型复制传递比较
数字传值传值传值
布尔传值传值传值
字符串不可变不可变传值
对象传址传址传址

参考文章

支付宝打赏 微信打赏

听说赞过就能年薪百万