苏苏的博客

简约至极

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);

注意两点:

  1. var obj=new Object() 声明提升

变为

var obj;
obj.name='hello';
obj=new Object();
obj.name='world';

函数的已存在一个变量形参obj,再次的变量申明会忽略

2.obj=new Object() 时,obj的修改就不会影响外层obj变量了,因为他此时已经脱离执行那个堆内存对象了.

参考 http://www.zhihu.com/question/27114726

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来实现的
    };
  }