Javascript传值与传引用
Javascript 参数传递
说起参数传递,首先需要弄清楚javascript里的数据类型
原始数据类型
Undefined
Null
Boolean
Number
String
引用数据类型
Object
Array
Function
Date
等
原始数据类型存储在栈的简单数据段,他们的值直接存储在变量访问的位置(因原始数据类型占据的空间是固定的,可以存储在较小的内存区域栈
中)
引用数据类型是存储在堆中的对象,存储在变量处的值只是一个指针,指向存储对象的内存地址,这是因为引用类型的大小会改变.
不同的内存分配机制带来不同的访问机制
在JavaScript中,是不允许直接访问保存在堆内存中的对象的,访问对象时必须取得对象在堆内存中的地址,然后按地址去取得对象中的值.
这便是传说中的按引用访问.
而原始类型则是直接访问到的.
复制变量时的不同
原始值:
会将原始值的副本赋值给新变量.此后两个变量完全独立.
引用值:
会把内存地址赋值给新变量,也就是说两个变量都指向堆内存中的同一个对象. 他们中任何一个改变都会反映到另一个身上.
参数传递的不同
最重要的一点:ECMAScript
中所有函数的参数都是按值传递的.
但原始值和引用值仍会造成不同的后果.
原始值:
把变量里的值传递给参数,之后两个变量互不影响.(就是把实参复制给形参的过程)
引用值:
任然是将实参里面的值复制到形参,但是注意对象变量它里面的值是这个对象的堆内存地址
也就是说形参和实参都是指向同一个堆内存对象.
但是也要记住另外一点:如果形参被赋值为另外一个对象时,那么这个形参将会丢弃对上次指向的堆内存地址,而指向新对象的堆内存地址.
此时,形参和实参相互脱离,互不影响,原先的实参任然指向原先对象的堆内存地址.
如果是添加修改形参的属性,那么就是修改堆内存中的对象,形参和实参将同时得到反映,因为他们指向的是同一个堆内存对象.
这种传递方式被称为Call By Sharing
function box(obj)
{
obj.name='hello';
var obj=new Object();
obj.name='world';
}
var obj=new Object();
box(obj);
console.log(obj.name);
注意两点:
var obj=new Object()
声明提升
变为
var obj;
obj.name='hello';
obj=new Object();
obj.name='world';
函数的已存在一个变量形参obj
,再次的变量申明会忽略
2.obj=new Object()
时,obj的修改就不会影响外层obj变量了,因为他此时已经脱离执行那个堆内存对象了.
Object.create
简单来讲,new Object()是一种通过构造函数来创建object的方式,而Object.create(proto, [ propertiesObject ]) 不需要通过构造函数就可以创建一个object,Object.create()的第一个参数是必须要的,第二个参数可选。其实Object.create()内部依然是通过new一个构造函数的方式来实现的,它有构造函数,不过这个构造函数是隐式存在的,看一下使老旧浏览器支持Object.create方法的“polyfill”就可以对它们之间的区别一目了然了:
if (!Object.create) {
Object.create = function (o) {
function F() {} //定义了一个隐式的构造函数
F.prototype = o;
return new F(); //其实还是通过new来实现的
};
}