JavaScript - pass objects by reference [duplicate] - javascript

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How can I store reference to a variable within an array?
Consider the following code:
var a = 'cat';
var b = 'elephant';
var myArray = [a,b];
a = 'bear';
myArray[0] will still return 'cat'. Is there a way to store references in the array instead of clones, so that myArray[0] will return 'bear'?

While I agree with everyone else saying that you should just use myArray[0] = whatever, if you really want to accomplish what you're trying to accomplish you could make sure that all you variables in the array are objects.
var a = {animal: 'cat'},
b = {animal: 'elephant'};
var myArray = [a, b];
a.animal = 'bear';
myArray[0].animal is now 'bear'.

No. JavaScript doesn't do references in that way.

Nope, it is not possible. JavaScript doesn't support such references.
Only objects are stored as references. But I doubt it's what you want here.

You've kind of answered your own question. If you want myArray[0] to equal bear, then set:
myArray[0] = "bear";

Even if your array holds references to objects, making a variable refer to an entirely different object would not change the contents of the array.
Your code does not modify the object variable a refers to. It makes variable a refer to a different object altogether.
Just like your JavaScript code, the following Java code won't work because, like JavaScript, Java passes references to objects by value:
Integer intOne = new Integer(1);
Integer intTwo = new Integer(2);
Integer[] intArray = new Integer[2];
intArray[0] = intOne;
intArray[1] = intTwo;
/* Make intTwo refer to a completely new object */
intTwo = new Integer(45);
System.out.println(intArray[1]);
/* output = 2 */
In Java, if you change the object referenced by a variable (instead of assigning a new reference to a variable) you get the behavior you desire.
Example:
Thing thingOne = new Thing("funky");
Thing thingTwo = new Thing("junky");
Thing[] thingArray = new Thing [2];
thingArray[0] = thingOne;
thingArray[1] = thingTwo;
/* Modify the object referenced by thingTwo */
thingTwo.setName("Yippee");
System.out.println(thingArray[1].getName());
/* output = Yippee */
class Thing
{
public Thing(String n) { name = n; }
private String name;
public String getName() { return name; }
public void setName(String s) { name = s; }
}

Related

Assigning the same function to different variables

