2012-04-19 23 views
66

¿Podemos pasar una referencia de una variable que es inmutable como argumento en una función?Punteros en JavaScript?

Ejemplo:

var x = 0; 
function a(x) 
{ 
    x++; 
} 
a(x); 
alert(x); //Here I want to have 1 instead of 0 
+0

Argumentan que este es un mal estilo ya que tiene la intención de utilizar los efectos secundarios de una función para causar una mutación. Esto puede hacer que su código sea más difícil de seguir. – spex

Respuesta

107

Desde JavaScript no soporta el paso de parámetros por referencia, se tendrá que hacer la variable de un objeto en su lugar:

var x = {Value: 0}; 
 

 
function a(obj) 
 
{ 
 
    obj.Value++; 
 
} 
 

 
a(x); 
 
document.write(x.Value); //Here i want to have 1 instead of 0

En este caso, x es una referencia a un objeto. Cuando se pasa x a la función a, esa referencia se copia a obj. Por lo tanto, obj y x se refieren a lo mismo en la memoria. Cambiar la propiedad Value de obj afecta a la propiedad Value de x.

Javascript siempre pasará los parámetros de función por valor. Eso es simplemente una especificación del lenguaje. Usted podría crear x en un ámbito local para ambas funciones, y no pasar la variable en absoluto.

+0

¿Hay alguna manera de hacerlo así que otra persona simplemente lo hará: var x = 0; a (x); y que la función establece un objeto con el valor de x? (o algo así) – user1342369

+5

