Опыт интервью, который сделал меня таким грустным.

Недавно моя подруга потеряла вакансию, которую ей очень нравилась, просто потому, что она не знала, как определить, является ли переменная объектом циклической ссылки.

Что меня разозлило, так это то, что интервьюер бесцеремонно сказал ей после окончания: "Ваша основа Javascript слишком плоха, вам не нужно продолжать интервью позже".

Какое ужасное интервью…

1. TypeError: циклическое значение объекта

Друзья мои, возможно вы сталкивались с такой ошибкой, она не чужда фронтенд-разработчику.

Исключение JavaScript «циклическое значение объекта» возникает, когда ссылки на объекты находятся в JSON. JSON.stringify() не пытается их решить и соответственно терпит неудачу.

2. 3 примера объектов с циклическими ссылками

Когда вы используете функцию JSON.stringify(obj), убедитесь, что obj не является объектом с циклической ссылкой, иначе будет выдано исключение.

На самом деле существует как минимум три способа заставить объект иметь циклическую ссылку.

  1. Два объекта ссылаются друг на друга
let obj1 = { name: 'fatfish1' }
let obj2 = { name: 'fatfish2' }
// The properties of object 1 refer to object 2
obj1.obj = obj2
// The properties of object 2 refer to object 1
obj2.obj = obj1

  1. Свойства объекта являются его собственными
let obj = { name: 'fatfish1' }
// The value of child is obj
obj.child = obj

  1. Свойства объекта являются частью его свойств
let obj = {
  name: 'fatfish',
  child: {
    age: 100
  }
}

obj.child.obj = obj.child

3. Циклический

После приведенного выше анализа давайте попробуем реализовать функцию, функция которой состоит в том, чтобы судить, является ли объект круговым эталонным объектом.

// Check if an object has a circular reference
  const isCyclic = (obj) => {
  // Use the Set data type to store detected objects
  let stackSet = new Set()
  let detected = false

  const detect = (obj) => {
    // If it is not an object type, you can skip it directly
    if (obj && typeof obj != 'object') {
      return
    }
    // When the object to be checked already exists in the stackSet, it means that there is a circular reference
    if (stackSet.has(obj)) {
      return detected = true
    }
    // Save the current obj as a stackSet
    stackSet.add(obj)
    for (let key in obj) {
      if (obj.hasOwnProperty(key)) {
        detect(obj[key])
      }
    }
    // After the level detection is completed, delete the current object to prevent misjudgment
    /*
      For example:
      an object's attribute points to the same reference. 
      If it is not deleted, it will be regarded as a circular reference
      let tempObj = {
        name: 'fatfish'
      }
      let obj4 = {
        obj1: tempObj,
        obj2: tempObj
      }
    */
    stackSet.delete(obj)
  }
  detect(obj)
  return detected
}

Пройти тест

// 1. Two objects refer to each other
let obj1 = { name: 'fatfish1' }
let obj2 = { name: 'fatfish2' }
// The properties of object 1 refer to object 2
obj1.obj = obj2
// The properties of object 2 refer to object 1
obj2.obj = obj1
console.log(isCyclic(obj1)) // true
console.log(isCyclic(obj2)) // true
// 2. The properties of an object are its own
let obj = { name: 'fatfish1' }
// The value of child is obj
obj.child = obj
console.log(isCyclic(obj)) // true
// 3. An object's properties are part of its properties
let obj = {
  name: 'fatfish',
  child: {
    age: 100
  }
}
obj3.child.obj = obj3.child
console.log(isCyclic(obj3)) // true
// 4. A property of an object points to the same object
let tempObj = {
  name: 'fatfish'
}
let obj4 = {
  obj1: tempObj,
  obj2: tempObj
}
console.log(isCyclic(obj4)) // false
// 5. other data types
console.log(isCyclic(1)) // false
console.log(isCyclic('fatfish')) // false
console.log(isCyclic(false)) // false
console.log(isCyclic(null)) // false
console.log(isCyclic(undefined)) // false
console.log(isCyclic([])) // false
console.log(isCyclic(Symbol('fatfish'))) // false

Отлично, isCyclic проходит все тесты.

4. Используйте более безопасный json-цикл

Наконец, вы можете использовать json-cycle для решения возможных проблем с циклическими ссылками.

var jc = require('json-cycle');
var a = {};
a.self = a;
console.log(JSON.stringify(jc.decycle(a))); //  {{"$ref":"$"}}

Дополнительные материалы на PlainEnglish.io. Подпишитесь на нашу бесплатную еженедельную рассылку новостей. Присоединяйтесь к нашему сообществу Discord и следите за нами в Twitter, LinkedIn и YouTube.

Узнайте, как привлечь внимание к своему стартапу с помощью Circuit.