zoukankan      html  css  js  c++  java
  • JavaScript 专题系列第六篇,讲解深浅拷贝的技巧和以及实现深浅拷贝的思路

    拷贝也是面试经典呐!

    数组的浅拷贝

    如果是数组,我们可以利用数组的一些方法比如:slice、concat 返回一个新数组的特性来实现拷贝。

    比如:

    var arr = ['old', 1, true, null, undefined];
    
    var new_arr = arr.concat();
    
    new_arr[0] = 'new';
    
    console.log(arr) // ["old", 1, true, null, undefined]
    console.log(new_arr) // ["new", 1, true, null, undefined]

    用 slice 可以这样做:

    var new_arr = arr.slice();

    但是如果数组嵌套了对象或者数组的话,比如:

    var arr = [{old: 'old'}, ['old']];
    
    var new_arr = arr.concat();
    
    arr[0].old = 'new';
    arr[1][0] = 'new';
    
    console.log(arr) // [{old: 'new'}, ['new']]
    console.log(new_arr) // [{old: 'new'}, ['new']]

    我们会发现,无论是新数组还是旧数组都发生了变化,也就是说使用 concat 方法,克隆的并不彻底。

    如果数组元素是基本类型,就会拷贝一份,互不影响,而如果是对象或者数组,就会只拷贝对象和数组的引用,这样我们无论在新旧数组进行了修改,两者都会发生变化。

    我们把这种复制引用的拷贝方法称之为浅拷贝,与之对应的就是深拷贝,深拷贝就是指完全的拷贝一个对象,即使嵌套了对象,两者也相互分离,修改一个对象的属性,神马影院也不会影响另一个。

    所以我们可以看出使用 concat 和 slice 是一种浅拷贝。

    数组的深拷贝

    那如何深拷贝一个数组呢?这里介绍一个技巧,不仅适用于数组还适用于对象!那就是:

    var arr = ['old', 1, true, ['old1', 'old2'], {old: 1}]
    
    var new_arr = JSON.parse( JSON.stringify(arr) );
    
    console.log(new_arr);

    是一个简单粗暴的好方法,就是有一个问题,不能拷贝函数,我们做个试验:

    var arr = [function(){
        console.log(a)
    }, {
        b: function(){
            console.log(b)
        }
    }]
    
    var new_arr = JSON.parse(JSON.stringify(arr));
    
    console.log(new_arr);

    我们会发现 new_arr 变成了:

    浅拷贝的实现

    以上三个方法 concat、slice、JSON.stringify 都算是技巧类,可以根据实际项目情况选择使用,接下来我们思考下如何实现一个对象或者数组的浅拷贝。

    想一想,好像很简单,遍历对象,然后把属性和属性值都放在一个新的对象不就好了~

    嗯,就是这么简单,注意几个小点就可以了:

    var shallowCopy = function(obj) {
        // 只拷贝对象
        if (typeof obj !== 'object') return;
        // 根据obj的类型判断是新建一个数组还是对象
        var newObj = obj instanceof Array ? [] : {};
        // 遍历obj,并且判断是obj的属性才拷贝
        for (var key in obj) {
            if (obj.hasOwnProperty(key)) {
                newObj[key] = obj[key];
            }
        }
        return newObj;
    }

    深拷贝的实现

    那如何实现一个深拷贝呢?说起来也好简单,我们在拷贝的时候判断一下属性值的类型,如果是对象,我们递归调用深拷贝函数不就好了~

    var deepCopy = function(obj) {
        if (typeof obj !== 'object') return;
        var newObj = obj instanceof Array ? [] : {};
        for (var key in obj) {
            if (obj.hasOwnProperty(key)) {
                newObj[key] = typeof obj[key] === 'object' ? www.10rz.net/deepCopy(obj[key]) : obj[key];
            }
        }
        return newObj;
    }

    性能问题

    尽管使用深拷贝会完全的克隆一个新对象,不会产生副作用,但是深拷贝因为使用递归,性能会不如浅拷贝,在开发中,还是要根据实际情况进行选择。

    下期预告

    难道到这里就结束了?是的。然而本篇实际上是一个铺垫,我们真正要看的是 jquery 的 extend 函数的实现,下一篇,我们会讲一讲如何从零实现一个 jquery 的 extend 函数。

  • 相关阅读:
    解惑如何保证数组元素的可见性(yet)
    为什么内存锁在有事务切面的情况下会形同虚设 隔离级别与事务
    小事故合集
    第4种打整包插件,urlfactory already set
    三目运算符与字节码阅读
    servlet application/x-www-form-urlencoded 坑
    多实例重复发邮件
    当动态代理遇到ioc (五)使用cglib切面与自定义类加载器构建独有环境aop日志
    mac笔记本如何重制secureCRT的体验期|试用版本
    npm install出现的错误
  • 原文地址:https://www.cnblogs.com/tianshifu/p/7156535.html
Copyright © 2011-2022 走看看