Page 1 of 1

JavaScript - Weird Array assignment behavior

Posted: Tue Aug 09, 2005 9:37 pm
by Ambush Commander
Hello, I'm learning JavaScript, and I'm getting really hung up on this:

Code: Select all

i = new Array();
    i[0] = 'asdf';
    i[1] = 'pork';
    j = i;
    k = i;
    j.splice(0,1);
    alert(i);
Theoretically, i should still be an Array with asdf and pork, but it's just pork now. Can someone explain this behavior to me as in PHP, this would never ever happen unless I passed a reference.

Posted: Tue Aug 09, 2005 9:41 pm
by feyd
you hit it on the nose.. the array is being passed around as a reference. Javascript is mostly based off of C and C++, therefore an array's name is merely a pointer (reference) to the data. All objects in Javascript are passed by reference. Arrays in Javascript are objects.

Posted: Tue Aug 09, 2005 9:42 pm
by Ambush Commander
So then how do I get a "copy" of the array?

Posted: Tue Aug 09, 2005 10:34 pm
by feyd
create it:

Code: Select all

<html>
	<head>
		<title>Feyd's wacky world of tests</title>
		<script language="Javascript">
			function displayIt(obj)
			{
				var where = 'input';
				if(arguments.length > 1)
					where = arguments[1];
				var buf = new Array();
				if(typeof(obj) == 'object')
				{
					for(var i in obj)
					{
						buf[buf.length] = 'object['+i+'] = ' + obj[i];
					}
					buf = buf.join('\n');
				}
				else
				{
					buf = obj;
				}
				document.getElementById(where).innerHTML = '<pre>'+buf+'</pre>';
			}

			function clone(obj)
			{
				var newb;
				var con = obj.constructor.toString();
				var type = con.replace(/^\s*function\s*([a-z_][a-z0-9_]*)\(.*/ig,'$1');
				type = type.split('\n');
				type = type[0];
				eval('var clone = new '+type+'();');
				for(var i in obj)
				{
					clone[i] = obj[i];
				}
				return clone;
			}

			function testIt()
			{
				var arr = new Array('asdf','ASDF','FDAS','fdas','1234','4321');
				var ar2 = clone(arr);
				arr.shift();
				arr.shift();
				displayIt(arr);
				displayIt(ar2,'output');
			}
		</script>
		<style>
			div#input,
			div#output
			{
				border: 1px solid gray;
				background: whitesmoke;
				border-top: 1px solid red;
				margin-bottom: 10px;
				padding: 2px 4px;
				width: 250px;
			}
		</style>
	</head>
	<body>
		<a href="javascript:testIt();">Test it!</a>
		<div>
		Array 1:<div id="input"></div>
		Array 2:<div id="output"></div>
		</div>
	</body>
</html>
tested in Firefox 1.0.6 and IE 6.0.2900 SP2

Posted: Wed Aug 10, 2005 12:04 pm
by Ambush Commander
Wow! That's very complicated.

If I'm not mistaken, the first function is a convenience function to let you output the contents of an object in a fashion that is more descriptive than [object Object].

Clone() is our copier function. Hmm... it appears that taking the function "constructor" and translating it into a string like "function Array(arg) {etc.". and grab the "Array". Then you create a new object on what you based the function on, then you loop through the old Object and assign those values to the new object. Speculation If the array contained objects, I bet you'd have references! Possible solution: make the function recursive. [/endspeculation] Then you return the cloned object.

Wow. That's pretty spiffy. I suppose that if you pass the function a blank copy of the new object, that would eliminate the fancy regexps and the eval.

Lots of tricks hmm... well I guess I have to learn more.

It occured to me that if I create a constructor that initializes the objects with the values I want it to have, all I have to do is:

Code: Select all

i = new ArrayWithValues();
j = new ArrayWithValues();
And they'll be copies, which works for my instance.