资讯专栏INFORMATION COLUMN

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

马永翠 / 2492人阅读

摘要:中参数传递为什么必定是按值传递,有些疑惑,以下是一些理解。指两个变量是两个独立的变量,唯独在于他们各自的对象都是在同一个堆内存空间的。就是实际上没有把堆内存中的对象作为函数参数。

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

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

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

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

简单来说,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),外部变量不会有改变。就是实际上没有把堆内存中的对象作为函数参数。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/93204.html

相关文章

  • JS函数参数传递和引用传递

    摘要:学习中函数参数值传递和引用传递的学习中函数参数值传递和引用传递在红宝书中说到,中所有函数的参数都是按值传递的。 学习JS中函数参数值传递和引用传递的学习 JS中函数参数值传递和引用传递 在JavaScript红宝书中说到,ECMAScript中所有函数的参数都是按值传递的。理解这个概念先要从JS的堆内存和栈内存说起:栈内存为自动分配的内存空间,它由系统自动释放;堆内存则是动态分配的内存...

    ZHAO_ 评论0 收藏0
  • JS程序

    摘要:设计模式是以面向对象编程为基础的,的面向对象编程和传统的的面向对象编程有些差别,这让我一开始接触的时候感到十分痛苦,但是这只能靠自己慢慢积累慢慢思考。想继续了解设计模式必须要先搞懂面向对象编程,否则只会让你自己更痛苦。 JavaScript 中的构造函数 学习总结。知识只有分享才有存在的意义。 是时候替换你的 for 循环大法了~ 《小分享》JavaScript中数组的那些迭代方法~ ...

    melody_lql 评论0 收藏0
  • 理解JavaScript变量和类型

    摘要:接着下一个例子赋予副本新的地址可见,函数参数传递的并不是变量的引用,而是变量拷贝的副本,当变量是原始类型时,这个副本就是值本身,当变量是引用类型是,这个副本是指向堆内存的地址。 转载自ConardLi: 《【JS进阶】 你真的掌握变量和类型了吗》 公众号: code秘密花园 1. JavaScript数据类型 ECMAScript标准规定了7种数据类型,这些数据类型分为原始类型和对象...

    xiaodao 评论0 收藏0
  • JavaScript参数传递方式

    这几天遇到js参数传递方式的问题,深切探究一番,将所得结果总结于此 常见的几种传递方式 传值调用(call by value) 在传值调用中实际参数被求值,其值被绑定到函数中对应的变量上(通常是把值复制到新内存区域)。在函数返回后调用者作用域里的曾传给函数的任何东西都不会变。 传引用调用(call by reference) 在传引用调用求值中,传递给函数的是它的实际参数的隐式引用(即实际参数的地...

    jcc 评论0 收藏0
  • js类型、引用类型、堆、栈、函数参数传递方式、连续赋等概念学习

    摘要:值类型基本类型和栈内存值类型也称为原始数据或原始值这类值存储在栈内存中基本类型的值不可以修改。目前中的基本类型一共有六种。堆的使用规则当创建数组时,就会在堆内存中创建一个数组对象,并且在栈内存中创建一个对数组的引用。 值类型(基本类型)和栈内存 值类型也称为原始数据或原始值(primitive value).这类值存储在栈(stack)内存中, 基本类型的值不可以修改。每当我们定义一个...

    hizengzeng 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<