实现深、浅拷贝

2021-05-10  本文已影响0人  欢欣的膜笛

数据分为基本数据类型(String, Number, Boolean, Null, Undefined,Symbol)和对象数据类型。
基本数据类型的特点:直接存储在栈(stack)中的数据
引用数据类型的特点:存储的是该对象在栈中引用,真实的数据存放在堆内存里

引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址。当解释器寻找引用值时,会首先检索其在栈中的地址,取得地址后从堆中获得实体。

浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存。
深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。

实现浅拷贝

// 实现方式一:Object.assign
let target = {};
let source = {
    a: '123',
    b: { name: 'yd' }
};
Object.assign(target, source);
console.log(target); // { a: '123', b: { name: 'yd' } }

// 实现方式二:Array.prototype.slice、Array.prototype.concat
let array = [{ a: 1 }, { b: 2 }];
console.log(array.slice(0)); // [{a: 1}, {b: 2}]
console.log([].concat(array)); // [{a: 1}, {b: 2}]

// 实现方式三:扩展运算符
let obj = {
    a: 1,
    b: { c: 1 }
};
console.log({ ...obj }); // { a: 1, b: { c: 1 } }

// 实现方式四:
function cloneShallow(source) {
    let target = {};
    for (let key in source) {
        if (Object.prototype.hasOwnProperty.call(source, key)) {
            target[key] = source[key];
        }
    }
    return target;
}

实现深拷贝

// 实现方式一:JSON.stringify
/*
 * 缺点:
 * 1、日期类型的数据会直接变成字符串的形式,而不是对象的形式
 * 2、正则类型的数据会变成空对象{}
 * 3、函数会丢失
*/

// 实现方式二:自定义实现深拷贝函数
function cloneDeep(data) {
    // 当 null NaN undefined number string 等基本数据类型时直接返回
    if (data === null || typeof data !== 'object') {
        return data
    }

    // Date类型
    if (data instanceof Date) {
        return new Date(data.valueOf())
    }

    // 正则类型
    if (data instanceof RegExp) {
        return new RegExp(data)
    }

    // Map 集合
    if (data instanceof Map) {
        let m = new Map()
        data.forEach((v, k) => m.set(k, cloneDeep(v)))
        return m
    }

    // Set 集合
    if (data instanceof Set) {
        let s = new Set()
        for (let val of data.values()) {
            s.add(cloneDeep(val))
        }
        return s
    }

    // 数组、对象等引用数据类型
    if (typeof data === 'object') {
        const copyData = Array.isArray(data) ? [] : {}
        for (const key in data) {
            if (data.hasOwnProperty(key)) {
                copyData[key] = cloneDeep(data[key])
            }
        }
        return copyData
    }

    // 函数
    if (data instanceof Function) {
        return (new data()).constructor
    }

    return data
}

// 实现方式三:使用 lodash.js 中的 cloneDeep 函数

实现 JSON(parse + stringify)

if (!window.JSON) {
    window.JSON = {
        parse: function (sJSON) {
            return eval('(' + jsonStr + ')');
            // return new Function('return ' + jsonStr)();
        },
        stringify: (function () {
            var toString = Object.prototype.toString;
            var isArray = Array.isArray || function (array) {
                return toString.call(array) === '[object Array]'
            };
            var escMap = {
                '"': '\\"',
                "\\": "\\\\",
                "\b": "\\b",
                "\f": "\\f",
                "\n": "\\n",
                "\r": "\\r",
                "\t": "\\t",
            };
            var escFunc = function (m) {
                return escMap[m] || "\\u" + (m.charCodeAt(0) + 0x10000).toString(16).substr(1);
            };
            var escRE = /[\\"\u0000-\u001F\u2028\u2029]/g;
            return function stringify(value) {
                if (value == null) {
                    return 'null';
                } else if (typeof value === 'number') {
                    // isFinite() 函数用于检查其参数是否是无穷大,如果参数是 NaN,正无穷大或者负无穷大,会返回 false,其他返回 true。
                    return isFinite(value) ? value.toString() : 'null';
                } else if (typeof value === 'boolean') {
                    return value.toString();
                } else if (typeof value === 'object') {
                    if (typeof value.toJSON === 'function') {
                        return stringify(value.toJSON());
                    } else if (isArray(value)) {
                        var res = '[';
                        for (var i = 0; i < value.length; i++) {
                            res += (i ? ', ' : '') + stringify(value[i]);
                        }
                        return res + ']';
                    } else if (toString.call(value) === '[object Object]') {
                        var tmp = [];
                        for (var k in value) {
                            if (value.hasOwnProperty(k)) {
                                tmp.push(stringify(k) + ': ' + stringify(value[k]));
                            }
                        }
                        return '{' + tmp.join(', ') + '}';
                    }
                }
                return '"' + value.toString().replace(escRE, escFunc) + '"';
            };
        })(),
    };
}
上一篇 下一篇

猜你喜欢

热点阅读