深入理解JavaScript变量、指针与引用机制

作者:灵感回路

时间:2026-10-22

浏览:95

本文深入解析JavaScript中变量、指针与引用的核心机制。通过对比基本类型与引用类型的内存存储差异,阐明对象比较、原型链查找及函数参数传递(按值传递)的具体行为,帮助开发者准确理解内存地址与对象引用的关系。

文章目录

JavaScript变量、指针与引用机制详解

本文通过具体示例,详细解析JavaScript中变量、指针及引用的功能与操作方式,供读者参考学习。

变量的内存分配与赋值

1、变量

我们常会思考:编程语言中的“变量”究竟代表什么含义?

实际上,当定义变量a时,系统会在存储器中分配一组存储单元,并将其命名为a。变量a的值,即这组存储单元中存放的具体数据。

以JS代码为例:


var a;
a=10;

第一行语句在存储器中分配一组存储单元,命名为a;

第二行语句在该单元中存入数字10。

此时变量a的值为10,意味着存储单元组a中保存的信息是10。

若对a再次执行赋值操作:


a="hello";

此时a的值变为字符串“hello”。这表示将存储单元组a中的信息更新为字符串“hello”,原数字10被覆盖。

指针的概念与JS中的体现

2、指针

若将变量a在存储器中的地址存入另一个变量b,会发生什么?

直接访问变量b时,得到的是变量a在存储器中的地址,而非a的值。此时,变量b被称为指针。

由此产生一个问题:如何通过变量b访问到变量a的值?

在C语言中,通常使用*符号,例如:


int c=10,b;
int *p;/*p是指向int类型的指针*/
p=&c;/* &c获取变量c的地址,然后赋值给变量p,这样p存储的是变量c的地址,即p是指向c的指针*/
b=*p;/* *p访问p指向的对象,然后将值赋值给b*/

虽然JS中没有显式的指针变量类型,但指针的应用无处不在。例如:


var o1={b:1};
var o2={b:1};
o1===o2;//false
o1==o2;//false

引用类型的比较与对象地址

这里o1和o2指向相同的对象结构,为何不相等?这需要深入理解JavaScript中的引用类型与指针机制。

首先需明确:

对o1和o2赋值时,并非在o1地址中存储对象{b:1}、在o2地址中存储对象{b:1}。

其次,实际发生的操作是:

var o1={b:1}在堆内存中创建了一个对象{b:1},o1存储了该对象在堆内存中的地址,即o1是一个指针,指向{b:1};

同理,var o2={b:1}也在堆内存中创建了一个对象{b:1},o2存储了该对象在堆内存中的地址,即o2也是一个指针,指向{b:1};

由于两个相同的对象{b:1}是先后创建,它们在堆内存中占据不同的地址。

此外还需知道:

在JavaScript中,引用类型(对象、数组、正则、Date、函数)的比较,实质是比较指针是否指向存储器中的同一段地址。只有指向同一地址时,两者才相等。

显然,o1这个指针指向堆内存中创建的第一个对象{b:1};

o2指针则指向堆内存中创建的第二个对象{b:1};

但两个对象相互独立,并非同一对象,因此o1和o2未指向相同的堆内存地址,故不相等。

原型链与对象引用

再看常见应用场景:


var o={a:1};
o.__proto__===Object.prototype;//true

对象o的构造函数是Object,Object有一个prototype属性,且prototype是一个指针,指向存储器中的一个对象,此对象将被由构造函数创建的对象实例所共享。

作为Object的实例,o也有一个指针__proto__,它指向Object的prototype属性所指向的对象。

此处全等判断返回true,清晰表明两者指向相同的堆内存地址,即指向同一对象。

引用类型的赋值与共享

若想主动让两个引用类型指向同一对象,应如何操作?


var obj1={b:1};
var obj2=obj1;
obj1===obj2;//true
obj1==obj2;//true

可见,对于引用类型,直接使用'='赋值即使两者指向同一对象。 因此推测,若通过obj1修改对象值,obj2再次访问时将看到修改后的对象:


obj1.name='ls';
obj1;//{b: 1, name: "ls"}
obj2;//{b: 1, name: "ls"}

确实如此。作为对比:


o1.name='ls';
o1;//{b: 1, name: "ls"}
o2;//{b: 1}

基本类型与引用类型的区别

那么,对于基本类型呢?


var s1=1;
var s2=2;
s1===s2;//true

在JS中,基本类型只需值相等,两个变量即视为相等。

引用类型的值与函数参数传递

3、引用

首先,需深入理解引用类型的值。

前文提到,obj1和obj2指向堆内存中存储的同一对象。访问obj1和obj2时,均返回同一对象。可以说:obj1的值与obj2的值相同。

对于o1和o2,它们指向堆内存中不同地址的两个{b:1}对象,o1和o2拥有不同的值。

因此,对于引用类型,所谓的“值”,指的是保存在内存中的对象。若是同一对象,则值相同;不同对象则值不同。

在JS中,参数传递均按值传递。例如:


var a1=1,b1=2;
function add(a,b){
  a++;
  b--;
  return a+b;
};
add(a1,b1);//3
a1;//1
b1;//2

此处,函数add中的形参a、b分别得到变量a1、b1的值的拷贝,即按值传递。

在add函数执行环境中对a、b的操作,不会影响全局变量a1、b1。

再看引用类型:


function setName(obj){
   obj.name="Nicholas";
   obj=new Object();
   obj.name="Greg";
}
var person=new Object();
setName(person);
alert(person.name);//"Nicholas"

执行setName(person)时,person指向的内存地址被传入obj,使obj也指向相同的内存地址,即同一对象。此处的按值传递,传递的是内存地址。

若通过obj修改该对象,外部访问person时也能体现出来。

我们可能产生疑问:既然指向同一对象,为何不是按引用传递?

首先,观察函数内部对obj重新赋值,使obj指向新创建的对象。若按引用传递,外部person也会指向新创建的对象。实际上,person仍指向原对象。

对于引用类型的按值传递,可通俗理解为:

1、实参将指向的内存地址传递给形参,按值传递的值即内存地址; 2、形参修改它和实参共同指向的对象后,外部实参会反映出来; 3、但形参始终无法修改实参指向的内存地址,即若将形参指向新对象,实参不会指向新对象。

基于以上三点,不难理解上述代码的运行结果。

更多关于JavaScript相关内容感兴趣的读者可查看本站专题:《JavaScript数组操作技巧总结》、《JavaScript事件相关操作与技巧大全》、《JavaScript数据结构与算法技巧总结》、《JavaScript操作DOM技巧总结》及《JavaScript字符与字符串操作技巧总结》

希望本文所述对大家JavaScript程序设计有所帮助。

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章