Если у меня есть ссылка на объект:
var test = {};
потенциально (но не сразу) будет иметь вложенные объекты, что-то вроде:
{level1: {level2: {level3: "level3"}}};
Как лучше всего проверить наличие свойства в глубоко вложенных объектах?
alert(test.level1);
доходность undefined
, но alert(test.level1.level2.level3);
терпит неудачу.
В настоящее время я делаю что-то вроде этого:
if(test.level1 && test.level1.level2 && test.level1.level2.level3) {
alert(test.level1.level2.level3);
}
но мне было интересно, есть ли лучший способ.
javascript
object
properties
nested
user113716
источник
источник
Ответы:
Вы должны делать это шаг за шагом, если не хотите,
TypeError
потому что, если один из участников являетсяnull
илиundefined
, и вы пытаетесь получить доступ к члену, будет выдано исключение.Вы можете либо просто
catch
исключить, либо создать функцию для проверки существования нескольких уровней, что-то вроде этого:ES6 ОБНОВЛЕНИЕ:
Вот более короткая версия исходной функции, использующая функции ES6 и рекурсию (она также находится в правильной форме хвостового вызова ):
Однако, если вы хотите получить значение вложенного свойства, а не только проверить его существование, вот простая однострочная функция:
Вышеуказанная функция позволяет получить значение вложенных свойств, иначе вернется
undefined
.ОБНОВЛЕНИЕ 2019-10-17:
Опциональное предложение цепочки достигла этап 3 на процессе комитета ECMAScript , это позволит вам безопасно доступу глубоко вложенные свойствам, используя маркер
?.
, новый необязательный оператор цепочки :Если какой-либо из уровней, к которым осуществляется доступ, является
null
илиundefined
выражение будет разрешеноundefined
само по себе.Предложение также позволяет безопасно обрабатывать вызовы методов:
Выше выражение будет производить ,
undefined
еслиobj
,obj.level1
илиobj.level1.method
являютсяnull
илиundefined
, иначе это вызовет функцию.Вы можете начать играть с этой функцией с Babel, используя дополнительный плагин цепочки .Начиная с Babel 7.8.0 , ES2020 поддерживается по умолчанию
Проверьте этот пример на Babel REPL.
«ОБНОВЛЕНИЕ: декабрь 2019»
Факультативное предложение о цепочке, наконец, достигло стадии 4 на заседании комитета TC39 в декабре 2019 года. Это означает, что эта функция будет частью стандарта ECMAScript 2020 .
источник
arguments
на самом деле не массив.Array.prototype.slice.call(arguments)
преобразует его в формальный массив. Learnvar obj = arguments[0];
и начатьvar i = 1
вместо того , чтобы копироватьarguments
объектargs
объявление переменной может быть удалено и...args
может использоваться как второй аргументcheckNested
метода. developer.mozilla.org/en/docs/Web/JavaScript/Reference/…Вот образец, который я взял от Оливера Стила :
Фактически, вся эта статья - обсуждение того, как вы можете сделать это в javascript. Он останавливается на использовании приведенного выше синтаксиса (который не так уж сложно прочитать, как только вы привыкнете к нему) в качестве идиомы.
источник
(test || {})
том, что если тест не определен, то вы делаете({}.level1 || {})
. Конечно,{}.level1
не определено, так что это означает, что вы делаете{}.level2
, и так далее.test
не объявлено, то будет ReferenceError , но это не проблема, потому что, если он не объявлен, есть ошибка, которую нужно исправить, поэтому ошибка - это хорошо.if(test.level1 && test.level1.level2 && test.level1.level2.level3)
Обновить
Похоже, что lodash добавил
_.get
для всех ваших нужд получения вложенных свойств.https://lodash.com/docs#get
Предыдущий ответ
Пользователям lodash может понравиться lodash.contrib, в котором есть несколько методов, которые решают эту проблему .
GetPath
Подпись:
_.getPath(obj:Object, ks:String|Array)
Получает значение на любой глубине вложенного объекта на основе пути, описанного данными ключами. Ключи могут быть заданы в виде массива или в виде строки, разделенной точками. Возвращает,
undefined
если путь не может быть достигнут.источник
function isPathDefined(object, path) { return typeof _.getPath(object, path) !== 'undefined'; }
_.get(countries, 'greece.sparta.playwright', 'default'); // → 'default' _.has(countries, 'greece.spart.playwright') // → false
var url = _.get(e, 'currentTarget.myurl', null) || _.get(e, 'currentTarget.attributes.myurl.nodeValue', null) || null
Я провел тесты производительности (спасибо cdMinix за добавление lodash) для некоторых предложений, предложенных по этому вопросу, с результатами, перечисленными ниже.
Обертывание объекта (Оливер Стил) - 34% - самый быстрый
Оригинальное решение (предложено в вопросе) - 45%
checkNested - 50%
get_if_exist - 52%
validChain - 54%
objHasKeys - 63%
nestedPropertyExists - 69%
_.get - 72%
самый глубокий - 86%
грустные клоуны - 100% - самый медленный
источник
_.get()
? насколько он эффективен по сравнению с этими ответами?reduce
илиtry/catch
из удобства.try { test.level1.level2.level3 } catch (e) { // some logger e }
Вы можете прочитать свойство объекта на любой глубине, если вы справляетесь имя как строка:
't.level1.level2.level3'
.Возвращается,
undefined
если какой-либо из сегментов естьundefined
.источник
Если вы кодируете в среде ES6 (или используете 6to5 ), вы можете воспользоваться синтаксисом функции стрелки :
Что касается производительности, то при использовании
try..catch
блока не снижается производительность при использовании блока. Если свойство не установлено, это влияет на производительность.Попробуйте просто использовать
_.has
:источник
try-catch
подход - лучший ответ. Существует философское различие между запросом объекта для его типа и предположением, что API существует, и, соответственно, ошибкой, если это не так. Последнее больше подходит для слабо типизированных языков. См. Stackoverflow.com/a/408305/2419669 .try-catch
Подход также намного яснее , чемif (foo && foo.bar && foo.bar.baz && foo.bar.baz.qux) { ... }
.как насчет
источник
hasOwnProperty()
n раз?Ответ ES6, тщательно протестирован :)
→ см. Codepen с полным тестовым покрытием
источник
===
для разных фальшивок и добавил тест. Если у вас есть идея получше, дайте мне знать).false
. И тогда вы можете захотеть, чтобы в вашем объекте было установлено значениеundefined
(я знаю, что это странно, но это JS). Я сделал положительное ложное значение, установленное в'Prop not Found'
:const hasTruthyProp = prop => prop === 'Prop not found' ? false : true const path = obj => path => path.reduce((obj, prop) => { return obj && obj.hasOwnProperty(prop) ? obj[prop] : 'Prop not found' }, obj) const myFunc = compose(hasTruthyProp, path(obj))
Вы также можете использовать дополнительное предложение о связывании tc39 вместе с babel 7 - tc39-offer-option-chaining
Код будет выглядеть так:
источник
Я попробовал рекурсивный подход:
В
! keys.length ||
выгоняет рекурсии , чтобы он не запустить функцию без каких - либо ключей , оставленных для тестирования. тесты:Я использую его, чтобы напечатать дружественный HTML вид множества объектов с неизвестным ключом / значениями, например:
источник
Я думаю, что следующий скрипт дает более читаемое представление.
объявить функцию:
затем используйте это так:
Я называю это "техникой грустного клоуна", потому что она использует знак o (
РЕДАКТИРОВАТЬ:
вот версия для TypeScript
он дает проверки типов во время компиляции (а также intellisense, если вы используете такой инструмент, как Visual Studio)
использование такое же:
но на этот раз intellisense работает!
Кроме того, вы можете установить значение по умолчанию:
источник
°0o <°(())))><
Object
тип. +1.создать глобальный
function
и использовать во всем проектепопробуй это
если условие
источник
Один простой способ заключается в следующем:
try/catch
Улавливает случаи , когда для какой - либо из более высокого уровня объектов , таких как тест, test.level1, test.level1.level2 не определены.источник
Я не видел ни одного примера использования прокси
Так что я придумал свой. Самое замечательное в этом то, что вам не нужно интерполировать строки. На самом деле вы можете вернуть
объектнуюфункцию с цепочкой и сделать с ней некоторые магические вещи. Вы даже можете вызывать функции и получать индексы массива для проверки глубоких объектов.Показать фрагмент кода
Приведенный выше код отлично работает для синхронных вещей. Но как бы вы протестировали что-то асинхронное, как этот вызов ajax? Как вы это тестируете? Что делать, если ответ не JSON, когда он возвращает ошибку 500 HTTP?
уверен, что вы можете использовать async / await, чтобы избавиться от некоторых обратных вызовов. Но что, если бы вы могли сделать это еще более волшебным образом? что-то похожее на это:
Вы, наверное, задаетесь вопросом, где все обещания и
.then
цепочки ... это может блокировать все, что вы знаете ... но, используя ту же технику Proxy с обещанием, вы можете фактически протестировать глубоко вложенный сложный путь его существования, даже не написав ни одной функции.Показать фрагмент кода
источник
Основываясь на этом ответе , я придумал эту универсальную функцию,
ES2015
которая решит проблемуисточник
function validChain (object, path) { return path.split('.').reduce((a, b) => (a || { })[b], object) !== undefined }
Я создал небольшую функцию для безопасного получения вложенных свойств объекта.
Или более простая, но немного нечитаемая версия:
Или даже короче, но без отступления от ложного флага:
У меня есть тест с:
И вот несколько тестов:
Чтобы увидеть весь код с документацией и тестами, которые я пробовал, вы можете проверить мой github gist: https://gist.github.com/vsambor/3df9ad75ff3de489bbcb7b8c60beebf4#file-javascriptgetnestedvalues-js
источник
Короче, ES5 версия превосходного ответа @ CMS:
С похожим тестом:
источник
checkObjHasKeys(test, ['level1', 'level2', 'asdf', 'asdf']);
success = false;
наreturn false
. Вы должны выручить, как только вы узнаете, что он сломался, ничего более глубокого не может существовать, если он нулевой или неопределенный. Это предотвратит ошибки в более глубоких вложенных элементах, поскольку они, очевидно, тоже не существуют.Я искал возвращаемое значение, если свойство существует, поэтому я изменил ответ в CMS выше. Вот что я придумал:
источник
Ответ, данный CMS, отлично работает со следующей модификацией для нулевых проверок, а также
источник
Следующие варианты были разработаны, начиная с этого ответа . Одно и то же дерево для обоих:
Прекратить поиск, когда не определено
Убедитесь, что каждый уровень один за другим
источник
Я знаю, что этот вопрос старый, но я хотел предложить расширение, добавив его ко всем объектам. Я знаю, что люди, как правило, не одобряют использование прототипа Object для расширенной функциональности объекта, но я не нахожу ничего проще, чем делать это. Кроме того, теперь это разрешено с помощью метода Object.defineProperty .
Теперь, чтобы проверить любое свойство в любом объекте, вы можете просто сделать:
Вот jsfiddle, чтобы проверить его, и, в частности, он включает в себя некоторый jQuery, который ломается, если вы напрямую изменяете Object.prototype из-за того, что свойство становится перечисляемым. Это должно хорошо работать со сторонними библиотеками.
источник
Я думаю, что это небольшое улучшение (становится 1-лайнер):
Это работает, потому что оператор && возвращает последний операнд, который он оценил (и он закорачивается).
источник
Это работает со всеми объектами и массивами :)
например:
это мой улучшенный вариант ответа Брайана
Я использовал _has в качестве имени свойства, потому что оно может конфликтовать с существующим свойством has (например, maps)
Вот скрипка
источник
Вот мое мнение - большинство из этих решений игнорируют случай вложенного массива, как в:
Я могу хотеть проверить
obj.l2[0].k
С помощью функции ниже, вы можете сделать
deeptest('l2[0].k',obj)
Функция вернет true, если объект существует, иначе false
источник
Теперь мы также можем использовать
reduce
для циклического перебора вложенных ключей:источник
Вы можете сделать это с помощью рекурсивной функции. Это будет работать, даже если вы не знаете имя всех вложенных ключей объекта.
источник
есть функция здесь в thecodeabode (safeRead), которая сделает это безопасным способом ... т.е.
если какое-либо свойство имеет значение null или не определено, возвращается пустая строка
источник
Основываясь на предыдущем комментарии , вот еще одна версия, где основной объект также не может быть определен:
источник
Я написал свою собственную функцию, которая выбирает желаемый путь и имеет хорошую и плохую функцию обратного вызова.
Применение:
источник
источник