值与引用

JavaScript对值和引用的赋值/传递在语法上没有什么区别,完全根据值的类型来决定。

举个例子:

// 简单值赋值
var  a = 2;
var b = a;  // b只是a的值的一个复本
b++;
a; // 2
b; // 3

例子中 2 是一个标量基本类型值,所有变量a持有该值的一个复本,b持有它的另外一个复本。 b更改时,a的值保持不变。

// 复合值赋值
var c = [1, 2, 3, 4];
var d = c; // d是[1, 2, 3, 4]的一个引用
d.push(5);
c; // 1, 2, 3, 4, 5
d; //1, 2, 3, 4, 5

c 和 d 则分别指向同一个复合值[1, 2, 3, 4]的两个不同的引用。 注意:c 和 d 仅仅是指向值 [1, 2, 3, 4], 并非持有。所以它们更改的是同一个值(例如调用.push(5)), 随后它们都指向更改后的新值[1, 2, 3, 4, 5]。

结论:
1、简单值(即基本类型值)总是通过值复制的方式类赋值/引用,包括 null、undefined、字符串、数字、布尔和ES6中的symbol。

2、复合值——对象(包括数组、封装对象)和函数,则总是通过引用复制的方式来赋值/传递。



我们要明白的是引用复制指向的是值本身而非变量,所以一个引用无法更改另一个引用的指向

var a = [1, 2, 3];
var b = a;
a; // [1, 2, 3]
b; // [1, 2, 3]

b = [4, 5, 6];
a; // [1, 2, 3]
b; // [4, 5, 6]

b = [4, 5, 6] 并不影响a指向值[1, 2, 3], 除非b不是指向数组的引用,而是指向a的指针,但是JavaScript中不存在这种情况!

有时候下面这种情况又让人很是困惑:

function foo (x) {
  x.push(4);
  x; // 1, 2, 3, 4

  x = [4, 5, 6];
  x.push(7);
  x; // [4, 5, 6, 7];
}

var a = [1, 2, 3];
foo(a);
a; // 是[1, 2, 3, 4],不是[4, 5, 6, 7];

我们向函数传递a的时候,实际是将引用a的一个复本赋值给x,而a仍然指向[1, 2, 3]. 在函数中我们可以通过x来更改数组的值(.push(4)之后变为[1, 2, 3, 4])。但x = [4, 5, 6, 7] 并不影响a的指向,所有a仍然指向[1, 2, 3, 4]。

我们不能通过x来更改引用a的指向,只能更改a和x的共同指向的值。

如果我们要更改a的值为[4, 5, 6, 7],必须更改x指向的数组,而不是为x赋值一个新的数组。

function foo(x) {
    x.push(4);
    x; // [1, 2, 3, 4]

    x.length = 0; // 清空数组
    x.push([4, 5, 6, 7]);
    x; //[4, 5, 6, 7]
}
var a = [1, 2, 3];
foo(a);
a; // 是[4, 5, 6, 7]而不是[1, 2, 3, 4]

从上例中我们可以看出,x.length = 0和x.push(4) 并没有创建新的数组,而是更改了当前数组。于是a指向的值变成了[4, 5, 6, 7]。

所以我们无法自行决定使用值赋值还是引用复制, 一切由值的类型来决定

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值