Soy un poco principiante en javascript. Estaba tratando de encontrar una manera de evitar las funciones anidadas. Eche un vistazo a los siguientes 2 ejemplos

// example 1
var x = 45;
function apple(){
    var y = 60;
    setTimeout(function(){
        console.log(y);
        console.log(x);
    }, 20);
}
apple();
console.log(x);

Bueno, el valor y se mantiene y se imprime en la consola ya que setTimeout forma un cierre con la función apple() y funciona bien. Ahora eche un vistazo al siguiente código

var x = 45;
var run = function(){
        console.log(y);
        console.log(x);
}; 
function apple(){
    var y = 60;
    setTimeout(run, 20);
}
apple();
console.log(x);

Solo quería colocar el cuerpo de la función por separado y pasar el manejador de la función como argumento, pero lo que estoy atrapado es cómo hago que las variables de la función apple() estén disponibles para la función run() porque no forman un cierre nunca más. ¿Hay alguna solución para hacerlo posible? Amablemente ayúdame.

Responda de manera genérica, para que también sea aplicable a la API de nodejs. He visto que setTimeout acepta más argumentos pero quiero que la solución sea aplicable independientemente del prototipo de la función.

Actualizar

Lo siento, pero creo que todas las respuestas hacen la llamada a la función usando pasar por valor. No está logrando cierres. Toman el valor actual de y y lo pasan como argumento de función y suponen que hay una declaración de y = 80 después de setTimeout() como el siguiente código

var y = 60;
setTimeout(run, 20);
y = 80; 

Imprime y = 60 y no el 80 dentro de run(). De hecho, quiero mantener la referencia de y y no capturar su valor como lo hacen los cierres. Gracias

1
user3205479 10 may. 2016 a las 14:34

3 respuestas

La mejor respuesta

Puede usar bind:

var x = 45;
var run = function(y){
        console.log(y);
        console.log(x);
}; 
function apple(){
    var y = 60;
    setTimeout(run.bind(null, y), 20);
}
apple();
console.log(x);

El primer argumento para vincular es lo que querrá vincular a this. Después de eso, cada argumento se pasa a la función recién creada. Observe que agregué y como argumento a la función run.

Lo que bind le ofrece es una nueva función con un contexto predefinido (this) y posiblemente valores predeterminados para los argumentos.

Sin embargo, tenga en cuenta que siempre debe evitar escenarios como este. Nunca es una buena idea modificar las variables externas dentro de una función, y generará mucho dolor y se volverá gris prematuramente. Debería intentar refactorizar su código para poder pasar y devolver valores, y no confiar en referencias o variables de alcance global.

2
Schlaus 10 may. 2016 a las 11:46

Podría hacer con y lo mismo que hace con x (configurándolo como global).

0
Marc Compte 15 may. 2016 a las 17:56

Su variable y no está en el alcance de run(), por lo que debe pasarla a run. También puede pasar la ejecución como parámetro a apple(cb_fn) https://jsfiddle.net/stevenkaspar/ttxxpoof /

var x = 45;
var y = 80;
var run = function(){ 
  console.log('could be 80 or 85(depending on race condition): ' + y);
  console.log('should be 45: ' + x);
}; 

function apple(cb_fn){
  var y = 60; // you can declar var y again to have another ignore global y
  setTimeout(function(){
    console.log('should be 60: ' + y);
    cb_fn(); // this would be a callback function
  }, 20);
}

apple(run); // you need to pass run in as a "callback" function
console.log('should be 45: ' + x);
y = 85;
console.log('should be 85: ' + y);
0
Steven Kaspar 10 may. 2016 a las 12:51