美文网首页
js的值传递和引用传递

js的值传递和引用传递

作者: FFriday | 来源:发表于2017-08-06 20:10 被阅读190次

    我们知道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 ]}
    

    相关文章

      网友评论

          本文标题:js的值传递和引用传递

          本文链接:https://www.haomeiwen.com/subject/lqawlxtx.html