Как сделать "публичное статическое поле" в классе ES6?
Я делаю класс Javascript, и я хотел бы иметь публичное статическое поле, как в Java. Это соответствующий код:
export default class Agent {
CIRCLE: 1,
SQUARE: 2,
...
Это ошибка, я получаю:
line 2, col 11, Class properties must be methods. Expected '(' but instead saw ':'.
похоже, что модули ES6 не позволяют этого. Есть ли способ получить желаемое поведение или мне нужно написать геттер?
5 ответов:
вы делаете "публичное статическое поле" с помощью метода доступа и ключевого слова "static":
class Agent { static get CIRCLE() { return 1; } static get SQUARE() { return 2; } } Agent.CIRCLE; // 1
глядя на спецификации, 14.5 - определения классов - вы бы увидели что-то подозрительно релевантное :)
ClassElement[Yield]:
MethodDefinition[?Выход]
статический MethodDefinition[?Выход];Так что оттуда вы можете следовать к 14.5.14 - Во Время Выполнения Семантики: ClassDefinitionEvaluation-чтобы дважды проверить, действительно ли он делает то, что он выглядит. В частности, шаг 20:
- для каждого ClassElement m в порядке от методов
- если IsStatic of m is false, тогда
- пусть status является результатом выполнения PropertyDefinitionEvaluation для m с аргументами proto и false.
- еще,
- пусть статус будет результат выполнения PropertyDefinitionEvaluation для m с аргументами F и false.
- если состояние является внезапным завершением, то
- установите LexicalEnvironment текущего контекста выполнения в lex.
- статус возврата.
IsStatic определяется ранее в 14.5.9
ClassElement : статический MethodDefinition
Вернуть true.Так
PropertyMethodDefinition
вызывается с" F " (конструктор, объект функции) в качестве аргумента, который в свою очередь создает метод доступа к этому объекту.этой работает по крайней мере, в ietp (Tech preview), а также компиляторы 6to5 и Traceur.
есть Этап 3 ECMAScript предложение называется "Класс Поля" Даниэль Эренберг и Джефф Моррисон, который стремится решить эту проблему.
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' } }
выше эквивалентно:
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 / plugin-proposal-class-properties (входит в предустановка stage-3), так что вы можете использовать эту функцию, даже если среда выполнения JavaScript не поддерживает его.
по сравнению с решением @kangax объявления геттера, это решение также может быть более производительным, так как здесь свойство доступно напрямую, а не через вызов функции.
Если это предложение будет принято, то можно будет написать код JavaScript таким образом, который больше похож на традиционные объектно-ориентированные языки, такие как Java и C♯.
Edit: унифицированное предложение полей класса теперь на стадии 3; обновление до Babel v7.х пакетов.
в текущих проектах ECMAScript 6 (по состоянию на февраль 2015 года) все свойства класса должны быть методами, а не значениями (примечание в ECMAScript "свойство" аналогично по концепции полю ООП, за исключением значения поля должно быть
Function
объект, а не любое другое значение, например,Number
илиObject
).вы все еще можете указать их с помощью традиционных описателей свойств конструктора ECMAScript:
class Agent { } Agent.CIRCLE = 1; Agent.SQUARE = 2; ...
чтобы получить полное преимущество статической переменной я за такой подход. Чтобы быть более конкретным, мы можем использовать его для использования частной переменной или иметь только общедоступный геттер, или иметь как геттер, так и сеттер. В последнем случае это то же самое, что и одно из решений, опубликованных выше.
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'];
Я мог бы создать другой класс, расширяющий Url, и это сработало.
я использовал babel для преобразования моего кода ES6 в ES5
ответ@kangax не имитирует все статическое поведение традиционного языка ООП, потому что вы не можете получить доступ к статическому свойству по его экземпляру, например
const agent = new Agent; agent.CIRCLE; // Undefined
Если вы хотите получить доступ к статическому свойству так же, как ООП, вот мое решение:
class NewApp { get MULTIPLE_VERSIONS_SUPPORTED() { return this.constructor.MULTIPLE_VERSIONS_SUPPORTED; // Late binding for inheritance } } NewApp.MULTIPLE_VERSIONS_SUPPORTED = true;
тестовый код следующим образом.
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