基于TDD,实现深拷贝

236 阅读1分钟

基于TDD,实现深拷贝

测试采用 Jest ,需要注意的是,使用import导入,需要配置babel

首先,我们来写一份测试用例

import { clone } from "./deepClone.js"

describe("test deep clone", () => {
  it("case 1", () => {
    const target = {
      a: 1, // 数字
      b: "string", // 字符串
      d: {
        // 子节点
        child: "child"
      }
    }
    const result = clone(target)
    expect(result).toStrictEqual(target)
  })
  it("case 2 null", () => {
    const target = {
      a: 1, 
      b: "string", 
      c: undefined, // null
      d: {
        child: "child"
      }
    }
    const result = clone(target)
    expect(result).toStrictEqual(target)
  })

  it("case 3 Array", () => {
    const target = {
      a: 1,
      b: "string",
      c: undefined,
      d: {
        child: "child"
      },
      e: [1, 2, 3]
    }
    const result = clone(target)
    expect(result).toStrictEqual(target)
  })
  it("case 4 Circular reference", () => {
    const target = {
      a: 1,
      b: "string",
      c: undefined,
      d: {
        child: "child"
      },
      e: [1, 2, 3]
    }
    target.target = target
    const result = clone(target)
    expect(result).toStrictEqual(target)
  })
})


case 1

这里,我们常见的拷贝可以使用JSON.parse(JSON.stringify(target))

// deepClone.js
export function clone(target) {
  return JSON.parse(JSON.stringify(target))
}

case 2 空值处理

image-20220512162337505

上述的代码,遇到undefined的时候,会移除掉这个元素,所以上述方法并不适用,我们可以尝试写出以下代码

// deepClone.js
export function clone(target) {
    // 当target是对象时处理
  if (typeof target === 'object') {
    let newTarget = {}

    for (const key in target) {
      newTarget[key] = clone(target[key])
    }
    return newTarget
  } else {
    return target
  }
}

case 3 数组

测试用例加入了数组

image-20220512162211206

这时候需要对Array这种特殊的object做处理

// deepClone.js
export function clone(target) {
  if (typeof target === 'object') {
    // 对数组进行处理
    let newTarget = Array.isArray(target) ? [] : {}

    for (const key in target) {
      newTarget[key] = clone(target[key])
    }
    return newTarget
  } else {
    return target
  }
}

case 4 循环引用

image-20220513154832561

// deepClone.js
export function clone(target, map = new Map()) {
  if (typeof target === 'object') {
    let newTarget = Array.isArray(target) ? [] : {}
    if (map.get(target)) {
      return map.get(target)
    }
    map.set(target, newTarget)

    for (const key in target) {
      newTarget[key] = clone(target[key], map)
    }
    return newTarget
  } else {
    return target
  }
}

测试愉快地通过了

image-20220513160908875