7

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?

  • This answer might help you to understand 'pass-by-reference' in javascript http://stackoverflow.com/a/7744623/1793653 – shriidhar Dec 07 '14 at 09:00

6 Answers6

10

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
}
g.kertesz
  • 434
  • 3
  • 10
4

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
}
6502
  • 112,025
  • 15
  • 165
  • 265
  • So numbers are immutable right? If `x = new Number(5)` or `x = 5`, there is no operation such that `x` maintains the same reference but has a different value. When I do `console.log(new Number(5))` it gives `Number {[[PrimitiveValue]]: 5}`. But I'm assuming you can't mutate that `[[PrimitiveValue]]`, right? – soktinpk Dec 07 '14 at 14:16
  • @soktinpk: yes, number an strings are immutable in Javascript. You can however create an object with a `valueOf()` method that can behave like a number in math expressions but that has mutable state you can control. – 6502 Dec 07 '14 at 14:25
2

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.

Sarbbottam
  • 5,410
  • 4
  • 30
  • 41
2

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.) Numbers 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.
    }
}
Community
  • 1
  • 1
Jörg W Mittag
  • 363,080
  • 75
  • 446
  • 653
0
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
}
Anubhav
  • 7,138
  • 5
  • 21
  • 33
0

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

http://jsfiddle.net/bfm01b4x/

ryanlutgen
  • 2,951
  • 1
  • 21
  • 31
  • Java (and JS) objects are passed by name, (the a reference to the object is passed by value). Object arguments (not attributes) are not passed by reference. The terminology matters. 'attribute' in java has a specific meaning which is different to 'field' - see https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.7 – Pete Kirkham Dec 07 '14 at 18:24