Oye, gracias por presentarme [fragmentos de código en SO] (http://meta.stackoverflow.com/q/269753/1256925). No había oído hablar de ellos antes de verlos utilizados en su respuesta. – Joeytje50

+0

@ Joeytje50 - Sí, [esta función] (http://blog.stackoverflow.com/2014/09/introducing-runnable-javascript-css-and-html-code-snippets/) se acaba de agregar en septiembre. ¡Muy útil! –

19

Esta pregunta puede ayudar: How to pass variable by reference in javascript? Read data from ActiveX function which returns more than one value

En resumen, Javascript tipos primitivos siempre se pasan por valor, mientras que los valores dentro de los objetos se pasan por referencia (gracias a los comentaristas de señalando mi descuido). Así que para evitar esto, usted tiene que poner su número entero dentro de un objeto:

var myobj = {x:0}; 
 

 
function a(obj) 
 
{ 
 
    obj.x++; 
 
} 
 

 
a(myobj); 
 
alert(myobj.x); // returns 1 
 

 

+2

Las variables de objeto también se pasan siempre por valor, es solo que * el valor es una referencia * a un objeto. Hay una diferencia entre * pasar por referencia * y * pasar una referencia por valor *. A saber, cuando pasa 'x' por valor, si' x' es un objeto o no, no puede reemplazarlo con un valor completamente diferente de la forma en que lo verá la persona que llama. – cHao

+0

* mientras que los objetos se pasan por referencia * simplemente no es cierto. Nada en JavaScript se pasa por referencia. –

+0

Si pasa un tipo de primado por valor (se hace referencia a x), ¿por qué x no cambia después, a menos que pase el objeto – SuperUberDuper

1

En JavaScript que sería un mundial. Sin embargo, su función sería la misma familia:

function a(){ 
    x++; 
}; 

Desde x es en el contexto global, que no es necesario para pasarlo a la función.

+1

? Punto válido, aunque señalaría que la variable no necesita ser global (y muchos aconsejarían no hacer esto nunca), simplemente tiene que estar en el mismo alcance que la persona que llama y quien llama. –

+0

Ese es un gran punto. – Maess

0

En JavaScript, no puede pasar variables por referencia a una función. Sin embargo, puede pasar un objeto por referencia.

+3

Simplemente no es cierto. No puede pasar nada por referencia en JavaScript. –

+1

La referencia del objeto se pasa como valor, por lo que todo se pasa como valor. –

+0

observación interesante; parece IMPOSIBLE crear una referencia a una primitiva existente en JavaScript; una vez que un primitivo está vinculado, cualquier cambio en este primitivo nunca puede ser notado por sus referendos ingenuos porque los referentes apuntan al valor que la variable, que pasa a ser un primitivo; así que la única manera de "señalar" a una primitiva es si la primitiva está envuelta en una variable cuyo tipo de "objeto"; ya que ningún otro tipo puede almacenar una referencia. TLDR; no hay operador Perl "\" en JavaScript; es una referencia para empezar, o nunca se puede señalar. – Dmitry

11

He encontrado una manera ligeramente diferente de implementar punteros que es quizás más general y más fácil de entender desde una perspectiva C (y por lo tanto cabe más en el formato del ejemplo de los usuarios).

En JavaScript, al igual que en C, las variables de matriz son en realidad solo punteros a la matriz, por lo que puede utilizar una matriz exactamente igual que declarar un puntero. De esta forma, todos los punteros en su código se pueden usar de la misma manera, a pesar de lo que usted denominó la variable en el objeto original.

También permite usar dos notaciones diferentes que hacen referencia a la dirección del puntero y a la dirección del puntero.

Aquí es un ejemplo (utilizo el guión para denotar un puntero):

var _x = [ 10 ]; 

function foo(_a){ 
    _a[0] += 10; 
} 

foo(_x); 

console.log(_x[0]); 

Rendimientos

output: 20 
8

Usted se refiere a 'x' del objeto de la ventana

var x = 0; 

function a(key, ref) { 
    ref = ref || window; // object reference - default window 
    ref[key]++; 
} 

a('x');     // string 
alert(x); 
3

Respuesta tardía, pero he encontrado una manera de pasar valores primitivos por referencia mediante cierres. Es bastante complicado crear un puntero, pero funciona.

function ptr(get, set) { 
    return { get: get, set: set }; 
} 

function helloWorld(namePtr) { 
    console.log(namePtr.get()); 
    namePtr.set('jack'); 
    console.log(namePtr.get()) 
} 

var myName = 'joe'; 
var myNamePtr = ptr(
    function() { return myName; }, 
    function (value) { myName = value; } 
); 

helloWorld(myNamePtr); // joe, jack 
console.log(myName); // jack 

En ES6, el código se puede acortar a usar expresiones lambda:

var myName = 'joe'; 
var myNamePtr = ptr(=> myName, v => myName = v); 

helloWorld(myNamePtr); // joe, jack 
console.log(myName); // jack 
-1

En su ejemplo que en realidad tienen 2 variables con el mismo nombre. La variable (global) xy la función tienen un alcance de variable x. Es interesante ver que javascript, cuando se le da una opción de qué hacer con 2 variables del mismo nombre, va con el nombre del ámbito de la función e ignora la variable fuera del alcance.

Es probablemente no es seguro suponer JavaScript siempre se comportan de esta manera ...

Salud!

+0

Esta respuesta no agrega ningún valor a esta publicación. La respuesta de @Mike Christensen es más detallada y ya está aceptada. – Alexander

0

estoy pensando que al contrario que en C o en cualquier idioma con punteros:

/** Javascript **/ 
var o = {x:10,y:20}; 
var o2 = {z:50,w:200}; 
  • , obviamente, en Javascript no se puede acceder a los objetos o y o2direcciones en la memoria
  • pero no puede comparar su dirección tampoco: (no trivial possibil dad a tipo ellos, y luego el acceso de dicotomía)

.

o == o2 // obviously false : not the same address in memory 
o <= o2 // true ! 
o >= o2 // also true !! 

que es un gran problema:

  • Esto significa que usted puede enumerar/gestionar todos los objetos creados (asignados) por su aplicación,

  • de ese enorme lista de objetos , calcule algo de información sobre estos (cómo están vinculados entre sí, por ejemplo)

  • b ut cuando desea recuperar la información que creó sobre un objeto específico, no puede encontrarla en su lista enorme por dicotomía: no hay identificador único por objeto que podría utilizarse como un reemplazo de la dirección de memoria real

esto finalmente significa que este es un problema enorme, si se desea escribir en javascript:

  • un depurador de JavaScript/IDE
  • o una especialmente optimizado recolector de basura
  • un estructura de datos del cajón/analizador de
1

Javascript debe sólo hay que poner los punteros en la mezcla coz que resuelve muchos problemas. Significa que el código puede referirse a un nombre de variable desconocido o variables que se crearon dinámicamente. También hace que la codificación y la inyección modulares sean fáciles.

Esto es lo que veo como el más cercano que puede llegar a los punteros en la práctica c

en JS:

var a = 78;  // creates a var with integer value of 78 
var pointer = 'a' // note it is a string representation of the var name 
eval (pointer + ' = 12'); // equivalent to: eval ('a = 12'); but changes value of a to 12 

en c:

int a = 78;  // creates a var with integer value of 78 
int pointer = &a; // makes pointer to refer to the same address mem as a 
*pointer = 12; // changes the value of a to 12 
0

JavaScript no soportan el paso de tipos primitivos por referencia. Sin embargo, hay una solución.

Coloque todas las variables que necesita para pasar en un objeto. En este caso, solo hay una variable, x. En lugar de pasar la variable, pase el nombre de la variable como una cadena, que es "x".

var variables = {x:0}; 
 
function a(x) 
 
{ 
 
    variables[x]++; 
 
} 
 
a("x"); 
 
alert(variables.x);

1

Podría ser imposible ya que JavaScript no tiene operador "\" de Perl para obtener una primitiva de referencia, pero hay una manera de crear un "efectivamente un puntero" objeto de un primitivo que usa este patrón.

Esta solución tiene más sentido para cuando ya tiene la primitiva (por lo que ya no puede ponerla en un objeto sin la necesidad de modificar otro código), pero aún necesita pasarle un puntero para otras partes de su código para jugar con su estado; por lo que todavía puede jugar con su estado utilizando el proxy sin fisuras que se comporta como un puntero.

var proxyContainer = {}; 

// | attaches a pointer-lookalike getter/setter pair 
// | to the container object. 
var connect = function(container) { 
    // | primitive, can't create a reference to it anymore 
    var cant_touch_this = 1337; 

    // | we know where to bind our accessor/mutator 
    // | so we can bind the pair to effectively behave 
    // | like a pointer in most common use cases. 
    Object.defineProperty(container, 'cant_touch_this', { 
     'get': function() { 
      return cant_touch_this; 
     },     
     'set': function(val) { 
      cant_touch_this = val; 
     } 
    }); 
}; 

// | not quite direct, but still "touchable" 
var f = function(x) { 
    x.cant_touch_this += 1; 
}; 

connect(proxyContainer); 

// | looks like we're just getting cant_touch_this 
// | but we're actually calling the accessor. 
console.log(proxyContainer.cant_touch_this); 

// | looks like we're touching cant_touch_this 
// | but we're actually calling the mutator. 
proxyContainer.cant_touch_this = 90; 

// | looks like we touched cant_touch_this 
// | but we actually called a mutator which touched it for us. 
console.log(proxyContainer.cant_touch_this); 

f(proxyContainer); 

// | we kinda did it! :) 
console.log(proxyContainer.cant_touch_this); 
0

Dependiendo de lo que le gustaría hacer, simplemente podría guardar el nombre de la variable, y luego acceder a ella más adelante, así:

function toAccessMyVariable(variableName){ 
    alert(window[variableName]); 
} 

var myFavoriteNumber = 6; 

toAccessMyVariable("myFavoriteNumber"); 

para aplicar a su ejemplo específico, se puede hacer algo como esto:

var x = 0; 
var pointerToX = "x"; 

function a(variableName) 
{ 
    window[variableName]++; 
} 
a(pointerToX); 
alert(x); //Here I want to have 1 instead of 0