js中函数参数值传递的理解

AlgoLuminaryX
• 阅读 1204

js中参数传递为什么必定是按值传递,有些疑惑,以下是一些理解。

js高级程序设计(第三版)的第四章,表明了基本数据类型(Undefined、Null、Boolean、Number、String)是按值访问的,对象是按引用访问的。

首先,看下引用类型变量是怎样的(obj1、obj2都是对象类型):

var obj1 = new Object();
var obj2 = obj1;

js中函数参数值传递的理解

简单来说,obj1、obj2都是变量,他们分别有一个指针,各自指向各自的栈内存,然后栈内存中存放有堆内存地址和一些别的数据,那么就又有第二个指针根据栈内存中存放的地址指向堆内存,堆内存中存放的是同一个的对象(因为obj1和obj2栈内存中的地址是相同的)。


注意到书中原话:

当从一个变量向另一个变量复制引用类型的值时,同样也会将存储在变量对象中的值复制一份放到为新变量分配的空间中。不同的是,这个值的副本实际上是一个指针,而这个指针指向存储在堆中的一个对象。复制操作结束后,两个变量实际上将引用同一个对象。因此,改变其中一个变量,就会影响另一个变量。

然后,实验代码如下:

var t1 = new Object();
var t2 = t1;
t2.name ="t1";
t2 = new Object();      //本质为t2的指针指向了一个新空间
console.log(t1.name);   //输出t1
console.log(t2.name);   //输出undefined

分析:

 var t2 = t1;

这行代码实质是把t1栈内存中的数据复制在t2的栈内存中,栈内存中存放的堆内存地址就是一样的,因而指向了同一个堆内存地址,即指向同一个对象。

t2 = new Object();

这行代码就是把t2在栈内存中存放的地址改变了,变成了一个此刻不在使用的地址,然后t2的指针指向了这个新地址,所以之后t1和t2无关了。

可以看出,书中写的 复制操作结束后,两个变量实际上将引用同一个对象。 指两个变量是两个独立的变量,唯独在于他们各自的对象都是在同一个堆内存空间的。我通俗理解为:t1和t2两个变量本身是按值访问的,t1和t2指向的对象是按引用访问的,但实际上定义变量,自然是为了操作变量指向的对象。


下面是对于函数参数传递中的一些理解:

先看一下,让人误以为参数是引用传递的代码:

var t1 = new Object();
function change(obj){
    obj.name = "lalala";
}
change(t1);
console.log(t1.name);  //输出了lalala

结果是外部的t1多了一个属性name,原因就在于确实是参数传递,把t1按值传递给了obj,操作他们各自属性的时候,属性仍然是按引用传递的,我们传的参数又不是t1的属性。

强调一下,我上面说t1的属性,是不正确的说法,严格来说,不是t1多了一个属性,也不是t1的属性,而是t1指向的对象多了一个属性,或者说那是t1指向的对象的属性,t1只是一个变量罢了。

再看下面代码:

var t1 = new Object();
function change(obj){
    obj.name = "t1";
    obj = new Object();
    obj.name = "new t1";
}
change(t1);
console.log(t1.name); //输出t1

输出结果,t1.name仍然是‘‘t1’’,再进行obj = new Object()时候,因为栈内存中数据的改变,这里的obj最终指向的对象不是t1指向的对象了,就函数内部再也操作不到t1一开始指向的对象了,类似于下面代码中t2的重新声明。

var t1 = new Object();
var t2 = t1;
t2.name ="t1";
t2 = new Object();
console.log(t1.name);  //输出t1
console.log(t2.name);  //输出undefined

结论:函数的参数传递是按值传递的,但对于参数是引用类型变量,该变量指向的对象的属性(就是t1.name之类的)是按引用访问的,因此改变对象的属性会反映在外部对象上;但变量本身按值传递了,因此改变内部变量(就只改变t1、t2),外部变量不会有改变。就是实际上没有把堆内存中的对象作为函数参数。

