ECMAScript中函数传递的参数是object的话,是按值传递还是按引用传递?

ECMAScript中函数传递的参数是object的话,是按值传递还是按引用传递?

之前看书时,有下面2段代码,当时看的时候感觉不甚理解,后来查了很多资料,现在整理了一下,分享出来一起学习。

function setName(obj) {
    obj.name = "Nic";
};
var person = new Object();
setName(person);
alert(person.name); // Nic
function setName(obj) {
    obj.name = "Nic";
    obj = new Object();
    obj.name = "lala";
};
var person = new Object();
setName(person);
alert(person.name); // Nic
ES中包含两种不同数据类型的值:基本类型值和引用类型值。
  • 基本类型值是指简单的数据段,比如:UNdefined、Null、Number、String、Boolean。
  • 而引用类型值指可能由多个值构成的对象。比如Object,Array,Function,Date等,引用类型的值是保存在内存中的变量。引用类型的值是按引用访问的。因为js不允许直接访问内存中的位置(不能直接操作对象的内存空间),在操作对象时,实际是在操作对象的引用而不是实际对象。
不同类型值存储在内存中的不同位置
  • 基本类型值:存储在栈(stack)中,也就是说,它们的值直接存储在变量访问的位置。因为可以操作保存在变量中的实际的值,基本数据类型是按值访问的,而且不能给基本类型的值添加属性和方法,所以这些基本类型占据的空间是固定的,可将他们存储在较小的内存区域 – 栈中。这样存储便于迅速查寻变量的值。
  • 引用类型值:存储在堆(heap)中的对象,也就是说,存储在变量处的值是一个指针(point),指向存储对象的内存地址。这是因为:引用值是对象,对象的属性和方法可能会发生改变,所以不能把它放在栈中,否则会降低变量查寻的速度。相反,放在变量的栈空间中的值是该对象存储在堆中的地址。地址的大小是固定的,所以把它存储在栈中对变量性能无任何负面影响。如下图所示:

image

不同的内存分配机制也带来了不同的访问机制

在javascript中是不允许直接访问保存在堆内存中的对象的,所以在访问一个对象时,首先得到的是这个对象在堆内存中的地址,然后再按照这个地址去获得这个对象中的值。而基础类型的值则是可以直接访问到的。

复制变量
  • 基本类型值:如果从一个变量向另一个变量复制基本类型值,会在变量对象上创建一个新值,然后把该值复制到位新变量分配的位置上。此后,这两个变量可以参与任何操作而不会相互影响。
  • 引用类型值:在将一个变量向另一个变量复制引用类型的值时,也会将存储在变量对象中的变量中的值复制一份放到新变量分配的空间中,不同的是,这个值的副本是一个指针,也就是说这两个变量都指向了堆内存中的同一个对象,改变其中一个变量,就会影响另一个变量。如下例所示:
var obj1 = new Object();
var obj2 = obj1;
obj1.name = "Nic";
alert(boj2.name); // Nic

保存在变量中的对象和保存在堆中的对象之间的关系如下图所示。

image

参数传递

ECMAScript中所有函数的参数都是按值来传递的。把函数外部的值复制给函数内部的参数,就和把值从一个变量复制到另一个变量一样。基本类型值的传递如同基本类型变量的复制,而引用类型值的传递,则如同引用类型变量的复制一样。但是为什么涉及到基本类型与引用类型的值时仍然有区别呢,就是因为内存分配时的差别。
- 基本类型值:只是把变量里的值传递给参数,之后参数和这个变量互不影响。
- 引用类型值:对象变量它里面的值是这个对象在堆内存中的内存地址,因此它传递的值也就是这个内存地址,这也就是为什么函数内部对这个参数的修改会体现在外部的原因了,因为它们都指向同一个对象呀。

现在可以很清楚的理解最开始的两段代码了!

第一段代码中,person中保存了一个对象的地址,然后将person复制给obj,在函数内部,obj 和 person 指向同一个对象。于是,当在函数内部为obj添加name属性后,函数外部的person也将有所反映。第二段代码中,在函数setName()第一行,为obj添加name属性,此时外部的person也拥有了这个属性,函数第二行代码,将另一个新对象赋值给obj,此时,obj中保存的地址变成了新对象的地址,此时函数内部obj和函数外部的person指向的对象就不一样了,所以最后person.name输出的是NIC。


如有不对之处,请各位指正!谢谢!

参考:
https://www.zhihu.com/question/27114726/answer/35481766
http://www.w3school.com.cn/js/pro_js_value.asp

展开阅读全文

没有更多推荐了,返回首页