Si j'ai une référence à un objet:
var test = {};
qui auront potentiellement (mais pas immédiatement) des objets imbriqués, quelque chose comme:
{level1: {level2: {level3: "level3"}}};
Quelle est la meilleure façon de vérifier l'existence d'une propriété dans des objets profondément imbriqués?
alert(test.level1);
cède undefined
, mais alert(test.level1.level2.level3);
échoue.
Je fais actuellement quelque chose comme ça:
if(test.level1 && test.level1.level2 && test.level1.level2.level3) {
alert(test.level1.level2.level3);
}
mais je me demandais s'il y avait une meilleure façon.
javascript
object
properties
nested
user113716
la source
la source
Réponses:
Vous devez le faire étape par étape si vous ne voulez pas de
TypeError
car si l'un des membres estnull
ouundefined
, et que vous essayez d'accéder à un membre, une exception sera levée.Vous pouvez soit simplement
catch
l'exception, soit créer une fonction pour tester l'existence de plusieurs niveaux, quelque chose comme ceci:MISE À JOUR ES6:
Voici une version plus courte de la fonction d'origine, utilisant les fonctionnalités ES6 et la récursivité (elle est également sous la forme d'un appel d'appel approprié ):
Cependant, si vous souhaitez obtenir la valeur d'une propriété imbriquée et non seulement vérifier son existence, voici une fonction simple sur une ligne:
La fonction ci-dessus vous permet d'obtenir la valeur des propriétés imbriquées, sinon elle reviendra
undefined
.MISE À JOUR 2019-10-17:
La proposition de chaînage facultative a atteint l'étape 3 du processus du comité ECMAScript , cela vous permettra d'accéder en toute sécurité aux propriétés profondément imbriquées, en utilisant le jeton
?.
, le nouvel opérateur de chaînage facultatif :Si l'un des niveaux accessibles est
null
ouundefined
l'expression se résoudra d'undefined
elle-même.La proposition vous permet également de gérer les appels de méthode en toute sécurité:
L'expression ci - dessus produira
undefined
siobj
,obj.level1
ouobj.level1.method
sontnull
ouundefined
, sinon , il appellera la fonction.Vous pouvez commencer à jouer avec cette fonctionnalité avec Babel en utilisant le plugin de chaînage en option .Depuis Babel 7.8.0 , ES2020 est pris en charge par défaut
Consultez cet exemple sur le Babel REPL.
🎉🎉MISE À JOUR: décembre 2019 🎉🎉
La proposition de chaînage facultatif a finalement atteint l'étape 4 lors de la réunion de décembre 2019 du comité TC39. Cela signifie que cette fonctionnalité fera partie de la norme ECMAScript 2020 .
la source
arguments
n'est pas réellement un tableau.Array.prototype.slice.call(arguments)
le convertit en un tableau formel. Apprendrevar obj = arguments[0];
et à commencer auvar i = 1
lieu de copier l'arguments
objetargs
déclaration de variable peut être supprimée et...args
peut être utilisée comme deuxième argument de lacheckNested
méthode. developer.mozilla.org/en/docs/Web/JavaScript/Reference/…Voici un modèle que j'ai choisi d'Oliver Steele :
En fait, cet article est une discussion sur la façon dont vous pouvez le faire en javascript. Il décide d'utiliser la syntaxe ci-dessus (qui n'est pas si difficile à lire une fois que vous vous y êtes habitué) comme idiome.
la source
(test || {})
est que si le test n'est pas défini, alors vous le faites({}.level1 || {})
. Bien sûr,{}.level1
n'est pas défini, ce qui signifie que vous faites{}.level2
, et ainsi de suite.test
n'est pas déclaré, il y aura une ReferenceError , mais ce n'est pas un problème, car s'il n'est pas déclaré, il y a un bug à corriger, donc l'erreur est une bonne chose.if(test.level1 && test.level1.level2 && test.level1.level2.level3)
Mise à jour
On dirait que lodash a ajouté
_.get
pour tous vos besoins immobiliers imbriqués.https://lodash.com/docs#get
Réponse précédente
Les utilisateurs de lodash peuvent profiter de lodash.contrib qui dispose de quelques méthodes pour atténuer ce problème .
getPath
Signature:
_.getPath(obj:Object, ks:String|Array)
Obtient la valeur à n'importe quelle profondeur dans un objet imbriqué en fonction du chemin décrit par les clés données. Les clés peuvent être données sous forme de tableau ou de chaîne séparée par des points. Renvoie
undefined
si le chemin ne peut pas être atteint.la source
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
J'ai fait des tests de performance (merci cdMinix pour avoir ajouté lodash) sur certaines des suggestions proposées à cette question avec les résultats listés ci-dessous.
Object Wrap (par Oliver Steele) - 34% - le plus rapide
Solution originale (suggérée en question) - 45%
checkNested - 50%
get_if_exist - 52%
validChain - 54%
objHasKeys - 63%
nestedPropertyExists - 69%
_.get - 72%
plus habile - 86%
clowns tristes - 100% - les plus lents
la source
_.get()
? Quelle est sa performance par rapport à ces réponses?reduce
outry/catch
par commodité.try { test.level1.level2.level3 } catch (e) { // some logger e }
Vous pouvez lire une propriété d'objet à toute profondeur, si vous gérez le nom comme une chaîne:
't.level1.level2.level3'
.Il retourne
undefined
si l'un des segments l'estundefined
.la source
Si vous codez dans un environnement ES6 (ou utilisez 6to5 ), vous pouvez profiter de la syntaxe de la fonction flèche :
En ce qui concerne les performances, il n'y a pas de pénalité de performances pour l'utilisation de
try..catch
block si la propriété est définie. Il y a un impact sur les performances si la propriété n'est pas définie.Pensez simplement à utiliser
_.has
:la source
try-catch
approche est la meilleure réponse. Il y a une différence philosophique entre interroger un objet pour son type et supposer que l'API existe et échouer en conséquence si ce n'est pas le cas. Ce dernier est plus approprié dans les langues peu typées. Voir stackoverflow.com/a/408305/2419669 . L'try-catch
approche est également beaucoup plus claire queif (foo && foo.bar && foo.bar.baz && foo.bar.baz.qux) { ... }
.que diriez-vous
la source
hasOwnProperty()
n fois?Réponse ES6, minutieusement testée :)
→ voir Codepen avec une couverture complète des tests
la source
===
pour les différents falsys, et ajoute un test. Si vous avez une meilleure idée, faites le moi savoir).false
. Et puis vous voudrez peut-être avoir une valeur dans votre objet défini surundefined
(je sais que c'est bizarre mais c'est JS). J'ai fait une fausse valeur positive fixée à'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))
Vous pouvez également utiliser la proposition de chaînage facultative tc39 avec babel 7 - chaînage-facultatif-tc39-proposition
Le code ressemblerait à ceci:
la source
J'ai essayé une approche récursive:
Les
! keys.length ||
coups de pied hors de la récursivité afin qu'il n'exécute pas la fonction avec aucune clé à gauche pour tester. Tests:Je l'utilise pour imprimer une vue html conviviale d'un tas d'objets avec des clés / valeurs inconnues, par exemple:
la source
Je pense que le script suivant donne une représentation plus lisible.
déclarer une fonction:
puis utilisez-le comme ceci:
Je l'appelle "technique du clown triste" car elle utilise le signe o (
ÉDITER:
voici une version pour TypeScript
il donne des vérifications de type au moment de la compilation (ainsi que l'intellisense si vous utilisez un outil comme Visual Studio)
l'usage est le même:
mais cette fois l'intellisense fonctionne!
de plus, vous pouvez définir une valeur par défaut:
la source
°0o <°(())))><
Object
type. +1.créer un global
function
et utiliser dans tout le projetessaye ça
si condition
la source
Une façon simple est la suivante:
Le
try/catch
capture les cas où aucun des objets de niveau supérieur tels que test, test.level1, test.level1.level2 n'est défini.la source
Je n'ai vu aucun exemple de personne utilisant des proxys
J'ai donc créé le mien. La grande chose à ce sujet est que vous n'avez pas à interpoler les chaînes. Vous pouvez en fait retourner une fonction d'
objetchaînable et faire des choses magiques avec. Vous pouvez même appeler des fonctions et obtenir des index de tableau pour rechercher des objets profondsAfficher l'extrait de code
Le code ci-dessus fonctionne bien pour les choses synchrones. Mais comment testeriez-vous quelque chose d'asynchrone comme cet appel ajax? Comment testez-vous cela? que faire si la réponse n'est pas json lorsqu'elle renvoie une erreur http 500?
vous pouvez utiliser async / wait pour vous débarrasser de certains rappels. Et si vous pouviez le faire encore plus par magie? quelque chose qui ressemble à ceci:
Vous vous demandez probablement où se trouvent toutes les promesses et
.then
chaînes ... cela pourrait bloquer pour tout ce que vous savez ... mais en utilisant la même technique de proxy avec promesse, vous pouvez réellement tester un chemin complexe profondément imbriqué pour son existence sans jamais écrire une seule fonctionAfficher l'extrait de code
la source
Sur la base de cette réponse , j'ai trouvé cette fonction générique
ES2015
qui résoudrait le problèmela source
function validChain (object, path) { return path.split('.').reduce((a, b) => (a || { })[b], object) !== undefined }
J'ai créé une petite fonction pour obtenir les propriétés des objets imbriqués en toute sécurité.
Ou une version plus simple mais légèrement illisible:
Ou encore plus court mais sans repli sur le drapeau falsifié:
J'ai testé avec:
Et voici quelques tests:
Pour voir tout le code avec la documentation et les tests que j'ai essayés, vous pouvez vérifier mon github gistub: https://gist.github.com/vsambor/3df9ad75ff3de489bbcb7b8c60beebf4#file-javascriptgetnestedvalues-js
la source
Une version ES5 plus courte de l'excellente réponse de @ CMS:
Avec un test similaire:
la source
checkObjHasKeys(test, ['level1', 'level2', 'asdf', 'asdf']);
success = false;
pourreturn false
. Vous devriez renflouer une fois que vous savez qu'il se casse, rien de plus profond ne peut exister une fois qu'il est nul ou indéfini. Cela éviterait les erreurs sur les éléments imbriqués plus profonds, car ils n'existent évidemment pas non plus.Je pense que c'est une légère amélioration (devient une doublure):
Cela fonctionne car l'opérateur && renvoie l'opérande final qu'il a évalué (et court-circuite).
la source
Je cherchais la valeur à renvoyer si la propriété existe, j'ai donc modifié la réponse par CMS ci-dessus. Voici ce que j'ai trouvé:
la source
La réponse donnée par CMS fonctionne bien avec la modification suivante pour les contrôles nuls également
la source
Les options suivantes ont été élaborées à partir de cette réponse . Même arbre pour les deux:
Arrêtez la recherche lorsque vous n'êtes pas défini
Assurez chaque niveau un par un
la source
Je sais que cette question est ancienne, mais je voulais proposer une extension en l'ajoutant à tous les objets. Je sais que les gens ont tendance à froncer les sourcils en utilisant le prototype Object pour une fonctionnalité d'objet étendue, mais je ne trouve rien de plus simple que de faire cela. De plus, il est désormais autorisé avec la méthode Object.defineProperty .
Maintenant, pour tester n'importe quelle propriété dans n'importe quel objet, vous pouvez simplement faire:
Voici un jsfiddle pour le tester, et en particulier il inclut un jQuery qui se casse si vous modifiez le Object.prototype directement à cause de la propriété devenant énumérable. Cela devrait fonctionner correctement avec les bibliothèques tierces.
la source
Cela fonctionne avec tous les objets et tableaux :)
ex:
c'est ma version améliorée de la réponse de Brian
J'ai utilisé _has comme nom de propriété car il peut entrer en conflit avec une propriété existante (ex: maps)
Voici le violon
la source
Voici mon point de vue à ce sujet - la plupart de ces solutions ignorent le cas d'un tableau imbriqué comme dans:
Je veux peut-être vérifier
obj.l2[0].k
Avec la fonction ci-dessous, vous pouvez faire
deeptest('l2[0].k',obj)
La fonction retournera true si l'objet existe, false sinon
la source
Maintenant, nous pouvons également utiliser
reduce
pour parcourir les clés imbriquées:la source
Vous pouvez le faire en utilisant la fonction récursive. Cela fonctionnera même si vous ne connaissez pas le nom de toutes les clés d'objets imbriquées.
la source
theres une fonction ici sur le codeabode (safeRead) qui le fera de manière sûre ... ie
si une propriété est nulle ou non définie, une chaîne vide est retournée
la source
Sur la base d' un commentaire précédent , voici une autre version où l'objet principal ne pouvait pas non plus être défini:
la source
J'ai écrit ma propre fonction qui prend le chemin souhaité et a une bonne et une mauvaise fonction de rappel.
Usage:
la source
la source