web-dev-qa-db-fra.com

Accès aux biens sans risque (et affectation conditionnelle) dans ES6/2015

Existe-t-il un opérateur d'accès à la propriété null- safe (propagation/existence nulle) dans ES6 (ES2015/JavaScript.next/Harmony) tel que?.in CoffeeScript par exemple? Ou est-ce prévu pour ES7?

var aThing = getSomething()
...
aThing = possiblyNull?.thing

Ce sera à peu près comme:

if (possiblyNull != null) aThing = possiblyNull.thing

Idéalement, la solution ne devrait pas affecter (même undefined) à aThing si possiblyNull est null

109
ııı

Fonctionnalité accomplie actuellement à l'étape 1: Chaînage facultatif.

https://github.com/tc39/proposal-optional-chaining

Si vous voulez l'utiliser aujourd'hui, il existe un plugin Babel qui accomplit cela.

https://github.com/davidyaha/ecmascript-optionals-proposal

Update (2017-08-01): Si vous souhaitez utiliser un plugin officiel, vous pouvez essayer la version alpha de Babel 7 avec la nouvelle transformation. Votre kilométrage peut varier

https://www.npmjs.com/package/babel-plugin-transform-optional-chaining

72
basicdays

Ce n'est pas aussi gentil que le? opérateur, mais pour obtenir un résultat similaire, vous pouvez obtenir:

user && user.address && user.address.postcode

Puisque null et undefined sont tous les deux des valeurs falsy ( voir cette référence ), la propriété située après l'opérateur && est accessible uniquement si le précédent n'est ni nul ni indéfini.

Alternativement, vous pouvez écrire une fonction comme celle-ci:

function _try(func, fallbackValue) {
    try {
        var value = func();
        return (value === null || value === undefined) ? fallbackValue : value;
    } catch (e) {
        return fallbackValue;
    }
}

Usage:

_try(() => user.address.postcode) // return postcode or undefined 

Ou, avec une valeur de repli:

_try(() => user.address.postcode, "none") // return postcode or a custom string
41
tocqueville

Non. Vous pouvez utiliser lodash # get ou quelque chose comme ça pour cela en JavaScript.

28
Girafa

Alternative à la vanille pour un accès sécurisé à la propriété

(((a.b || {}).c || {}).d || {}).e

L’affectation conditionnelle la plus concise serait probablement la suivante:

try { b = a.b.c.d.e } catch(e) {}
10
yagger

En passant par la liste ici , il n’existe actuellement aucune proposition visant à ajouter le parcours en toute sécurité à Ecmascript. Donc, non seulement il n'y a pas de moyen agréable de faire cela, mais cela ne sera pas ajouté dans un avenir prévisible.

3
Antimony

Je sais que c’est une question JavaScript, mais je pense que Ruby s’y emploie de toutes les manières demandées. Je pense donc que c’est un point de référence pertinent. 

.&, try, et && ont leurs forces et leurs pièges potentiels. Voici un bon aperçu de ces options: http://mitrev.net/Ruby/2015/11/13/the-operator-in-Ruby/

TLDR; La conclusion des Rubyists est que Dig est à la fois plus facile pour les yeux et plus sûr encore que une valeur ou null soit attribuée.

Voici une simple implémentation dans TypeScript:

export function Dig(target: any, ...keys: Array<string>): any {
  let digged = target
  for (const key of keys) {
    if (typeof digged === 'undefined') {
      return undefined // can also return null or a default value
    }
    if (typeof key === 'function') {
      digged = key(digged)
    } else {
      digged = digged[key]
    }
  }
  return digged
}

Ceci peut être utilisé pour n’importe quelle profondeur d’imbrication et manipule des fonctions.

a = Dig(b, 'c', 'd', 'e');
foo = () => ({});
bar = Dig(a, foo, 'b', 'c')

L’approche try est également agréable à lire dans JS, comme indiqué dans les réponses précédentes. Cela ne nécessite pas non plus de bouclage, ce qui est un inconvénient de cette implémentation. 

0
theUtherSide

Une méthode de récupération en profondeur sûre semble un choix naturel pour underscore.js, mais le problème est d’éviter la programmation par chaîne. Modifier la réponse de @ Felipe pour éviter la programmation de chaînes (ou au moins repousser les cas Edge à l'appelant):

function safeGet(obj, props) {
   return (props.length==1) ? obj[keys[0]] :safeGet(obj[props[0]], props.slice(1))
}

Exemple: 

var test = { 
  a: { 
    b: 'b property value',
    c: { }
  } 
}
safeGet(test, ['a', 'b']) 
safeGet(test, "a.b".split('.'))  
0
prototype