Coder Perfect

Is JavaScript a reference-based or value-based language?

Problem

The primitive types (number, string, etc.) are passed by value, but objects are unknown because they can be both passed-by-value (if we consider that a variable holding an object is actually a reference to the object) and passed-by-reference (if we consider that a variable holding an object is actually a reference to the object) (when we consider that the variable to the object holds the object itself).

Although it doesn’t really matter in the end, I’m curious as to how the reasons passing conventions should be presented. Is there a section of the JavaScript specification that states what the semantics should be in this case?

Asked by Danail Nachev

Solution #1

In JavaScript, it’s intriguing. Consider the following scenario:

This results in the following output:

10
changed
unchanged

Instead, the thing being passed in is being passed by value. But the item that is passed by value is itself a reference. Technically, this is called call-by-sharing.

In practical terms, this means that if you change the parameter itself (as with num and obj2), that won’t affect the item that was fed into the parameter. However, if you update the parameter’s internals, it will propagate back up (as with obj1).

Answered by 22 revs, 16 users 42%

Solution #2

It’s always pass by value, but in the case of objects, the variable’s value is a reference. As a result, if you supply an object and change its members inside the method, those changes will survive outside of the function. This makes it appear as if it’s a pass-by-reference system. However, if you modify the value of the object variable, the change will not last, indicating that it is indeed pass by value.

Example:

Output:

before changeObject: foo
in changeObject: bar
after changeObject: foo

before changeMember: foo
in changeMember: bar
after changeMember: bar

Answered by Tim Goodman

Solution #3

The variable maintains a reference to the object, not the item itself. You can now give that reference to another variable, and both variables will now refer to the same object. It’s always a value pass (even when that value is a reference…).

There is no method to change the value of a parameterized variable, which would be available if JavaScript supported passing by reference.

Answered by Shog9

Solution #4

My thoughts on the subject… This is my interpretation of the situation. (If I’m wrong, please correct me.)

It’s time to toss everything you’ve learned about pass by value / reference out the window.

Because it doesn’t matter whether it’s passed by value, reference, or anything in JavaScript. It’s the difference between mutation and assignment of arguments provided into a function that matters.

OK, I’ll do my best to explain what I’m talking about. Let’s pretend you have a few items.

var object1 = {};
var object2 = {};

“Assignment” is what we’ve done… The variables “object1” and “object2” have been allocated to two separate empty objects.

Let’s pretend that we prefer object 1… As a result, we’ll “assign” a new variable.

var favoriteObject = object1;

Then, for whatever reason, we conclude that object 2 is preferable. As a result, we do some re-assignment.

favoriteObject = object2;

Neither object1 nor object2 were affected. We haven’t made any changes to the data. All we did was re-assign which object is our favorite. It’s crucial to understand that favoriteObject and object2 are both assigned to the same object. Either of those variables can be used to alter the object.

object2.name = 'Fred';
console.log(favoriteObject.name) // Logs Fred
favoriteObject.name = 'Joe';
console.log(object2.name); // Logs Joe

Let’s take a look at some primitives, such as strings.

var string1 = 'Hello world';
var string2 = 'Goodbye world';

We choose a favorite once more.

var favoriteString = string1;

‘Hello world’ is assigned to both our favoriteString and string1 variables. What if we wish to switch our favoriteString? What is going to happen???

favoriteString = 'Hello everyone';
console.log(favoriteString); // Logs 'Hello everyone'
console.log(string1); // Logs 'Hello world'

What the hell has happened? String1 could not be changed by altering favoriteString… Why?? We didn’t make any changes to our string object. All we did was “RE ASSIGN” the favoriteString variable to a new string. This essentially disconnected it from string1. In the previous example, when we renamed our object, we didn’t assign anything. (Well, not to the variable itself, … we did, however, assign the name property to a new string.) Instead, we mutated the object which keeps the connections between the 2 variables and the underlying objects. (Even if we had wanted to modify or mutate the string object itself, we couldn’t have, because strings are actually immutable in JavaScript.)

Now we’ll move on to functions and argument passing…. When you call a function and pass a parameter, you’re effectively making a “assignment” to a new variable, and it works exactly the same as if you used the equal (=) sign to do the assignment.

Take these examples.

var myString = 'hello';

// Assign to a new variable (just like when you pass to a function)
var param1 = myString;
param1 = 'world'; // Re assignment

console.log(myString); // Logs 'hello'
console.log(param1);   // Logs 'world'

Now, the same thing, but this time with a purpose.

