按值传递和按地址传递

变量分为基本类型(值型)和引用类型变量. 基本数据类型包括数字,字符串,布尔,null,undefined这些, 引用数据类型包括object(Object,Array, RegExp, Date, Math...), 函数.

如果将基本类型的值赋值给变量, 变量会将这个值的本身保存起来:

var a = 123; // 将数值123赋给变量a
var b = a;  // 将变量a的值(数值123)赋给变量b

此时如果将变量b自增操作, 变量a的值不会受到影响;

b++;
console.log(b);   // 124
console.log(a);   // 123

如果将对象赋值给变量, 实际上是把对象的引用赋值给了变量; 变量保存的只是对象在内存中的地址.

var a = {x:1, y:3};  
var b = a;  // 将对象的地址赋值给b

上面的代码, 变量a和b都指向相同的地址, 也就是引用了同一个对象; 如果对b所引用的对象进行改变, 这一改变也会体现在变量a之中;

b.x++;
console.log(b.x); // 2
console.log(a.x); // 2

接下来看这段代码:

var a = {x:1,y:2};
var b = a;  // b和a指向同一个对象
a = {x:2,y:1};   // a重新赋值,指向另一个对象
console.log(b.x);

这段代码通过赋值运算符将a重新赋值, 于是a不再引用一开始的对象, a与b之间的联系被切断, 因此不会再互相影响.

函数的参数(按值传递)

ECMAScript中所有函数的参数都是按值传递的;

function swap(a,b) {
  var tmp = a;
  a = b;
  b = temp;
}
var one = 1;
var zero = 0;
swap(one, zero);
console.log(one, zero); // one与zero的值没有发生改变

把函数外部的值赋值给函数内部的参数, 相当于把值从一个变量复制给另一个变量一样. 函数的参数a和b可以理解成函数的私有变量,它们被赋于了全部变量one和zero的值, 然而这两个函数内部变量赋值的改变影响不到全部变量one和zero.

如果使用对象, 情况又会有所不同:

function setName(obj) {
  obj.name = "Nicolas";
}

var person = new Object();
setName(person);
console.log(person.name);

以上代码创建了一个对象, 将对象保存到变量person中. 变量person被传递到函数setName后被复制给了obj, 这一步可以理解成, 对象的引用地址被复制给了obj. obj和person引用了同一个对象. 于是, 当在函数内部为obj添加name属性后, 函数外部的person也会有所反映.有的人会认为如果把引用类型数据作为参数, 参数就是按引用传递的. 其实无论传递了什么, 全都是按值传递. 改写下上面的代码:

function setName(obj) {
  obj.name = "Nicolas";
  obj = new Object();
  obj.name = "Greg";
}

var person = new Object();
setName(person);
console.log(person.name); // "Nicolas"

这个例子中在函数内部创建了一个新的object对象并将name属性设置为"Greg", 如果person是按引用传递的, person就会被修改了name属性为"Greg"的新对象; 而事实上并没有. 说明即使在函数内部修改了参数的值, 也影响不到原始引用. 实际上函数内部重写的obj是引用了一个只在函数局部作用域中存在的对象, 函数执行完毕后这个对象就会被销毁.

本文参考了javascript高级程序设计第3版和javascript编程全解(然而写得比原书乱多了...)

posted @ 2015-07-13 15:44  supersylph  阅读(1817)  评论(0编辑  收藏  举报