Uso adecuado de const para definir funciones en JavaScript

183

Me interesa saber si hay algún límite con respecto a qué tipos de valores se pueden establecer usando constJavaScript, en particular funciones. ¿Es esto válido? De acuerdo, funciona, pero ¿se considera una mala práctica por alguna razón?

const doSomething = () => {
   ...
}

¿Deberían definirse todas las funciones de esta manera en ES6? No parece que esto se haya dado cuenta, si es así.

Gracias por cualquier comentario!

David Sinclair
fuente
Parece que hace varias preguntas: 1) "Estoy interesado si hay algún límite en cuanto a qué tipos de valores se pueden establecer usando const en JavaScript" No. 2) "¿Es esto válido?" Si. 3) "se considera una mala práctica por cualquier motivo" Supongo que no ha existido durante el tiempo suficiente para decir algo al respecto, pero no veo por qué esto debería ser una práctica de almohadilla. No es muy diferente de var doSomething = <function def>;. 4) "¿Deberían definirse todas las funciones de esta manera en ES6?" Me parece engorroso. Me gustan las declaraciones de funciones. Cada uno lo suyo.
Felix Kling
1
A mi modo de ver (opinión, no un hecho), tiene sentido si desea no permitir la redefinición de funciones. Si es sano o si tiene algún uso funcional, eso es discutible. Si cree que se ajusta a su escenario de uso, no creo que alguien pueda discutir su decisión y considerarla una mala práctica.
Mjh
44
Supongo que la pregunta es con qué quieres lograr const. ¿Desea evitar anular la función? Supongo que sabes tu código para no hacer esto de todos modos. ¿Desea expresar la intención de doSomething, es decir, que tiene una función y no cambia su valor? Creo que las declaraciones de funciones comunican esta intención claramente también. Por lo tanto, si necesita "protección en tiempo de ejecución" contra anulación, hágalo. De lo contrario, no veo mucho beneficio. Por supuesto, si solías usarlo principalmente var foo = function() {};, lo usaría en constlugar de var.
Felix Kling
55
@FelixKling, "Supongo que sabes tu código para no hacer esto de todos modos". Este es un argumento bastante malo. De lo contrario, no tiene sentido en constabsoluto.
Meandre

Respuestas:

253

No hay problema con lo que has hecho, pero debes recordar la diferencia entre las declaraciones de funciones y las expresiones de funciones.

Una declaración de función, es decir:

function doSomething () {}

Se eleva completamente a la parte superior del alcance (y les gusta lety consttambién tienen un alcance de bloque).

Esto significa que lo siguiente funcionará:

doSomething() // works!
function doSomething() {}

Una expresión de función, es decir:

[const | let | var] = function () {} (or () =>

Es la creación de una función anónima ( function () {}) y la creación de una variable, y luego la asignación de esa función anónima a esa variable.

Por lo tanto, las reglas habituales sobre el levantamiento de variables dentro de un alcance: las variables de ámbito de bloque ( lety const) no se alzan undefineden la parte superior de su alcance de bloque.

Esto significa:

if (true) {
    doSomething() // will fail
    const doSomething = function () {}
}

Fallará ya doSomethingque no está definido. (Lanzará un ReferenceError)

Si cambia a usar var, obtiene el levantamiento de la variable, pero se inicializará para undefinedque el bloque de código anterior todavía no funcione. (Esto arrojará un TypeErrordado doSomethingque no es una función en el momento en que lo llama)

En lo que respecta a las prácticas estándar, siempre debe usar la herramienta adecuada para el trabajo.

Axel Rauschmayer tiene una excelente publicación sobre alcance y elevación, incluida la semántica es6: Variables y alcance en ES6

tkone
fuente
77
Solo me gustaría agregar que las clases es6 usan const internamente para proteger el nombre de la clase de ser reasignado dentro de la clase.
user2342460
2
Una sutil diferencia entre a function a(){console.log(this);} y b const a=_=>{console.log(this);} es si lo llamas como a.call(someVar);, en a , se imprimirá someVar, en b , se imprimirá window.
Qian Chen
100

Aunque usar constpara definir funciones parece un truco, viene con algunas grandes ventajas que lo hacen superior (en mi opinión)

  1. Hace que la función sea inmutable, por lo que no tiene que preocuparse de que alguna otra pieza de código cambie esa función.

  2. Puede usar la sintaxis de flecha gruesa, que es más corta y limpia.

  3. El uso de las funciones de flecha se encarga del thisenlace por usted.

ejemplo con function

// define a function
function add(x, y) { return x + y; }

// use it
console.log(add(1, 2)); // 3

// oops, someone mutated your function
add = function (x, y) { return x - y; };

// now this is not what you expected
console.log(add(1, 2)); // -1

mismo ejemplo con const

// define a function (wow! that is 8 chars shorter)
const add = (x, y) => x + y;

// use it
console.log(add(1, 2)); // 3

// someone tries to mutate the function
add = (x, y) => x - y; // Uncaught TypeError: Assignment to constant variable.
// the intruder fails and your function remains unchanged

gafi
fuente
1
Y puede declarar dos veces la función add (x, y), pero no puede declarar dos veces const add = ...
TatianaP
33
1. La inmutabilidad es un beneficio real, pero es muy raro que alguien sobrescriba una función. 2. La sintaxis de flecha gruesa no es más corta a menos que su función pueda ser una expresión. function f(x, y) {tiene 18 caracteres, const f = (x, y) => {tiene 21 caracteres, entonces 3 caracteres más. 3. Mantener este enlace solo importa si las funciones se definen dentro de un método (u otra función que tenga sentido). En el script de nivel superior no tiene sentido. No digo que estés equivocado, solo que las razones que mencionas no son terriblemente relevantes.
Desnudo
@Nakedible, ¿cuáles son otras razones válidas?
Anish Ramaswamy
13
Una ventaja de la sintaxis de función antigua es que durante la depuración tiene un nombre.
user949300
3
Usaría linters para evitar volver a vincular la declaración de función.
Franklin Yu
32

Han pasado tres años desde que se hizo esta pregunta, pero ahora me la estoy cruzando. Dado que esta respuesta está muy por debajo de la pila, permítame repetirla:

P: Me interesa saber si hay algún límite respecto de qué tipos de valores se pueden establecer usando const en JavaScript, en particular funciones. ¿Es esto válido? De acuerdo, funciona, pero ¿se considera una mala práctica por alguna razón?

Estaba motivado para investigar un poco después de observar a un prolífico codificador de JavaScript que siempre usa una constdeclaración functions, incluso cuando no hay una razón / beneficio aparente.

En respuesta a " ¿se considera una mala práctica por alguna razón? ", Permítanme decir, en mi opinión, sí, o al menos, hay ventajas al usar la functiondeclaración.

Me parece que esto es en gran medida una cuestión de preferencia y estilo. Hay algunos buenos argumentos presentados anteriormente, pero ninguno tan claro como se hace en este artículo:

Confusión constante: por qué sigo usando declaraciones de función de JavaScript de medium.freecodecamp.org/Bill Sourour, JavaScript guru, consultor y profesor.

Insto a todos a leer ese artículo, incluso si ya ha tomado una decisión.

Aquí están los puntos principales:

Las declaraciones de función tienen dos ventajas claras sobre las expresiones de función [const]:

Ventaja # 1: claridad de intención

Al escanear miles de líneas de código por día, es útil poder descubrir la intención del programador de la manera más rápida y fácil posible.

Ventaja # 2: Orden de declaración == orden de ejecución

Idealmente, quiero declarar mi código más o menos en el orden en que espero que se ejecute.

Este es el showtopper para mí: cualquier valor declarado usando la palabra clave const es inaccesible hasta que la ejecución lo alcance.

Lo que acabo de describir anteriormente nos obliga a escribir código que se ve al revés. Tenemos que comenzar con la función de nivel más bajo y avanzar hacia arriba.

Mi cerebro no funciona de esa manera. Quiero el contexto antes de los detalles.

La mayoría del código está escrito por humanos. Por lo tanto, tiene sentido que el orden de comprensión de la mayoría de las personas siga aproximadamente el orden de ejecución de la mayoría de los códigos.

JMichaelTX
fuente
1
¿Puedes comentar un poco más sobre la claridad de la intención? Obtengo el n. ° 2, pero por lo que puedo decir, el n. ° 1 es solo una (¿pre?) Reiteración del n. ° 2. Puedo pensar en un caso, es decir, funciones que tienen su propio defaultErrorHandlerconst asignado como una función anónima que luego puedo llamar desde los encargados de la promesa. Esto me permitiría opcionalmente 'anular' este controlador de errores predeterminado dentro de las funciones que necesitaba. Algunos solo necesitan devolver un objeto de error y otros necesitan devolver una respuesta http, variando los niveles de verbosidad. Sin embargo, la estructura del código puede ser un patrón familiar independientemente.
Jake T.
¡Quizás mi idea es demasiado complicada! Solo estoy pensando en algunas nuevas prácticas, no he pasado mucho tiempo implementándolas todavía. Simplemente descubrí que me gusta .then( res.success, res.error )mucho más que las funciones anónimas que estaba declarando simplemente llamar res.success(value);. Tener un .then( ..., defaultErrorHandler)patrón común podría ser agradable, con una función defaultErrorHandler definida de nivel superior y, opcionalmente, tener una función const defaultErrorHandler = error => { ... }declarada dentro del alcance de una función como se desee.
Jake T.
1
@JakeT. RE "¿Puedes comentar un poco más sobre la claridad de la intención?". Bueno, en primer lugar, esa declaración no fue hecha por mí, sino por freecodecamp.org/Bill Sourour, el autor de ese artículo. Pero tiene mucho sentido común para mí. Si leo "function tomorrow ()", inmediatamente sé que ES una función. Pero si leo "const tomorrow = () =>", me detengo por un momento y analizo la sintaxis en mi cabeza para finalmente determinar, OK, sí, es una función.
JMichaelTX
1
Otra cosa, si tengo un guión largo escrito por otra persona y quiero ver todas las funciones, puedo hacer una búsqueda rápida en "función" para encontrarlas. O incluso mejor, puedo escribir un rápido JS RegEx para extraer todas las funciones. En mi opinión, la declaración "const" es solo para datos (no funciones) que NO cambiarán.
JMichaelTX
10

El uso de constalgunos beneficios es muy importante y algunos dirían que debe usarse siempre que sea posible debido a lo deliberado e indicativo que es.

Es, por lo que puedo decir, la declaración de variables más indicativa y predecible en JavaScript, y una de las más útiles, PORQUE está limitada. ¿Por qué? Porque elimina algunas posibilidades disponibles vary letdeclaraciones.

¿Qué puedes inferir cuando lees un const? Usted sabe todo lo siguiente simplemente leyendo la constdeclaración de declaración, Y sin buscar otras referencias a esa variable:

  • el valor está vinculado a esa variable (aunque su objeto subyacente no es profundamente inmutable)
  • no se puede acceder fuera de su bloque que contiene inmediatamente
  • nunca se accede al enlace antes de la declaración, debido a las reglas de la Zona muerta temporal (TDZ).

La siguiente cita es de un artículo que argumenta los beneficios de lety const. También responde más directamente a su pregunta sobre las restricciones / límites de la palabra clave:

Las restricciones como las que ofrece lety constson una forma poderosa de hacer que el código sea más fácil de entender. Intente acumular tantas restricciones como sea posible en el código que escriba. Cuantas más restricciones declarativas limiten el significado de un fragmento de código, más fácil y rápido será para los humanos leer, analizar y comprender un fragmento de código en el futuro.

De acuerdo, hay más reglas para una constdeclaración que para una vardeclaración: ámbito de bloque, TDZ, asignar en la declaración, sin reasignación. Mientras que las vardeclaraciones solo señalan el alcance de la función. Sin embargo, contar las reglas no ofrece mucha información. Es mejor sopesar estas reglas en términos de complejidad: ¿la regla agrega o resta complejidad? En el caso de const, el alcance de bloque significa un alcance más estrecho que el alcance de función, TDZ significa que no necesitamos escanear el alcance hacia atrás desde la declaración para detectar el uso antes de la declaración, y las reglas de asignación significan que el enlace siempre preservará el misma referencia

Cuanto más limitadas son las declaraciones, más simple se vuelve un fragmento de código. A medida que agregamos restricciones a lo que podría significar una declaración, el código se vuelve menos impredecible. Esta es una de las principales razones por las cuales los programas con tipos estáticos son generalmente más fáciles de leer que los con tipos dinámicos. La escritura estática impone una gran restricción al escritor del programa, pero también impone una gran restricción sobre cómo se puede interpretar el programa, lo que hace que su código sea más fácil de entender.

Con estos argumentos en mente, se recomienda que utilice constsiempre que sea posible, ya que es la afirmación que nos da la menor posibilidad de pensar.

Fuente: https://ponyfoo.com/articles/var-let-const

mrmaclean89
fuente