function myFunc(param1) {
    param1 = 'world';

    console.log(param1);   // Logs 'world'
}

var myString = 'hello';
// Calls myFunc and assigns param1 to myString just like param1 = myString
myFunc(myString);

console.log(myString); // logs 'hello'

Now let’s look at some instances that use objects instead of functions… first, without the function.

var myObject = {
    firstName: 'Joe',
    lastName: 'Smith'
};

// Assign to a new variable (just like when you pass to a function)
var otherObj = myObject;

// Let's mutate our object
otherObj.firstName = 'Sue'; // I guess Joe decided to be a girl

console.log(myObject.firstName); // Logs 'Sue'
console.log(otherObj.firstName); // Logs 'Sue'

// Now, let's reassign the variable
otherObj = {
    firstName: 'Jack',
    lastName: 'Frost'
};

// Now, otherObj and myObject are assigned to 2 very different objects
// And mutating one object has no influence on the other
console.log(myObject.firstName); // Logs 'Sue'
console.log(otherObj.firstName); // Logs 'Jack';

Now, do the same thing, but with a call to a function.

function myFunc(otherObj) {

    // Let's mutate our object
    otherObj.firstName = 'Sue';
    console.log(otherObj.firstName); // Logs 'Sue'

    // Now let's re-assign
    otherObj = {
        firstName: 'Jack',
        lastName: 'Frost'
    };
    console.log(otherObj.firstName); // Logs 'Jack'

    // Again, otherObj and myObject are assigned to 2 very different objects
    // And mutating one object doesn't magically mutate the other
}

var myObject = {
    firstName: 'Joe',
    lastName: 'Smith'
};

// Calls myFunc and assigns otherObj to myObject just like otherObj = myObject
myFunc(myObject);

console.log(myObject.firstName); // Logs 'Sue', just like before

Okay, if you’ve read this far, you should now have a better knowledge of how JavaScript function calls work. It makes no difference whether anything is passed by value or by reference… What matters is the distinction between assignment and mutation.

When you give a variable to a function, you’re “assigning” it to whatever the argument variable’s name is, exactly like when you use the equal (=) sign.

Keep in mind that the equals sign (=) denotes assignment. Always remember that with JavaScript, supplying an argument to a function also means assigning it. They are identical, and the two variables are linked in the same way (which is to say, they aren’t, unless you count the fact that they are assigned to the same object).

Only when the underlying object is altered (in which case you haven’t edited the variable, but the object itself) does “changing a variable” effect a separate variable.

There is no point in making a distinction between objects and primitives, because it works the same exact way as if you didn’t have a function and just used the equal sign to assign to a new variable.

Only when the name of the variable you send into the function matches the name of the function parameter is there a problem. When this happens, you must treat the parameter as if it were a whole new private variable within the function (because it is)

function myFunc(myString) {
    // myString is private and does not affect the outer variable
    myString = 'hello';
}

var myString = 'test';
myString = myString; // Does nothing, myString is still 'test';

myFunc(myString);
console.log(myString); // Logs 'test'

Answered by Ray Perea

Solution #5

These terms/concepts were coined long before JS was developed, and therefore do not correctly reflect the semantics of javascript. Trying to apply them to JS, I believe, produces more confusion than it solves.

So don’t get too caught up in the phrase “pass by reference/value.”

Consider the following:

So, if I had to name it, I’d call it “pass-by-pointer” because, while we don’t deal with pointers in JS, the underlying engine does.

// code
var obj = {
    name: 'Fred',
    num: 1
};

// illustration
               'Fred'
              /
             /
(obj) ---- {}
             \
              \
               1
// code
obj.name = 'George';


// illustration
                 'Fred'


(obj) ---- {} ----- 'George'
             \
              \
               1
// code
obj = {};

// illustration
                 'Fred'


(obj)      {} ----- 'George'
  |          \
  |           \
 { }            1
// code
var obj = {
    text: 'Hello world!'
};

/* function parameters get their own pointer to 
 * the arguments that are passed in, just like any other variable */
someFunc(obj);


// illustration
(caller scope)        (someFunc scope)
           \             /
            \           /
             \         /
              \       /
               \     /
                 { }
                  |
                  |
                  |
            'Hello world'

Some final comments:

var a = [1,2];
var b = a;

a = [];
console.log(b); // [1,2]
// doesn't work because `b` is still pointing at the original array

Answered by geg

Post is based on https://stackoverflow.com/questions/518000/is-javascript-a-pass-by-reference-or-pass-by-value-language