When an object is pushed into an array, does it refer to the same instance of the object?
Eg:
function object() {
var count = 1;
}
array = [];
var obj = new object();
array.push(obj);
here, is the object inside the array, "array[0]", the same instance of the object outside the array, "obj"?
Also, if I was to pass obj into another function, will I be passing the same instance of the object into the function's parameters or will the function create a new object?
When you push the object into the array, there is still only one instance of the object. The variable contans a reference to the object, and the array contains another reference to the same object.
If you change the object then the change is visible both when you view it through the variable and the array, as it's the same object. However if you change the variable (for example assigning another object to it), that won't affect the array; it will still reference the original object.
When you pass the object as a parameter to a function, the reference is passed by value. There is still only one instance of the object, but the parameter is separate from the variable that you use in the call. If you change the object inside the function the change is visible outside the function as it's the same object, but if you change the parameter that won't affect the variable that you used in the call.
Objects in javascript are passed into arrays by reference. To crib a bit of your code,
function object(){
var count = 1;
}
array = [];
var obj = new object();
array.push(obj);
array.push(obj);
array[1]['n'] = 5
produces
array
=> [ { n: 5 }, { n: 5 } ]
This is because you're just working with a reference to the actual object. Therefore, any references to the object are the same - be they inside the array, duplicates, or what have you. If you want a deep copy, you'll need to implement that yourself.
Javascript is pass by value for primitives (for objects too - but in that case, the value is a reference to the object). However, when an object is passed into an array, this value is a reference to an object. When you pass an object or array, you are passing a reference to that object, and it is possible to modify the contents of that object, but if you attempt to overwrite the reference it will not affect the copy of the reference held by the caller i.e. the reference itself is passed by value.
When you pass in a primitive (e.g. string/number), the value is passed in by value. Any changes to that variable while in the function are separate from whatever happens outside the function.
Pass by value for primitives
function testFunction(x) {
// x is 4
x = 5;
// x is now 5
}
var x = 4;
alert(x); // x is equal to 4
testFunction(x);
alert(x); // x is still equal to 4
Passing an object is by reference (pass by value but this value is a reference):
function myObject() {
this.value = 5;
}
var o = new myObject();
alert(o.value); // o.value = 5
function objectchanger(fnc) {
fnc.value = 6;
}
objectchanger(o);
alert(o.value); // o.value is now equal to 6
Passing in a method of an object is not passed by reference though (due to the lost context when you pass in a function as a parameter).
Everything not a primitive type is passed by reference.
Related
I'm a little confused about the passing of a hash as parameter to a function.
I know that when a variable is passed to the function through a parameter, to this is applied a copy of the value.
But this is not valid with the hashes, at least not always.
Example:
var a = {b: 'hello world'};
var change = function(h){
h = true;
};
var change_v2 = function(h){
h.b = 'another hello';
};
console.log(a); // will print the original hash
change(a);
console.log(a); // naturally, will print the original hash
change_v2(a);
console.log(a); // this print b == 'another hello'
So, why the reference is used sometime for the hashes?
Can someone explain how javascript works in this case?
The simple answer to your question is that a value was copied -- a does not contain any object (what you called a hash) but actually contains a reference to the object and this reference was copied into the parameter local.
Read below for a more detailed explanation of why this happens, pass-by-value vs pass-by-reference.
In JavaScript, variables do not hold objects, they hold a reference to an object. This is an important distinction.
All parameters are pass-by-value in JavaScript. The object references stored in variables are passed by value.
These two behaviors combine to cause the specific behavior you are seeing. Let's lay out some examples of each passing behavior to prove that JavaScript passes arguments by value.
function foo(a) {
a.bar = 2;
}
var b = { bar: 1 };
foo(b);
b.bar would still be 1 if objects were passed by value, but this is not the case in JavaScript.
b.bar would be 2 if (a) the object reference was passed by value, or (b) the argument itself was passed by value.
So in this case, "pass reference by value" and "pass argument by reference" don't have a difference in behavior. Now let's introduce a case where they are different.
function foo(a) {
a = { bar: 2 };
}
var b = { bar: 1 };
foo(b);
b.bar will be 1 if the object is passed by value, which isn't what happens.
b.bar will also be 1 if the object reference is passed by value, which is what happens.
b.bar will be 2 if the argument is passed by reference.
So in summary, you have to realize two things:
Variables never contain objects, but they can contain a reference to an object. Two variables both holding a reference to the same object will reflect changes made to that object.
All arguments are passed by value, that is, the callee has no access directly to the variable that was passed in, but only to the value received by the parameter -- which can be an object reference. Manipulation of that object can cause the appearance of pass-by-reference, but note that the variable passed into the function still refers to the same object so the passed variable was not modified in any way.
As a side note, if objects were values that could be directly stored in variables, then {} === {} would be true, but it's not -- because the references are compared and found to be not equal, as these references refer to two different objects.
Javascript is pass-by-reference. Always. Assignment changes a name to refer to some value.
So,
function foo(h)
{ h = "bar"; }
The name h is a parameter to the function. The assignment affects the name h only, and that name exists only in the scope of the call to the function.
In contrast, the statement h.b = "bar"; does not assign to the name h. It assigns to the field b within the object that is referenced by the name h.
This is because JavaScript passes parameters by value.
Passing a parameter by value is like assigning formal parameters values to actual parameters. For example consider
function f(obj) { obj.a = 10; }
o = { a : 20 };
f(o);
The above code will function as if the value of o is assigned to obj like if you do
o = { a : 20 }
obj = o;
obj.a = 10;
console.log(o.a);
you will see the same effect.
See a detailed explanation here
I'm trying to create a function that accepts a global variable as a parameter and changes the value of that global variable. Here's a simple example that illustrates what I'm trying to do:
var number = 20;
function setnew(num) {
num += 1;
};
setnew(number);
console.log(number) //-> 20
//I want this to return 21
Even after the setnew function is invoked, number remains unchanged. Can someone explain why number remains unchanged and suggest another way to achieve my intended goal?
Since Javascript does not support true reference passing where you can change the original variable, you can't directly do what you're asking. The usual work-around is to wrap the global in an object.
var myGlobal = {
counter: 0;
};
function increment(obj, prop) {
++obj[prop];
}
increment(myGlobal, "counter");
increment(myGlobal, "counter");
console.log(myGlobal.counter); // 2
Or, if the property name is already known, you can just do this:
var myGlobal = {
counter: 0;
};
function incrementCnt(obj) {
++obj.counter;
}
incrementCnt(myGlobal);
incrementCnt(myGlobal);
console.log(myGlobal.counter); // 2
This works because when you pass an object to a function, what is passed is a pointer to that same object (the object is not copied). So, if you modify any property on that object, there is only one copy of the object so you are modifying the property on that one copy of the object and everyone who has a reference to that object will see the property change.
Primitives like numbers and booleans are passed by value which works like a copy was made so the original can never be affected from the function.
Can someone explain why number remains unchanged and suggest another
way to achieve my intended goal?
When passing a number to a function, the value of the number is copied to a new variable which is the argument to the function. Changing the value of that argument to the function ONLY affects that argument - it has no connection at all to the original variable. This is because in Javascript primitives are passed by value, not by reference. So, no reference is maintained at all to where the value came from. When you receive it in the function, it is a new variable that stands on its own.
Another possible work-around is to just return the modified value from your function and allow the caller to assign that modified value to whatever they want:
var counter = 0;
function increment(val) {
return val + 10;
}
counter = increment(counter);
console.log(counter); // 10
If you were to pass in a object instead of a primitive, you would be able to update it.
For example:
var number = { value: 20 };
function setnew(num) {
num.value += 1;
};
setnew(number);
console.log(number.value) //-> 21
Basically when you pass in an object, javascript is actually only passing a reference to the variable, while when you pass an integer, it is going to pass a copy of the value.
I am trying to create a function which will dynamically set the value of whatever global variable is passed as a parameter. It's not working, and I'm trying to figure out why. Can someone please explain why this doesn't work:
var things = 5;
function setup(variable) {
variable = 7;
}
setup(things);
console.log(things); //should return 7. returns 5 instead. the function had no effect on the global variable
and this also doesn't work:
var things = 5;
function setup(variable) {
window.variable = 7;
}
setup(things);
console.log(things); //should return 7, but returns 5. still not accessing the global variable.
but this does:
var things = 5;
function setup(variable) {
window[variable] = 7;
}
setup("things");
console.log(things); //returns 7
I suspect that what is happening is that the parameter variable is being set as a local variable inside of the function, so any changes are only happening to the local version. But this seems strange because the parameter that's been passed is a global variable. Can someone explain to me what is happening and how to better write this code? Does this require a method (which can then use this to access the original object)?
Thanks!!
Javascript is pass-by-value. (Objects, arrays, and other non-primitives are passed by value-of-reference.) That means that the value of the variable (or reference) is passed to the function, but the function parameter does not become an alias for the actual argument. Thus, you cannot change a variable outside a function without referencing it (as you do in your last example).
See this answer in another thread for more information.
Inside of functions are "variable environments". When the function setup is declared, and the parameter variable set, it creates a local variable in setup's variable environment for variable (the parameter).
So that is why this assignment
function setup(variable) {
variable = 7;
}
Will never change the value sent to variable.
Variables in JavaScript are values. As the variable is passed around, the only thing passed is the value of the variable. However, the value of the variable is assigned to the parameter (again poorly named in this example) variable. When the value of the parameter is assigned to 7, that only changes the local variable, and not the value of the passed variable.
//the value of things is 5
var things = 5;
//the passed value 5 is assigned to variable
function setup(variable) {
//the value of variable is changed to 7 (and nothing is done with 5)
variable = 7;
}
//the value of things is sent to setup
setup(things);
Hopefully this will be a little more enlightening. Consider a situation where setup was actually modifying the value of variable. A good example is when the value has state, such as an array or an object.
//the value of things this time is an object
var things = {};
//the passed value of object is assigned to variable
function setup(variable){
//the value of variable (the object) has a property added named msg with a value of "hello world"
variable.msg = "hello world";
}
//the value of things (an object) is sent to setup
setup(things);
alert(things.msg);//hello world
When variables are passed as arguments to functions, a copy of their value is made and assigned to the name of the argument in the function.
For example:
function foo(a) {
a = 7; // sets the temporary variable(argument) a to 7
}
var bar = 24;
foo(bar); // copies bar's value and passes in the copy to foo
For a function to modify a variable itself, you would have to access it another way. In other languages there are things called pointers that point to a place in memory. This allows you to modify variables directly, as you have where they are located - you can simulate this with JavaScript:
var spam = 3;
var memory = ["bar", 29, "x", foo, false];
function foo(a) {
memory[a] = 7;
}
foo(3);
The above example sets an array called memory and fills it with random gibberish. Then, a function named foo is created that allows for the modification of elements in this memory array.
I am trying to wrap my head around this idea of 'argument passing.' In a book I am reading it states that arguments are only passed by value not by reference.
function addTen(num) {
num + = 10;
return num;
}
var count = 20;
var result = addTen(count);
alert(count); // 20 - no change
alert(result); // 30
The example above is pretty clear, but the example below leaves me very confused.
When person is passed to the setName function, doesn't it mirror the local variable 'obj'
and flow down the statements in the function?
i.e. person is first set to the property name, then it's assigned to a new Object, and finally this new created person object is assigned the property 'Gregg'????
Why do you get 'Nicholas'!!!!
function setName(obj) {
obj.name = "Nicholas";
obj = new Object();
obj.name = "Greg";
}
var person = new Object();
setName(person);
alert(person.name); //" Nicholas"
Objects are passed to function as a copy of the reference. Now what happens in your example is next:
var person = new Object();
function setName(obj) { // a local obj* is created, it contains a copy of the reference to the original person object
obj.name = "Nicholas"; // creates a new property to the original obj, since obj here has a reference to the original obj
obj = new Object(); // assigns a new object to the local obj, obj is not referring to the original obj anymore
obj.name = "Greg"; // creates a new property to the local obj
}
setName(person);
alert( person.name); //" Nicholas"
* = obj is a local variable containing a value, which is a reference to the original obj. When you later change the value of the local variable, it's not reflecting to the original object.
You get "Nicholas" precisely because JavaScript is never "by reference". If it was, you'd be able to update the person variable from any location. That's not the case, so the new Object() in the function doesn't mutate the outer person variable.
But it's also not the case that variables refer to the objects themselves, but rather variables hold a special type of reference that let you update the object without directly accessing the memory.
That's why although JavaScript is always "by value", you never get a full copy of an object. You're merely getting a copy of that special reference. As a result, you can manipulate the original object passed via the copy of the reference, but you can't actually replace it via the reference.
Everything is pass-by-value in JavaScript. When you pass anything as an argument, JS makes a copy of that and sends it to the function. When an Object is passed, JS copies the reference of that object into another variable and passes that copied variable to the function. Now, since the passed variable is still pointing to the object, you can alter its properties using the . or [] notation. But if you use new to define a new object then that variable just points to the new reference.
function setName(obj) {
obj.name = "Nicholas"; // obj pointing to person reference
obj = new Object(); // obj now pointing to another reference
obj.name = "Greg"; // you have changed the new reference not person reference
}
var person = new Object(); // person pointing to person reference
setName(person);
alert( person.name); //" Nicholas"
Parameters are passed by value, and for objects that means that the value is a copy of the reference to the object.
It's the same thing as when you do a simple assignment, that is also by value:
// a variable that contains a reference to an object:
var person = new Object();
// another variable, that gets a reference to the same object:
var people = person;
// a function call with a reference to the object:
setName(person);
In the function, the parameter is a local variable that works independently of the variable used to send the reference into the function, but it references the same object:
function setName(obj) {
// as the variable references the original object, it changes the object:
obj.name = "Nicholas";
// now the variable gets a reference to a new object
obj = new Object();
// the new object is changed
obj.name = "Greg";
}
Pass by reference means this:
function a(obj) {
obj = 3;
}
var test = new Object();
a(test);
console.log(test); //3, so I have lost the object forever
I.E. even variable assignments will be visible to the caller.
Of course if the target function modifies an object passed to it then those modifications
to the object itself will be visible to the caller.
I have the following source code.
testObj = {}
function testFun()
{
this.name = "hi";
}
function test () {
var instanceOfTestFun = new testFun();
testObj.pointerToFun = instanceOfTestFun;
instanceOfTestFun = null;
console.log(testObj);
}
$(document).ready(test);
I expected to see 'null' for the console output of testObj, but I see testFun function. I thought javascript uses 'pass by ref' for objects.
Please...advise me...
testObj.pointerToFun and instanceOfTestFun are two references to the same object.
When you write instanceOfTestFun = null, you're changing instanceOfTestFun to point to nothing.
This does not affect testObj.pointerToFun, which still refers to the original object.
If you change the original object (eg, instanceOfTestFun.name = "bye"), you will see the change through both accessors, since they both point to the (now-changed) object.
You don't destroy the object itself if you set a property that holds a reference to it (instanceOfTestFun) to null. You can only indirectly destroy an object by removing the last reference to it (which is, at that point, the value held by testObj.pointerToFun), so it will be garbage-collected.
Under no circumstance can you delete a property of testObj without referencing it.
Don't confuse properties (instanceOfTestFun, testObj, testObj.pointerToFun) with the values they can hold (references to properties, as after testObj.pointerToFun = instanceOfTestFun, or plain values, as 9 or null).
var x = {};
The above line creates an object and stores a reference to it inside the variable x.
var y = x;
The above line copies the reference from variable x to variable y. Now, both x and y hold references to the object.
x = null;
The above line deletes the reference that was stored inside x. The object that was referenced by this reference is not garbage-collected, since variable y still holds a reference to it.
Any given object lives as long as it's referenced by at least one reference.