zoukankan      html  css  js  c++  java
  • JS基本类型-引用类型-深浅拷贝

    在JavaScript中变量包含两种类型的值:一种是基本类型,一种是引用类型。

    基本类型包括:数值、字符串、null、undefined、布尔值
    引用类型包括:对象、数组、函数、正则…

    补充: null和undefined的区别

    null表示"没有对象",即该处不应该有值。

      典型用法是:

    (1) 作为函数的参数,表示该函数的参数不是对象。

    (2) 作为对象原型链的终点。

    undefined表示"缺少值",就是此处应该有一个值,但是还没有定义。

      典型用法是:

    (1)变量被声明了,但没有赋值时,就等于undefined。

    (2) 调用函数时,应该提供的参数没有提供,该参数等于undefined。

    (3)对象没有赋值的属性,该属性的值为undefined。

    (4)函数没有返回值时,默认返回undefined。

    1.引用类型的动态属性

    对于引用类型的值,我们可以为其添加属性和方法,也可以改变或删除属性和方法,

    对于基本类型的值,尽管给其添加属性和方法不会报错,但这是无效的。

    var obj=new Object();
    obj.name="zuobaiquan";
    var str="zbq";
    str.age=20;
    console.log(obj.name);// zuobaiquan
    console.log(str.age);// undefined

    2.基本类型值和引用类型值的复制

    2.1基本类型值

    基本类型值是指在栈内存保存的简单数据段,在复制基本类型值的时候,会开辟出一个新的内存空间,将值复制到新的内存空间。

    var a = 1;
    var b = a;
    a = 2;
    console.log(a);//输出2;
    console.log(b);//输出1;

    var a = 1;

    var b = a;

    a = 2;

    从上面例子看出,当一个变量的值是基本类型,把它复制给另一个变量,复制完成后改变它的值,不会影响已经复制了它的值的变量。

    2.1引用类型值

    引用类型值是保存在堆内存中的对象,变量保存的只是指向该内存的地址,在复制引用类型值的时候,其实只复制了指向该内存的地址。

    var a = {
       name: 'Kitty',
       age: '20',
       sex: 'man'
    };
    var b = a;
    a.name = 'Jack';
    console.log(a);//输出{name: 'Jack',age: 20,sex: 'man'}
    console.log(b);//输出{name: 'Jack',age: 20,sex: 'man'}

    var a = {name: ‘Kitty’,age: ‘20’,sex: ‘man’};

    var b = a;

    a.name = ‘Jack’;

    从上面例子看出,当一个变量的值是引用类型值,把它复制给另外一个变量,复制的只是指向储存对象内存的地址,所以复制完成后,改变它的值,会影响复制了它的值的变量。
    注意:如果有两个变量的值是引用类型值,就算它们的值完全相同,它们也是不相等的,因为它们指向的内存地址不同,例子:

    3.对象的浅拷贝和深拷贝

    当一个变量是对象,如果像上面那样直接将一个变量赋值给另一个变量,如果改变某个变量的值,另外一个变量也会跟着改变,如果我们不想发生这种情况,就需要写一个函数用来拷贝对象。

    3.1浅拷贝

    当对象里的属性的值只有基本类型的值时候。

    var a = {
         name: 'Kitty',
         age: 12,
         sex: 'man'
    }
    function copy(obj){
        var newObj = {};
        for(vl in obj){
             newObj[vl] = obj[vl] 
        }
        return newObj;
    }

    例子:

    从上面例子看到,我们通过这种方式拷贝对象,改变某个变量的值,并不会影响另一个变量。

    3.1深拷贝

    当对象里的属性的值还是一个对象,这时候用上面的方法就不行了,例子:

    这时候要改进这个函数:

    使用递归的方法:

    function deepCopy(obj){
         var newObj = {};
         for(vl in obj){
             if(typeof obj[vl] === 'object' && obj[vl] !== null){
                 newObj[vl] = deepCopy(obj[vl]);
             }else{
                 newObj[vl] = obj[vl];
             }       
         }
         return newObj;
    }

    例子:

    使用JSON的方法:

    JSON.stringify(),将一个对象解析成字符串。
    JSON.parse(),从一个字符串中解析出json 对象。

    我们可以使用上面两个个方法来进行对象的深拷贝:

    JSON.parse(JSON.stringify());

    例子:

    JSON.parse(JSON.stringify(obj)) 实现深拷贝的一些坑

    1.如果json里面有时间对象,则序列化结果:时间对象=>字符串的形式;

    let obj = {
        age: 18,
        date: new Date()
    };
    let objCopy = JSON.parse(JSON.stringify(obj));
    console.log('obj', obj); // {age: 18, date: Thu Mar 12 2020 15:39:35 GMT+0800 (中国标准时间)}
    console.log('objCopy', objCopy); //{age: 18, date: "2020-03-12T07:39:35.372Z"}

    2.如果json里有RegExp、Error对象,则序列化的结果将只得到空对象 RegExp、Error => {};

    let obj = {
        age: 18,
        reg: new RegExp('\w+'),
        err: new Error('error message')
    };
    let objCopy = JSON.parse(JSON.stringify(obj));
    console.log('obj', obj); //{age: 18, reg: /w+/, err: Error: error message
        at <anonymous>:4:10}
    console.log('objCopy', objCopy); // {age: 18, reg: {…}, err: {…}}

    3.如果json里有 function,undefined,则序列化的结果会把 function,undefined 丢失

    let obj = {
        age: 18,
        fn: function () {
            console.log('fn');
        },
        hh: undefined
    };
    let objCopy = JSON.parse(JSON.stringify(obj));
    console.log('obj', obj); //{age: 18, hh: undefined, fn: ƒ}
    console.log('objCopy', objCopy); //{age: 18}

    4.如果json里有NaN、Infinity和-Infinity,则序列化的结果会变成null;

    let obj = {
        age: 18,
        hh: NaN,
        isInfinite: 1.7976931348623157E+10308,
        minusInfinity: -1.7976931348623157E+10308
    };
    let objCopy = JSON.parse(JSON.stringify(obj));
    console.log('obj', obj); //{age: 18, hh: NaN, isInfinite: Infinity, minusInfinity: -Infinity}
    console.log('objCopy', objCopy); //{age: 18, hh: null, isInfinite: null, minusInfinity: null}

    5.如果json里有对象是由构造函数生成的,则序列化的结果会丢弃对象的 constructor;

    6.如果对象中存在循环引用的情况也无法实现深拷贝

    来源:https://segmentfault.com/a/1190000020297508

    如何拷贝数组呢

    拷贝一个数组但是对副本的修改不影响原来的数组

    //方法1
    var a = [1,2,3];
    var b = a.slice(0);
    a.reverse();
    console.log(a);//[3,2,1]
    console.log(b);//[1,2,3]

    //方法2 var c = [4,5,6]; var d = c.concat(); c.reverse(); console.log(c);//[6,5,4] console.log(d);//[4,5,6] //方法3 var arr = [1,2,3,4,5] var [ ...arr2 ] = arr arr[2] = 5 console.log(arr) console.log(arr2) //方法4 var arr = [1,2,3,4,5] var arr2 = copyArr(arr) function copyArr(arr) { let res = [] for (let i = 0; i < arr.length; i++) { res.push(arr[i]) } return res }
     
  • 相关阅读:
    Oracle-学习笔记(==》集合函数与分组四)
    Mysql--学习笔记(==》简单查询三)
    Mysql-学习笔记(==》插入修改数据二)
    Mysql-学习笔记(==》建表修改一)
    EasyUI的DataGrid 打印导出
    SQL 中ROLLUP 用法
    easyui commbox嵌入一个checkbox的实现
    Easyui Layout Center 全屏方法扩展
    Datagrid扩展方法InitEditGrid{支持单元格编辑}
    Datagrid扩展方法onClickCell{easyui-datagrid-扩充-支持单元格编辑}
  • 原文地址:https://www.cnblogs.com/zuobaiquan01/p/8414306.html
Copyright © 2011-2022 走看看