极客时间返利平台,你可以在上边通过山月的链接购买课程,并添加我的微信 (shanyue94) 领取返现。
山月训练营之面试直通车 服务上线了,从准备简历、八股文准备、项目经历准备、面试、面经、面经解答、主观问题答复、谈薪再到入职的一条龙服务。

# JS 如何检测到对象中有循环引用

更多描述

示例,如下数据为循环结构/循环引用

const user = { id: 10086, name: "山月" };
user._user = user;

追问:

  1. 由于 JSON.stringify 序列化对象时,将跳过不枚举的 key,因此此时可不考虑不可枚举的 key
  2. 如果考虑不可枚举 key 与 Symbol 如何处理

Issue

欢迎在 Gtihub Issue 中回答此问题: Issue 683 (opens new window)

TODO

Author

回答者: yoyou (opens new window)

const a = {
a:1,
c: 3
}

const b = {
  a: a,
  c: 3
}
a.b = b;

//JSON.stringify(a);

const keyMap = new Map();
keyMap.set(a, "1");
keyMap.set(b, "2");
function circle(target) {
  const keys = Object.keys(target);
  for(let i = 0; i < keys.length; i++) {
    const key = keys[i];
    const val = target[key];
    if(keyMap.has(val)) {
      return true
    }else {
      keyMap.set(val, key)
      if(typeof val === 'object') {
        circle(val)
      }
    }
  }
  return false;
}
console.log(circle(a))

Author

回答者: iotale (opens new window)

const a = {
a:1,
c: 3
}

const b = {
  a: a,
  c: 3
}
a.b = b;

//JSON.stringify(a);

const keyMap = new Map();
keyMap.set(a, "1");
keyMap.set(b, "2");
function circle(target) {
  const keys = Object.keys(target);
  for(let i = 0; i < keys.length; i++) {
    const key = keys[i];
    const val = target[key];
    if(keyMap.has(val)) {
      return true
    }else {
      keyMap.set(val, key)
      if(typeof val === 'object') {
        circle(val)
      }
    }
  }
  return false;
}
console.log(circle(a))

可以将 Object.keys() 替换为 Reflect.ownKeys()

function isCircularReference(value) {
  const isObject = (value) =>
    Object.prototype.toString.call(value) === "[object Object]";
  const memory = new WeakMap();
  let isCycled = false;
  const traverse = function (value) {
    if (isObject(value)) {
      if (memory.has(value)) {
        isCycled = true;
        return;
      }
      memory.set(value, true);
      const keys = Object.keys(value);
      for (const key of keys) {
        traverse(value[key]);
      }
    }
  };
  traverse(value);
  return isCycled;
}
function isCircularReference(value) {
  const isObject = (value) =>
    Object.prototype.toString.call(value) === "[object Object]";
  const memory = new WeakMap();
  let isCycled = false;
  const traverse = function (value) {
    if (isObject(value)) {
      if (memory.has(value)) {
        isCycled = true;
        return;
      }
      memory.set(value, true);
      const keys = Object.keys(value);
      for (const key of keys) {
        traverse(value[key]);
      }
    }
  };
  traverse(value);
  return isCycled;
}
// isObject改为isPrimitive
const isPrimitive = (value) =>
  /Number|Boolean|String|Undefined|Null|Symbol/.test(
    Object.prototype.toString.call(value)
  );

希望不可枚举和 Symbol 可以 Reflect.ownKeys(obj).map(curr => obj[curr]) 获取全部的 key 对应的 values Object 上面也有 不过是分开的 两个 API

function checkObj(obj, set = new Set()) {
  if ((typeof obj === "object" && obj !== null) || Array.isArray(obj)) {
    if (set.has(obj)) {
      return true;
    } else {
      set.add(obj);
    }
    return Object.values(obj).some((curr) => {
      return checkObj(curr, set);
    });
  }
  return false;
}

Author

回答者: Hishengs (opens new window)

function isCircular(obj) {
  try {
    JSON.stringify(obj);
  } catch (e) {
    return e.message.includes("Converting circular structure to JSON");
  }
  return false;
}
Last Updated: 11/27/2021, 6:11:48 PM