代码之家  ›  专栏  ›  技术社区  ›  MaiaVictor

使用JSON.stringify进行深度比较和克隆可以吗?

  •  20
  • MaiaVictor  · 技术社区  · 11 年前

    在尝试了几种对JSON可序列化对象进行深度比较和复制的实现后,我注意到最快的实现通常只有:

    function deep_clone(a){
       return JSON.parse(JSON.stringify(a));
    };
    function is_equal(a,b){
        return JSON.stringify(a) === JSON.stringify(b);
    };
    

    不过我觉得这是在作弊。就像我会发现一些将来会困扰我的问题一样。用这些可以吗?

    4 回复  |  直到 7 年前
        1
  •  30
  •   Adam Azad    6 年前

    JavaScript不能保证密钥的顺序。

    如果它们以相同的顺序输入,这种方法在大多数情况下都会起作用,但并不可靠。

    此外,对于深度相等但键按不同顺序输入的对象,它将返回false:

    JSON.stringify({ a: 1, b: 2}) === "{"a":1,"b":2}"
    
    JSON.stringify({ b: 2, a: 1}) === "{"b":2,"a":1}"
    
        2
  •  14
  •   Jason Rogers    8 年前

    我意识到这是一个老问题,但我只想在答案中再加一点,因为否则有人可能会错误地认为使用 JSON.stringify 对于比较/克隆,只要不用于比较/克隆成员无序的对象,它就可以正常工作。(公平地说,他们 不应该 想着离开;它说:“如果(成员)按相同的顺序输入,这种方法就会奏效 大部分时间 .")

    代码可能最能说明潜在的打嗝:

    JSON.stringify(NaN) === JSON.stringify(null)
    // => true
    
    JSON.stringify(Infinity) === JSON.stringify(null)
    // => true
    
    // or, to put it all together:
    JSON.stringify({ val1: (1 / 0), val2: parseInt("hi there"), val3: NaN }) === JSON.stringify({ val1: NaN, val2: null, val3: null })
    // => true
    
    // and here's the same example with "cloning" rather than comparison:
    JSON.parse(JSON.stringify({ val1: (1 / 0), val2: parseInt("hi there"), val3: NaN }))
    // => Object {val1: null, val2: null, val3: null}
    

    即使订购不是问题(正如其他人所说,可能是问题),这些怪癖也会造成麻烦。在大多数情况下,这些怪癖可能不太可能引起人们的注意,但最好注意它们,因为它们可能会导致一些很难找到的bug。

        3
  •  0
  •   John Fontana    11 年前

    只要键值对总是按相同的顺序排列,是的,您可以使用stringify使用deep equals运算符(===)进行比较。

        4
  •  0
  •   rahulmishra    2 年前

    我编写此函数是为了深入比较任何对象数组或值: 如果你愿意,可以使用它:)我用对象和数组中随机进入顺序的大量对象样本进行了测试。

    function c(x, y) {
      if (!x && !y) return !0
      if (!x || !y) return !1
      if (typeof (x) !==
          typeof (y)) return !1
      if (x instanceof Array) {
        if (
          x.length != y.length) return !1
        const f = []
        for (let i = 0; i < x.length; i++) {
          if (!c(x[i], y[i])) f.push(i)
        }
        const g = [...f]
        for (const i of f) {
          let r = !1
          for (const j of g) {
            if (
              c(x[i], y[j])) {
              g.splice(g.indexOf(j), 1)
              r++
              break
            }
          }
          if (!r) { return !1 }
        }
        return !0
      } else if (x instanceof Object) {
        const e1 =
              Object.entries(x)
        try {
          return c(e1, r(Object.entries(y),
            e1))
        } catch (e) {
          return !1
        }
      } else {
        return x === y
      }
    
      function r(
        u, v) {
        const a = []
        if (u.length != v.length) return u
        for (
          let i = 0; i < v.length; i++) {
          a.push(m(u, v[i][0]))
        }
        return a
      }
    
      function m(a, k) {
        for (let i = 0; i < a.length; i++) {
          if (a[i][0] === k) return [a[i][0], a[i][1]]
        }
        throw 0
      }
    }