SOURCE

function getType(obj){
    return Object.prototype.toString.call(obj).slice(8,-1)
}

// 深度优先遍历思想实现拷贝函数, arr存放所有已访问的父级节点
// 循环节点有两种情况,一种是父级引用,另一种是同级引用
function DFSdeepCopy(obj,arr = []){
    const type = getType(obj)
    let _obj = {}
    if(['Array','Object'].includes(type)){
        console.log('执行')
        if(type === 'Array'){
            _obj = []
        }
        let index = arr.indexOf(obj)
        if(index === -1){
            arr.push(obj)
            for(let item in obj){
                _obj[item] = DFSdeepCopy(obj[item],arr)
            }
        }else{
            _obj = arr[index]
        }
    }else if(type === 'Function'){
        _obj = obj
    }else{
        _obj = obj
    }
    return _obj
}


var template = {
    a:1,
    b:[1,2,3],
    c:true,
    d:{
        name:['tome'],
        age:null,
        friends:undefined,
    }
}
template.d.self = template.d

// const copyObj = DFSdeepCopy(template)


const copyObj = BFSdeepCopy(template)
console.log(copyObj)

// 广度优先遍历思想实现拷贝函数
// 广度优先遍历要用到栈结构
function BFSdeepCopy(obj){
    let origin = [obj];
    let copyObj = {};
    let copy = [copyObj]

    // 环状数据的引用
    let queue = []
    let copyQueue = []

    while(origin.length > 0){
        let items = origin.shift()
        let _obj = copy.shift()

        queue.push(items)

        const type = getType(items)
        if(type === 'Array' || type === 'Object'){

            for(let item in items){
                let val = items[item]
                if(getType(val) === 'Array'){
                    _obj[item] = []
                    queue.push(item)
                    copy.push(_obj[item])
                }else if(getType(val) === 'Object'){
                    const index = copyQueue.indexOf(items)
                    if(index === -1){
                        _obj[item] = {}
                        queue.push(item)
                        copy.push(_obj[item])
                    }else{
                        _obj[item] = copyQueue[index]
                    }
                }else if(getType(val) === 'Function'){
                    _obj[item] = eval('('+ val.toString() + ')')
                }else{
                    _obj[item] = val
                }
            }

            copyQueue.push(items)

        }else if(type === 'Function'){
            _obj = eval('('+ val.toString() + ')')
        }else if(type === 'Symbol'){
            // Symbol表示独一无二的数,第七种数据类型
        }else{
            _obj[items] = items
        }
    }
    
    return copyObj

}

function getType(obj){
    return Object.prototype.toString.call(obj).slice(8,-1)
}

console 命令行工具 X clear

                    
>
console