Actualmente en ES5, muchos de nosotros estamos usando el siguiente patrón en marcos para crear clases y variables de clase, lo cual es cómodo:
// ES 5
FrameWork.Class({
variable: 'string',
variable2: true,
init: function(){
},
addItem: function(){
}
});
En ES6 puede crear clases de forma nativa, pero no hay opción para tener variables de clase:
// ES6
class MyClass {
const MY_CONST = 'string'; // <-- this is not possible in ES6
constructor(){
this.MY_CONST;
}
}
Lamentablemente, lo anterior no funcionará, ya que las clases solo pueden contener métodos.
Entiendo que puedo this.myVar = true
en constructor
... pero yo no quiero 'basura' mi constructor, especialmente cuando tengo 20-30 + parametros para una clase más grande.
Estaba pensando en muchas formas de manejar este problema, pero aún no he encontrado ninguna buena. (Por ejemplo: cree un ClassConfig
controlador y pase un parameter
objeto, que se declara por separado de la clase. Luego, el controlador se adjuntaría a la clase. Estaba pensando WeakMaps
en integrarme de alguna manera).
¿Qué tipo de ideas tendrías para manejar esta situación?
fuente
this.member = member
en su constructor con 20-30 parámetros?public variable2 = true
en clase? Esto lo definiría en el prototipo.Respuestas:
Actualización 2018:
Ahora hay una propuesta de la etapa 3: espero que esta respuesta quede obsoleta en unos meses.
Mientras tanto, cualquiera que use TypeScript o babel puede usar la sintaxis:
Dentro de un cuerpo de declaración / expresión de clase y definirá una variable. Espero que en unos meses / semanas pueda publicar una actualización.
Actualización: Chrome 74 ahora viene con esta sintaxis funcionando.
Las notas en el wiki de ES para la propuesta en ES6 ( clases mínimamente máximas ) nota:
Esto significa que lo que está pidiendo se consideró y se decidió explícitamente en contra.
¿pero por qué?
Buena pregunta. La buena gente de TC39 quiere que las declaraciones de clase declaren y definan las capacidades de una clase. No sus miembros. Una declaración de clase ES6 define su contrato para su usuario.
Recuerde, una definición de clase define los métodos de prototipo : definir variables en el prototipo generalmente no es algo que haga. Por supuesto, puede usar:
En el constructor como sugeriste. Ver también el resumen del consenso .
ES7 y más allá
Se está trabajando en una nueva propuesta para ES7 que permite variables de instancia más concisas a través de declaraciones y expresiones de clase: https://esdiscuss.org/topic/es7-property-initializers
fuente
static
propiedadesstatic
funciona solo para métodos.Solo para agregar a la respuesta de Benjamin: las variables de clase son posibles, pero no las usaría
prototype
para configurarlas.Para una verdadera variable de clase, querría hacer algo como lo siguiente:
Desde un método de clase se puede acceder a esa variable como
this.constructor.foo
(oMyClass.foo
).Estas propiedades de clase generalmente no serían accesibles desde la instancia de clase. es decir,
MyClass.foo
da'bar'
peronew MyClass().foo
esundefined
Si también desea tener acceso a su variable de clase desde una instancia, deberá definir adicionalmente un getter:
Solo he probado esto con Traceur, pero creo que funcionará igual en una implementación estándar.
JavaScript realmente no tiene clases . Incluso con ES6 estamos viendo un lenguaje basado en objetos o prototipos en lugar de un lenguaje basado en clases. En cualquiera
function X () {}
,X.prototype.constructor
apunta de nuevo aX
. Cuandonew
se utiliza el operadorX
, se crea un nuevo objeto heredandoX.prototype
. Todas las propiedades indefinidas en ese nuevo objeto (incluidoconstructor
) se buscan desde allí. Podemos pensar en esto como generar propiedades de objetos y clases.fuente
Babel admite variables de clase en ESNext, consulte este ejemplo :
fuente
En tu ejemplo:
Debido a que MY_CONST es primitivo https://developer.mozilla.org/en-US/docs/Glossary/Primitive solo podemos hacer:
Pero si el
MY_CONST
tipo de referencia comostatic get MY_CONST() {return ['string'];}
salida de alerta es cadena, falso . En tal caso, eldelete
operador puede hacer el truco:Y finalmente para la variable de clase no
const
:fuente
delete
operador, si está solo, por razones de rendimiento. Lo que realmente quieres aquí esObject.defineProperty
.Dado que su problema es principalmente estilístico (no quiere llenar el constructor con un montón de declaraciones), también se puede resolver estilísticamente.
A mi modo de ver, muchos lenguajes basados en clases tienen el constructor como una función nombrada después del nombre de la clase. Estilísticamente podríamos usar eso para hacer una clase ES6 que estilísticamente todavía tiene sentido pero no agrupa las acciones típicas que tienen lugar en el constructor con todas las declaraciones de propiedades que estamos haciendo. Simplemente usamos el constructor JS real como el "área de declaración", luego hacemos una función llamada clase que de otro modo tratamos como el área "otras cosas del constructor", llamándola al final del verdadero constructor.
Ambos serán llamados a medida que se construya la nueva instancia.
Es como tener 2 constructores donde separa las declaraciones y las otras acciones de constructor que desea realizar, y estilísticamente hace que no sea demasiado difícil entender que eso también está sucediendo.
Creo que es un buen estilo para usar cuando se trata de muchas declaraciones y / o muchas acciones que deben ocurrir en la instanciación y que desean mantener las dos ideas distintas entre sí.
NOTA : no uso las ideas idiomáticas típicas de "inicialización" (como un método
init()
oinitialize()
) porque a menudo se usan de manera diferente. Hay una especie de presunta diferencia entre la idea de construir e inicializar. Al trabajar con constructores, las personas saben que se les llama automáticamente como parte de la creación de instancias. Al ver uninit
método, muchas personas van a suponer, sin una segunda mirada, que necesitan hacer algo a lo largo de la formavar mc = MyClass(); mc.init();
, porque así es como normalmente se inicializa. No estoy tratando de agregar un proceso de inicialización para el usuario de la clase, estoy tratando de agregar al proceso de construcción de la clase en sí.Si bien algunas personas pueden hacer una doble toma por un momento, ese es realmente el punto: les comunica que la intención es parte de la construcción, incluso si eso les hace hacer una pequeña toma doble y decir "eso no es cómo funcionan los constructores de ES6 "y toman un segundo vistazo al constructor real para decir" oh, lo llaman en la parte inferior, ya veo ", eso es mucho mejor que NO comunicar esa intención (o comunicarla incorrectamente) y probablemente obtener mucha información personas que lo usan mal, tratando de inicializarlo desde afuera y basura. Eso es muy intencional al patrón que sugiero.
Para aquellos que no quieren seguir ese patrón, todo lo contrario también puede funcionar. Agrupe las declaraciones a otra función al principio. Quizás lo denomine "propiedades" o "publicProperties" o algo así. Luego pon el resto de las cosas en el constructor normal.
Tenga en cuenta que este segundo método puede parecer más limpio, pero también tiene un problema inherente en el que
properties
se anula cuando una clase que usa este método extiende a otra. Tendría que dar más nombres únicosproperties
para evitar eso. Mi primer método no tiene este problema porque su mitad falsa del constructor lleva el nombre exclusivo de la clase.fuente
init
.init
es un patrón que se usa con frecuencia y que a menudo se llama desde fuera de la clase cuando el usuario externo quiere inicializar, es decirvar b = new Thing(); b.init();
. Esta es una opción 100% estilística que preferiría comunicar que es una segunda función que se llama automáticamente al aprovechar los patrones que se encuentran en otros idiomas. Es mucho menos probable que alguien vea esto y asuma que necesita llamar alMyClass
método desde afuera, más probable que se dé cuenta de que la intención es un segundo método que actúa en la construcción (es decir, llamado por sí mismo en la instanciación).MyClass
.$myvar
forma estándar de referirse a las variables destinadas a contener objetos jQuery no es convenientemente similar al patrón de tener $ al comienzo de las variables a las que están acostumbrados tantos programadores PHP. Solo esa pequeña implicación de que "sí, no es exactamente lo mismo ... pero mira ... ¡sigue siendo una variable porque esa es la forma en que las variables se hacen en algunos idiomas!" ayudaproperties()
función. Sin embargo, las cosas se vuelven un poco más complicadas al extender las clases, por lo que sugeriría que si usa unaproperties()
función en todas sus clases para declarar sus propiedades de clase, prefija el nombre del método con el nombre de la clase (IE:MyClassProperties()
para evitar anular accidentalmente llamadas a funciones dentro de subclases. Además, tenga en cuenta que cualquier llamada asuper()
debe declararse primero en el constructor de la clase.¿Qué hay de la vieja escuela?
En el constructor solo mencionas los vars que deben calcularse. Me gusta la herencia de prototipos para esta característica: puede ayudar a ahorrar mucha memoria (en caso de que haya muchos vars nunca asignados).
fuente
Como Benjamin dijo en su respuesta, TC39 decidió explícitamente no incluir esta característica al menos para ES2015. Sin embargo, el consenso parece ser que lo agregarán en ES2016.
La sintaxis aún no se ha decidido, pero hay una propuesta preliminar para ES2016 que le permitirá declarar propiedades estáticas en una clase.
Gracias a la magia de babel, puedes usar esto hoy. Habilite la transformación de las propiedades de clase de acuerdo con estas instrucciones y listo. Aquí hay un ejemplo de la sintaxis:
Esta propuesta está en un estado muy temprano, así que prepárate para ajustar tu sintaxis a medida que pasa el tiempo.
fuente
[Hilo largo, no estoy seguro si ya está en la lista como una opción ...].
Una alternativa simple solo para los concursantes sería definir la constante fuera de la clase. Solo será accesible desde el módulo en sí, a menos que esté acompañado de un captador.
Esta manera
prototype
no está llena de basura y obtienes elconst
.fuente
var
lugar deconst
2) usa varias instancias de esta clase? Luego, las variables externas se cambiarán con cada instancia de la claseES7
sintaxis de miembro de clase:ES7
tiene una solución para 'desechar' su función de constructor. Aquí hay un ejemplo:El ejemplo anterior se vería de la siguiente manera
ES6
:Tenga en cuenta al usar esto que es posible que esta sintaxis no sea compatible con todos los navegadores y que deba transpilarse una versión anterior de JS.
Bonus: una fábrica de objetos:
fuente
Puede imitar el comportamiento de las clases es6 ... y usar sus variables de clase :)
Lo puse en GitHub
fuente
La forma en que resolví esto, que es otra opción (si tiene jQuery disponible), fue definir los campos en un objeto de la vieja escuela y luego extender la clase con ese objeto. Tampoco quería salpicar al constructor con tareas, esto parecía ser una buena solución.
- Actualización Siguiendo el comentario de Bergi.
Sin versión JQuery:
Todavía terminas con un constructor 'gordo', pero al menos todo en una clase y asignado en un solo golpe.
EDITAR # 2: ahora he completado el círculo y ahora estoy asignando valores en el constructor, por ejemplo
¿Por qué? Realmente simple, usando lo anterior más algunos comentarios de JSdoc, PHPStorm pudo completar el código en las propiedades. Asignar todos los vars en un solo golpe fue bueno, pero la imposibilidad de codificar para completar las propiedades, en mi opinión, no vale la pena (casi ciertamente minúscula) beneficio de rendimiento.
fuente
class
sintaxis, también puede hacerloObject.assign
. No hay necesidad de jQuery.MyClassFields
un constructor, no tiene ningún método. ¿Puedes explicar por qué hiciste esto (en lugar de, por ejemplo, una función de fábrica simple que devuelve un objeto literal)?Bueno, puedes declarar variables dentro del Constructor.
fuente
Aún así, no puede declarar ninguna clase como en otros lenguajes de programación. Pero puedes crear tantas variables de clase. Pero el problema es el alcance del objeto de clase. Entonces, según yo, la mejor forma de programación OOP en ES6 Javascript: -
fuente
Este es un combo un poco hack de estática y funciona para mí
usado en otro lugar
fuente
singleton_instance
como nombre de propiedad para que todos entiendan lo que está haciendo aquí.