怎么理解 JavaScript访问变量有按值和按引用两种方式?

JavaScript高级程序设计4.1.3(170页)中有这么一句话:访问变量有按值和按引用两种方式。
这句话怎么理解?什么是按值?什么是按引用?

阅读 7.7k
6 个回答

尽信书不如无书。

我恰好今天刚看了书中这个地方。我觉得书里说的不准确,至少不清楚。

首先要弄清楚一些概念:变量、值、值的类型、引用、对象。

如果这些概念没搞清楚,就没办法讨论这个问题。

变量:变量就是一个定义在某个作用域的名字(name),它是一个identifier。它绑定(bind)了一块内存。

:值就是变量绑定的那块内存里面存放的数据。至于存放的数据的具体代表什么(含义是什么),暂且不管。但是本质上就是一段二进制数。

值的类型:即变量绑定的那块内存里放的数据应该如何去解释,或者说如何解码。在JS中值的类型有很多种,但是可以归结成两类:基本类型和引用类型。基本类型就是说:变量绑定的那块内存里放的数据的含义就是它看起来的那个样子。引用类型就是说:变量绑定的那块内存里放的数据,并不是我真正想要的数据,它是一个元数据、一个地址,一个指向我真正想用的数据的位置的指针。

总结一下就是:变量是一个名字,它绑定一块存储空间,这个空间要么放数据,要么放数据的地址(或者某种引用)。

引用:见上面。

对象:上面说的那些不能被变量直接绑定,而是要通过引用来间接绑定的数据就是对象。而且对象数据与非变量数据相比有一个特点,即它是有内部结构的,即属性

所以在JS中变量有两种模式:

  1. 名字->数据

  2. 名字->数据(引用)->数据(对象)

接下来可以讨论问题了。

问题是讨论JS中变量“访问”有几种类型?按值和按引用?

那么,我们应该首先定义一下什么是“访问”?不知道,因为没有一个地方来给出一个标准定义。但是我猜访问的意思大概是:通过变量去取得你真正想要的数据。假设是这个意思的话,那么很简单,确实是两种,分别对应上面两种变量模式。即基本类型数据就是直接取变量的“值”;而对象类型的数据要通过取变量的值代表的引用,然后再取它指向的对象。

但是,如果不限于“访问”,我们来讨论一下对变量的“操作”呢?

首先来看一下,对一个变量的操作有几种类型。

  1. 属性访问

读:很多操作符都涉及到对变量的读,比如加减乘除等算术运算、关系运算、逻辑运算和位运算等等。这些运算大都是针对基本类型数据(或者先将操作数转为基本类型)的,所以是“按值”操作的。

写:能改变一个变量的值的操作只要三种,即自增、自减和赋值(包括+=这类)。显然也都是“按值”。那么赋值操作呢?也是按值,因为赋值时只是将变量绑定的内存拷贝到另一个变量绑定的内存中,与内存中存的数据的含义无关。

属性访问:属性访问是对对象来说的,只有对象才有属性。(当然JS比较特殊的一点是,对基本类型数据也可以访问属性,这是因为在这里JS执行引擎会把基本类型数据包装成一个对象,这种情况暂不讨论)显然这里需要访问对象的内部状态,要通过引用链接到对象。所以这种情况是按引用。

说了这么多,到后面觉得有些凌乱,有些不严谨了。

试着总结一下:

  1. 对于对象数据才有的操作,是按引用。比如属性访问。

  2. 对于基本类型数据才有的操作,是按值。比如加减乘除。

  3. 对于所有类型数据都有的操作,并且操作的语义与操作数是什么类型无关的情况,按值。比如赋值、传参等。

敬请指正。

在最新的 ECMAScript 标准中,定义了 7 种数据类型,其中 string number boolean null undefined symbol 为原始数据类型,object为引用数据类型

新手上路,请多包涵

值针对的是基本类型。引用针对的是对象,引用传递的是对象的地址(想想C语言的指针)。对于引用的值(对象),可以改变内部状态。

值传递示例:

function hi(a) {
    a = 12;
    console.log("in func: " + a );
}

a = 24;
hi(a);
console.log("out of func: " + a );

输出:

in func: 12
out of func: 24

引用示例:

function hi(a) {
    a.push(44);
    console.log("in func: " + a );
}

a = [2,33];
hi(a);
console.log("out of func: " + a );

输出:

in func: 2,33,44
out of func: 2,33,44

按值访问相当于是将原数据的值进行一次拷贝,给新的变量,原变量发生改变后,按值访问的不会变化。一般是string,number这样的基本类型。

var a = 1;
var b = a;
alert(a+";"+b);//1;1
a = 2;
alert(a+";"+b);//2;1  b不会发生改变,因为是按值访问

按引用是指在内存区内只有一份,新的变量只是拥有一个指向它的指针,一旦内存区内的内容发生变化,所有指向它的引用都将发生变化,一般是对象,包括用户自定义对象和内置对象,Array和Function。

var a = {name: "Zoe"};
var b = a;
console.log(a.name);//Zoe
console.log(b.name);//Zoe

a.name = "Alex"; 
console.log(a.name);//Alex
console.log(b.name);//Alex 按引用访问,指针指向的区域已经被更改

是70页而不是170页,然后这边主要讲的是传递参数的问题,有两大种,一种是基本类型,一种是引用类型

新手上路,请多包涵

于其像书里说的那样,还不如说 访问变量根据变量的值不同,分为访问保存着基本类型值的变量和访问保存着引用类型值的变量。这样是否好理解一点。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