1

I wrote code like the following:

function setAtoB(a, b) {
    console.log('entered function');
    a = b;
}
var x = {};
var y = {'t':3};
setAtoB(x, y);
console.log(x);

I then got output like this:

entered function
{}

It seems to me that x should have been {'t':3}. Does anyone know why it's still {}, and how I can assign values within a function?

John L.
  • 1,903
  • 2
  • 13
  • 15

2 Answers2

4

In the setAtoB function, you're replacing a with b, which breaks a's reference to the caller one level higher in the call stack. When passing in objects into functions, you can replace their properties without breaking that link, but the moment you perform any type of reassignment, that link breaks and a new object is created.

For example, if you instead replace just the properties, then the references are preserved:

function setAtoB(a, b) {
    console.log('entered function');
    a.t = b.t;
}
var x = {};
var y = {'t':3};
setAtoB(x, y);
console.log(x);    // output: Object {t: 3} 
jamesmortensen
  • 33,636
  • 11
  • 99
  • 120
  • The reference is not preserved, after calling `setAtoB` and then doing like `x.t=20` y's `t` property will not equal 20 – Patrick Evans Jun 29 '14 at 17:47
  • @PatrickEvans - Not sure I follow. It seems changing x.t to 20 results in printing 20: http://jsfiddle.net/HaS5b/ – jamesmortensen Jun 29 '14 at 17:50
  • 1
    Ah, I see what you're saying, yeh, when you copy properties from one object to another, you're making an actual copy of those properties, which may or may not be what you want. But in this case, that aligns with what the OP is looking for as a result. – jamesmortensen Jun 29 '14 at 17:54
  • 1
    +1 overall, though *"...a's reference to the caller one level higher in the call stack"* seems confusing or misleading. There's no reference to the caller and the issue doesn't really have anything to do with the call stack, unless I've just completely missed what you're saying there. The reference in question is to the object itself, which is held by `x` and copied to `a`, then replaced by the one held by `y` and copied to `b`. – cookie monster Jun 29 '14 at 18:20
  • @cookiemonster - I tried to explain it more in laymans terms. The way I've remembered how object references are handled is to think of it as being connected to the object reference in the higher level closure. In fact, by thinking of it this way, when testing, I've been able to build global objects that hold references to dependencies I've injected into prototypes and modules so that I can spy on their values to determine state, or even control the state remotely from the level of the global scope. So long as I don't reassign the injected object, the reference remains. Hope this helps clarify. – jamesmortensen Jun 29 '14 at 21:19
  • 1
    I see. I tend to think of it more in the sense of a boxed pointer where the pointer dereferencing is limited and controlled by the box, the pointer points to the actual object that exists in some unknown place in memory, and the box object is passed/assigned by value (copied). So to use some pseudo syntax `var foo = [0x1030e0d8] -> [b1="bar", b2="baz"]`. – cookie monster Jun 29 '14 at 23:52
4

JavaScript is always pass-by-value, so you just can't directly do what you describe. You can modify the properties of an object when a reference to it is passed into your function, but you cannot change the original variable used in the calling environment. In other words, in the call:

setAtoB(x, y);

it's a copy of the value of variable "x" that's passed to the function. The value of variable "x" is a reference to an object, so a copy of that reference is what's passed. That reference works just as well as the copy still present in "x" to make changes to the referenced object, but changing the parameter that contains the copy has no effect on the value of "x".

Pointy
  • 405,095
  • 59
  • 585
  • 614
  • 1
    "object references are pass by value" is something someone once said when writing about Java. Maybe this guy: http://javadude.com/articles/passbyvalue.htm But I can't remember who first wrote about it. I also covered the same concept with JavaScript here: http://blog.opensourceopportunities.com/2008/07/javascript-and-java-are-pass-by-value.html. While somewhat confusing to newcomers to these languages, what you wrote is factually correct. "JavaScript is always pass-by-value...". – jamesmortensen Jun 29 '14 at 21:25
  • 2
    @jmort253 yes, it's terribly confusing. The problem is that the terms "pass-by-value" and "pass-by-reference" have specific technical meaning, but for people who aren't compiler/interpreter implementers it's kind-of arcane. This question actually gets to the heart of the matter! Also see [a blog post I did](http://whatsthepointy.blogspot.com/2013/11/javascript-does-not-have-pass-by.html). – Pointy Jun 29 '14 at 21:57