Способ доступа к свойству без знания его пути во вложенном объекте js - PullRequest
0 голосов
/ 07 июня 2018

есть ли способ получить доступ к вложенному свойству внутри объекта, не зная его пути?Например, у меня может быть что-то вроде этого

let test1 = {
  location: {
    state: {
     className: 'myCalss'
    }
 }
};

let test2 = {
  params: {
    className: 'myCalss'
  }
};

Есть ли аккуратный способ "извлечь" свойство className?У меня есть решение, но оно довольно уродливое, и оно учитывает только эти два случая, мне было интересно, есть ли что-нибудь более гибкое, что я мог бы сделать

Ответы [ 2 ]

0 голосов
/ 07 июня 2018

Вот несколько элегантный подход к созданию методов получения вложенных свойств:

const getProperty = property => {
  const getter = o => {
    if (o && typeof o === 'object') {
      return Object.entries(o)
        .map(([key, value]) => key === property ? value : getter(value))
        .filter(Boolean)
        .shift()
    }
  }

  return getter
}

const test1 = {
  location: {
    state: {
      className: 'test1'
    }
  }
}

const test2 = {
  params: {
    className: 'test2'
  }
}

const test3 = {}

const getClassName = getProperty('className')

console.log(getClassName(test1))
console.log(getClassName(test2))
console.log(getClassName(test3))

Если вы хотите, чтобы циклические объекты не вызывали переполнение стека, я предлагаю использовать WeakSet для отслеживания повторных ссылок на объекты:

const getProperty = property => {
  const getter = (o, ws = new WeakSet()) => {
    if (o && typeof o === 'object' && !ws.has(o)) {
      ws.add(o)
      return Object.entries(o)
        .map(([key, value]) => key === property ? value : getter(value, ws))
        .filter(Boolean)
        .shift()
    }
  }

  return getter
}

const test1 = {
  location: {
    state: {
      className: 'test1'
    }
  }
}

const test2 = {
  params: {
    className: 'test2'
  }
}

const test3 = {}
const test4 = {
  a: {
    b: {}
  }
}

test4.a.self = test4
test4.a.b.self = test4
test4.a.b.className = 'test4'

const getClassName = getProperty('className')

console.log(getClassName(test1))
console.log(getClassName(test2))
console.log(getClassName(test3))
console.log(getClassName(test4))
0 голосов
/ 07 июня 2018

Конечно.Дайте это попробовать.Он рекурсивно перебирает объект и возвращает первое совпадение.Вы можете настроить цикл for так, чтобы он соответствовал всем или последним, в соответствии с вашими потребностями

let test1 = {
  location: {
    state: {
     className: 'myCalss'
    }
 }
};

let test2 = {
  params: {
    className: 'myCalss'
  }
};

function getClassName(obj) {
  if(typeof obj === "object" && 'className' in obj) {
    return obj.className
  }
  const keys = Object.keys(obj)
  for(let i = 0; i < keys.length; i++) {
    let key = keys[i]
    let res = getClassName(obj[key])
    if(res) return res
  }
  return null
}

console.log(getClassName(test1), getClassName(test2))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...