usar sintaxis funciones funcion flecha example es6 cuando anonimas javascript reactjs ecmascript-6 arrow-functions

sintaxis - map javascript



¿Qué significan las funciones de flecha múltiple en javascript? (7)

He estado leyendo un montón de código de react y veo cosas como esta que no entiendo:

handleChange = field => e => { e.preventDefault(); /// Do something here }


Comprender las sintaxis disponibles de las funciones de flecha le dará una idea de qué comportamiento están introduciendo cuando están "encadenados" en los ejemplos que proporcionó.

Cuando una función de flecha se escribe sin llaves de bloque, con o sin múltiples parámetros, la expresión que constituye el cuerpo de la función se devuelve implícitamente . En su ejemplo, esa expresión es otra función de flecha.

No arrow funcs Implicitly return `e=>{…}` Explicitly return `e=>{…}` --------------------------------------------------------------------------------- function (field) { | field => e => { | field => { return function (e) { | | return e => { e.preventDefault() | e.preventDefault() | e.preventDefault() } | | } } | } | }

Otra ventaja de escribir funciones anónimas utilizando la sintaxis de flecha es que están vinculadas léxicamente al alcance en el que están definidas. Desde ''Funciones de flecha'' en MDN :

Una expresión de función de flecha tiene una sintaxis más corta en comparación con las expresiones de función y enlaza léxicamente this valor. Las funciones de flecha son siempre anonymous .

Esto es particularmente pertinente en su ejemplo teniendo en cuenta que está tomado de una aplicación reactjs . Como lo señaló @naomik, en React a menudo accedes a las funciones miembro de un componente usando this . Por ejemplo:

Unbound Explicitly bound Implicitly bound ------------------------------------------------------------------------------ function (field) { | function (field) { | field => e => { return function (e) { | return function (e) { | this.setState(...) | this.setState(...) | this.setState(...) } | }.bind(this) | } | }.bind(this) | }


El ejemplo en su pregunta es el de una curried function que utiliza la arrow function de arrow function y tiene un implicit return para el primer argumento.

La función de flecha enlaza esto léxicamente, es decir, no tienen su propio argumento, pero toman el valor de this del alcance adjunto

Un equivalente del código anterior sería

const handleChange = (field) { return function(e) { e.preventDefault(); /// Do something here }.bind(this); }.bind(this);

Una cosa más a tener en cuenta sobre su ejemplo es que define handleChange como una constante o una función. Probablemente lo esté usando como parte de un método de clase y use una class fields syntax

así que en lugar de vincular la función externa directamente, la vincularía en el constructor de la clase

class Something{ constructor(props) { super(props); this.handleChange = this.handleChange.bind(this); } handleChange(field) { return function(e) { e.preventDefault(); // do something } } }

Otra cosa a tener en cuenta en el ejemplo es la diferencia entre el retorno implícito y explícito.

const abc = (field) => field * 2;

Arriba hay un ejemplo de retorno implícito, es decir. toma el campo de valor como argumento y devuelve el field*2 resultado field*2 que especifica explícitamente la función a devolver

Para un retorno explícito, le diría explícitamente al método que devuelva el valor

const abc = () => { return field*2; }

Otra cosa a tener en cuenta sobre las funciones de flecha es que no tienen sus propios arguments sino que también los heredan del alcance de los padres.

Por ejemplo, si solo define una función de flecha como

const handleChange = () => { console.log(arguments) // would give an error on running since arguments in undefined }

Como alternativa, las funciones de flecha proporcionan los parámetros de descanso que puede usar

const handleChange = (...args) => { console.log(args); }


Piénselo así, cada vez que ve una flecha, la reemplaza con una function .
function parameters se definen antes de la flecha.
Entonces en tu ejemplo:

field => // function(field){} e => { e.preventDefault(); } // function(e){e.preventDefault();}

y luego juntos:

function (field) { return function (e) { e.preventDefault(); }; }

De los documentos :

// Basic syntax: (param1, param2, paramN) => { statements } (param1, param2, paramN) => expression // equivalent to: => { return expression; } // Parentheses are optional when there''s only one argument: singleParam => { statements } singleParam => expression


Puede que no esté totalmente relacionado, pero dado que la pregunta mencionada reacciona usa el caso (y sigo tropezando con este hilo SO): hay un aspecto importante de la función de doble flecha que no se menciona explícitamente aquí. Solo se nombra la ''primera'' flecha (función) (y por lo tanto ''distinguible'' por el tiempo de ejecución), las flechas siguientes son anónimas y desde el punto de vista de React cuentan como un objeto ''nuevo'' en cada render.

Por lo tanto, la función de doble flecha hará que cualquier componente puro se vuelva a procesar todo el tiempo.

Ejemplo

Tiene un componente principal con un controlador de cambios como:

var handleChange = field => e => { e.preventDefault(); /// Do something here }

y con un render como:

{ tasks.map(task => <MyTask handleChange={this.handleChange(task)}/> }

handleChange luego se usa en una entrada o haga clic. Y todo esto funciona y se ve muy bien. PERO significa que cualquier cambio que hará que los padres vuelvan a rendirse (como un cambio de estado completamente no relacionado) también volverá a procesar TODA su MyTask, aunque sean Componentes Puros.

Esto puede aliviarse de muchas maneras, como pasar la flecha ''más externa'' y el objeto con el que lo alimentaría o escribir una función de actualización personalizada o volver a lo básico, como escribir funciones con nombre (y vincular esto manualmente ...)


Un consejo general, si se confunde con alguna de las nuevas sintaxis de JS y cómo se compilará, puede verificar babel . Por ejemplo, copiar su código en babel y seleccionar el preajuste es2015 dará una salida como esta

handleChange = function handleChange(field) { return function (e) { e.preventDefault(); // Do something here }; };


Breve y simple 🎈

Es una función que devuelve otra función escrita de forma breve.

const handleChange = field => e => { e.preventDefault() // Do something here } // is equal to function handleChange(field) { return function(e) { e.preventDefault() // Do something here } }

Por qué la gente lo hace

¿Te has enfrentado cuando necesitas escribir una función que se puede personalizar? ¿O tiene que escribir una función de devolución de llamada que tenga parámetros fijos (argumentos), pero necesita pasar más variables a la función pero evitando las variables globales? Si su respuesta es " ", entonces es la forma de hacerlo.

Por ejemplo, tenemos un button con devolución de llamada onClick. Y necesitamos pasar la id a la función, pero onClick acepta solo un event parámetro, no podemos pasar parámetros adicionales dentro de este modo:

const handleClick = (event, id) { event.preventDefault() // Dispatch some delete action by passing record id }

¡No funcionará!

Por lo tanto, hacemos una función que devolverá otra función con su propio alcance de variables sin ninguna variable global, porque las variables globales son malvadas 😈.

Debajo de la función handleClick(props.id)} se llamará y devolverá una función y tendrá id en su alcance. No importa cuántas veces se presione, los identificadores no se afectarán ni cambiarán entre sí, están totalmente aislados.

const handleClick = id => event { event.preventDefault() // Dispatch some delete action by passing record id } const Confirm = props => ( <div> <h1>Are you sure to delete?</h1> <button onClick={handleClick(props.id)}> Delete </button> </div )


Esa es una función curry

Primero, examine esta función con dos parámetros ...

const add = (x, y) => x + y add(2, 3) //=> 5

Aquí está de nuevo en forma de curry ...

const add = x => y => x + y

Aquí está el mismo código 1 sin funciones de flecha ...

const add = function (x) { return function (y) { return x + y } }

Centrarse en el return

Puede ser útil visualizarlo de otra manera. Sabemos que las funciones de flecha funcionan así: prestemos especial atención al valor de retorno .

const f = someParam => returnValue

Entonces, nuestra función add devuelve una función : podemos usar paréntesis para mayor claridad. El texto en negrita es el valor de retorno de nuestra función add

const add = x => (y => x + y)

En otras palabras, add un número devuelve una función

add(2) // returns (y => 2 + y)

Llamar a funciones curry

Entonces, para usar nuestra función de curry, tenemos que llamarlo un poco diferente ...

add(2)(3) // returns 5

Esto se debe a que la primera llamada de función (externa) devuelve una segunda función (interna). Solo después de llamar a la segunda función, realmente obtenemos el resultado. Esto es más evidente si separamos las llamadas en dos líneas ...

const add2 = add(2) // returns function(y) { return 2 + y } add2(3) // returns 5

Aplicando nuestra nueva comprensión a su código

relacionado: "¿Cuál es la diferencia entre encuadernación, aplicación parcial y curry?"

Bien, ahora que entendemos cómo funciona, veamos tu código

handleChange = field => e => { e.preventDefault() /// Do something here }

Comenzaremos por representarlo sin usar las funciones de flecha ...

handleChange = function(field) { return function(e) { e.preventDefault() // Do something here // return ... }; };

Sin embargo, debido a que las funciones de flecha unen léxicamente this , en realidad se vería más así ...

handleChange = function(field) { return function(e) { e.preventDefault() // Do something here // return ... }.bind(this) }.bind(this)

Quizás ahora podamos ver lo que esto está haciendo más claramente. La función handleChange está creando una función para un field específico. Esta es una técnica práctica de React porque debes configurar tus propios oyentes en cada entrada para actualizar el estado de tus aplicaciones. Al usar la función handleChange , podemos eliminar todo el código duplicado que resultaría en la configuración de escuchas de change para cada campo. ¡Bueno!

1 Aquí no tuve que vincular this léxicamente porque la función de add original no usa ningún contexto, por lo que no es importante preservarla en este caso.

Aún más flechas

Se pueden secuenciar más de dos funciones de flecha, si es necesario:

const three = a => b => c => a + b + c const four = a => b => c => d => a + b + c + d three (1) (2) (3) // 6 four (1) (2) (3) (4) // 10

Las funciones curry son capaces de sorprender. A continuación, vemos $ definido como una función currificada con dos parámetros, pero en el sitio de la llamada, parece que podemos proporcionar cualquier número de argumentos. El curry es la abstracción de la arity .

const $ = x => k => $ (k (x)) const add = x => y => x + y const mult = x => y => x * y $ (1) // 1 (add (2)) // + 2 = 3 (mult (6)) // * 6 = 18 (console.log) // 18 $ (7) // 7 (add (1)) // + 1 = 8 (mult (8)) // * 8 = 64 (mult (2)) // * 2 = 128 (mult (2)) // * 2 = 256 (console.log) // 256

Aplicación parcial

La aplicación parcial es un concepto relacionado. Nos permite aplicar parcialmente funciones, similares al currículum, excepto que la función no tiene que definirse en forma de currículum.

const partial = (f, ...a) => (...b) => f (...a, ...b) const add3 = (x, y, z) => x + y + z partial (add3) (1, 2, 3) // 6 partial (add3, 1) (2, 3) // 6 partial (add3, 1, 2) (3) // 6 partial (add3, 1, 2, 3) () // 6 partial (add3, 1, 1, 1, 1) (1, 1, 1, 1, 1) // 3

Aquí hay una demostración funcional de partial que puedes jugar en tu propio navegador:

const partial = (f, ...a) => (...b) => f (...a, ...b) const preventDefault = (f, event) => ( event .preventDefault () , f (event) ) const logKeypress = event => console .log (event.which) document .querySelector (''input[name=foo]'') .addEventListener (''keydown'', partial (preventDefault, logKeypress))

<input name="foo" placeholder="type here to see ascii codes" size="50">