function foo(a) {
if (/* Some condition */) {
// perform task 1
// perform task 3
}
else {
// perform task 2
// perform task 3
}
}
Tengo una función cuya estructura es similar a la anterior. Quiero abstraer la tarea 3 en una función, bar()
pero deseo limitar el acceso a esta función solo dentro del alcance de foo(a)
.
Para lograr lo que quiero, ¿es correcto cambiar a lo siguiente?
function foo(a) {
function bar() {
// Perform task 3
}
if (/* Some condition */) {
// Perform task 1
bar();
}
else {
// Perform task 2
bar();
}
}
Si lo anterior es correcto, ¿ bar()
se redefine cada vez que foo(a)
se llama? (Me preocupa el desperdicio de recursos de CPU aquí).
javascript
tamakisquare
fuente
fuente
Respuestas:
Sí, lo que tienes ahí está bien. Algunas notas:
bar
se crea en cada llamada a la funciónfoo
, pero:bar
haga, algunos motores pueden determinar que pueden "en línea", eliminando la llamada de función por completo. V8 hace esto, y estoy seguro de que no es el único motor que lo hace. Naturalmente, solo pueden hacer esto si no cambia el comportamiento del código.bar
creado cada vez variará ampliamente entre los motores de JavaScript. Sibar
es trivial, variará de indetectable a bastante pequeño. Si no estás llamandofoo
miles de veces seguidas (por ejemplo, desde unmousemove
controlador), no me preocuparía. Incluso si es así, solo me preocuparía si veo un problema en motores más lentos. Aquí hay un caso de prueba que involucra operaciones DOM , que sugiere que hay un impacto, pero trivial (probablemente eliminado por las cosas DOM). Aquí hay un caso de prueba que hace computación pura que muestra un impacto mucho mayor, pero francamente incluso, estamos hablando de una diferencia de microsegundos porque incluso un aumento del 92% en algo que requiere microsegundos para suceder sigue siendo muy, muy rápido. Hasta / a menos que haya visto un impacto en el mundo real, no es algo de qué preocuparse.bar
solo será accesible desde dentro de la función, y tiene acceso a todas las variables y argumentos para esa llamada a la función. Esto hace que este sea un patrón muy útil.fuente
bar
se crea una copia de en cada llamada defoo
)foo
. Si no llamasfoo
miles de veces seguidas (por ejemplo, no en unmousemove
controlador), entonces no me preocuparía en absoluto. Y tenga en cuenta que algunos motores (V8, por ejemplo) incorporarán el código de todos modos, eliminando por completo la llamada a la función, siempre que hacerlo no cambie lo que está sucediendo de una manera que pueda detectarse externamente.bar()
en cada llamada? Además, ¿ayudaría usarfoo.prototype.bar
para definir la función?bar
tiene acceso a las variables y argumentos para la llamada afoo
(cualquier cosa en la que desee que opere, debe pasarla), lo que puede complicar un poco las cosas, pero en una situación de rendimiento crítico en la que ha visto un problema real, puede refactorizar así para ver si resuelve el problema. No, el usofoo.prototype
no ayudaría realmente (por un lado,bar
ya no sería privado).Para eso están los cierres.
var foo = (function () { function bar() { // perform task 3 }; function innerfoo (a) { if (/* some cond */ ) { // perform task 1 bar(); } else { // perform task 2 bar(); } } return innerfoo; })();
Innerfoo (un cierre) contiene una referencia a bar y solo se devuelve una referencia a innerfoo desde una función anónima que se llama solo una vez para crear el cierre.
El bar no es accesible desde el exterior de esta manera.
fuente
var foo = (function () { var bar = function () { // perform task 3 } return function (a) { if (/*some condition*/) { // perform task 1 bar(); } else { // perform task 2 bar(); } }; }());
El cierre mantiene el alcance de
bar()
contenido, devolviendo la nueva función de la función anónima autoejecutable establece un alcance más visible afoo()
. La función de autoejecución anónima se ejecuta exactamente una vez, por lo que solo hay unabar()
instancia, y cada ejecución de lafoo()
usará.fuente
Sí, eso funciona bien.
La función interna no se recrea cada vez que ingresa a la función externa, pero se reasigna.
Si prueba este código:
function test() { function demo() { alert('1'); } demo(); demo = function() { alert('2'); }; demo(); } test(); test();
se mostrará
1
,2
,1
,2
, no1
,2
,2
,2
.fuente
demo()
cada tiempotest()
debe ser un problema de desempeño? ¿Depende de la complejidad dedemo()
?Creé un jsperf para probar las expresiones anidadas frente a las no anidadas y las expresiones de función frente a las declaraciones de función, y me sorprendió ver que los casos de prueba anidados funcionaban 20 veces más rápido que los no anidados. (Anticipé diferencias opuestas o insignificantes).
https://jsperf.com/nested-functions-vs-not-nested-2/1
Esto está en Chrome 76, macOS.
fuente