2010-10-26 16 views
5

Digamos que tengo estas dos funciones:Javascript: Re-asignación de una función a otra función

function fnChanger(fn) { 
    fn = function() { sys.print('Changed!'); } 
} 
function foo() { 
    sys.print('Unchanged'); 
} 

Ahora, si llamo foo(), veo Unchanged, como se esperaba. Sin embargo, si llamo fnChanger primera, todavía veo Unchanged:

fnChanger(foo); 
foo(); //Unchanged 

Ahora, supongo que esto se debe a foo no se está pasando a fnChanger por referencia, pero puedo estar equivocado.

¿Por qué fnChanger no cambia foo para imprimir Changed!?
Además, ¿cómo puedo obtener fnChanger para cambiar foo sin mucha sintaxis desordenada?

PD: Estoy usando node.js para probar todo esto, así que de ahí viene el sys.print.

Respuesta

5

La asignación al argumento fn solo hace que ese identificador apunte a la función anónima, foo en el ámbito externo no se ve afectado.

Cuando pasa un objeto como argumento, uno puede decir "las referencias se pasan por valor". La asignación simplemente reemplaza la ubicación donde se hace referencia al identificador fn.

Así es como funciona el evaluation strategy en JavaScript.

Justo antes de la asignación en las fnChanger funciones, los dos identificadores, lo global foo y el argumento fn, apuntan a la misma función de objeto:

 
       --------------------------------------------- 
    foo -----> |function foo { sys.print('Un changed!'); } | 
       --------------------------------------------- 
       ^
        | 
    fn ------------- 

Después de la asignación, fn simplemente apunte a la nueva función:

 
       --------------------------------------------- 
    foo -----> | function foo { sys.print('Unchanged!'); } | 
       --------------------------------------------- 

       --------------------------------------- 
    fn ------> | function { sys.print('Changed!'); } | 
       --------------------------------------- 

¿Cómo podría cambiarlo?

Bueno, suponiendo que foo es una función en el ámbito global, se podría hacer algo como esto:

function fnChanger(obj, name) { 
    obj[name] = function() { sys.print('Changed!'); }; 
} 

function foo() { 
    sys.print('Unchanged'); 
} 

fnChanger(this, 'foo'); 
foo(); // Changed! 

Lo anterior funcionará porque en la función fnChanger, se requiere un objeto base de y una nombre de propiedad, las funciones declaradas en el contexto de ejecución global están vinculadas como propiedades del objeto global , por lo tanto, podemos reasignar su valor de esa manera.

La línea fnChanger(this, 'foo'); deberían ser ejecutados también en el ámbito global, pasará el valor this (que se refiere al objeto global en este ámbito de aplicación) y un nombre de propiedad, lo que permite realizar una asignación al identificador GlobalObject.foo.

Si ese código se encontraban dentro de una función, no hay manera de que podamos obtener un objeto base de, porque en este "contexto función ejecución de código", declaraciones de funciones (declaraciones de variables y parámetros formales de la función también) están unidos como propiedades de un objeto no accesible, llamado Objeto Variable (una cadena de estos Objetos Variables, forma la Cadena de Alcance), y si fuera el caso, la única solución alternativa sería usar eval.

Más información:

+0

Sí, me estaba empezando a sospechar que es lo que está sucediendo. Gracias por la aclaración y el enlace; nunca supe exactamente cómo llamarlo ni cómo funcionó. ¿Cómo puedo evitar esto? –

+0

Ok, me gusta ese enfoque. No tan desordenado como estaba pensando hacer: pasar un objeto que contiene la función que se va a cambiar. –

2

Como @CMS señaló que no se puede asignar dentro de la función debido al alcance. Sin embargo, puede reasignar así:

var fnChanger = function() { 
    return function() { 
     alert('changed!'); 
    } 
} 

var foo = function() { 
    alert('Unchanged'); 
} 

foo = fnChanger(); 
foo(); 

example

+0

Sí, pensé en eso. Sin embargo, dudo en hacerlo a cambio en el código real. Por un lado, es más limpio, pero por otro lado, no concuerda exactamente con lo que hace la función. –

Cuestiones relacionadas