2010-02-24 14 views
42

Considere este código javascript:Función-Indicador Javascript Asignación

var bar = function() { alert("A"); } 
var foo = bar; 
bar = function() { alert("B"); }; 
foo(); 

Cuando se ejecuta este código me sale "A". ¿Este comportamiento es parte de la especificación de JavaScript y puedo confiar en él?

Respuesta

35

Sí, eso es esperado y por diseño.

Su pregunta es básicamente: ¿foo referencia bar como puntero o referencia lo haría en otro idioma?

La respuesta es no: el valor de bar en el momento de la asignación se asigna a foo.

+0

por qué es una copia del valor que se pasa cuando las funciones no son tipos primitivos? – thed0ctor

+0

No importa, esto se responde a continuación: http://stackoverflow.com/a/11598151/1316465 – thed0ctor

+1

Solo para aclarar la última frase de esta respuesta, recuerde que el 'valor de la barra' es un 'puntero a la función', no la función en sí misma Por lo tanto, después de 'foo = bar', foo recibe una copia por valor de ese puntero, por lo que tanto foo como la barra apuntan al objeto de función independiente. – drodsou

1

Esta es asignar una variable a una función sin nombre, no es un puntero a una función

1

Sí, se ha creado un puntero a la función original "A". Cuando reasigna la barra, está reasignando, pero todavía está dejando solo referencias a la función anterior.

Para responder a su pregunta, sí, puede confiar en ella.

5

Sí, no hay nada de especial en el hecho de que las variables se refieren a funciones, no hay alias involucrados.

var bar = 1; 
var foo = bar; 
bar = "something entirely different"; 
// foo is still 1 
3

Sí, este es el comportamiento correcto.

//create variable bar and assign a function to it 
var bar = function() { alert("A"); } 
//assign value of bar to the newly created variable foo 
var foo = bar; 
//assign a new function to the variable bar 
//since foo and bar are not pointers, value of foo doesn't change 
bar = function() { alert("B"); }; 
//call the function stored in foo 
foo(); 
2

Estos no son punteros a las funciones (y no hay punteros en JS de forma nativa). Las funciones en JS pueden ser anónimas y son objetos de primera clase. Por lo tanto

function() { alert("A"); } 

crea una función anónima que alerta a "A" en la ejecución;

var bar = function() { alert("A"); }; 

asigne esa función a la barra;

var foo = bar; 

asignar foo a bar, que es la función de "A".

bar = function() { alert("B"); }; 

rebind bar a la función anónima "B". Esto no afectará a foo ni a la otra función "A".

foo(); 

Llamar a la función almacenada en foo, que es la función "A".


Actualmente en idiomas donde hay puntos de función, p. C tampoco afectará a foo. No sé de dónde sacas la idea de obtener una "B" en la reasignación.

void A(void) { printf("A\n"); } 
void B(void) { printf("B\n"); } 
typedef void(*fptr_t)(void); 
fptr_t foo = A; 
fptr_t bar = foo; 
bar = B; 
foo(); // should print "A" 
5

Está asignando el valor de una función anónima a una variable, no a un puntero.
Si desea jugar con punteros, puede usar objetos que se pasan por referencia, no copiar.

Éstos son algunos ejemplos:

"obj2" es una referencia de "obj1", cambia "obj2", y "obj1" se cambia. Alertará false.

var obj1 = {prop:true}, 
    obj2 = obj1; 
obj2.prop = false; 
alert(obj1.prop); 

"apuntalar" puntos a una propiedad que no es un objeto, "apuntalar" no es un puntero a este objeto, sino una copia. Si cambia "prop", "obj1" no cambia. Se alerta true

var obj1 = {prop:true}, 
    prop = obj1.prop; 
prop = false; 
alert(obj1.prop); 

"obj2" es una referencia a la propiedad "subObj" de "obj1". si se cambia "obj2", se cambia "obj1". Alertará false.

var obj1 = {subObj:{prop:true}}, 
    obj2 = obj1.subObj; 
obj2.prop = false; 
alert(obj1.subObj.prop); 
+1

Gracias. Estos ejemplos fueron lo que quería al leer este hilo. :-) – jmk2142

18

Estoy un poco tarde aquí, pero pensé que daría una respuesta de todos modos y daría algo.

Es mejor no pensar en términos de punteros y referencias de memoria cuando se discuten los aspectos internos de JavaScript (o ECMAScript) cuando se trata de las especificaciones. Las variables son registros de entorno internos y se almacenan y referencian por nombre, no por dirección de memoria. Lo que está haciendo su declaración de asignación, internamente y por diseño, es buscar el nombre del registro del entorno (ya sea "foo" o "bar") y asignar el valor a ese registro.

Así,

var bar = function() { alert("A"); } 

es asignar la "barra" registro del valor medio (función anónima).

var foo = bar; 

llama internamente GetValue ("barra") que recupera el valor asociado a la "barra" registro y luego asigna ese valor a la disco "foo". Por lo tanto, después, el valor original de la barra todavía se puede usar, ya que ahora está asociado con foo.

Debido JavaScript referencias de cadena y no la dirección de memoria es precisamente por eso que puede hacer cosas como esta:

someObject["someProperty"] 

que está mirando hacia arriba el valor basado en el nombre de la propiedad.

54

En otros ejemplos, no se pasó nada por valor; todo fue pasado por referencia.

bar y foo son ambos punteros

Todos los VARs/Palancas de objetos primitivos NO en javascript son punteros; los punteros SON nativos de javascript, son los predeterminados.

var bar = function() { alert("A"); } //bar is a pointer to function1 
var foo = bar; //pointer copied; foo is now also a pointer to function1 
bar = function() { alert("B"); }; //bar points to function2 
foo(); //foo is still a pointer to function1 

que se ejecutará en los errores y los errores ocultos si usted piensa que son copias. Especialmente si trabajas con objetos complejos. Por ejemplo

function person(name){this.name = name} 
var john = new person("john") 
var backup = john 
backup.name //john 
john.name = "jack" 
backup.name //jack, NOT john 

Para COPIAR realmente, una no primitiva en javascript requiere más trabajo que simplemente a = b. Por ejemplo:

function person(name){ this.name = name} 
var john = new person("john") 
var backup = new Object() 
backup = JSON.parse(JSON.stringify(john)) 
backup.__proto__ = john.__proto__ //useful in some cases 
john.name = "jack" 
backup.name //john 
+2

Gracias por aclarar esto, estaba confundido buscando en línea si las "funciones" eran primitivas cuando me dijeron que no. – thed0ctor

+0

Esta respuesta debería servir como una prueba de por qué deberíamos aprender más ciencias de la computación y menos programación ... –

0

me gustaría añadir También funciona para el pre-definidos funciones con nombre, así:

function myfunc() { alert("A"); } 
var bar = myfunc; 
var foo = bar; 
bar = function() { alert("B"); }; 
foo(); 

esto va a hacer lo mismo, lo que indica que los nombres de las funciones actúan como matriz nombres (punteros).

0

Para cada FunctionDeclaration f en el código, con el fin de texto fuente hacer:

Deje fn ser el identificador de FunctionDeclaration f.

Sea fo el resultado de una instancia de FunctionDeclaration f como se describe en la Cláusula 13.

Let funcAlreadyDeclared ser el resultado de una llamada al método concreto HasBinding de env que pasaban fn como argumento.

Si funcAlreadyDeclared es falso, llame al método concreto CreateMutableBinding de env pasando fn y ConfigurableBinding como argumentos.

Referencias

Cuestiones relacionadas