复制变量的值:
看下面的代码:
var num1=5;
var num2=num1;
这里先将num1的值置为5,再使用num1来初始化num2,num1和num2之间是完全独立互不影响的,比如你将上面代码中加一句
num1=8;
会发现其对num2的值没有影响,他们的内存分析图如下:
num2改变前
num2改变后
可以看出他们之间并没有任何关联,自然改成任意值都不会影响其余变量
所以,对于基本变量来说,将一个变量值A复制到另一个变量B上时,相当于重新开辟了一个变量B的内存空间并给它赋予值A,就好比是A和B都从超市买了一瓶可乐,B喝了多少都和A没有关系,因为A有自己的可乐。
再看下面的代码:
var obj1=new Object();
var obj2=obj1;
这里创建obj2也会重新开辟一个内存空间,但是用于初始化它的值不是一个新的对象,而是obj1,obj1此时已经指向一个对象,所以用obj1来初始化obj2实际上也是将obj1指向的对象来初始化obj2,也就是说他们之间会相互影响。我们在上面的代码加一句:
obj1.name="小明";
alert(obj2.name); //输出"小明"
可以发现,当我们改变obj1的值时,obj2的值也会随之改变,他们的内存分析图如下:
可以看出,obj1和obj2的值是同一个,当我们执行语句new Object()时,就会在堆内存中创建一个对象,而被对象初始化的变量都是引用变量,比如上面的obj1,而被引用变量初始化的变量,类型也是引用变量,并且其值是被用于初始化它的引用所指向的对象,比如上面的obj2。这就好比A买了一瓶可乐,A喝了一点再给B,B此时拿到的可乐是剩下的,因为他们是共享这瓶可乐的。
传递参数
在JavaScript中,所有函数的参数都是按值传递的,没有按引用传递,即将函数外部的值作为参数传进函数时,在函数内用以接受的参数和传进来的参数并不是同一个值,就和上文中的复制变量一样,函数内的参数所占用的内存空间和函数外传进来的参数所占用的内存空间是区分开的,参看下面的例子:
function add(num){
num+=10;
alert(num); //输出30
}
var count=20;
add(count);
alert(count); //输出20
显然可以看出,num值的改变对count没有任何影响,因为他们本身就是两个互不干扰的独立变量,num只是一个局部变量,他的生命周期就是函数的执行期间,执行期间num的值会发生变化,但从头到尾都不会对num造成任何影响。
再来看看对于引用类型数据的传参,看下面的例子:
function setName(obj){
obj.name="小明";
}
var person=new Object();
person.name="小红";
setName(person);
alert(person.name); //"小明"
很多人在这里会觉得当引用类型数据当做参数时就是按引用传递,他们会觉得函数中obj的改变影响了函数外的person的值,所以会产生误解,实际上,这依然是按值传递,因为所谓的按引用传递,意思是函数中用以接收实参的局部变量的内存空间与实参的内存空间是同一个,但显然不是,这里的obj和person会互相影响完全是因为他们所指向的值是同一个对象,而不是因为他们的内存空间相同。看以下例子:
function setName(obj){
obj.name="小明";
obj=new Object();
obj.name="小李";
}
var person =new Object();
setName(person);
alert(person.name); //"小明"
看以上这份代码,当执行函数中
obj.name="小明";
这句时,内存图如下:
执行
obj=new Object();
obj.name="小李";
这两句时,内存图如下:
所以,从本质上来讲,obj和person依然是两个独立的变量,他们可以指向任意对象,只有当他们指向同一个对象时才会互相影响,所以并不是说传递的参数是引用时,传递方式就是按引用传递。
(这就是假设的按引用传递,person和obj共享同一块内存,实际情况推翻了这种可能性)