ChatGPT解决这个技术问题 Extra ChatGPT

Is JavaScript a pass-by-reference or pass-by-value language?

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

Although it doesn't really matter at the end, I want to know what is the correct way to present the arguments passing conventions. Is there an excerpt from JavaScript specification, which defines what should be the semantics regarding this?

I think you accidentally flipped your definitions of passed-by-value and passed-by-reference... "passed-by-value (in case we consider that a variable holding an object is in fact a reference to the object) and passed-by-reference (when we consider that the variable to the object holds the object itself)"
Yes. Regardless of syntax, in any function call in any programming language, pass-by-reference means the data associated with the passed variable is not copied when passed to the function, and thus any modifications made by the function to the passed variable will be retained in the program after the function call terminates. Pass-by-value means the data associated with the variable is actually copied when passed to the function and any modifications made by such function to such variable will be lost when the variable goes out of scope of the function's body when the function returns.
This old question is somewhat toxic because its heavily-upvoted answer is incorrect. JavaScript is strictly pass-by-value.
@DanailNachev The terminology is regrettably confusing. The thing is, "pass by value" and "pass by reference" are terms that predate a lot of more modern programming language features. The words "value" and "reference" refer specifically to the parameter as it appears in the function call expression. JavaScript always evaluates each expression in a function call parameter list before calling the function, so the parameters are always values. The confusing part is that references to objects are common JavaScript values. That doesn't make it a "pass by reference" language, however.
@DanailNachev "pass by reference" specifically means that if you have var x=3, y=x; f(x); alert(y === x); then function f() can make the alert report false and not true. In JavaScript, that's not possible, so it's not pass-by-reference. It's good that it's possible to pass references to modifiable objects, but that's not what "pass by reference" means. As I said, it's a shame that the terminology is so confusing.

2
22 revs, 16 users 42%

It's interesting in JavaScript. Consider this example:

function changeStuff(a, b, c) { a = a * 10; b.item = "changed"; c = {item: "changed"}; } var num = 10; var obj1 = {item: "unchanged"}; var obj2 = {item: "unchanged"}; changeStuff(num, obj1, obj2); console.log(num); console.log(obj1.item); console.log(obj2.item);

This produces the output:

10
changed
unchanged

If obj1 was not a reference at all, then changing obj1.item would have no effect on the obj1 outside of the function.

If the argument was a proper reference, then everything would have changed. num would be 100, and obj2.item would read "changed". Instead, num stays 10 and obj2.item remains "unchanged".

Instead, the situation is that the item passed in is 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. But if you change the internals of the parameter, that will propagate back up (as with obj1).