点赞
收藏
评论区
推荐文章
晴空闲云 晴空闲云
4年前
javascript实践教程-05-数据类型
本节目标1.掌握js中7种数据类型。2.掌握5种基本数据类型number、string、boolean、null、undefined的声明。3.掌握js中数组的声明和数组相关的方法。4.掌握js中对象的声明和属性、方法的使用。内容摘要本篇介绍了js中的7种数据类型,其中5种基本数据类型:number、string、boolean、null、unde
九旬 九旬
3年前
函数参数传递
函数参数传递在JavaScript中函数传参,分为两种:基础类型(Number、String、Boolean..)引用类型(Object、Array、Funcion..)基础类型传参看下面的例子:js
待兔 待兔
5年前
[Dart]Dart语言之旅<二>:变量
变量以下是创建变量并为其分配值的示例:varname'Bob';变量是引用。名为name的变量包含对值为“Bob”的String类型的对象的引用。默认值未初始化的变量的初始值为null。即使是数字类型的变量,初始值也为null,因为数字也是对象。intlineCount;assert(lineCountnull)
劳伦斯 劳伦斯
4年前
前端面试题自检 JS CSS 部分
JS类型JavaScript的简单数据类型Number,String,Boolean,Undefined,Null,Symboltypeof操作符的返回值numberstringbooleanundefinedobjectfunction
Wesley13 Wesley13
4年前
Java中只存在值传递
在Java中并不存在引用传递(即地址传递),对于变量(可以是基本数据类型,也可以是引用数据类型)而言,可以理解为就是一个地址。传递,存在着拷贝操作。举个列子:1、在方法参数上,传递的是基本数据类型。定义了一个用于交换两个整型数的方法:publicstaticvoidswap(inta,intb){in
Wesley13 Wesley13
4年前
Java对象的浅拷贝和深拷贝&&String类型的赋值
Java中的数据类型分为基本数据类型和引用数据类型。对于这两种数据类型,在进行赋值操作、方法传参或返回值时,会有值传递和引用(地址)传递的差别。浅拷贝(ShallowCopy):①对于数据类型是基本数据类型的成员变量,浅拷贝会直接进行值传递,也就是将该属性值复制一份给新的对象。因为是两份不同的数据,所以对其中一个对象的该成员变量值进行修改,
Stella981 Stella981
4年前
JavaScript的深拷贝和浅拷贝
一、数据类型数据分为基本数据类型(String,Number,Boolean,Null,Undefined,Symbol)和对象数据类型。、1.基本数据类型的特点:直接存储在栈(stack)中的数据2.引用数据类型的特点:存储的是该对象在栈中引用,真实的数据放在堆内存里。引用数据类型在栈中存储了指针,该指针指向堆中该实
Wesley13 Wesley13
4年前
Java里的按值传递与引用传递
按值传递还是按引用传递这个在Java里面是经常被提起的问题,也有一些争论,似乎最后还有一个所谓的结论:“在Java里面参数传递都是按值传递”。事实上,这很容易让人迷惑,下面先分别看看什么是按值传递,什么是按引用传递,只要能正确理解,至于称作按什么传递就不是个大问题了。1:按值传递是什么指的是在方法调用时,传递的参
Stella981 Stella981
4年前
JavaScript学习小结
JavaScirpt变量可用来保存两种类型值:基本类型值,引用类型值基本类型值:Undefined,Null,Boolean,Number,String基本类型及引用类型值特点:1.基本类型值在内存中占据固定大小的空间,被保存在栈内存中;2.从一个变量向另一个变量复制基本类型值,会创建这个值的一个副本;
Easter79 Easter79
4年前
Swift3.0 类和结构体的选择
结构体实例总是通过值传递,类实例总是通过引用传递先说说值类型和引用类型的区别值类型被赋予给一个变量、常量或者被传递给一个函数的时候,其值会被拷贝在Swift中,所有的结构体和枚举类型都是值类型。这意味着它们的实例,以及实例中所包含的任何值类型属性,在代码中传递的时候都会被复制。引用类型在被赋予到一个变量、常
Stella981 Stella981
4年前
JavaScript深入之参数按值传递
定义在《JavaScript高级程序设计》第三版4.1.3,讲到传递参数:ECMAScript中所有函数的参数都是按值传递的。什么是按值传递呢?也就是说,把函数外部的值复制给函数内部的参数,就和把值从一个变量复制到另一个变量一样。按值传递举个简单的例子:varvalue1;fun
AlgoLuminaryX
AlgoLuminaryX
Lv1
写不成书,只记得、相思一点。
文章
3
粉丝
0
获赞
0