函数内修改对象后为什么会影响引用对象

拭目以待 发布于

  由浅至深讲解在函数内修改对象属性时,为什么会影响到引用对象。你可能在面试中看到过,也可能在书上看到过,更有可能是在工作中被这个特性折腾的够苦。


函数内修改以参数形式传入的对象:

var o1 = {x:1,y:2,z:3};
function testObjectOne(d){
  d.x = 4;
}
testObjectOne(o1);
console.log(o1); //=> {x: 4, y: 2, z: 3}

   上面这段代码,可能直接就想到了正确的结果,也可能看到结果后就明白了为什么。


再来一段思考下:

var o2 = {x:1,y:2,z:3};
function testObjectTwo(d){
  d={};
}
testObjectTwo(o2);
console.log(o2); // => {x: 1, y: 2, z: 3}

  到这里可能就有不那么明白了,为什么testObjectOne()与testObjectTwo()中的形参都是属于Object类型,而结果却和想向中的不一样。


用另外一种形式来重构下上面的代码,会更清析:

var or1 = {x:1,y:2,z:3};
function testObjectOneRes(d){
  var d = d;  //声明了一个局部变量d,并将or1通过参数赋值于d;
  console.log(d === or1); // => true  新声明的变量d与or1是同一个对象
  d.x = 4;
}
testObjectOneRes(or1);
console.log(or1);  // => {x: 4, y: 2, z: 3}
var or2 = {x:1,y:2,z:3};
function testObjectTwoRes(d){
  var d={};//声明了一个局部变量d,并赋值一个空对象。
}
testObjectTwoRes(or2);
console.log(or2); // => {x: 1, y: 2, z: 3}

   console.log(d === or1)输出结果为true, d与or1属性、值完全相等。

   Object在javascript中属于引用类型,引用类型变量存储的只是一个指针,这个指针指向内存中的对象。在示例中赋值给局部变量d的只是or1的指针,所以两个变量会完全相等。

   1、testObjectOneRes()中:

   var d = d;声明了一个局部变量d, 并将全局变量or1所存储的指针赋值于局部变量d,此时两个变量共同指向了同一个对象,无论修改哪个变量,都会对内存中指向的对象进行修改。

   2、testObjectTwoRes()中:

   var d={};声明了一个局部变量d,并对其赋值了一个对象。此时该变量中存储了一个新创建的空对象指针。由于作用域的关系肯定是不会对函数外的变量有影响。

javascript中引用类型共有三个:Object, Array, function,下面对Array类型执行相同的操作:

var array1 = [1, 2, 3, 4];
function testArrayOne(d){
  d[2] = 5;
}
testArrayOne(array1);
console.log(array1); 
//输出结果为[1, 2, 5, 4]
var array2 = [1, 2, 3, 4];
function testArrayTwo(d){
  d = []; 
}
testArrayTwo(array2);
console.log(array2);
//输出结果为[1, 2, 3, 4]

   与Object比较,Array类型在执行同样的操作后也会有一样的效果。


字符串虽然不是引用类型,但是由于字符串可以通过索引值进行值获取,而造成了一些误解:

var s = 'lovejavascript';
function testString(d){
  d[5] = 'J';
}
testString(s);
console.log(s);

   对于字符串需要注意两点:

   1、string类型的变量,只能通过索引获取,而不能修改。

   2、string类型的变量存储的是值,而不是指针。