This is exactly same (or at least semantically) as C#. Object has two type: Value (primitive types) and Reference.
I think this is also used in Java: reference-by-value.
the real reason is that within changeStuff, num, obj1, and obj2 are references. When you change the item property of the object referenced by obj1, you are changing the value of the item property that was originally set to "unchanged". When you assign obj2 a value of {item: "changed"} you are changing the reference to a new object (which immediately goes out of scope when the function exits). It becomes more apparent what's happening if you name the function params things like numf, obj1f, and obj2f. Then you see that the params were hiding the external var names.
@BartoNaz Not really. What you want is to pass the reference by reference, instead of passing the reference by value. But JavaScript always passes the reference by value, just like it passes everything else by value. (For comparison, C# has pass-reference-by-value behavior similar to JavaScript and Java, but lets you specify pass-reference-by-reference with the ref keyword.) Usually you would just have the function return the new object, and do the assignment at the point where you call the function. E.g., foo = GetNewFoo(); instead of GetNewFoo(foo);
Although this answer is the most popular it can be slightly confusing because it states "If it was pure pass by value". JavaScript is pure pass-by-value. But the value that is passed is a reference. This is not constrained to parameter-passing at all. You could simply copy the variable by var obj1 = { item: 'unchanged' }; var obj2 = obj1; obj2.item = 'changed'; and would observe the same effect as in your example. Therefore I personally refer the answer of Tim Goodman
a
adiga

It's always pass by value, but for objects the value of the variable is a reference. Because of this, when you pass an object and change its members, those changes persist outside of the function. This makes it look like pass by reference. But if you actually change the value of the object variable you will see that the change does not persist, proving it's really pass by value.

Example:

function changeObject(x) { x = { member: "bar" }; console.log("in changeObject: " + x.member); } function changeMember(x) { x.member = "bar"; console.log("in changeMember: " + x.member); } var x = { member: "foo" }; console.log("before changeObject: " + x.member); changeObject(x); console.log("after changeObject: " + x.member); /* change did not persist */ console.log("before changeMember: " + x.member); changeMember(x); console.log("after changeMember: " + x.member); /* change persists */

Output:

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

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

@daylight: Actually, you're wrong; if it was passed by const ref trying to do changeObject would cause an error, rather than just failing. Try assigning a new value to a const reference in C++ and the compiler rejects it. In user terms, that's the difference between pass by value and pass by const reference.
@daylight: It's not constant ref. In changeObject, I've changed x to contain a reference to the new object. x = {member:"bar"}; is equivalent to x = new Object(); x.member = "bar"; What I'm saying is also true of C#, by the way.
@daylight: For C#, you can see this from outside the function, if you use the ref keyword you can pass the reference by reference (instead of the default of passing the reference by value), and then the change to point to a new Object() will persist.
@adityamenon It's hard to answer "why", but I would note that the designers of Java and C# made a similar choice; this isn't just some JavaScript weirdness. Really, it's very consistently pass-by-value, the thing that makes it confusing for people is that a value can be a reference. It's not much different than passing a pointer around (by value) in C++ and then dereferencing it to set the members. No one would be surprised that that change persists. But because these languages abstract away the pointer and silently do the dereferencing for you, people get confused.
In other words, the confusing thing here isn't pass-by-value/pass-by-reference. Everything is pass-by-value, full stop. The confusing thing is that you cannot pass an object, nor can you store an object in a variable. Every time you think you're doing that, you're actually passing or storing a reference to that object. But when you go to access its members, there's a silent dereferencing that happens, that perpetuates the fiction that your variable held the actual object.
P
Peter Mortensen

The variable doesn't "hold" the object; it holds a reference. You can assign that reference to another variable, and now both reference the same object. It's always pass by value (even when that value is a reference...).

There's no way to alter the value held by a variable passed as a parameter, which would be possible if JavaScript supported passing by reference.


This confuses me just a bit. Isn't passing a reference pass-by-reference?
The author means that by passing a reference, you're passing a reference value (another way to think of it is passing the value of the memory address). So that's why if you redeclare the object, the original doesn't change, because you're creating a new object at a different memory location. If you change a property, the original object changes because you changed it at the original memory location (that was not reassigned).
The phrase "passing a reference by value" seems unnecessarily confusing and redundant. When passing a reference of course some value must be passed. While technically true, it is likely the default assumption of most people that anything is passed by value unless otherwise specified. So of course a reference is passed by value unless it itself is passed by reference (kind of like a pointer to a pointer in C), but in this case Javascript doesn't even support that so I don't think it helps make the concept any clearer
The point of confusion with JavaScript is that it provides no choice in the matter, @geg: complex types will always be handled indirectly, simple types always directly. There's no way to get a reference to an integer, nor prevent passing a reference to a tuple. This ... Is just going to be awkward sometimes.
to put simply after a decade, the reference is copied by value.
H
Harry B

My two cents... This is the way I understand it. (Feel free to correct me if I'm wrong)

It's time to throw out everything you know about pass by value / reference.

Because in JavaScript, it doesn't matter whether it's passed by value or by reference or whatever. What matters is mutation vs assignment of the parameters passed into a function.

OK, let me do my best to explain what I mean. Let's say you have a few objects.

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

What we have done is "assignment"... We've assigned 2 separate empty objects to the variables "object1" and "object2".

Now, let's say that we like object1 better... So, we "assign" a new variable.

var favoriteObject = object1;

Next, for whatever reason, we decide that we like object 2 better. So, we do a little re-assignment.

favoriteObject = object2;

Nothing happened to object1 or to object2. We haven't changed any data at all. All we did was re-assign what our favorite object is. It is important to know that object2 and favoriteObject are both assigned to the same object. We can change that object via either of those variables.

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

OK, now let's look at primitives like strings for example

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

Again, we pick a favorite.

var favoriteString = string1;

Both our favoriteString and string1 variables are assigned to 'Hello world'. Now, what if we want to change our favoriteString??? What will happen???

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

Uh oh.... What has happened. We couldn't change string1 by changing favoriteString... Why?? Because we didn't change 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, on to functions and passing parameters.... When you call a function, and pass a parameter, what you are essentially doing is an "assignment" to a new variable, and it works exactly the same as if you assigned using the equal (=) sign.

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 with a function

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'

OK, now let’s give a few examples using objects instead... 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, the same thing, but with a function call

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

OK, if you read through this entire post, perhaps you now have a better understanding of how function calls work in JavaScript. It doesn't matter whether something is passed by reference or by value... What matters is assignment vs mutation.

Every time you pass a variable to a function, you are "Assigning" to whatever the name of the parameter variable is, just like if you used the equal (=) sign.

Always remember that the equals sign (=) means assignment. Always remember that passing a parameter to a function in JavaScript also means assignment. They are the same and the 2 variables are connected in exactly the same way (which is to say they aren't, unless you count that they are assigned to the same object).

The only time that "modifying a variable" affects a different variable is when the underlying object is mutated (in which case you haven't modified the variable, but the object itself.

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.

The only gotcha is when the name of the variable you pass into the function is the same as the name of the function parameter. When this happens, you have to treat the parameter inside the function as if it was a whole new variable private to 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'

For any C programmers, think of char*. foo(char *a){a="hello";} does nothing, but if you do foo(char *a){a[0]='h';a[1]='i';a[2]=0;} it is changed outside because a is a memory location passed by value that references a string (char array). Passing structs (similar to js objects) by value in C is allowed, but not recommended. JavaScript simply enforces these best practices and hides the unnecessary and usually undesired cruft... and it sure makes for easier reading.
This is correct - the terms pass-by-value and pass-by-reference have meanings in programming language design, and those meanings have nothing at all to do with object mutation. It's all about how function parameters work.
Now that I understand that obj1 = obj2 means that both obj1 and obj2 are now pointing to the same reference location, and if I modify the internals of obj2, referencing obj1 will expose the same internals. How do I copy an object such that when I do source = { "id":"1"}; copy = source /*this is wrong*/; copy.id="2" that source is still {"id":"1"}?
I posted another answer with traditional definitions to hopefully reduce confusion. Traditional definitions of "pass-by-value" and "pass-by-reference" were defined back in the day of memory pointers before automatic dereferencing. It was perfectly well understood that an object variable's value was actually the memory pointer location, not the object. Although your discussion of assignment vs mutation is perhaps useful, it is not necessary to throw out the traditional terms nor their definitions. Mutation, assignment, pass-by-value, pass-by-reference, etc. must not contradict each other.
does "Number" is a "immutable" too?
r
ruleboy21

These phrases/concepts were originally defined long before JS was created and they don't accurately describe the semantics for javascript. I think trying to apply them to JS causes more confusion than not.

So don't get hung up on "pass by reference/value".

Consider the following:

Variables are pointers to values. Reassigning a variable merely points that pointer at a new value. Reassigning a variable will never affect other variables that were pointing at that same object because each variable has its own pointer.

So if I had to give it a name I'd say "pass-by-pointer" -- we don't deal with pointers in JS but 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:

The phrases "pass by value/reference" are only used to describe the behavior of a language, not necessarily the actual underlying implementation. As a result of this abstraction, critical details that are essential for a decent explanation are lost, which inevitably leads to the current situation where a single term doesn't adequately describe the actual behavior without additional info.

It's tempting to think that primitives are enforced by special rules while objects are not, but primitives are simply the end of the pointer chain.

As a final example, consider why a common attempt to clear an array doesn't work as expected.

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


Follow-up questions for extra credit ;) How does garbage collection work? If I cycle a variable through a million {'George', 1} values, but only use one of them at a time, then how are the others managed? And what happens when I assign a variable to the value of another variable? Am I then pointing to a pointer, or pointing to the pointee of the right operand? Does var myExistingVar = {"blah", 42}; var obj = myExistingVar; result in obj pointing to {"blah", 42}, or to myExistingVar?
@MichaelHoffmann These deserve their own SO questions and are probably already answered better than I can manage. That being said, 1) I ran a memory profile in the browser dev tools for a loop function such as the one you described and saw spikes in memory usage throughout the looping process. This would seem to indicate that new identical objects are indeed being created in each iteration of the loop. When the spikes suddenly fall, the garbage collector just cleaned up a group of these unused objects.
@MichaelHoffmann 2) Regarding something like var a = b, javascript does not provide a mechanism for using pointers and so a variable can never point to a pointer (as you can in C), although the underlying javascript engine undoubtedly uses them. So...var a = b will point a "to the pointee of the right operand"
There is no need to forget about "pass by reference/value"! These terms have historical meanings that describe exactly what you attempt to describe. If we throw out the historical terms and definitions and become too lazy to learn what they originally meant, then we lose the ability to communicate effectively between generations. There would be no good way discuss the differences between different languages and systems. Instead, new programmers need to learn and understand the traditional terms and why and were they came from. Otherwise, we collectively lose knowledge and understanding.
Your illustration was really helpful - thanks.
P
Peter Mortensen

An object outside a function is passed into a function by giving a reference to the outside object.

When you use that reference to manipulate its object, the object outside is thus affected. However, if inside the function you decided to point the reference to something else, you did not affect the object outside at all, because all you did was re-direct the reference to something else.


P
Phil Mander

Think of it like this: It's always pass by value. However, the value of an object is not the object itself, but a reference to that object.

Here is an example, passing a number (a primitive type)

function changePrimitive(val) {
    // At this point there are two '10's in memory.
    // Changing one won't affect the other
    val = val * 10;
}
var x = 10;
changePrimitive(x);
// x === 10

Repeating this with an object yields different results:

function changeObject(obj) {
    // At this point there are two references (x and obj) in memory,
    // but these both point to the same object.
    // changing the object will change the underlying object that
    // x and obj both hold a reference to.
    obj.val = obj.val * 10;
}
var x = { val: 10 };
changeObject(x);
// x === { val: 100 }

One more example:

function changeObject(obj) {
    // Again there are two references (x and obj) in memory,
    // these both point to the same object.
    // now we create a completely new object and assign it.
    // obj's reference now points to the new object.
    // x's reference doesn't change.
    obj = { val: 100 };
}
var x = { val: 10 };
changeObject(x);
// x === { val: 10}

C
Community

A very detailed explanation about copying, passing and comparing by value and by reference is in this chapter of the "JavaScript: The Definitive Guide" book.

Before we leave the topic of manipulating objects and arrays by reference, we need to clear up a point of nomenclature. The phrase "pass by reference" can have several meanings. To some readers, the phrase refers to a function invocation technique that allows a function to assign new values to its arguments and to have those modified values visible outside the function. This is not the way the term is used in this book. Here, we mean simply that a reference to an object or array -- not the object itself -- is passed to a function. A function can use the reference to modify properties of the object or elements of the array. But if the function overwrites the reference with a reference to a new object or array, that modification is not visible outside of the function. Readers familiar with the other meaning of this term may prefer to say that objects and arrays are passed by value, but the value that is passed is actually a reference rather than the object itself.


Wow, this is incredibly confusing. Who in their right mind would define a well-established term to mean the exact opposite and then use it that way? No wonder so many answers here on this question are so confused.
This answer is the key to understanding what other people write on this subject. Most people don't realise there are two definitions of the term 'pass by reference', so when you read their explanation you have to make an educated guess as to which meaning of the term they are using. The book chapter linked to in this answer is also useful for deeper understanding of the topic.
n
namgold

JavaScript is always pass-by-value; everything is of value type.

Objects are values, and member functions of objects are values themselves (remember that functions are first-class objects in JavaScript). Also, regarding the concept that everything in JavaScript is an object; this is wrong. Strings, symbols, numbers, booleans, nulls, and undefineds are primitives.

On occasion they can leverage some member functions and properties inherited from their base prototypes, but this is only for convenience. It does not mean that they are objects themselves. Try the following for reference:

x = "test"; console.log(x.foo); x.foo = 12; console.log(x.foo);

In both console.log you will find the value to be undefined.


-1, it is not always pass by value. From MDC: "If you pass an object (i.e. a non-primitive value, such as Array or a user-defined object) as a parameter, a reference to the object is passed to the function."
@Nick: It is always pass by value. Period. A reference to the object is passed by value to the function. That's not passing by reference. "Pass by reference" could almost be thought of as passing the variable itself, rather than its value; any changes the function makes to the argument (including replacing it with a different object entirely!) would be reflected in the caller. That last bit isn't possible in JS, because JS does not pass by reference -- it passes references by value. The distinction is subtle, but rather important to understanding its limitations.
For future stackers... About this reference of yours: x = "teste"; x.foo = 12; etc. Just because a property isn't persistent it doesn't mean it's not an object. As MDN says: In JavaScript, almost everything is an object. All primitive types except null and undefined are treated as objects. They can be assigned properties (assigned properties of some types are not persistent), and they have all characteristics of objects. link
MDN is a user-edited wiki and it is wrong there. The normative reference is ECMA-262. See S. 8 "The Reference Specification Type", which explains how references are resolved, and also 8.12.5 "[[Put]]", which is used to explain AssignmentExpression to a Reference, and, for object coersion 9.9 ToObject. For primitive values, Michael already explained what ToObject does, as in the specification. But see also s. 4.3.2 primitive value.
@WonderLand: No, he's not. People who've never been able to pass by reference may never understand the differences between passing by reference and passing a reference by value. But they're there, and they matter. I don't care to misinform people just cause it sounds easier.
z
zangw

In JavaScript, the type of the value solely controls whether that value will be assigned by value-copy or by reference-copy.

Primitive values are always assigned/passed by value-copy:

null

undefined

string

number

boolean

symbol in ES6

Compound values are always assigned/passed by reference-copy

objects

arrays

function

For example

var a = 2;
var b = a; // `b` is always a copy of the value in `a`
b++;
a; // 2
b; // 3

var c = [1,2,3];
var d = c; // `d` is a reference to the shared `[1,2,3]` value
d.push( 4 );
c; // [1,2,3,4]
d; // [1,2,3,4]

In the above snippet, because 2 is a scalar primitive, a holds one initial copy of that value, and b is assigned another copy of the value. When changing b, you are in no way changing the value in a.

But both c and d are separate references to the same shared value [1,2,3], which is a compound value. It's important to note that neither c nor d more "owns" the [1,2,3] value -- both are just equal peer references to the value. So, when using either reference to modify (.push(4)) the actual shared array value itself, it's affecting just the one shared value, and both references will reference the newly modified value [1,2,3,4].

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

// later
b = [4,5,6];
a; // [1,2,3]
b; // [4,5,6]

When we make the assignment b = [4,5,6], we are doing absolutely nothing to affect where a is still referencing ([1,2,3]). To do that, b would have to be a pointer to a rather than a reference to the array -- but no such capability exists in JS!

function foo(x) {
    x.push( 4 );
    x; // [1,2,3,4]

    // later
    x = [4,5,6];
    x.push( 7 );
    x; // [4,5,6,7]
}

var a = [1,2,3];

foo( a );

a; // [1,2,3,4]  not  [4,5,6,7]

When we pass in the argument a, it assigns a copy of the a reference to x. x and a are separate references pointing at the same [1,2,3] value. Now, inside the function, we can use that reference to mutate the value itself (push(4)). But when we make the assignment x = [4,5,6], this is in no way affecting where the initial reference a is pointing -- still points at the (now modified) [1,2,3,4] value.

To effectively pass a compound value (like an array) by value-copy, you need to manually make a copy of it, so that the reference passed doesn't still point to the original. For example:

foo( a.slice() );

Compound value (object, array, etc) that can be passed by reference-copy

function foo(wrapper) {
    wrapper.a = 42;
}

var obj = {
    a: 2
};

foo( obj );

obj.a; // 42

Here, obj acts as a wrapper for the scalar primitive property a. When passed to foo(..), a copy of the obj reference is passed in and set to the wrapperparameter. We now can use the wrapper reference to access the shared object, and update its property. After the function finishes, obj.a will see the updated value 42.

Source


You first state "Compound values are always assigned/passed by reference-copy", and then you state "assigns a copy of the a reference to x". In the case of what you call a "compound value", the actual variable value IS the reference (i.e. the memory pointer). Just as you explained, the reference is copied... so the variables value is copied, again emphasizing that the REFERENCE IS THE VALUE. That means JavaScript is pass-by-value for all types. Pass-by-value means passing a copy of the variables value. It does not matter that the value is a references to an object / array.
You introduce new terminology (value-copy/reference-copy) and that just makes things more complex. There are just copies, period. If you pass a primitive you passed a copy of the actual primitive data, if you pass an object, you passed a copy of the object's memory location. That's all you need to say. Anything more just further confuses people.
T
TechDogLover OR kiaNasirzadeh

well, it's about 'performance' and 'speed' and in the simple word 'memory management' in a programming language.

in javascript we can put values in two layer: type1-objects and type2-all other types of value such as string & boolean & etc

if you imagine memory as below squares which in every one of them just one type2-value can be saved:

https://i.stack.imgur.com/wFWOsm.png

every type2-value (green) is a single square while a type1-value (blue) is a group of them:

https://i.stack.imgur.com/vwu2vm.png

the point is that if you want to indicate a type2-value, the address is plain but if you want to do the same thing for type1-value that's not easy at all! :

https://i.stack.imgur.com/ZISOHm.png

and in a more complicated story:

https://i.stack.imgur.com/GIEvCm.png

https://i.stack.imgur.com/orhtHm.png

while the green arrow here is a typical variable, the purple one is an object variable, so because the green arrow(typical variable) has just one task (and that is indicating a typical value) we don't need to separate it's value from it so we move the green arrow with the value of that wherever it goes and in all assignments, functions and so on ...

but we cant do the same thing with the purple arrow, we may want to move 'john' cell here or many other things..., so the purple arrow will stick to its place and just typical arrows that were assigned to it will move ...

a very confusing situation is where you can't realize how your referenced variable changes, let's take a look at a very good example:

let arr = [1, 2, 3, 4, 5]; //arr is an object now and a purple arrow is indicating it
let obj2 = arr; // now, obj2 is another purple arrow that is indicating the value of arr obj
let obj3 = ['a', 'b', 'c'];
obj2.push(6); // first pic below - making a new hand for the blue circle to point the 6
//obj2 = [1, 2, 3, 4, 5, 6]
//arr = [1, 2, 3, 4, 5, 6]
//we changed the blue circle object value (type1-value) and due to arr and obj2 are indicating that so both of them changed
obj2 = obj3; //next pic below - changing the direction of obj2 array from blue circle to orange circle so obj2 is no more [1,2,3,4,5,6] and it's no more about changing anything in it but we completely changed its direction and now obj2 is pointing to obj3
//obj2 = ['a', 'b', 'c'];
//obj3 = ['a', 'b', 'c'];

https://i.stack.imgur.com/fELHnm.png


P
Peter Mortensen

This is little more explanation for pass by value and pass by reference (JavaScript). In this concept, they are talking about passing the variable by reference and passing the variable by reference.

Pass by value (primitive type)

var a = 3;
var b = a;

console.log(a); // a = 3
console.log(b); // b = 3

a=4;
console.log(a); // a = 4
console.log(b); // b = 3

applies to all primitive type in JavaScript (string, number, Boolean, undefined, and null).

a is allocated a memory (say 0x001) and b creates a copy of the value in memory (say 0x002).

So changing the value of a variable doesn't affect the other, as they both reside in two different locations.

Pass by reference (objects)

var c = { "name" : "john" };
var d = c;

console.log(c); // { "name" : "john" }
console.log(d); // { "name" : "john" }

c.name = "doe";

console.log(c); // { "name" : "doe" }
console.log(d); // { "name" : "doe" }

The JavaScript engine assigns the object to the variable c, and it points to some memory, say (0x012).

When d=c, in this step d points to the same location (0x012).

Changing the value of any changes value for both the variable.

Functions are objects

Special case, pass by reference (objects)

c = {"name" : "jane"};
console.log(c); // { "name" : "jane" }
console.log(d); // { "name" : "doe" }

The equal(=) operator sets up new memory space or address


In your so-called special case, it is not the assignment operator that causes the allocation of memory space, it is the object literal itself. The curley bracket notation causes the creation of a new object. The property c is set to a copy of the new object's reference.
This is not pass by reference. This is pass by value, who's value happens to be a reference.
C
C Perkins

Semantics!! Setting concrete definitions will necessarily make some answers and comments incompatible since they are not describing the same thing even when using the same words and phrases, but it is critical to get past the confusion (especially for new programmers).

First of all, there are multiple levels of abstraction that not everyone seems to grasp. Newer programmers who have learned on 4th or 5th generation languages may have difficulty wrapping their mind around concepts familiar to assembly or C programmers not phased by pointers to pointers to pointers. Pass-by-reference does not simply mean the ability to change a referenced object using a function parameter variable.

Variable: Combined concept of a symbol which references a value at a particular location in memory. This term is usually too loaded to be used alone in discussing details.

Symbol: Text string used to refer to variable (i.e. variable's name).

Value: Particular bits stored in memory and referenced using variable's symbol.

Memory location: Where a variable's value is stored. (The location itself is represented by a number separate from the value stored at the location.)

Function parameter: Variable declared in a function definition, used for referencing variables passed to the function.

Function argument: Variable outside the function which is passed to the function by the caller.

Object variable: Variable whose basic underlying value is not the "object" itself, rather its value is a pointer (memory location value) to another location in memory where the object's actual data is stored. In most higher-generation languages, the "pointer" aspect is effectively hidden by automatic de-referencing in various contexts.

Primitive variable: Variable whose value IS the actual value. Even this concept can be complicated by auto-boxing and object-like contexts of various languages, but the general ideas is that the variable's value IS the actual value represented by the variable's symbol rather than a pointer to another memory location.

Function arguments and parameters are not the same thing. Also, a variable's value is not the variable's object (as already pointed out by various people, but apparently ignored). These distinctions are critical to proper understanding.

Pass-by-value or Call-by-sharing (for objects): The function argument's value is COPIED to another memory location which is referenced by the function's parameter symbol (regardless of whether it's on the stack or heap). In other words, the function parameter received a copy of the passed argument's value... AND (critical) the argument's value IS NEVER UPDATED / ALTERED / CHANGED by the calling function. Remember, an object variable's value is NOT the object itself, rather it is the pointer to the object, so passing an object variable by value copies the pointer to the function parameter variable. The function parameter's value points to the exact same object in memory. The object data itself can be altered directly via the function parameter, BUT the function argument's value IS NEVER UPDATED, so it will continue to point to the same object throughout and even after the function call (even if its object's data was altered or if the function parameter is assigned a different object altogether). It is incorrect to conclude that the function argument was passed by reference just because the referenced object is updatable via the function parameter variable.

Call / Pass-by-reference: The function argument's value can/will be updated directly by the corresponding function parameter. If it helps, the function parameter becomes an effective "alias" for the argument--they effectively refer to the same value at the same memory location. If a function argument is an object variable, the ability to change the object's data is no different than the pass-by-value case since the function parameter will still point to the same object as the argument. But in the object variable case, if the function parameter is set to a completely different object, then the argument will likewise also point to the different object--this does not happen in the pass-by-value case.

JavaScript does not pass by reference. If you read closely, you will realize that all contrary opinions misunderstand what is meant by pass-by-value and they falsely conclude that the ability to update an object's data via the function parameter is synonymous to "pass-by-value".

Object clone/copy: A new object is created and the original object's data is copied. This can be a deep copy or shallow copy, but the point is that a new object is created. Creating a copy of an object is a separate concept from pass-by-value. Some languages distinguish between class object and structs (or the like), and may have different behavior for passing variables of the different types. But JavaScript does not do anything like this automatically when passing object variables. But the absence of automatic object cloning does not translate to pass-by-reference.


x
xameeramir

sharing what I know of references in JavaScript

In JavaScript, when assigning an object to a variable, the value assigned to the variable is a reference to the object:

var a = { a: 1, b: 2, c: 3 }; var b = a; // b.c is referencing to a.c value console.log(b.c) // Output: 3 // Changing value of b.c b.c = 4 // Also changes the value of a.c console.log(a.c) // Output: 4


This is an overly simplistic answer which says nothing that earlier answers haven't explained better. I'm confused about why you call out arrays as a special case.
"objects are stored as references" is misleading. What I think you mean is that when assigning an object to a variable, the value assigned to the variable is a reference to the object.
this does not address the problem of updating an object inside of a function that does not update the object outside of the function. That is the whole picture where it seems to work as values instead of reference. Hence -1
@amaster Thanks for pointing that out! Can you suggest an edit, please?
Haha, I tried... my suggested edit changed too much amd was not allowed
g
georgeawg

JavaScript passes primitive types by value and object types by reference

Now, people like to bicker endlessly about whether "pass by reference" is the correct way to describe what Java et al. actually do. The point is this: Passing an object does not copy the object. An object passed to a function can have its members modified by the function. A primitive value passed to a function cannot be modified by the function. A copy is made. In my book that's called passing by reference.

Brian Bi - Which programming languages are pass by reference?

Update

Here is a rebuttal to this:

There is no "pass by reference" available in JavaScript.


@Amy Because that's describing pass by value, not pass by reference. This answer is a good one that shows the difference: stackoverflow.com/a/3638034/3307720
@nasch I understand the difference. #1 and #2 are describing pass-by-ref semantics. #3 is describing pass-by-value semantics.
@Amy 1, 2, and 3 are all consistent with pass by value. To have pass by reference you would also need 4: assigning the reference to a new value inside the function (with the = operator) also reassigns the reference outside the function. This is not the case with Javascript, making it exclusively pass by value. When passing an object, you pass a pointer to the object, and you pass that pointer by value.
That isn't generally what is meant by "pass-by-reference". You've satisfied my query, and I disagree with you. Thanks.
"In my book that's called passing by reference." – In every single compiler book, interpreter book, programming language theory book, and computer science book ever written, it is not.
P
Peter Mortensen

Observation: If there isn't any way for an observer to examine the underlying memory of the engine, there is no way to determine whether an immutable value gets copied or a reference gets passed.

JavaScript is more or less agnostic to the underlying memory model. There is no such thing as a reference². JavaScript has values. Two variables can hold the same value (or more accurate: two environment records can bind the same value). The only type of values that can be mutated are objects through their abstract [[Get]] and [[Set]] operations. If you forget about computers and memory, this is all you need to describe JavaScript's behaviour, and it allows you to understand the specification.

 let a = { prop: 1 };
 let b = a; // a and b hold the same value
 a.prop = "test"; // The object gets mutated, can be observed through both a and b
 b = { prop: 2 }; // b holds now a different value

Now you might ask yourself how two variables can hold the same value on a computer. You might then look into the source code of a JavaScript engine and you'll most likely find something which a programmer of the language the engine was written in would call a reference.

So in fact you can say that JavaScript is "pass by value", whereas the value can be shared, and you can say that JavaScript is "pass by reference", which might be a useful logical abstraction for programmers from low level languages, or you might call the behaviour "call by sharing".

As there is no such thing as a reference in JavaScript, all of these are neither wrong nor on point. Therefore I don't think the answer is particularly useful to search for.

² The term Reference in the specification is not a reference in the traditional sense. It is a container for an object and the name of a property, and it is an intermediate value (e.g., a.b evaluates to Reference { value = a, name = "b" }). The term reference also sometimes appears in the specification in unrelated sections.


G
Gianluca Ghettini

Everything is passed by value.

Basic types are passed by value (i.e. a new copy of the actual variable value is passed to the function).

Complex types (objects) are passed as "pointer to the object". So the actual stuff you are passing is a pointer which is passed by value (it's an address, a numerical value like any other). Obviously if you try to modify a property of the object inside the function, the modification will be reflected even outside of such function. That's because you are accessing the property via the pointer which points to the unique copy of the property.

The confusion here has arises over "passing a pointer by value" and "passing an object by reference".


d
dpp

My simple way to understand this...

When calling a function, you are passing the content (reference or value) of the argument variables, not the the variables themselves. var var1 = 13; var var2 = { prop: 2 }; //13 and var2's content (reference) are being passed here foo(var1, var2);

Inside the function, parameter variables, inVar1 and inVar2, receive the contents being passed. function foo(inVar1, inVar2){ //changing contents of inVar1 and inVar2 won't affect variables outside inVar1 = 20; inVar2 = { prop: 7 }; }

Since inVar2 received the reference of { prop: 2 }, you can change the value of the object's property. function foo(inVar1, inVar2){ inVar2.prop = 7; }


You clearly articulated my understanding. The main thing to note is we are passing content (reference or value)
m
miguelr

The MDN docs explain it clearly, without being too verbose:

The parameters of a function call are the function's arguments. Arguments are passed to functions by value. If the function changes the value of an argument, this change is not reflected globally or in the calling function. However, object references are values, too, and they are special: if the function changes the referred object's properties, that change is visible outside the function, (...)

Source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions#Description


J
John Sonderson

Passing arguments to a function in JavaScript is analogous to passing parameters by pointer value in C:

/*
The following C program demonstrates how arguments
to JavaScript functions are passed in a way analogous
to pass-by-pointer-value in C. The original JavaScript
test case by @Shog9 follows with the translation of
the code into C. This should make things clear to
those transitioning from C to JavaScript.

function changeStuff(num, obj1, obj2)
{
    num = num * 10;
    obj1.item = "changed";
    obj2 = {item: "changed"};
}

var num = 10;
var obj1 = {item: "unchanged"};
var obj2 = {item: "unchanged"};
changeStuff(num, obj1, obj2);
console.log(num);
console.log(obj1.item);    
console.log(obj2.item);

This produces the output:

10
changed
unchanged
*/

#include <stdio.h>
#include <stdlib.h>

struct obj {
    char *item;
};

void changeStuff(int *num, struct obj *obj1, struct obj *obj2)
{
    // make pointer point to a new memory location
    // holding the new integer value
    int *old_num = num;
    num = malloc(sizeof(int));
    *num = *old_num * 10;
    // make property of structure pointed to by pointer
    // point to the new value
    obj1->item = "changed";
    // make pointer point to a new memory location
    // holding the new structure value
    obj2 = malloc(sizeof(struct obj));
    obj2->item = "changed";
    free(num); // end of scope
    free(obj2); // end of scope
}

int num = 10;
struct obj obj1 = { "unchanged" };
struct obj obj2 = { "unchanged" };

int main()
{
    // pass pointers by value: the pointers
    // will be copied into the argument list
    // of the called function and the copied
    // pointers will point to the same values
    // as the original pointers
    changeStuff(&num, &obj1, &obj2);
    printf("%d\n", num);
    puts(obj1.item);
    puts(obj2.item);
    return 0;
}

I don't think this is the case in JavaScript: ```javascript var num = 5;
@DanailNachev: While that may be technically true, the difference is only observable for mutable objects which ECMAScript primitives aren't.
C
Community

For programming language lawyers, I've went through the following sections of ECMAScript 5.1 (which is easier to read than the latest edition), and go as far as asking it on the ECMAScript mailing list.

TL;DR: Everythings're passed by value, but properties of Objects are references, and the definition of Object is creepily lacking in the standard.

Construction of Argument Lists

Section 11.2.4 "Argument Lists" says the following on producing a argument list consisting of only 1 argument:

The production ArgumentList : AssignmentExpression is evaluated as follows: Let ref be the result of evaluating AssignmentExpression. Let arg be GetValue(ref). Return a List whose sole item is arg.

The section also enumerate cases where argument list has 0 or >1 arguments.

Thus, everything's are passed by reference.

Access of Object Properties

Section 11.2.1 "Property Accessors"

The production MemberExpression : MemberExpression [ Expression ] is evaluated as follows: Let baseReference be the result of evaluating MemberExpression. Let baseValue be GetValue(baseReference). Let propertyNameReference be the result of evaluating Expression. Let propertyNameValue be GetValue(propertyNameReference). Call CheckObjectCoercible(baseValue). Let propertyNameString be ToString(propertyNameValue). If the syntactic production that is being evaluated is contained in strict mode code, let strict be true, else let strict be false. Return a value of type Reference whose base value is baseValue and whose referenced name is propertyNameString, and whose strict mode flag is strict.

Thus, properties of Objects are always available as reference.

On Reference

It is described in section 8.7 "The Reference Specification Type", that references are not real types in the language - they're only used to describe the behavior of the delete, the typeof, and the assignment operators.

Definition of "Object"

It is defined in 5.1 edition that "An Object is a collection of properties". Therefore, we can infer, that the value of the object is the collection, but as to what is the value of the collection is poorly defined in the spec, and requires a bit of effort to understand.


It never ceases to amaze me how many people get confused by the distinctions among arguments passed by value, arguments passed by reference, operations on whole objects, and operations on their properties. In 1979, I didn't get my degree in computer science, electing instead to add 15 hours or so of CS electives to my MBA program. Nevertheless, it soon became clear to me that my grasp of these concepts was at least as good as that held by any of my colleagues who had degrees in computer science or mathematics. Study Assembler, and it will become quite clear.
Reference in the specification has nothing to do with the behaviour in question. It's an intermediate construct to explain why a.b = 1 is able to know which object (a) the property (b) gets set on (cause a.b evaluates to the Reference { a, "b" }).
l
lid

The most succinct explanation I found was in the AirBNB style guide:

Primitives: When you access a primitive type you work directly on its value string number boolean null undefined

string

number

boolean

null

undefined

E.g.:

var foo = 1,
    bar = foo;

bar = 9;

console.log(foo, bar); // => 1, 9

Complex: When you access a complex type you work on a reference to its value object array function

object

array

function

E.g.:

var foo = [1, 2],
    bar = foo;

bar[0] = 9;

console.log(foo[0], bar[0]); // => 9, 9

I.e. effectively primitive types are passed by value, and complex types are passed by reference.


No, everything is always passed by value. It just depends on what you are passing (a value or a reference). See this.
s
steviesh

I've read through these answers multiple times, but didn't REALLY get it until I learned about the technical definition of "Call by sharing" as termed by Barbara Liskov

The semantics of call by sharing differ from call by reference in that assignments to function arguments within the function aren't visible to the caller (unlike by reference semantics)[citation needed], so e.g. if a variable was passed, it is not possible to simulate an assignment on that variable in the caller's scope. However, since the function has access to the same object as the caller (no copy is made), mutations to those objects, if the objects are mutable, within the function are visible to the caller, which may appear to differ from call by value semantics. Mutations of a mutable object within the function are visible to the caller because the object is not copied or cloned — it is shared.

That is, parameter references are alterable if you go and access the parameter value itself. On the other hand, assignment to a parameter will disappear after evaluation, and is non-accessible to the function caller.


No, whether an object is mutable or not isn't really the issue. Everything is always passed by value. It just depends on what you are passing (a value or a reference). See this.
What she's describing is passing a reference BY-VALUE. There is no reason to introduce new terminology.
P
Peter Mortensen

In a low-level language, if you want to pass a variable by reference, you have to use a specific syntax in the creation of the function:

int myAge = 14;
increaseAgeByRef(myAge);
function increaseAgeByRef(int &age) {
  *age = *age + 1;
}

The &age is a reference to myAge, but if you want the value you have to convert the reference, using *age.

JavaScript is a high level language that does this conversion for you.

So, although objects are passed by reference, the language converts the reference parameter to the value. You don't need to use &, on the function definition, to pass it by reference, neither *, on the function body, to convert the reference to the value, JavaScript does it for you.

That's why when you try to change an object inside a function, by replacing it's value (i.e. age = {value:5}), the change doesn't persist, but if you change it's properties (i.e. age.value = 5), it does.

Learn more


No, it is not necessary (or allowed) to dereference references in C++. Either it is pointers that are dereferenced or references that aren't.
This answer is factually wrong. JavaScript does no such conversion. It is impossible to pass by reference in JavaScript. The entire point of "pass by reference" is for a function to be able to change the value of myAge. You can't do that in JavaScript. You can change properties an on object myAge references but you can't not change myAge the variable itself. That is what "pass by reference' means, to be able to change the value of a variable outside the function.
T
TomoMiha

If you want (normal) function parameter behavior like in other languages (passing copy of a value) then just clone the object before passing into a function:

function run()
{
    var test = [];
    test.push(1);

    console.log('before: '+test); // 1

    changeVariable(_.clone(test)); // (Note: I am using lodash _.clone() function)
 
    console.log('after: '+test); // 1 
}


function changeVariable(test2) {
  var test1 = test2;
  test1.push(2); 
  console.log('inside func:', test1);  // inside func: [1,2]
}   


run();    

J
Jack

I have found the extend method of the Underscore.js library very useful when I want to pass in an object as a parameter which may either be modified or replaced entirely.

function replaceOrModify(aObj) {
  if (modify) {

    aObj.setNewValue('foo');

  } else {

   var newObj = new MyObject();
   // _.extend(destination, *sources) 
   _.extend(newObj, aObj);
  }
}

l
lyslim

I would say it is pass-by-copy -

Consider arguments and variable objects are objects created during the execution context created in the beginning of function invocation - and your actual value/reference passed into the function just get stored in this arguments + variable objects.

Simply speaking, for primitive types, the values get copied in the beginning of function call, for object type, the reference get copied.


"pass-by-copy" === pass by value
M
Mukund Kumar

primitive type variable like string,number are always pass as pass by value. Array and Object is passed as pass by reference or pass by value based on these two condition. if you are changing value of that Object or array with new Object or Array then it is pass by Value. object1 = {item: "car"}; array1=[1,2,3]; here you are assigning new object or array to old one.you are not changing the value of property of old object.so it is pass by value. if you are changing a property value of an object or array then it is pass by Reference. object1.key1= "car"; array1[0]=9; here you are changing a property value of old object.you are not assigning new object or array to old one.so it is pass by reference.

Code

    function passVar(object1, object2, number1) {

        object1.key1= "laptop";
        object2 = {
            key2: "computer"
        };
        number1 = number1 + 1;
    }

    var object1 = {
        key1: "car"
    };
    var object2 = {
        key2: "bike"
    };
    var number1 = 10;

    passVar(object1, object2, number1);
    console.log(object1.key1);
    console.log(object2.key2);
    console.log(number1);

Output: -
    laptop
    bike
    10

The assignment operator is not to be confused with a function call. When you assign new data to an existing variable the reference count of the old data decreases and new data is associated with the old variable. Basically, the variable ends up pointing to the new data. The same is true of property variables. Since these assignments are not function calls they have nothing to do with pass-by-value or pass-by-reference.
No, everything is always passed by value. It just depends on what you are passing (a value or a reference). See this.
P
Peter Mortensen

An easy way to determine whether something is "pass by reference" is whether you can write a "swap" function. For example, in C, you can do:

void swap(int *i, int *j)
{
    int t;
    t = *i;
    *i = *j;
    *j = t;
}

If you can't do the equivalent of that in JavaScript, it is not "pass by reference".


This isn't really pass by reference. You are passing pointers into the function, and those pointers are being passed in by value. A better example would be C++'s & operator or C#'s "ref" keyword, both are truly pass by reference.
Even easier is that everything is passed by value in JavaScript.
P
Peter Mortensen

Primitives (number, Boolean, etc.) are passed by value. Strings are immutable, so it doesn't really matter for them. Objects are passed by reference (the reference is passed by value).


No, everything is always passed by value. It just depends on what you are passing (a value or a reference). See this.
Your second statement is contradicting itself.