function box(obj){
obj.name='Lee';
var obj = new Object();
obj.name='kkk';
}
var obj = new Object();
box(obj);
alert(obj.name);
lee
` 而不是kkk呢?这个的原因是js在传递对象(Object,Array,Date等)是是“引用传递”,但在传递基本数据类型(Number,String, Boolean等)时是“值传递”。
值传递,将数值进行复制后,作为参数。
比如:
function add(x) {x = x + 1; return x}; var a = 10; add(a); // 11
console.log(a); // 10
这个a的值不会变是“值传递”。参数x用a进行初始化,类似于x=a;但由于a是基本类型,所以执行后,x=10;a=10;但这两个“10”是内存里面不同的地方,对其中任何一个的修改都不会影响到另一个值。(也就是说,基本类型在赋值的时候会把这个值完全复制一遍,然后给x)。
引用传递,将参数的“指针”进行赋值。
var a = {data:1};
var b = a;
b.data = 10;
console.log(a.data); // 10
console.log(b.data); // 10
对象在赋值的时候,进行的是“引用传递”,并没有生成一个新的对象,而是将之前对象的“指针”,赋值给了b。(也就是说,执行var b = a;
后,a,b指向的是同一块内存区域。所以对b的修改会影响a。
回到这题来,实际上就是(我将外面的obj改名为obj0了,便于区分):
function box(obj){
// 进入后,函数里面的obj和传入的参数obj0指向同一个对象
obj.name='Lee'; // 修改那个对象,也就是obj0.name被改变了。
var obj = new Object(); // 新建一个对象,这是obj指向那个新的对象了(此时obj0的修改已经完成)
obj.name='kkk'; // 在刚才新建的对象上进行操作,和外部的obj0没有关系。
}
var obj0 = new Object();
box(obj0);
alert(obj0.name);//所以结果为Lee
首先说明两点:
使用var声明的变量会存在声明提前
函数的参数会有声明变脸的效果
根据上述两点变量已经声明了变量obj,那个var obj = new Object()
等价于obj = new Object()
;
function box(obj){
obj.name='Lee';//此处的obj为传入的值
obj = new Object(); //此处将obj覆盖
obj.name='kkk';//这里的obj为后面新建的obj
}
box(obj);
console.log(obj.name);//弹出外面的obj的name
还有函数传值全部是按值传递,没有按引用传递
上面说到变量提升,那么提升后应该是这样:
function box(obj) {
var obj;
obj.name = 'Lee';
obj = new Object();
obj.name = 'kkk';
}
var obj = new Object();
box(obj);
console.log(obj.name);
OK,然后让我用简单粗暴的办法,在 box()
里面插几条 console.log(obj)
,然后在全局的 obj
声明之后给 name 属性赋个值。就变成这样:
function box(obj) {
var obj;
console.log(obj);
obj.name = 'Lee';
console.log(obj);
obj = new Object();
console.log(obj);
obj.name = 'kkk';
console.log(obj);
}
var obj = new Object();
obj.name = 'test';
box(obj);
console.log(obj.name);
// 返回的结果
// { name: 'test' }
// { name: 'Lee' }
// {}
// { name: 'kkk' }
// Lee
可以看到,即使 box()
中声明的 obj
提升到函数顶部,后面 log 出来的依旧还是传入的 obj
。提升后的变量声明由于已经存在了传入的 obj
,所以实质上这句是没用的。
虽然函数的参数是按值传递的,但是对象的值其实是内存中的指针地址,所以函数中的 obj
(未在函数中再次赋值之前)与全局作用域 obj
实际上是同一个。
参考:javascript传递参数如果是object的话,是按值传递还是按引用传递?
在函数中再次赋值之后,obj
变成了这个局部作用域中的变量(new
了一个新的 Object
,并赋值给了 obj
。obj
的值不再指向全局作用域下的 obj
),所以后面再怎么修改都跟全局作用域下的 obj
没有关系了。
以上是查阅以及测试之后,思考得出。如果有地方不对,望高人指点。