深度拷贝循环引用的问题

2017-02-21 14:13:19 +08:00
 dnxbf321

对象 a 、 b 存在循环引用,现在要编写一个 copy 函数,能够正常拷贝 a

var a = {}
var b = {}
a['b'] = b
b['a'] = a

console.log(copy(a))

以下代码能够正常运行

var store = [] // store 写在 copy 函数外

function copy(data) {
  var isType = function(v, type) {
    return Object.prototype.toString.call(v).toLowerCase() === '[object ' + type + ']'
  }

  var checkInStore = function(checkV) {
    for (var i = 0, len = store.length; i < len; i++) {
      if (store[i] === checkV) {
        return true
      }
    }
    return false
  }

  var _copy = function(_data) {
    if (checkInStore(_data)) {
      return _data
    } else {
      store.push(_data)
      var ret = isType(_data, 'array') ? [] : {}
      for (var k in _data) {
        var v = _data[k]
        if (typeof v === 'object') {
          ret[k] = copy(v)
        } else {
          ret[k] = v
        }
      }
      return ret
    }
  }

  return _copy(data)
}

以下代码会抛错

function copy(data) {
  var isType = function(v, type) {
    return Object.prototype.toString.call(v).toLowerCase() === '[object ' + type + ']'
  }

  var store = [] // store 写在函数里
  var checkInStore = function(checkV) {
    for (var i = 0, len = store.length; i < len; i++) {
      if (store[i] === checkV) {
        return true
      }
    }
    return false
  }

  var _copy = function(_data) {
    if (checkInStore(_data)) {
      return _data
    } else {
      store.push(_data)
      var ret = isType(_data, 'array') ? [] : {}
      for (var k in _data) {
        var v = _data[k]
        if (typeof v === 'object') {
          ret[k] = copy(v)
        } else {
          ret[k] = v
        }
      }
      return ret
    }
  }

  return _copy(data)
}

将 store 写在 copy 函数外、函数内会有不同的结果。这是为什么啊?半天想不出来,求大神指教,感觉是个作用域问题

3440 次点击
所在节点    JavaScript
4 条回复
xss
2017-02-21 14:43:25 +08:00
store 在外面, 位于全局作用域, 无论递归调用多少次 copy, 最终都会顺着原型链找到全局域上的 store.
store 写在里面, 在递归调用 copy 的时候, 每个调用栈内部都有一个单独的 store 状态, 所以, 你确定每次的 store 的状态都是正确的?
fyh1807008
2017-02-21 14:44:09 +08:00
递归循环调用?
第二个函数每次 store 都被初始化为[],就没有临界值结束循环了
fyh1807008
2017-02-21 15:17:26 +08:00
其实第二段代码只要把 `ret[k] = copy(v)` 改成 `ret[k] = _copy(v)` 就会形成一个闭包,始终保存住 store,isType, checkInStore
dnxbf321
2017-02-21 19:09:10 +08:00
@xss 打断点的时候我也发现 store 每次都初始化过了。
@fyh1807008 惊醒梦中人,手误,我也是想递归时调用 _copy 函数,误写

谢谢

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/342046

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX