Existe-t-il un moyen de faire fonctionner quelque chose comme le suivant en JavaScript?
var foo = {
a: 5,
b: 6,
c: this.a + this.b // Doesn't work
};
Dans le formulaire actuel, ce code renvoie évidemment une erreur de référence car this
il ne fait pas référence à foo
. Mais existe- t - il un moyen de faire en sorte que les valeurs des propriétés d'un littéral d'objet dépendent d'autres propriétés déclarées précédemment?
javascript
object-literal
kpozin
la source
la source
foo.a
oufoo.b
sont modifiées, la valeur defoo.c
changera également en synchronisme. Cela peut ou non être ce qui est requis.this
se lie à l'objet imbriqué le plus profond. Par exemple:... x: { get c () { /*this is x, not foo*/ } } ...
foo
est déclarée en tant que variable etc
ne sera évaluée qu'au moment où elle est invoquée, l'utilisation defoo
insidec
fonctionnera, contrairement àthis
(soyez prudent cependant)Vous pourriez faire quelque chose comme:
Ce serait une sorte d'initialisation unique de l'objet.
Notez que vous affectez réellement la valeur de retour de
init()
àfoo
, vous devez donc le fairereturn this
.la source
delete this.init
avantreturn this
pour que cefoo
ne soit pas poliinit()
appel a été directement ajouté au littéral pour qu'il reste une seule expression. Mais bien sûr, vous pouvez appeler la fonction séparément de ce que vous voulez.La réponse évidente et simple manque, donc pour être complet:
Non. Toutes les solutions ici le reportent jusqu'à la création de l'objet (de diverses manières), puis affectent la troisième propriété. La façon la plus simple est de le faire:
Tous les autres sont simplement des moyens plus indirects de faire la même chose. (Felix est particulièrement intelligent, mais nécessite la création et la destruction d'une fonction temporaire, ajoutant de la complexité; et laisse soit une propriété supplémentaire sur l'objet ou [si vous
delete
cette propriété] a un impact sur les performances des accès ultérieurs à la propriété sur cet objet.)Si vous avez besoin que tout soit dans une même expression, vous pouvez le faire sans la propriété temporaire:
Ou bien sûr, si vous devez le faire plusieurs fois:
alors où vous devez l'utiliser:
la source
this
n'est disponible que pour les méthodes dudit objet, et pas d'autres types de propriétés. Une idée où je pourrais trouver ça? Merci!delete
est 10% plus rapide et gecko:delete
n'est que 1% plus lent.Instanciez simplement une fonction anonyme:
la source
new Point(x, y)
sauf que la fonction n'est pas nommée pour être réutilisée.var foo = function() { this.…; return this; }.call({});
ce qui n'est pas très différent sur le plan syntaxique mais sémantiquement sain.new
mot - clé.Maintenant, dans ES6, vous pouvez créer des propriétés mises en cache paresseux. Lors de la première utilisation, la propriété est évaluée une fois pour devenir une propriété statique normale. Résultat: la deuxième fois que la surcharge de la fonction mathématique est ignorée.
La magie est dans le getter.
Dans la flèche, le getter
this
reprend la portée lexicale environnante .la source
Object.defineProperty(foo, 'c', {get:function() {...}})
pour les définir. Cela se fait facilement de manière discrète dans une usine comme celle-ci. Bien sûr, si vous pouvez utiliser leget
sucre, il est plus lisible, mais la capacité est là.Une fermeture devrait régler ce problème;
Toutes les variables déclarées dans
foo
sont privéesfoo
, comme vous vous en doutez avec n'importe quelle déclaration de fonction et parce qu'elles sont toutes de portée, elles ont toutes accès les unes aux autres sans avoir besoin de s'y référerthis
, tout comme vous vous attendriez avec une fonction. La différence est que cette fonction renvoie un objet qui expose les variables privées et affecte cet objet àfoo
. En fin de compte, vous retournez uniquement l'interface que vous souhaitez exposer en tant qu'objet avec l'return {}
instruction.La fonction est ensuite exécutée à la fin avec le
()
qui provoque l'évaluation de l'ensemble de l'objet foo, toutes les variables dans instancié et l'objet de retour ajouté en tant que propriétés defoo()
.la source
Tu pourrais le faire comme ça
Cette méthode s'est avérée utile lorsque j'ai dû me référer à l'objet sur lequel une fonction a été déclarée à l'origine. Voici un exemple minimal de la façon dont je l'ai utilisé:
En définissant self en tant qu'objet contenant la fonction d'impression, vous autorisez la fonction à se référer à cet objet. Cela signifie que vous n'aurez pas à «lier» la fonction d'impression à un objet si vous devez la transmettre ailleurs.
Si vous préférez, utilisez
this
comme illustré ci-dessousEnsuite, le code suivant enregistrera 0, 1, 2, puis donnera une erreur
En utilisant la méthode self, vous garantissez que print renverra toujours le même objet quel que soit le contexte dans lequel la fonction est exécutée. Le code ci-dessus fonctionnera très bien et enregistrera 0, 1, 2 et 3 lors de l'utilisation de la version autonome de
createMyObject()
.la source
Pour l'achèvement, dans ES6, nous avons des classes (prises en charge au moment de l'écriture uniquement par les derniers navigateurs, mais disponibles dans Babel, TypeScript et autres transpilers)
la source
Vous pouvez le faire en utilisant le modèle de module. Juste comme:
Avec ce modèle, vous pouvez instancier plusieurs objets foo selon vos besoins.
http://jsfiddle.net/jPNxY/1/
la source
}();
, elle s'exécuterait automatiquement et retournerait un objet, pas une fonction. En outre,foo.c
est une fonction, donc y écrire écrase cette fonction et la prochaine invocation viafooObject.c()
échouera. Peut-être que ce violon est plus proche de ce que vous recherchez (c'est aussi un singleton, non conçu pour être instancié).Il existe plusieurs façons d'y parvenir; voici ce que j'utiliserais:
la source
juste pour la réflexion - placez les propriétés de l'objet hors d'une chronologie:
il y a aussi de meilleures réponses ci-dessus . C'est ainsi que j'ai modifié l'exemple de code avec lequel vous vous êtes interrogé.
MISE À JOUR:
la source
var foo = { get a(){return 5}, get b(){return 6}, get c(){return this.a + this.b} }
alors maintenant vous pouvez simplement faire à lafoo.c
place defoo.c()
:) (N'hésitez pas à coller cela dans votre réponse pour que le formatage soit meilleur!)Créer une nouvelle fonction sur votre objet littéral et invoquer un constructeur semble un changement radical par rapport au problème d'origine, et ce n'est pas nécessaire.
Vous ne pouvez pas référencer une propriété frère pendant l'initialisation littérale de l'objet.
La solution la plus simple pour les propriétés calculées suit (pas de tas, pas de fonctions, pas de constructeur):
la source
Les autres réponses publiées ici sont meilleures, mais voici une alternative qui:
init()
ou code en dehors du littéral objetFonctions anonymes auto-exécutables et stockage de fenêtres
La commande est garantie (
bar
avantbaz
).Cela pollue
window
bien sûr, mais je ne peux pas imaginer que quelqu'un écrive un script qui nécessitewindow.temp
d'être persistant. Peut êtretempMyApp
- si vous êtes paranoïaque.C'est aussi moche mais parfois utile. Par exemple, lorsque vous utilisez une API avec des conditions d'initialisation rigides et que vous n'avez pas envie de refactoriser la portée est correcte.
Et c'est sec, bien sûr.
la source
La clé de tout cela est SCOPE .
Vous devez encapsuler le "parent" (objet parent) de la propriété que vous souhaitez définir comme son propre objet instancié, puis vous pouvez faire des références aux propriétés frères en utilisant le mot clé
this
Il est très, très important de se rappeler que si vous vous référez
this
sans le faire au préalable,this
vous ferez référence à la portée extérieure ... qui sera l'window
objet.la source
si votre objet est écrit comme une fonction qui renvoie un objet ET que vous utilisez des 'méthodes' d'attribut d'objet ES6, alors il est possible:
la source
J'utilise le code suivant comme alternative, et cela fonctionne. Et la variable peut aussi être un tableau. (@ Fausto R.)
la source
Voici une méthode ES6 soignée:
Je l'utilise pour faire quelque chose comme ça:
la source
Que diriez-vous de cette solution, cela fonctionnera également avec les objets imbriqués avec tableau
la source
Ajout d'une option car je n'ai pas vu ce scénario exact couvert. Si vous ne voulez pas
c
mettre à jour quanda
oub
mettre à jour, alors un ES6 IIFE fonctionne bien.Pour mes besoins, j'ai un objet qui se rapporte à un tableau qui finira par être utilisé dans une boucle, donc je ne veux calculer une configuration commune qu'une seule fois, alors voici ce que j'ai:
Étant donné que je dois définir une propriété pour
indexOfSelectedTier
et que je dois utiliser cette valeur lors de la définition de lahasUpperTierSelection
propriété, je calcule d'abord cette valeur et la transmets en tant que paramètre à l'IIFEla source
Une autre approche serait de déclarer l'objet avant de lui affecter des propriétés:
Avec cela, vous pouvez utiliser le nom de variable d'objet pour accéder aux valeurs déjà attribuées.
Idéal pour le
config.js
fichier.la source
foo
qui pointe vers l'objet en question.C'est presque identique à la réponse de @ slicedtoad, mais n'utilise pas de fonction.
la source
Ici, nous utilisions des expressions de classe pour obtenir l'interface littérale d'objet imbriqué que nous souhaiterions. C'est la deuxième meilleure chose à mon humble avis de pouvoir référencer les propriétés d'un objet lors de la création.
La chose principale à noter est qu'en utilisant cette solution, vous avez exactement la même interface que vous auriez eue avec un objet littéral. Et la syntaxe est assez proche d'un littéral objet lui-même (par rapport à l'utilisation d'une fonction, etc.).
Comparez les éléments suivants
Solution que j'ai proposée
Solution si les littéraux d'objet auraient suffi
Un autre exemple
Ici, dans cette classe, vous pouvez combiner plusieurs chemins relatifs entre eux, ce qui n'est pas possible avec un objet littéral.
la source
Si vous souhaitez utiliser JS natif, les autres réponses fournissent de bonnes solutions.
Mais si vous êtes prêt à écrire des objets auto-référencés comme:
J'ai écrit une bibliothèque npm appelée self-referenced-object qui prend en charge cette syntaxe et renvoie un objet natif.
la source
b
valeur de la propriété doit être:${this.a + this.a}
. Deuxièmement, mais moins important, vous voudriez retourner un nombre, pas une chaîne en utilisant quelque chose commeparseInt
. Enfin et surtout, lorsque j'ai essayé cet exemple, cela ne fonctionne tout simplement pas, pour la même raison que l'OP le demande. Lethis
retourne undefined lorsqu'il est utilisé sa propre déclaration d'objet. @ alex-e-leon