利用深度/广度优先遍历手动实现JavaScript对象的深度拷贝

2/19/2022 javascriptstackqueue

# 前言

搜索JavaScript对象的深度拷贝,往往会冒出JSON转换和递归拷贝大法。但遇到大数据量,它们都有调用栈爆栈的风险 今天,我们尝试利用树的利用深度/广度优先遍历来实现对象的深度拷贝。以下代码在chrome环境下全部测试通过。

# 深度优先遍历实现对象的深度拷贝

 /**
 * 使用栈深度拷贝
 * @param {*} object 树形数据
 * @return {target}
 */
function deepCopy(orginObject) {
    if (orginObject == null || typeof orginObject !== 'object') {
        return;
    }
    console.log('starting')
    const resultObject = {}
    const rootKey = Symbol('root');
    //深度遍历需要创建栈
    const stack = [];
    for (let key of Object.keys(orginObject)) {
        stack.push({
        key: key,//属性名
        value: orginObject[key],//value属性记录当前节点下属数据
        parent: resultObject//记录节点在resultObject中的位置
        })
    }
    while (stack.length) {
        const currentNode = stack.pop();
        // const parent = currentNode.parent;
        // const currentKey = currentNode.key;
        // const currentValue = currentNode.value;
        const { key: currentKey, value: currentValue, parent: parent } = currentNode
        //若是无下属对象,返回其值
        if (currentValue == null || typeof currentValue !== 'object') {
            parent[currentKey] = currentValue;
        } else {
            //若下属值是对象,将子节点压入栈中
            parent[currentKey] = Object.prototype.toString.call(currentValue) === '[object Array]'?[]:{};
            for (let key of Object.keys(currentValue)) {
                console.log('loop:' + key, currentValue[key])
                stack.push({
                    key: key,
                    value: currentValue[key],
                    parent: parent[currentKey]
                })
            }
        }
    }
    return resultObject;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

# 广度优先遍历实现对象的深度拷贝

广度优先遍历对象,利用队列做中间节点缓存

 /**
 * 使用队列深度拷贝
 * @param {*} object 树形数据
 * @return {target}
 */
function deepCopy(orginObject) {
    if (orginObject == null || typeof orginObject !== 'object') {
        return;
    }
    console.log('starting')
    const resultObject = {}
    const rootKey = Symbol('root');
    //深度遍历需要创建栈
    const queue = [];
    for (let key of Object.keys(orginObject)) {
        queue.push({
            key: key,//属性名
            value: orginObject[key],//value属性记录当前节点下属数据
            parent: resultObject//记录节点在resultObject中的位置
        })
    }

    while (queue.length) {
        const currentNode = queue.shift();
        // const parent = currentNode.parent;
        // const currentKey = currentNode.key;
        // const currentValue = currentNode.value;
        const { key: currentKey, value: currentValue, parent: parent } = currentNode
        //若是无下属对象,返回其值
        if (currentValue == null || typeof currentValue !== 'object') {
            parent[currentKey] = currentValue;
        } else {
            //若下属值是对象,将子节点压入栈中
            parent[currentKey] = Object.prototype.toString.call(currentValue) === '[object Array]'?[]:{};
            for (let key of Object.keys(currentValue)) {
                console.log('loop:' + key, currentValue[key])
                queue.push({
                    key: key,
                    value: currentValue[key],
                    parent: parent[currentKey]
                })
            }
        }
    }
    return resultObject;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

# 测试

let object =
{
    "a": {
        "b": {
            "c": {
                "d": "qdkabcd"
            }
        },
        "d": {
            "x": [
                {
                    "d": "qdkabcd"
                },
                {
                    "f": "qdkabcd"
                }
            ]
        },
        "e": "qdkae"
    }
}

deepCopy(object)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# 链接

Last Updated: 12/26/2022, 11:54:10 AM