Je crée une classe Javascript et j'aimerais avoir un champ statique public comme en Java. Voici le code pertinent:
export default class Agent {
CIRCLE: 1,
SQUARE: 2,
...
Voici l'erreur que j'obtiens:
line 2, col 11, Class properties must be methods. Expected '(' but instead saw ':'.
Il semble que les modules ES6 ne permettent pas cela. Existe-t-il un moyen d'obtenir le comportement souhaité ou dois-je écrire un getter?
javascript
ecmascript-6
class-fields
aebabis
la source
la source
Réponses:
Vous créez un "champ statique public" en utilisant l'accesseur et un mot clé "statique":
class Agent { static get CIRCLE() { return 1; } static get SQUARE() { return 2; } } Agent.CIRCLE; // 1
En regardant une spécification, 14.5 - Définitions de classe - vous verriez quelque chose de suspectement pertinent :)
Ainsi, à partir de là, vous pouvez suivre la 14.5.14 - Sémantique d'exécution: ClassDefinitionEvaluation - pour vérifier si elle fait vraiment ce à quoi elle ressemble. Plus précisément, étape 20:
IsStatic est défini précédemment dans 14.5.9
Ainsi
PropertyMethodDefinition
est appelé avec "F" (constructeur, objet fonction) comme argument, qui à son tour crée une méthode accesseur sur cet objet .Cela fonctionne déjà au moins dans IETP (aperçu technique), ainsi que dans les compilateurs 6to5 et Traceur.
la source
unsafe.enable_getters_and_setters=true
à votre .flowconfig sous[options]
(ce qui est ennuyeux).Il existe une proposition ECMAScript Stage 3 appelée "Static Class Features" par Daniel Ehrenberg et Jeff Morrison qui vise à résoudre ce problème. Avec la proposition "Champs de classe" de l'étape 3 , le futur code ressemblera à ceci:
class MyClass { static myStaticProp = 42; myProp = 42; myProp2 = this.myProp; myBoundFunc = () => { console.log(this.myProp); }; constructor() { console.log(MyClass.myStaticProp); // Prints '42' console.log(this.myProp); // Prints '42' this.myBoundFunc(); // Prints '42' } }
Ce qui précède est équivalent à:
class MyClass { constructor() { this.myProp = 42; this.myProp2 = this.myProp; this.myBoundFunc = () => { console.log(this.myProp); }; console.log(MyClass.myStaticProp); // Prints '42' console.log(this.myProp); // Prints '42' this.myBoundFunc(); // Prints '42' } } MyClass.myStaticProp = 42;
Babel prend en charge la transpilation des champs de classe via @ babel / plugin-proposal-class-properties (inclus dans le préréglage stage-3 ), afin que vous puissiez utiliser cette fonctionnalité même si votre environnement d'exécution JavaScript ne la prend pas en charge.
Comparée à la solution de @ kangax de déclarer un getter, cette solution peut également être plus performante, car ici la propriété est accédée directement au lieu d'appeler une fonction.
Si cette proposition est acceptée, il sera alors possible d'écrire du code JavaScript d'une manière plus similaire aux langages orientés objet traditionnels tels que Java et C♯.
Edit : Une proposition de champs de classe unifiée est maintenant à l'étape 3; mise à jour vers les packages Babel v7.x.
Edit (février 2020) : Les fonctionnalités de classe statique ont été divisées en une proposition différente. Merci @ GOTO0!
la source
Dans les versions actuelles d'ECMAScript 6 (à partir de février 2015), toutes les propriétés de classe doivent être des méthodes et non des valeurs (notez que dans ECMAScript, une "propriété" est similaire dans son concept à un champ POO, sauf que la valeur du champ doit être un
Function
objet, pas une une autre valeur telle que aNumber
ouObject
).Vous pouvez toujours les spécifier à l'aide des spécificateurs de propriété de constructeur ECMAScript traditionnels:
class Agent { } Agent.CIRCLE = 1; Agent.SQUARE = 2; ...
la source
class
syntaxe ES6 n'est de toute façon que du sucre syntaxique pour les fonctions de constructeur et les prototypes JS traditionnels.enum
).class
syntaxe présente également certaines différences nuancées. Par exemple, une méthode déclarée avecClass.prototype.method = function () {};
est énumérable (visible avec des boucles for-in), tandis que lesclass
méthodes ne sont pas énumérables.Pour tirer pleinement parti de la variable statique, j'ai suivi cette approche. Pour être plus précis, nous pouvons l'utiliser pour utiliser une variable privée ou avoir seulement un getter public, ou avoir à la fois un getter ou un setter. Dans le dernier cas, c'est la même chose que l'une des solutions affichées ci-dessus.
var Url = (() => { let _staticMember = []; return class { static getQueries(hash = document.location.hash) { return hash; } static get staticMember(){ return _staticMember; } }; })(); Usages: console.log(Url.staticMember); // []; Url.staticMember.push('it works'); console.log(Url.staticMember); // ['it works'];
Je pourrais créer une autre classe étendant Url et cela a fonctionné.
J'ai utilisé babel pour convertir mon code ES6 en ES5
la source
class Url { static getQueries… }; Url.staticMember = [];
été beaucoup plus simple?===
comparaisons donnent à la foisfalse
, btwLa réponse de @kangax n'imite pas tout le comportement statique du langage OOP traditionnel, car vous ne pouvez pas accéder à la propriété statique par son instance comme
const agent = new Agent; agent.CIRCLE; // Undefined
Si vous souhaitez accéder à une propriété statique comme celle de la POO, voici ma solution:
class NewApp { get MULTIPLE_VERSIONS_SUPPORTED() { return this.constructor.MULTIPLE_VERSIONS_SUPPORTED; // Late binding for inheritance } } NewApp.MULTIPLE_VERSIONS_SUPPORTED = true;
Testez le code comme suit.
class NewApp { get MULTIPLE_VERSIONS_SUPPORTED() { console.log('this.constructor.name:', this.constructor.name); // late binding return this.constructor.MULTIPLE_VERSIONS_SUPPORTED; } } // Static property can be accessed by class NewApp.MULTIPLE_VERSIONS_SUPPORTED = true; const newApp = new NewApp; // Static property can be accessed by it's instances console.log('newApp.MULTIPLE_VERSIONS_SUPPORTED:', newApp.MULTIPLE_VERSIONS_SUPPORTED); // true // Inheritance class StandardApp extends NewApp {} // Static property can be inherited console.log('StandardApp.MULTIPLE_VERSIONS_SUPPORTED:', StandardApp.MULTIPLE_VERSIONS_SUPPORTED); // true // Static property can be overwritten StandardApp.MULTIPLE_VERSIONS_SUPPORTED = false; const std = new StandardApp; console.log('std.MULTIPLE_VERSIONS_SUPPORTED:', std.MULTIPLE_VERSIONS_SUPPORTED); // false
la source
static
champ par une instance serait plutôt rare, n'est-ce pas? Dans certains langages, tels que Java, les IDE émettent en fait un avertissement / un indice si vous faites quelque chose comme ça.