js的值传递和引用传递

2017-08-06  本文已影响190人  FFriday

我们知道js中那些是值类型,那些是引用类型,这是必须要搞清楚。
JavaScript中的值类型:数值、布尔值、null、undefined
JavaScript中的引用类型:对象、数组、函数

堆栈

栈(stack)
由操作系统自动分配释放 ,存放函数的参数值局部变量的值等。其操作方式类似于数据结构中的栈。一种先进后出的数据结构。

堆(heap)
动态分配的内存,大小不定也不会自动释放。队列优先,先进先出。

值类型是存放在栈中的基本类型,对象数据则是在堆中创建并在栈中保留对象在堆中的地址。我们从下面的例子来理解

    var a = [1,2,3,4,5];
    var b = a;
    var c = a[0];
数据在内存中的存储示意图(图片来自‘小辉_Ray’的博客)

通过变量在内存中的存储我们可以看出来,所有的变量都是在栈内存中存在的,不同的是值类型存放的是值本身,引用类型存放的是指向堆内存对象的地址。
基本类型与引用类型最大的区别实际就是传值与传址的区别。


var a =1;
var array = [1,2,3];
var object = {a:1,b:2,c:3};

function reassign(num,arr,obj){
    //将参数重新赋值
    num = '';
    //arr 是array对象的引用拷贝,我们把这个引用重新赋值,这时的arr不在指向array所指向的对象,而是指向新的空数组
    //所以这时候我们再对arr进行操作,将不会影响array。
    //obj同理
    arr = [];
    arr.push(123);
    obj = '';
}
function operate(num,arr,obj){
    num = 2;
    arr.push(4);
    obj.test = 'test';
    // 我们直接对传递的参数进行操作,
    // 参数num是值类型,传递的是参数a的值拷贝,所以我们对num进行操作不会影响外层的a变量
    // arr,和obj,一个是数组,一个是对象,都是引用类型,传递的是对象地址的拷贝,我们对它的操作也会影响到外层变量的值,因为他们都指向相同的堆对象。
}


reassign(a,array,object);
console.log(a);      // 1
console.log(array);  // [1,2,3]
console.log(object); // {a:1,b:2,c:3}


operate(a,array,object);
console.log(a);      // 1
console.log(array);  // [1,2,3,4]
console.log(object); // {a:1,b:2,c:3,test:'test'}

对象的拷贝

js 深拷贝 vs 浅拷贝
浅拷贝

//如果对象的属性是引用类型,对对象的属性进行拷贝时,拷贝的只是对象属性的引用
function Copy(object) {
    var temp = {};
    for (var property in object) { 
      temp[property] = object[property];
    }
    return temp;
}

var obj = {}  
obj.a = "abc";
obj.b = [1,2];

var copyObj = Copy(obj);

console.log(copyObj);  // { a: 'abc', b: [ 1,2] }

copyObj.b.push(3); //这里向copyObj的b属性中push一个值,原始的obj对象也会受到影响,因为数组是引用类型

console.log(obj);  //{ a: 'abc', b: [ 1, 2, 3 ]}

深拷贝

// 实际编码中,很多时候浅拷贝并是我们想要的,我们希望拷贝完成后的对象和原对象不再有任何关联。
// 深拷贝
function Copy(source, target) {
    var target = target || {};
    for (var i in source) {
      if (typeof source[i] === 'object') { //这里有个疑问, 如果对象的属性是函数呢?
         target[i] = (source[i].constructor === Array) ? [] : {};
         Copy(source[i], target[i]);
      } else {
         target[i] = source[i];
      }
    }
    return target;
}  

var obj = {}  
obj.a = "abc";
obj.b = [1,2];
obj.c = function(){};

var copyObj = Copy(obj);

copyObj.b.push(3); //这里向copyObj的b属性中push一个值,原始的obj对象也会受到影响,因为数组是引用类型

console.log(copyObj);  // { a: 'abc', b: [ 1,2] }
console.log(obj);  //{ a: 'abc', b: [ 1, 2, 3 ]}
上一篇下一篇

猜你喜欢

热点阅读