¿JavaScript pasa por referencia?
¿JavaScript pasa por referencias o pasa por valores?
Aquí hay un ejemplo de JavaScript: The Good Parts. Estoy muy confundido acerca del parámetro my para la función rectángulo. En realidad es undefined, y se redefine dentro de la función. No hay una referencia original. Si lo elimino del parámetro de la función, la función interna area no puede acceder a él.
¿Es un closure? Pero no se devuelve ninguna función.
var shape = function (config) {
var that = {};
that.name = config.name || "";
that.area = function () {
return 0;
};
return that;
};
var rectangle = function (config, my) {
my = my || {};
my.l = config.length || 1;
my.w = config.width || 1;
var that = shape(config);
that.area = function () {
return my.l * my.w;
};
return that;
};
myShape = shape({
name: "Unhnown"
});
myRec = rectangle({
name: "Rectangle",
length: 4,
width: 6
});
console.log(myShape.name + " area is " + myShape.area() + " " + myRec.name + " area is " + myRec.area());
Respuesta #1
Los primitivos se pasan por valor, y los objetos se pasan por "copia de una referencia".
Específicamente, cuando pasas un objeto (o arreglo) estás (invisiblemente) pasando una referencia a ese objeto, y es posible modificar el contenido de ese objeto, pero si intentas sobrescribir la referencia no afectará la copia de la referencia que tiene el llamador, es decir, la referencia en sí se pasa por valor:
function replace(ref) {
ref = {}; // this code does _not_ affect the object passed
}
function update(ref) {
ref.key = 'newvalue'; // this code _does_ affect the _contents_ of the object
}
var a = { key: 'value' };
replace(a); // a still has its original value - it's unmodfied
update(a); // the _contents_ of 'a' are changed
Respuesta #2
Mis dos centavos.... Es irrelevante si JavaScript pasa los parámetros por referencia o por valor. Lo que realmente importa es la asignación contra la mutación.
Escribí una explicación más larga y detallada en este enlace.
Cuando pasas cualquier cosa (ya sea un objeto o un primitivo), todo lo que hace JavaScript es asignar una nueva variable dentro de la función... igual que usar el signo igual (=).
Cómo se comporta ese parámetro dentro de la función es exactamente lo mismo que se comportaría si simplemente asignaras una nueva variable usando el signo igual... Toma estos ejemplos simples.
var myString = 'Test string 1';
// Assignment - A link to the same place as myString
var sameString = myString;
// If I change sameString, it will not modify myString,
// it just re-assigns it to a whole new string
sameString = 'New string';
console.log(myString); // Logs 'Test string 1';
console.log(sameString); // Logs 'New string';Si pasara myString como un parámetro a una función, se comporta como si simplemente lo asignara a una nueva variable. Ahora, hagamos lo mismo, pero con una función en lugar de una simple asignación
function myFunc(sameString) {
// Reassignment... Again, it will not modify myString
sameString = 'New string';
}
var myString = 'Test string 1';
// This behaves the same as if we said sameString = myString
myFunc(myString);
console.log(myString); // Again, logs 'Test string 1';La única razón por la que puedes modificar objetos cuando los pasas a una función es porque no estás reasignando... En cambio, los objetos pueden ser cambiados o mutados.... De nuevo, funciona de la misma manera.
var myObject = { name: 'Joe'; }
// Assignment - We simply link to the same object
var sameObject = myObject;
// This time, we can mutate it. So a change to myObject affects sameObject and visa versa
myObject.name = 'Jack';
console.log(sameObject.name); // Logs 'Jack'
sameObject.name = 'Jill';
console.log(myObject.name); // Logs 'Jill'
// If we re-assign it, the link is lost
sameObject = { name: 'Howard' };
console.log(myObject.name); // Logs 'Jill'
Si yo pasara myObject como un parámetro a una función, se comporta como si simplemente lo hubiera asignado a una nueva variable. De nuevo, lo mismo con exactamente el mismo comportamiento pero con una función.
function myFunc(sameObject) {
// We mutate the object, so the myObject gets the change too... just like before.
sameObject.name = 'Jill';
// But, if we re-assign it, the link is lost
sameObject = {
name: 'Howard'
};
}
var myObject = {
name: 'Joe'
};
// This behaves the same as if we said sameObject = myObject;
myFunc(myObject);
console.log(myObject.name); // Logs 'Jill'Cada vez que pasas una variable a una función, estás «asignando» al nombre del parámetro, exactamente como si usaras el signo igual =.
Recuerda siempre que el signo igual = significa asignación. Y pasar un parámetro a una función también significa asignación. Son lo mismo y las dos variables están conectadas de exactamente la misma manera.
La única vez que modificar una variable afecta a otra variable es cuando el objeto subyacente se muta.
No tiene sentido hacer una distinción entre objetos y primitivos, porque funciona exactamente de la misma manera que si no tuvieras una función y simplemente usaras el signo igual para asignar a una nueva variable.
Respuesta #3
Piensa en esto así:
Siempre que creas un objeto en ECMAscript, este objeto se forma en un místico lugar universal de ECMAscript donde ningún hombre podrá llegar jamás. Todo lo que obtienes de regreso es una referencia a ese objeto en este lugar místico.
var obj = { };
Incluso obj es solo una referencia al objeto (que se encuentra en ese lugar especial y maravilloso) y, por lo tanto, solo puedes pasar esta referencia alrededor. Efectivamente, cualquier fragmento de código que acceda a obj modificará el objeto que está muy, muy lejos.
Respuesta #4
Los argumentos de función se pasan ya sea por valor o por compartición, pero nunca jamás por referencia en JavaScript!
Llamada por valor
Los tipos primitivos se pasan por valor:
var num = 123, str = "foo";
function f(num, str) {
num += 1;
str += "bar";
console.log("inside of f:", num, str);
}
f(num, str);
console.log("outside of f:", num, str);Reasignaciones dentro del ámbito de una función no son visibles en el ámbito circundante.
Esto también se aplica a los String, que son un tipo de datos compuesto y, sin embargo, inmutables:
var str = "foo";
function f(str) {
str[0] = "b"; // doesn't work, because strings are immutable
console.log("inside of f:", str);
}
f(str);
console.log("outside of f:", str);Llamada por compartición
Los objetos, es decir, todos los tipos que no son primitivos, se pasan por compartición. Una variable que contiene una referencia a un objeto en realidad solo contiene una copia de esta referencia. Si JavaScript siguiera una estrategia de evaluación por referencia, la variable contendría la referencia original. Esta es la diferencia crucial entre por compartición y por referencia.
¿Cuáles son las consecuencias prácticas de esta distinción?
var o = {x: "foo"}, p = {y: 123};
function f(o, p) {
o.x = "bar"; // Mutation
p = {x: 456}; // Reassignment
console.log("o inside of f:", o);
console.log("p inside of f:", p);
}
f(o, p);
console.log("o outside of f:", o);
console.log("p outside of f:", p);Mutar significa modificar ciertas propiedades de un Object existente. La copia de referencia a la que una variable está vinculada y que se refiere a este objeto permanece igual. Por lo tanto, las mutaciones son visibles en el ámbito del llamador.
Reasignar significa reemplazar la copia de referencia vinculada a una variable. Dado que es solo una copia, otras variables que contienen una copia de la misma referencia permanecen sin cambios. Por lo tanto, las reasignaciones no son visibles en el ámbito del llamador como lo serían con una estrategia de evaluación por referencia.
Más información sobre las estrategias de evaluación en ECMAScript.
Respuesta #5
Como con C, en última instancia, todo se pasa por valor. A diferencia de C, en realidad no puedes retroceder y pasar la ubicación de una variable, porque no tiene punteros, solo referencias.
Y las referencias que tiene son todas a objetos, no a variables. Hay varias maneras de lograr el mismo resultado, pero tienen que hacerse a mano, no simplemente agregando una palabra clave en el sitio de la llamada o de la declaración.