I was going through the WURFL.js source, I saw this towards the bottom of the page:
var logo=document.getElementById("hero"),heroText=document.getElementById("hero"), ...
Obviously, the variables, logo and heroText, are referring to the same thing. Isn't that an unnecessary overhead on the DOM parsing in JavaScript (since JavaScript has to look for the id hero each time)? Apparently, a more efficient one is:
var logo=document.getElementById("hero");
var heroText = logo;
In that case, heroText could be another object or could also be referring to the same object as logo. I don't know which because I don't know how the JavaScript interpreter works (I'm a C# person, a learner, though).
So my question is really this: (I'm assuming WURFL didn't make a mistake) how does JavaScript interpret the two lines? Thanks, in advance.
The difference would be (if it weren't returning a DOM element) that if you do
var getObj = function() { return {} };
var a = getObj();
var b = getObj();
a.test = 'hi';
console.log(b);
// Object {}
But if you do:
var getObj = function() { return {} };
var a = getObj();
var b = a;
a.test = 'hi';
console.log(b);
// Object {test: "hi"}
One results in two unique objects, the other in two references to the same object.
var a = document.getElementById('notify-container')
var b = document.getElementById('notify-container')
a.test = 'hi'
console.log(b.test);
//"hi"
So, in the instance you are showing, yes it is more efficient to do
var logo=document.getElementById("hero");
var heroText = logo;
There clearly seams to be a mistake. Because document.getElementById returns a 'live' representation of a node. That means that whenever that element changes, the variable that holds tha node ( logo, heroText ) is also changed; also, if you check those two variables for equality they will be the same.

How to define new object of variable type of array object?

jQuery has made my life easier but I'm still very beginner to JavaScript. So, may be, I'm asking a very stupid question here:
var t = {
rows: 3,
columns: 5,
getCellCount: function () {
return this.rows * this.columns;
}
};
var tn = t;
tn.rows = 6;
document.write(tn.rows + " , " + t.rows); // returns 6 , 6
I also tried var tn = new t(); // but seems wrong
So, How to retrieve old intrinsic value from object so that it results 6 , 3
tn and t are both pointing to the same object, that's why when you change tn.rows it also changes t.rows. There is no such thing as old intrinsic value.
You must copy the object in order to keep the old value. There are two: shallow copy and deep copy.
Copying the key-value pairs is pretty easy with Object.create.
var newObj = Object.create(oldObj);
Now if you change the values in newObj, it will not change the original one:
var a = {a:1}, b = Object.create(a);
b.a = 2;
console.log(a.a, b.a); //1,2
However, to perform a complete copy is really complicated. See more: How do I correctly clone a JavaScript object?
PS: The new keyword you mentioned is for creating an object as in classes.
function Car(n, y){ //This is called a "constructor"
var name = n, year = y; //Private variables
return {
getName: function(){ return name; }, //Getters
getYear: function(){ return year; }
};
}
var myNewCar = new Car("Toyota", 2010);
myNewCar.getName(); //"Toyota"
myNewCar.getYear(); //2010
(This is also how you create objects in Java, if you have taken those CS courses you would recognize this pattern.)
var tn = t;
simply makes both tn and t to point to the same object in memory. So, change in one object will reflect in other as well. You can clone the object, like this
function copyObject(sourceObject) {
var result = {};
for (var key in sourceObject) {
if (sourceObject.hasOwnProperty(key)) {
result[key] = sourceObject[key];
}
}
return result;
}
var tn = copyObject(t);
You are asking to clone a JSON object.
var tn={};
for (key in t) tn[key]=t[key];
There may be other "prettier" ways, but this guarantees the clone.
The = operator in javascript just changes what the object points to, so it will not create a copy of the original object. You can take a look here to see possible ways to create a clone of the object.
If you want to create a Javascript object, the conventional way is to create a function:
// Use capitalized names for Object-creating functions.
// I guessed that you wanted a matrix of some sort.
function Matrix(rows, columns) {
this.rows = rows;
this.columns = columns;
this.cellCount = function() {
return this.rows * this.columns;
}
this.dimensions = function() {
return this.rows, + ", " + this.columns;
}
this.copy = function() {
return new Matrix(this.rows, this.columns);
}
}
var t = new Matrix(6, 3);
There are more sophisticated ways to do this, using Object.create. Look at Javascript: The Good Parts.

Print name of constructor variable

Say, I have 2 constructors assigned to 2 variables:
var example1 = function(argument1){
this.argument1 = argument1;
}
var example2 = function(argument2){
this.argument2 = argument2;
}
And an array of objects containing objects from both of these constructors:
var array1 = new Array();
array1[0] = new example1(example);
array1[1] = new example2(example);
My question is, when I choose an item from the array, how can I print the name of the constructor variable it came from?
To make this clear and succint, here's an example:
console.log(array1[0].argument1)
Will print example. But I don't want that. I want it to print the name of the constructor variable it came from.
console.log(array1[0].constructor.toString());
Prints the content of the variable, but it is unsatisfactory.
You need to provide a name to a function:-
var example1 = function example1(argument1){
this.argument1 = argument1;
}
var array1 = new Array();
array1[0] = new example1({});
console.log(array1[0].constructor.name)
in most browsers, functions have a name, but you don't use it.
so, we have to resort to hacks to find your constructor in the cloud, which won't work in IE7, maybe 8:
console.log(Object.keys(self).filter(function(a){
return self[a]===array1[0].constructor;
})[0]);
if you didn't have the code running in the global scope, this trick won't work!
again, this is a hack and you should find a better way of doing things, like naming your functions, even if they are expressions.
Try instance of,
var example1 = function(argument1){
this.argument1 = argument1;
}
var example2 = function(argument2){
this.argument2 = argument2;
}
console.log(getName(array1[0]));
function getName(value) {
if (value instanceof example1) return 'example1';
if (value instanceof example2) return 'example2';
return '';
}

How did the value of Object Array in javascript be operated?

I feel puzzled when I rethink of these two functions:
The first one goes like this:
var test = [1,2,3];
var ele = test[0];
ele= 2;
alert(test[0]);
The result is 1. I think this is obvious. But when I meet this:
var test = [{id:1},{},{}];
var ele = test[0];
ele.id = 2;
alert(test[0].id);
The result turns to be 2
So could anyone tell me that how the javascript work when it happens like this in the object array?
In JavaScript, objects are assigned by reference, rather than copied in memory. So if you assign an existing object to a different variable, both will point to the same object in memory. Modifications to either will therefore be reflected in both.
var a = {id: 1, name: "bob"};
var b = a;
console.log(b.name); // bob
b.name = "bill";
console.log(a.name); // bill
So in your example, executing ele.id = 2; operates on the memory location holding the object at test[0]. The change to the id property of that object is reflected in both variables referencing it (test[0], ele)
Note that if you had assigned the entire array test to ele, modifying one of the array members would have been reflected in both test, ele since Arrays are objects in Javascript:
var test = [1,2,3];
// Assign array test to ele
var ele = test;
// Modify one member
ele[0] = 2;
alert(test[0]); // 2

Hash/associative array using several objects as key

Is there a way of making an associative array where each key is a hash of several objects? I'm not interested in inspecting each object's state, but rather the object's identity.
var myarray = {};
var a = new A();
var b = new B();
var c = new C();
// + is not right, but illustrates the hashing I'm after.
myarray[a + b + c] = 42;
The + operator is not right. In java I would arithmetically combine the System.identityHashCode() for each of these three instances and use the result to make my new hash key. Is there some similar mechanic in javascript?
Overriding the .toString() method in A, B and C is not an option since I'm interested in object identity, not state.
Actually impossible since Object keys in this language only can be strings and there's no equivalent of java's object identity.
:o)
You could overwrite the toString() method of the prototypes to create a unique hash for each instance. E.g.
A.prototype.toString = function() {
return /* something instance specific here */;
};
Even a + b + c would work then.
Update: Afaik, you cannot get an instance unique id (whatever that is) in JavaScript. You could however assign each instance some identifier.
This only works if you are creating the objects.
E.g.
var addIdentityTracker = (function() {
var pad = "0000000000",
id = 1;
function generateId() {
var i = (id++).toString();
return pad.substr(0, 10 - i.length) + i;
}
return function(Constr) {
var new_constr = function() {
this.___uid = generateId();
Constr.apply(this, arguments);
};
new_constr.prototype = Constr.prototype;
new_constr.prototype.toString = function() {
return this.___uid;
};
return new_constr;
};
}());
and then do:
A = addIdentityTracker(A);
var a = new A();
I'd suggest just assigning a unique ID to each object. Javascript doesn't come with a built-in unique ID mechanism, but you can assign a unique ID to any object you want and then use it as such. For example, you could do this:
// getUniqueID is a function that returns a unique ID for any javascript object.
// If no uniqueID is already present on the object, it coins one using a global
// counter and then stores it on the object.
// So that the uniqueID can be combined with other uniqueIDs easily and still
// create a unique union, the uniqueID here is a unique 10 character string.
// There is no randomness in the IDs as they are only required to be unique
// within the page, not random or unique in the universe. The monotomically
// increasing counter guarantees uniqueness within the page.
// Two globals we need for generating the unique ID
var idCntr = 0;
var controlStr = "0000000000"; // 10 digits long
function getUniqueID(o) {
if (!o.uniqueID) {
var base = idCntr++ + ""; // get string version of idCntr
o.uniqueID = controlStr.slice(0, controlStr.length - base.length) + base; // zero pad
}
return(o.uniqueID);
}
var myobj = {};
var a = new A();
var b = new B();
var c = new C();
myobj[getUniqueID(a) + getUniqueID(b) + getUniqueID(c)] = 42;
For you to fetch the same object back in the future, you'd have to combine the objects in the proper order again. If that wasn't easy, then you could make sure and always combine them in numeric order with the lowest numbers first so you always got a consistent order.

Categories

Resources