应该明确一点,js中只有值传递,不存在引用传递的情况。这儿分两种情况来看,首先是基本数据类型,以Number类型为例:
var a = 2; var b = a; a = a + 1; alert("a = " + a);// 打印:a = 3 alert("b = " + b);// 打印:b = 2
在这里var b = a,是把a的值复制一份传给了b,之后两者便是不想关的变量,来看内存中的数据存储结构(基本类型数据存在内存中栈内存中,并且占有固定的内存大小):
栈:
a : 3 |
b : 2 |
对于引用类型,js也是传值机制,只是此时传得值是对象在内存中的地址,地址值存在栈中(占固定栈内存),对象存在堆中(占有不固定内存):
var person = new Object(); function f(person){ person.name = "大光棍"; person.age = "20"; person = new Object(); person.name = "小光棍"; person.age = "10"; } f(person); alert("姓名:" + person.name + ",年龄:" + person.age ); // 打印:姓名:大光棍,年龄:20
这里要注意,var声明的person是一个全局变量,而作为参数的person是一个局部变量,也就是说二者不是同一个变量,开始在栈中只有一个person变量,里面存放着对象的地址值,当调用函数的时候该变量的地址值被复制了一份存在了局部变量person中,这是栈内有两个person变量,里面存有相同的地址值,指向同一个堆对象,接着使用局部变量的地址值为对象添加了姓名年龄属性。程序继续往下走,“person = new Object();”这句话将局部变量里的地址值替换为了指向堆内另一个对象的地址值,接下来为另一个对象添加了姓名和年龄属性,此时全局变量里的地址值并没有改变。当我们掉用完函数以后,局部变量已失去作用,“alert("姓名:" + person.name + ",年龄:" + person.age );”这句代码里的person其实是指的全局变量,因此结果会打印最初对象的属性!如果不好理解,这段代码与下面的代码其实是一个意思:
var person = new Object(); function f(p){ p.name = "大光棍"; p.age = "20"; p = new Object(); p.name = "小光棍"; p.age = "10"; } f(person); alert("姓名:" + person.name + ",年龄:" + person.age );
我们在函数内实际上仅仅是操作了局部变量……
再看下面代码:
var person = new Object(); function f(p){ p.name = "大光棍"; p.age = "20"; p = new Object(); person.name = "小光棍"; person.age = "10"; } f(person); alert("姓名:" + person.name + ",年龄:" + person.age ); // 打印:姓名:小光棍,年龄:10
这是不是好理解了呢……