作者:xl

    1. // map 处理循环拷贝
    2. function clone(origin, map = new Map()) {
    3. if (typeof origin !== 'object' || origin === null) {
    4. return origin;
    5. }
    6. if (map.get(origin)) {
    7. return map.get(origin);
    8. }
    9. let obj = {}
    10. if (Object.prototype.toString.call(origin) === '[object Array]') {
    11. obj = []
    12. }
    13. map.set(origin, obj);
    14. for (const key in origin) {
    15. obj[key] = clone(origin[key], map);
    16. }
    17. return obj;
    18. }

    作者:gochri

    1. /*
    2. String、Array、TypedArray、Map 和 Set 都是内置可迭代对象,因为它们的原型对象都拥有一个 Symbol.iterator 方法。
    3. Object.entries()方法返回一个给定对象自身可枚举属性的键值对数组,其排列与使用 for...in 循环遍历该对象时返回的顺序一致(区别在于 for-in 循环还会枚举原型链中的属性)。
    4. */
    5. // todo: 处理循环引用
    6. function isObject(value) {
    7. var type = typeof value;
    8. return value != null && (type == 'object' || type == 'function');
    9. }
    10. var deepCopy = (value) => {
    11. let result = {}
    12. if (!isObject(value)) {
    13. result = value
    14. return result
    15. }
    16. if (Array.isArray(value)) {
    17. result = new Array()
    18. for (let i in value) {
    19. result[i] = deepCopy(value[i])
    20. }
    21. return result
    22. }
    23. if (value instanceof Map) {
    24. result = new Map()
    25. for (let [k, v] of value) {
    26. result.set(k, deepCopy(v))
    27. }
    28. // return result
    29. }
    30. if (value instanceof Set) {
    31. result = new Set()
    32. for (let v of value) {
    33. result.add(deepCopy(v))
    34. }
    35. // return result
    36. }
    37. // Object no iterator
    38. // if (typeof value[Symbol.iterator] === 'function') {
    39. // for (const [k, v] of Object.entries(value)) {
    40. // result[k] = deepCopy(v)
    41. // }
    42. // }
    43. // Object
    44. for (let i in value) {
    45. result[i] = deepCopy(value[i])
    46. }
    47. // Promise Function todo:需进行拷贝
    48. if (typeof value === 'function') {
    49. result = value
    50. }
    51. // Symbol
    52. // default case
    53. return result
    54. }
    55. // ------------- TestCode ----------
    56. // var objects = new Set([1, 2, 3])
    57. // var objects = [1, 2, 3]
    58. var objects = new Map()
    59. objects.set('c', 5)
    60. objects.set('d', 6)
    61. objects.a = 4
    62. objects.b = function () {
    63. return new Promise((resolve, reject) => {
    64. if (this.a) {
    65. resolve(this.a)
    66. } else {
    67. reject('no this a')
    68. }
    69. })
    70. }
    71. // objects.__proto__.logA = () => { console.log('a', a) }
    72. var shallow = deepCopy(objects);
    73. objects.a = 2
    74. objects?.b()?.then(r => console.log(r)).catch(err => console.log(err))
    75. shallow?.b()?.then(r => console.log(r)).catch(err => console.log(err))
    76. console.log(shallow, shallow === objects);
    77. // => result
    78. // Map(2) { 'c' => 5, 'd' => 6, a: 4, b: [Function (anonymous)] } false
    79. // 2
    80. // 4

    作者:奥兰度

    1. let a = new Map()
    2. let b = {a}
    3. // 首先解决循环引用,代码结构,考虑特殊数据结构,比如包装对象,比如正则、函数、日期等等
    4. const isObject = (target) => (typeof target === 'object' || typeof target === 'function') && target !== null
    5. // 判断特殊对象的方法
    6. const getType = (obj) => Object.prototype.toString.call(obj)
    7. // 特殊对象类型
    8. const canTraverse = {
    9. '[object Map]': true,
    10. '[object Set]': true,
    11. '[object Array]': true,
    12. '[object Object]': true,
    13. '[object Arguments]': true,
    14. }
    15. const canNotTraverse = {
    16. '[object String]': true,
    17. '[object Number]': true,
    18. '[object Boolean]': true,
    19. '[object RegExp]': true,
    20. '[object Date]': true,
    21. '[object Error]': true,
    22. '[object Function]': true,
    23. '[object Symbol]': true,
    24. }
    25. const mapTag = '[object Map]'
    26. const setTag = '[object Set]'
    27. // 处理正则
    28. const handleRegExp = (target) => {
    29. const { source, flags } = target
    30. return new target.constructor(source, flags)
    31. }
    32. new RegExp('', '')
    33. let a = /aaa/g
    34. // TODO: Error:SyntaxError: Function statements require a function name
    35. const handleFun = (target) => {
    36. // 处理箭头函数
    37. if(!target.prototype) return target
    38. //
    39. const body = target.toString()
    40. return new Function(body)
    41. }
    42. const handleNotTraverse = (target, tag) => {
    43. const Ctor = target.constructor
    44. switch(tag) {
    45. case boolTag:
    46. case numberTag:
    47. case stringTag:
    48. case errorTag:
    49. case dateTag:
    50. return new Ctor(target)
    51. case regexpTag:
    52. return handleRegExp(target)
    53. case funcTag:
    54. return handleFun(target)
    55. default:
    56. return new Ctor(target)
    57. }
    58. }
    59. // 解决循环引用,解决 Map 带来的内存溢出问题
    60. const deepClone = (target = {}, map = new WeakMap()) => {
    61. if(!isObject(target)) {
    62. return target
    63. }
    64. let type = getType(target)
    65. let cloneTarget
    66. if(canTraverse[type]) {
    67. // 保留原型链的处理
    68. let ctor = target.constructor
    69. cloneTarget = new ctor()
    70. } else {
    71. handleNotTraverse(target, type)
    72. }
    73. // 有争议,循环引用的 set 类型并不能很好处理,因为其实是相当于表层浅复制了
    74. if(map.get(target)) {
    75. return target
    76. }
    77. map.set(target, true)
    78. if(type === mapTag) {
    79. target.forEach((item, key) => {
    80. cloneTarget.set(deepClone(key, map), deepClone(item, map))
    81. })
    82. }
    83. if(type === setTag){
    84. // Set 在 forEach 时,如果你对源 Set 添加东西,会造成爆栈
    85. target.forEach((item) => {
    86. cloneTarget.add(deepClone(item, map))
    87. })
    88. }
    89. // 处理数组、对象、Arguments
    90. for(let prop in target) {
    91. if(target.hasOwnProperty(prop)) {
    92. cloneTarget[prop] = deepClone(target[prop], map)
    93. }
    94. }
    95. return cloneTarget
    96. }

    作者:安静

    1. function deepClone(obj = {}) {
    2. if (typeof obj !== 'object' || obj == null) {
    3. // obj 是 null ,或者不是对象和数组,直接返回
    4. return obj
    5. }
    6. // 初始化返回结果
    7. let result
    8. if (obj instanceof Array) {
    9. result = []
    10. } else {
    11. result = {}
    12. }
    13. for (let key in obj) {
    14. // 保证 key 不是原型的属性
    15. if (obj.hasOwnProperty(key)) {
    16. // 递归调用!!!
    17. result[key] = deepClone(obj[key])
    18. }
    19. }
    20. // 返回结果
    21. return result
    22. }
    23. const obj1 = {
    24. age: 20,
    25. name: 'xxx',
    26. address: {
    27. city: 'beijing'
    28. },
    29. arr: ['a', 'b', 'c']
    30. }
    31. const obj2 = deepClone(obj1)
    32. obj2.address.city = 'shanghai'
    33. obj2.arr[0] = 'a1'
    34. console.log(obj1.address.city)
    35. console.log(obj1.arr[0])

    作者:
    作者: