Iets vreemd met arrays

  • Onderwerp starter Onderwerp starter Uturn
  • Startdatum Startdatum
Status
Niet open voor verdere reacties.

Uturn

Gebruiker
Lid geworden
7 apr 2009
Berichten
100
Dag allemaal,
Ik ontdek soms iets vreemd met JavaScript waar ik dan vervolgens lang mijn hoofd over breek en er niet uitkom. Waarschijnlijk is het iets stoms wat ik gewoon niet zie. Nu was ik een functie aan het schrijven om 3D arrays te verwerken. Om te testen wou ik een 3D array even met getallen opvullen zodat ik het resultaat kon zien. Voor zover ik weet kun je geen >1D array direct met getallen vullen, want dan krijg ik foutmeldingen. Dus doe ik het door eerst een array te vullen, die toe te kennen aan een array, en dan weer, zodat ik een 3D array krijg:

Code:
<html>
<head>

<script type="text/javascript">

var The3Darr = new Array;

function vulars() {
  var dummyar = new Array;
  var dummyar2 = new Array;

  dummyar[0] = 64;
  dummyar[1] = 1037;
  dummyar2[0] = dummyar;

  dummyar[0] = 36;
  dummyar[1] = 1037;
  dummyar[2] = 1200;
  dummyar2[1] = dummyar;

  dummyar[0] = 1;
  dummyar[1] = 1037;
  dummyar[2] = 1201;
  dummyar2[2] = dummyar;

  The3Darr[0] = dummyar2;

  dummyar[0] = 217;
  dummyar[1] = 1481;
  dummyar2[0] = dummyar;

  dummyar[0] = 217;
  dummyar[1] = 1481;
  dummyar[2] = 1250;
  dummyar2[1] = dummyar;

  dummyar[0] = 18;
  dummyar[1] = 1481;
  dummyar[2] = 1531;
  dummyar2[2] = dummyar;

  The3Darr[1] = dummyar2;
}


</script>

</head>

<body>

<script type="text/javascript">

vulars();


document.write(The3Darr[0] + "<br>");
document.write(The3Darr[1]);

</script>

</body>
</html>

De output van dit programma is:
18,1481,1531,18,1481,1531,18,1481,1531
18,1481,1531,18,1481,1531,18,1481,1531

Dus alleen de getallen uit de laatste serie komen terug, terwijl dat wanneer je tussendoor de dummyar's bekijkt, dan staan hierin wel de juiste waarden.

Kan iemand mij vertellen wat ik hier over het hoofd zie?
 
Het lijkt erop dat er bij het plaatsen van een array in een andere array enkel een referentie naar die array wordt gebruikt. Dat wil zeggen, op het moment dat je [js]dummyar2[0] = dummyar;[/js] uitvoert wordt het geheugenadres van dummyar in dummyar2[0] geplaatst. Omdat het geheugenadres van dummyar hetzelfde blijft zijn alle waarden gelijk aan de laatste waardes van dummyar.
Je kan het oplossen door na het plaatsen van dummyar in dummyar2 en van dummyar2 in The3arr er een nieuwe array van te maken:
[js]dummyar[0] = 64;
dummyar[1] = 1037;
dummyar2[0] = dummyar;

dummyar = new Array;
dummyar[0] = 36;
dummyar[1] = 1037;
dummyar[2] = 1200;
dummyar2[1] = dummyar;

dummyar = new Array;
dummyar[0] = 1;
dummyar[1] = 1037;
dummyar[2] = 1201;
dummyar2[2] = dummyar;

The3Darr[0] = dummyar2;

dummyar2 = new Array;
dummyar = new Array;
dummyar[0] = 217;
dummyar[1] = 1481;
dummyar2[0] = dummyar;

dummyar = new Array;
dummyar[0] = 217;
dummyar[1] = 1481;
dummyar[2] = 1250;
dummyar2[1] = dummyar;

dummyar = new Array;
dummyar[0] = 18;
dummyar[1] = 1481;
dummyar[2] = 1531;
dummyar2[2] = dummyar;

The3Darr[1] = dummyar2;[/js]

Al is dit een nettere manier: http://www.irt.org/script/365.htm (gevonden door te googelen op "javascript multidimensional arrays").

[edit]Overigens kan je best arrays direct met getallen vullen:
[js]var dummyar = new Array(64,1037);[/js]
Als je wilt kan je zelfs gebruik maken van naamloze arrays:
[js]The3Darr = new Array(new Array(new Array(64,1037), new Array(36,1037,1200), new Array(1,1037,1201)), new Array (new Array(217,1481), new Array(217,1481,1250), new Array(18,1481,1531)));[/js]
Deze laatste regel is precies gelijk aan bovenstaande lap code, al is het minder leesbaar.[/edit]
 
Laatst bewerkt:
Of zo: :)
[js]var a = [0,1,2,3,4,5,6,7];[/js]
Als je wilt kan je zelfs gebruik maken van naamloze arrays:
[js]The3Darr = new Array(new Array(new Array(64,1037), new Array(36,1037,1200), new Array(1,1037,1201)), new Array (new Array(217,1481), new Array(217,1481,1250), new Array(18,1481,1531)));[/js]
Dat wordt dan:
[js]The3Darr = [[[64,1037],[36,1037,1200],[1,1037,1201]],[[217,1481],[217,1481,1250],[18,1481,1531]]];[/js]

~/~

Met een object werkt het met {}
[js]smurf = {name: 'Grote smurf', color: 'blue', age: 'old', gender: 'male'};
document.write(smurf.color);[/js]
 
OK, thanks allebei. Ik was een beetje omslachtig aan het doen. Maar ik blijf het raar vinden, want je draagt de waarden toch over aan de array met een bepaald indexnummer vóórdat je de array weer veranderd? Dan zou het logisch zijn dat ze blijven staan?
De reden dat ik dit scriptje schreef was overigens voor een groter programma. In dit programma treedt dit effect ook op heb ik gisteren nog ontdekt, maar ben ik niet in staat de arrays handmatig met getallen te vullen dus kan ik die 'new Array' methoden niet gebruiken.

Ik gebruik deze 'methode' vaker, en ik heb er nooit problemen mee gehad. Ik zal wanneer ik iets meer tijd heb eens kijken wat precies het verschil is (wanneer het dan juist niet optreedt).
 
Maar ik blijf het raar vinden, want je draagt de waarden toch over aan de array met een bepaald indexnummer vóórdat je de array weer veranderd? Dan zou het logisch zijn dat ze blijven staan?

Dat zou je verwachten, maar blijkbaar worden de waardes in het geval van arrays niet gekopieerd en wordt er enkel een referentie (of pointer, zo je wilt) overgedragen.

Je kan overigens ook gebruik maken van de functie "slice" zoals wordt uitgelegd op How to copy arrays and objects in Javascript.
Je code wordt dan:
[js]dummyar[0] = 64;
dummyar[1] = 1037;
dummyar2[0] = dummyar.slice(0);[/js]
Ik heb het niet getest, maar dit zou ook moeten werken.
 
Thanks man:thumb:,
Interessant artikeltje. Daar staat precies waar ik het over heb. Weer wat geleerd!
Dat verklaard ook waarom ik wel eens heb gehad dat lokale variabelen binnen een functie veranderen wanneer je ze naar een andere functie stuurt en er daar bewerkingen mee uitvoert. Dat moet ook niet kunnen als het echt lokale variabelen zijn. Daar had ik al eens mijn hoofd over gebroken. Ook wanneer je lokale variabelen dezelfde naam geeft kun je problemen krijgen, nu moet ik in elke functie die aan een andere gekoppeld is steeds originele namen voor variabelen verzinnen en dat vind ik een beetje irritant:mad:. Een verbeterpuntje voor JavaScript vind ik.
 
Overgens kan je mischien beter met objecten in combi met arrays werken. Dan wordt je gehele code veel duidelijker. Bijvoorbeeld zoiets:

[JS]var vertex = function(x, y, z)
{
//punt in 3d space. Overgens is dit gejat van mn javascript-3d-engine.
//je kan het ook anders noemen - ligt er een beetje aan waar het voor is

this.x = x || 0;
this.y = y || 0;
this.z = z || 0;
}

var 3dpoints = [
new vertex(1, 3, 42),
new vertex(3, 2, 4),
new vertex(99, 88, 2),
new vertex(12, 1, 8)
];[/JS]
je verkrijgt je waardes dan zo:[JS]var eenVertex = 3dpoints[3];

//eenVertex is nu een 'vertex' object met properties x, y en z:
//alert(eenVertex.x); //is 8

//direct verkrijgen: 3dpoints[3].x;
//direct veranderen: 3dpoints[3].x = 1337;[/JS]
Ook wanneer je lokale variabelen dezelfde naam geeft kun je problemen krijgen, nu moet ik in elke functie die aan een andere gekoppeld is steeds originele namen voor variabelen verzinnen en dat vind ik een beetje irritant
Meh, je moet gewoon globale variabelen vermijden. Meestal zijn ze ook helemaal niet nodig, tenzij je de fout maakt om een globale variabele 'i' te noemen oid. en deze niet lokaal te defineren. (edit, =/)
 
Laatst bewerkt:
Met arrays gebeurd dat dus omdat de referentie aan de functie wordt doorgegeven:
[JS]var a = ['c','a','b'];

function ff(x) { x = x.sort();};

ff(a);

alert(a); // a,b,c[/JS]
Maar binnen een functie kun je de variabelen lokaal houden door er var voor te zetten: :)
[JS]var x = 0, y = 0;

function foo() {
var x = 1;
y = 2;
};

foo();

alert(x + ':' + y); // 0:2[/JS]
 
Maar binnen een functie kun je de variabelen lokaal houden door er var voor te zetten: :)
Ja ik weet het, maar ik heb wel eens gehad dat lokale variabelen niet echt lokaal bleven, ik kan het script alleen niet meer vinden. Ik heb juist nog geprobeerd een voorbeeld te schrijven, maar alles bleef lokaal. Het zal dan wel een fout van mezelf zijn geweest die ik over het hoofd heb gezien.

Bedankt Vegras voor de tip! Ik heb het scriptje geprobeerd. Dat is inderdaad echt veel handiger. Het werkte echter alleen wanneer ik de variabele 3dpoints veranderde in d3points, anders begint de naam natuurlijk met een cijfer en dat is niet toegestaan.
 
Status
Niet open voor verdere reacties.
Terug
Bovenaan Onderaan