В настоящее время в ES5 многие из нас используют следующий шаблон в рамках для создания классов и переменных класса, что удобно:
// ES 5
FrameWork.Class({
variable: 'string',
variable2: true,
init: function(){
},
addItem: function(){
}
});
В ES6 вы можете создавать классы изначально, но нет возможности иметь переменные класса:
// ES6
class MyClass {
const MY_CONST = 'string'; // <-- this is not possible in ES6
constructor(){
this.MY_CONST;
}
}
К сожалению, вышесказанное не сработает, так как классы могут содержать только методы.
Я понимаю, что могу this.myVar = true
в constructor
… но я не хочу «мусорить» моего конструктора, особенно когда у меня есть 20-30+ параметров для большего класса.
Я думал о многих способах решения этой проблемы, но пока не нашел хороших. (Например: создайте ClassConfig
обработчик и передайте parameter
объект, который объявлен отдельно от класса. Затем обработчик будет присоединен к классу. Я думал WeakMaps
также о какой-то интеграции.)
Какие у вас есть идеи, чтобы справиться с этой ситуацией?
источник
this.member = member
в вашем конструкторе с 20-30 параметрами?public variable2 = true
в классе? Это определило бы это по прототипу.Ответы:
2018 обновление:
В настоящее время есть предложение этапа 3 - я с нетерпением жду, чтобы этот ответ устарел через несколько месяцев.
Тем временем любой, кто использует TypeScript или babel, может использовать синтаксис:
Внутри объявления класса / тела выражения и он определит переменную. Надеюсь, через несколько месяцев / недель я смогу опубликовать обновление.
Обновление: Chrome 74 теперь поставляется с этим синтаксисом работает.
Примечания в вики ES для предложения в ES6 ( максимально минимальные классы )
Это означает, что то, о чем вы просите, было рассмотрено и явно отклонено.
но почему?
Хороший вопрос. Хорошие люди из TC39 хотят, чтобы объявления классов объявляли и определяли возможности класса. Не его участники. Объявление класса ES6 определяет свой контракт для своего пользователя.
Помните, определение класса определяет методы прототипа - определение переменных в прототипе обычно не то, что вы делаете. Вы можете, конечно, использовать:
В конструкторе, как вы предложили. Также см. Резюме консенсуса .
ES7 и выше
В настоящее время разрабатывается новое предложение для ES7, которое позволяет создавать более краткие переменные экземпляра с помощью объявлений и выражений классов - https://esdiscuss.org/topic/es7-property-initializers.
источник
static
свойстваstatic
работает только для методов.Просто добавьте к ответу Бенджамина - переменные класса возможны, но вы не будете использовать их
prototype
для установки.Для истинной переменной класса вы хотели бы сделать что-то вроде следующего:
Из метода класса эта переменная может быть доступна как
this.constructor.foo
(илиMyClass.foo
).Эти свойства класса обычно недоступны для экземпляра класса. т.е.
MyClass.foo
дает'bar'
ноnew MyClass().foo
естьundefined
Если вы также хотите иметь доступ к переменной вашего класса из экземпляра, вам придется дополнительно определить метод получения:
Я только что проверил это с Traceur, но я полагаю, что это будет работать так же в стандартной реализации.
У JavaScript действительно нет классов . Даже с ES6 мы смотрим на объектный или прототипный язык, а не на язык классов. В любом случае
function X () {}
,X.prototype.constructor
указывает наX
. Когдаnew
оператор включенX
, новый объект создается наследующимX.prototype
. Любые неопределенные свойства в этом новом объекте (включаяconstructor
) ищутся оттуда. Мы можем думать об этом как о генерации свойств объекта и класса.источник
Babel поддерживает переменные класса в ESNext, проверьте этот пример :
источник
В вашем примере:
Поскольку MY_CONST является примитивным https://developer.mozilla.org/en-US/docs/Glossary/Primitive, мы можем просто сделать:
Но если
MY_CONST
это ссылочный тип, такой какstatic get MY_CONST() {return ['string'];}
вывод оповещения, это строка, ложь . В таком случаеdelete
оператор может добиться цели:И, наконец, для переменной класса нет
const
:источник
delete
оператора, если он один из соображений производительности. То, что вы действительно хотите здесь, этоObject.defineProperty
.Поскольку ваша проблема в основном стилистическая (не нужно заполнять конструктор кучей объявлений), ее можно решить и стилистически.
На мой взгляд, во многих языках на основе классов конструктор является функцией, названной в честь самого имени класса. Стилистически мы могли бы использовать это для создания класса ES6, который стилистически все еще имеет смысл, но не группирует типичные действия, выполняемые в конструкторе, со всеми объявлениями свойств, которые мы делаем. Мы просто используем фактический конструктор JS в качестве «области объявления», а затем создаем класс с именем function, который в противном случае мы рассматриваем как область «другого конструктора», вызывая его в конце истинного конструктора.
Оба будут вызываться при создании нового экземпляра.
Скорее, как если бы у вас было 2 конструктора, в которых вы разделяете объявления и другие действия конструктора, которые вы хотите выполнить, и стилистически делает это не слишком трудным для понимания того, что происходит.
Я считаю, что это хороший стиль, который нужно использовать при работе со многими объявлениями и / или множеством действий, которые необходимо выполнить при создании экземпляра и которые хотят отличить две идеи друг от друга.
ПРИМЕЧАНИЕ : я очень целенаправленно не использую типичные идиоматические идеи «инициализации» (например,
init()
илиinitialize()
метод), потому что они часто используются по-разному. Существует некоторая предполагаемая разница между идеей конструирования и инициализации. Работая с конструкторами, люди знают, что они вызываются автоматически как часть реализации. Увидевinit
метод, многие люди без второго взгляда предполагают, что им нужно что-то делать в формеvar mc = MyClass(); mc.init();
, потому что именно так вы обычно инициализируете. Я не пытаюсь добавить процесс инициализации для пользователя класса, я пытаюсь добавить в процесс конструирования самого класса.Хотя некоторые люди могут сделать двойной дубль на мгновение, в этом-то и кроется смысл: они сообщают им, что намерение является частью конструкции, даже если это заставляет их делать двойной дубль и уходить, это не так. как работают конструкторы ES6 "и взгляните на фактического конструктора, чтобы сказать:" О, они называют это снизу, я вижу ", это гораздо лучше, чем НЕ сообщать об этом намерении (или неправильно сообщать об этом) и, вероятно, получать много люди используют это неправильно, пытаясь инициализировать это извне и мусор. Это очень преднамеренно для шаблона, который я предлагаю.
Для тех, кто не хочет следовать этому шаблону, может работать и обратное. Передайте объявления в другую функцию в начале. Может быть, назовите его «свойства» или «publicProperties» или что-то. Затем поместите остальные вещи в обычный конструктор.
Обратите внимание, что этот второй метод может выглядеть чище, но он также имеет внутреннюю проблему, которая
properties
переопределяется, поскольку один класс, использующий этот метод, расширяет другой. Вы должны были бы дать больше уникальных имен,properties
чтобы избежать этого. Мой первый метод не имеет этой проблемы, потому что его фиктивная половина конструктора имеет уникальное имя в честь класса.источник
init
.init
это шаблон используется часто, и нередко приводит к тому , чтобы быть вызваны извне класса , когда внешний пользователь хочет инициализировать, то естьvar b = new Thing(); b.init();
. Это 100% стилистический выбор, который я предпочел бы сообщить, что это 2-я функция, которая автоматически вызывается с использованием шаблонов, найденных на других языках. Гораздо менее вероятно, что кто-то посмотрит на это и предположит, что ему нужно вызватьMyClass
метод извне, более вероятно, что он поймет, что намерение - это 2-й метод, действующий в процессе разработки (т.е. вызываемый сам по себе при создании экземпляра).MyClass
.$myvar
стандартный способ обращения к переменным, предназначенным для хранения объектов jQuery, не похож на шаблон с $ в начале переменных, к которому привыкло так много PHP-программистов. Только тот маленький подтекст, что «да, это не то же самое ... но посмотрите ... это все еще переменная, потому что так переменные делаются в некоторых языках!» помогает.properties()
функцией. Тем не менее, при расширении классов все становится немного сложнее, поэтому я хотел бы предложить, чтобы при использованииproperties()
функции во всех ваших классах для объявления свойств класса вы добавляли префикс имени метода к имени класса (IE:MyClassProperties()
во избежание случайного переопределения). вызовы функций внутри подклассов. Также имейте в виду, что любые вызовыsuper()
должны быть объявлены первыми в конструкторе классов.Что насчет олдскульного пути?
В конструкторе вы упоминаете только те переменные, которые должны быть вычислены. Мне нравится наследование прототипов для этой функции - она может помочь сэкономить много памяти (в случае, если есть много никогда не назначенных переменных).
источник
Как сказал Бенджамин в своем ответе, TC39 явно решил не включать эту функцию по крайней мере для ES2015. Тем не менее, похоже, что они добавят его в ES2016.
Синтаксис еще не определен, но есть предварительное предложение для ES2016, которое позволит вам объявить статические свойства для класса.
Благодаря магии Вавилон, вы можете использовать это сегодня. Включите преобразование свойств класса в соответствии с этими инструкциями, и все готово. Вот пример синтаксиса:
Это предложение находится в очень раннем состоянии, поэтому будьте готовы изменить свой синтаксис со временем.
источник
Длинная тема, не уверен, что она уже указана в качестве опции ...
Простая альтернатива только для констант - определение константы вне класса. Это будет доступно только из самого модуля, если не сопровождается геттером.
Этот путь
prototype
не засорен, и вы получитеconst
.источник
var
вместоconst
2) несколько экземпляров этого класса? Затем внешние переменные будут меняться с каждым экземпляром классаES7
синтаксис члена класса:ES7
есть решение для «фальсификации» вашей функции конструктора. Вот пример:Приведенный выше пример будет выглядеть следующим образом
ES6
:При использовании этого обратите внимание, что этот синтаксис может поддерживаться не всеми браузерами и может потребоваться перенести более раннюю версию JS.
Бонус: объект фабрики:
источник
Вы можете имитировать поведение классов es6 ... и использовать переменные класса :)
Я положил это на GitHub
источник
Я решил эту проблему, что является еще одним вариантом (если у вас есть jQuery), состоял в том, чтобы определить поля в объекте старой школы, а затем расширить класс этим объектом. Я также не хотел перетекать конструктора с заданиями, это казалось изящным решением.
- Обновление После комментария Берги.
Нет версии JQuery:
Вы по-прежнему получаете «толстый» конструктор, но, по крайней мере, все это в одном классе и назначается в одном попадании.
РЕДАКТИРОВАТЬ # 2: Теперь я прошел полный круг и теперь назначаю значения в конструкторе, например
Почему? На самом деле все просто, используя вышеизложенное и некоторые комментарии JSdoc, PHPStorm смог выполнить код завершения свойств. Назначить все переменные одним ударом было бы неплохо, но невозможность написать код для завершения свойств, imo, не стоит (почти наверняка незначительного) выигрыша в производительности.
источник
class
синтаксис, вы также можете сделатьObject.assign
. Нет необходимости в jQuery.MyClassFields
конструктор - у него нет никаких методов. Можете ли вы объяснить, почему вы это сделали (вместо, скажем, простой фабричной функции, которая возвращает литерал объекта)?Ну, вы можете объявить переменные внутри конструктора.
источник
Тем не менее, вы не можете объявить какие-либо классы, как в других языках программирования. Но вы можете создать столько переменных класса. Но проблема заключается в объеме объекта класса. Итак, по мне, лучший способ ООП программирования в ES6 Javascript: -
источник
Это немного хакерская комбинация статики
в другом месте используется
источник
singleton_instance
в качестве имени свойства, чтобы все понимали, что вы здесь делаете.