In the below code we are passing an object. So, according to javascript we are passing a reference and manipulating.
var a = new Number(10);
x(a);
alert(a);
function x(n) {
n = n + 2;
}
But 10 is alerted instead of 12. Why?
In the below code we are passing an object. So, according to javascript we are passing a reference and manipulating.
var a = new Number(10);
x(a);
alert(a);
function x(n) {
n = n + 2;
}
But 10 is alerted instead of 12. Why?
n
is local to x
and first it is set to the same reference as global a
. The right hand side n + 2
is then evaluated to be a number (primitive).
The left hand side of the assignment, n
, is never evaluated, it is just an identifier there. So our local variable is now set to the primitive value of the right hand side. The value referenced by a
is never actually modified. See
var a = new Number(10);
x(a);
alert(a); // 10
function x(n) {
alert(typeof n); // object
n = n + 2;
alert(typeof n); // number
}
When you compute
n + 2
this results in a new "native number" even if n
is indeed a Number
object instance.
Assigning to n
then just changes what the local variable n
is referencing and doesn't change the Number
object instance. You can see that with
n = new Number(10);
console.log(typeof n); // ---> "object"
console.log(n + 2); // ---> 12
console.log(typeof (n+2)); // ---> "number"
n = n + 2;
console.log(typeof n); // ---> "number"
In Javascript (or Python or Lisp) there's no way to pass the "address" of a variable so that the called function mutates it. The only thing you can do is passing a setter function... for example:
function foo(setter) {
setter(42);
}
funciton bar() {
var x = 12;
foo(function(newx){x = newx;});
console.log(x); // ---> 42
}
Let me try to answer it with examples:
function modify(obj) {
// modifying the object itself
// though the object was passed as reference
// it behaves as pass by value
obj = {c:3};
}
var a = {b:2}
modify(a);
console.log(a)
// Object {b: 2}
function increment(obj) {
// modifying the value of an attribute
// working on the same reference
obj.b = obj.b + 1;
}
var a = {b:2}
increment(a);
console.log(a)
// Object {b: 3}
function augument(obj) {
// augument an attribute
// working on the same reference
obj.c = 3;
}
var a = {b:2}
augument(a);
console.log(a)
// Object {b: 2, c: 3}
Please refer the JSFiddle for working demo.
The answer is rather simple: because ECMAScript is pass-by-value and not pass-by-reference, and your code proves that. (More precisely, it is call-by-sharing, which is a specific kind of pass-by-value.)
See Is JavaScript a pass-by-reference or pass-by-value language? for some additional insight.
ECMAScript uses pass-by-value, or more precisely, a special case of pass-by-value where the value being passed is always a pointer. This special case is also sometimes known as call-by-sharing, call-by-object-sharing or call-by-object.
It's the same convention that is used by Java (for objects), C# (by default for reference types), Smalltalk, Python, Ruby and more or less every object-oriented language ever created.
Note: some types (e.g.) Number
s are actually passed directly by value and not with an intermediary pointer. However, since those are immutable, there is no observable behavioral difference between pass-by-value and call-by-object-sharing in this case, so you can greatly simplify your mental model by simply treating everything as call-by-object-sharing. Just interpret these special cases as internal compiler optimizations that you don't need to worry about.
Here's a simple example you can run to determine the argument passing convention of ECMAScript (or any other language, after you translate it):
function isEcmascriptPassByValue(foo) {
foo.push('More precisely, it is call-by-object-sharing!');
foo = 'No, ECMAScript is pass-by-reference.';
return;
}
var bar = ['Yes, of course, ECMAScript *is* pass-by-value!'];
isEcmascriptPassByValue(bar);
console.log(bar);
// Yes, of course, ECMAScript *is* pass-by-value!,
// More precisely, it is call-by-object-sharing!
If you are familiar with C#, it is a very good way to understand the differences between pass-by-value and pass-by-reference for value types and reference types, because C# supports all 4 combinations: pass-by-value for value types ("traditional pass-by-value"), pass-by-value for reference types (call-by-sharing, call-by-object, call-by-object-sharing as in ECMAScript), pass-by-reference for reference types, and pass-by-reference for value types.
(Actually, even if you don't know C#, this isn't too hard to follow.)
struct MutableCell
{
public string value;
}
class Program
{
static void IsCSharpPassByValue(string[] foo, MutableCell bar, ref string baz, ref MutableCell qux)
{
foo[0] = "More precisely, for reference types it is call-by-object-sharing, which is a special case of pass-by-value.";
foo = new string[] { "C# is not pass-by-reference." };
bar.value = "For value types, it is *not* call-by-sharing.";
bar = new MutableCell { value = "And also not pass-by-reference." };
baz = "It also supports pass-by-reference if explicitly requested.";
qux = new MutableCell { value = "Pass-by-reference is supported for value types as well." };
}
static void Main(string[] args)
{
var quux = new string[] { "Yes, of course, C# *is* pass-by-value!" };
var corge = new MutableCell { value = "For value types it is pure pass-by-value." };
var grault = "This string will vanish because of pass-by-reference.";
var garply = new MutableCell { value = "This string will vanish because of pass-by-reference." };
IsCSharpPassByValue(quux, corge, ref grault, ref garply);
Console.WriteLine(quux[0]);
// More precisely, for reference types it is call-by-object-sharing, which is a special case of pass-by-value.
Console.WriteLine(corge.value);
// For value types it is pure pass-by-value.
Console.WriteLine(grault);
// It also supports pass-by-reference if explicitly requested.
Console.WriteLine(garply.value);
// Pass-by-reference is supported for value types as well.
}
}
var a = new Number(10);
x(a);
alert(a);
function x(n) {
n = n + 2; // NOT VALID as this would essentially mean 10 = 10 + 2 since you are passing the 'value' of a and not 'a' itself
}
You need to write the following in order to get it working
var a = new Number(10);
x(a);
alert(a);
function x(n) {
a = n + 2; // reassign value of 'a' equal to the value passed into the function plus 2
}
JavaScript parameter passing works similar to that of Java. Single values are passed by value, but object attributes are passed by reference via their pointer values. A value itself will not be modified in a function, but attributes of an object would be modified.
Consider the following code:
function doThis(param1, param2) {
param1++;
if(param2 && param2.value) {
param2.value++;
}
}
var initialValue = 2;
var initialObject = {value: 2};
doThis(initialValue, initialObject);
alert(initialValue); //2
alert(initialObject.value); //3