Arrays passed by reference

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • Dormilich
    Recognized Expert Expert
    • Aug 2008
    • 8694

    Arrays passed by reference

    Hi,

    I’m currently doing a fun project, where I stumble upon the quite annoying fact, that between some methods the arrays (they are the parameters) are passed by reference, which screws up the logic.

    does anyone have an idea, how I can pass the arrays by value?
    Code:
    GAME.MagicSquare.prototype.createTable = function ()
    {
    	var doc    = document,
    	    // create various HTMLElements
    	    rows   = this.rows, 
    	    cols   = this.columns, 
    	    arr    = [],
    	    i, j, tr_i, td_j, num, range, values;
    	
    	range = (rows * cols);
    	// create the result array necessary for win test
    	this.result = [];
    	for (i = 1; i < range; i += 1) {
    		this.result.push(i);
    	}
    	// create mixed and valid configuration
    	do {
    		// couldn't get it to be passed by value
    		for (i = 0; i < range; i += 1) { // fix for problem #1
    			arr.push(i);
    		}
    		[B]values = this.scramble(arr);[/B] // <-- problem #1
    	}
    	[B]while (this.unsolvable(values));[/B] // <-- problem #2
    
    	// create the table
    
    	return table;
    };
    
    GAME.MagicSquare.prototype.scramble = function (a)
    {
    	var i, index,
    	    values = [];
    	
    	for (i = a.length; i--;) {
    		index = Math.round(Math.random() * 100 * i) % i;
    		values.push(a.splice(index, 1)[0]);
    	}
    // [I]a[/I] is now [] and in the calling function [I]arr[/I] also is []
    	return values;
    };
    
    GAME.MagicSquare.prototype.unsolvable = function (a)
    {
    	var i, j,
    	    inversion = 0, 
    	    l    = a.length, 
    	    zero = a.indexOf(0), 
    	    cols = this.columns;
    	// move the 0 to the last row
    	j = l - cols;
    	while (zero < j) {
    		a[zero] = a[zero + cols];
    		a[zero + cols] = 0;
    		zero += cols;
    	}
    // again, in the calling function, the array (named [I]values[/I]) always has the 0 in the last "row"
    	// determine number of values, that are placed after its successors
    	for (i = 0; i < l; i += 1) {
    		for (j = i + 1; j < l; j += 1) {
    			if (a[i] > a[j] && a[j] > 0) {
    				inversion += 1;
    			}
    		}
    	}
    	// even number of "inversion" means solvable
    	if (1 === (inversion % 2)) {
    		return true;
    	}
    	return false;
    };
    btw. tested in FF 3.6, Chrome (Opera quit due to Date.now()) / Mac
  • gits
    Recognized Expert Moderator Expert
    • May 2007
    • 5390

    #2
    yes ... arrays and objects are passed 'by reference' so therefor a deep-cloning function like this will do a deep copy of a passed object ... when you have 'flat' objects/arrays, i mean one level of values and not objects ... then even a concat() would work to copy the array ... but when a member itself is an object then even this would pass a reference to the new object ...

    kind regards

    Comment

    • Dormilich
      Recognized Expert Expert
      • Aug 2008
      • 8694

      #3
      thanks gits, I prototyped an array clone, that solves my problems.
      Code:
      Array.prototype.clone = function ()
      {
      	var i, c = [];
      	for (i = this.length; i--;) {
      		if (i in this) {
      			c[i] = this[i];
      		}
      	}
      	return c;
      };

      Comment

      • gits
        Recognized Expert Moderator Expert
        • May 2007
        • 5390

        #4
        yes ... for 'flat' arrays it will do :)

        Comment

        • Dormilich
          Recognized Expert Expert
          • Aug 2008
          • 8694

          #5
          I only use "flat" arrays in this case.

          wanna try it? play here.

          tested FF / Chrome / Opera / Safari – Mac, definitely not working in IE

          Comment

          • Dormilich
            Recognized Expert Expert
            • Aug 2008
            • 8694

            #6
            Originally posted by gits
            yes ... arrays and objects are passed 'by reference'
            that is, everything that is not a primitive?

            Comment

            • gits
              Recognized Expert Moderator Expert
              • May 2007
              • 5390

              #7
              ... nearly ... functions are not 'primitives' but are even copied instead of referenced ... which is a bit confusing ...

              Comment

              • Dormilich
                Recognized Expert Expert
                • Aug 2008
                • 8694

                #8
                does that mean that, in case of event handlers via addEventListene r(), the function body is copied to the element (or whereever the handler is stored)?

                Comment

                • gits
                  Recognized Expert Moderator Expert
                  • May 2007
                  • 5390

                  #9
                  that seems a bit tricky/unclear ... in case you do:

                  Code:
                  var foo = function() {
                      alert('bar');
                  }
                  
                  node.addEventListener('click', foo, true);
                  i think it passes a reference since we created one before ... when you then do:

                  Code:
                  foo = function() {
                      alert('foobar');
                  }
                  
                  othernode.addEventListener('click', foo, true);
                  the old ref is dropped but the first click-handler has the old foo-function while the othernode will have the new foo-function assigned. so in javascript it seems that basicly it doesn't really pass by reference but i seems more likely to pass a value of a reference or similar ... so that you could drop references like above but the old 'content' persists in an anonymous context then ... hopefully that makes any sense :) ... i think this seems like closures are supposed to work ...

                  an example of this behaviour is as follows:

                  Code:
                  var a = {
                     foo   : { test: 1, test1: 2 },
                     bar   : function(a) { alert(a) },
                     foobar: 'foobar1',
                     arr   : [1, [8, 9], {1: 1, 2: 2}, 4]
                  };
                  
                  var b = {};
                  
                  b.bar = a.bar;
                  b.arr = a.arr;
                  
                  // alerts 2
                  a.bar(2);
                  
                  b.arr[1] = ['foo'];
                  
                  b.bar = function(a) { alert(a + a) };
                  
                  // alerts 2
                  a.bar(2);
                  
                  // logs the array ['foo'] even for obj a
                  console.log(a.arr)
                  here are the references dropped too - the function is 'new' in b but 'old' in a while the references in the b.arr-array persists and the new value 'foo' then is reflected in both arr-arrays of a and b

                  kind regards

                  Comment

                  Working...