logi sisse meist KKK

Loomulikult oskan ma seda teha vahemuutujat kasutades:

var tmp = a;
a = b;
b = tmp;

Kuid see on kuidagi väga kohmakas lahendus. Kui ma seda kasutan, siis kirjutan alati juurde kommentaari selgitamaks, mis toimub. Tahaks seda väärtuste vahetamise operatsiooni kuidagi abstraktsemalt esitada. Tahaks kirjutada midagi sellist:

swap(a, b);

Aga sellist swap funktsiooni pole minu teada võimalik JavaScriptis kirjutada. Või äkki siiski on? Või on mingeid alternatiivseid skeeme kuidas seda operatsiooni sooritada?

küsitud Nov 05 '09 at 20:27

Rene%20Saarsoo's gravatar image

Rene Saarsoo ♦♦
1.1k101121


Ecmascript 5. versioonis on selline konstruktsioon juba sisse ehitatud, mulle saadaolevatest brauseritest oskab seda süntaksi esialgu ainult Firefox 3.6b1.

a = 1;
b = 10;
[a, b] = [b, a];
alert('a = ' + a + ' b = ' + b);

Tulemus: a = 10 b = 1

Nüüd on ainult aja küsimus, et millal see teistesse brauseritesse jõuab.

link

vastatud Nov 06 '09 at 17:06

Anti%20Veeranna's gravatar image

Anti Veeranna
2063

Antile siis vastuseks. Firefox 3.5.4

>>> a = 1; b = 10; [a, b] = [b, a]; console.log('a = ' + a + ' b = ' + b);
a = 10 b = 1

Seega tundub, et toimib juba praegu FF puhul. :)

link

vastatud Nov 10 '09 at 18:16

Kaspar%20Kalve's gravatar image

Kaspar Kalve
133118

Kusjuures toimib ka Firefox 3.0 ja Opera 9.

(Nov 10 '09 at 20:47) Rene Saarsoo ♦♦

Ma olen küll mitu aastat hiljaks jäänud, kuid panen oma lahenduse ikkagi kirja.

Faktitäpsuse huvides mainin esiteks ära, et Anti poolt viidatud destructuring assignment ei ole osa Ecma-262 v5 standardist ning esimene seda toetanud brauser polnud Firefox 3, vaid hoopis Firefox 2 (tugi saabus koos JavaScripti versiooniga 1.7). Tegu on osaga lõpetamata jäänud Ecma-262 v4 osaga ning standardiks saab tõenäoliselt alles kaugel tulevikus v6 (Harmony) osana.

Minu one-liner näeks välja aga nii

a = 5;
b = 6;

a = [b,b=a][0]

Tegu pole rangelt võttes päris puhta tehtega, kuna kasutusel on anonüümne massiivivärtus.

link

vastatud Apr 09 '11 at 10:10

Andris's gravatar image

Andris
2553310

Arvatavasti tuleb leppida asjaoluga, et tavaliste muutujate väärtusi niisama lihtsalt ümber vahetada ei saa. Ehk aga õnnestub meil struktureerida oma kood ümber nii, et asjad mille väärtusi vahetatakse pole mitte muutujad vaid mingi objekti koostisosad.

Variant 1: Massiivid

Massiivis kahe elemendi väärtuste vahetamiseks kasutatakse tavaliselt samuti vahemuutuja abi:

// vahetame väärtused "foo" ja "zap"
var arr = ["foo", "bar", "baz", "zap"];
var tmp = arr[0];
arr[0] = arr[3];
arr[3] = tmp;

Kuid massiivile võime kergesti defineerida elementide vahetamise meetodi:

Array.prototype.swap = function(a, b) {
  var tmp = this[a];
  this[a] = this[b];
  this[b] = tmp;
};

Ning koodis saab nüüd kirjutada juba üpris arusaadavalt:

// vahetame väärtused "foo" ja "zap"
var arr = ["foo", "bar", "baz", "zap"];
arr.swap(0, 3);

Variant 2: Väärtuspaarid

Sageli on vahetamise operatsiooni tarvis muutujate puhul, mis moodustavad teatud sorti paari. Näiteks programm, mis küsib kasutajalt isiku sünni- ja surma-aasta ning kui surm on enne sündi, siis automaatselt vahetab järjekorra:

var born = prompt("Sisesta sünniaasta");
var dead = prompt("Sisesta surma-aasta");
if (born > dead) {
  var tmp = born;
  born = dead;
  dead = tmp;
}
doSomething(born, dead);

Muutujad born ja dead moodustavad siin teatud loogilise paari. Nad luuakse koos, neid kasutatakse alati koos, nende teed ei lähe kunagi lahku. Seega võiksime nad tegelikult viiagi ühte objekti kokku:

var lifespan = {
  born: prompt("Sisesta sünniaasta"),
  dead: prompt("Sisesta surma-aasta")
};
if (lifespan.born > lifespan.dead) {
  var tmp = lifespan.born;
  lifespan.born = lifespan.dead;
  lifespan.dead = tmp;
}
doSomething(lifespan.born, lifespan.dead);

Nüüd aga seisab meie ees juba teostatavam ülesanne: objekti väljade väärtuste vahetamine. Selleks saame kergesti kirjutada funktsiooni:

function swap(obj, field1, field2) {
  var tmp = obj[field1];
  obj[field1] = obj[field2];
  obj[field2] = tmp;
}

Ning oma koodis seda kasutada:

var lifespan = {
  born: prompt("Sisesta sünniaasta"),
  dead: prompt("Sisesta surma-aasta")
};
if (lifespan.born > lifespan.dead) {
  swap(lifespan, "born", "dead");
}
doSomething(lifespan.born, lifespan.dead);

Need kaks varianti paistavad katvat päris suure hulga juhtudest kus ma tunnen, et mul vahetamise operatsiooni tarvis oleks.

link

vastatud Nov 05 '09 at 21:24

Rene%20Saarsoo's gravatar image

Rene Saarsoo ♦♦
1.1k101121

edited Nov 05 '09 at 22:44

Saan aru, et probleem on selles, et Javascriptis puudub pass-by-reference? Võib-olla saab seda emuleerida mitme tagastatava väärtusega. Ma pole eriline Javascripti kunn, aga PHP-s on olemas selline käsklus nagu list(), mis omistab massiivi väärtused parameetritena antud muutujatele. Ehk siis muutujad vahetab järgmine käsklus:

list($a,$b) = array($b,$a);

Iseasi on see, kas see just arusaadavam on kui abimuutuja kasutamine. Abimuutuja on ju klassika, programmeerimise A ja B :).

link

vastatud Nov 05 '09 at 21:03

Tambet%20Matiisen's gravatar image

Tambet Matiisen ♦♦
77791125

Olen sellest võimalusest PHP puhul teadlik. Kahjuks JavaScriptis list()-le vastav konstruktsioon puudub.

(Nov 05 '09 at 21:11) Rene Saarsoo ♦♦

Numbrilisi väärtusi saab teoreetiliselt vahetada ka järgnevalt, kuigi kas see on muidugi otstarbekas.

var a = 10;
var b = 20;

a = a + b;
b = a - b;
a = a - b;

// a = 20 ja b = 10
link

vastatud Nov 06 '09 at 13:20

Harri%20Siirak's gravatar image

Harri Siirak
6613

Mnjah, koodi see kindlasti selgemaks ei tee, pigem vastupidi.

(Nov 06 '09 at 14:38) Rene Saarsoo ♦♦

Pealegi, mis siis saab, kui ühel ilusal päeval on a ja b mitte arvud vaid arve sisaldavad stringid?

(Aug 03 '11 at 22:53) dig

Põhimõtteliselt saab ka nii:

function swap(v1, v2) {
        var t;
        eval('t =' + v1 + ';' + v1 + ' = ' + v2 + ';' + v2 + ' = t;');
}

// Näide
var a = 3;
var b = 4;

swap('a','b');
alert('a = ' + a + ', b=' + b);

On küll natuke kole, aga kui eesmärk on lihtsalt koodi veidi lühemaks teha, ehk kõlbaks. Nagu Rene tähele pani, ei tööta see variant skoopimisega hästi, ning selle vastu aitaks minu arust ainult veel koledam variant:

function swap(v1, v2) {
        return ('t =' + v1 + ';' + v1 + ' = ' + v2 + ';' + v2 + ' = t;');
}

// Näide
var a = 3;
var b = 4;

eval(swap('a','b'));

Sellel on nüüd omamoodi ajutise muutuja "t" olemasolu probleem, mida saaks ka häkiga lahendada, mis teeks seda asja veel koledamaks, jne...

link

vastatud Nov 10 '09 at 11:21

kt's gravatar image

kt ♦♦
112228

edited Nov 11 '09 at 09:56

Vastupidi: JavaScripti skoopimine justnimelt EI garanteeri seda. Kui sa kutsud seda swap() funktsiooni välja mõne teise funktsiooni sees kohalike muutujate nimedega, siis üritab swap() vahetada hoopis kahte samanimelist globaalset muutujat.

(Nov 10 '09 at 20:32) Rene Saarsoo ♦♦

Oh jah, see eval'i skoopimine on tõepoolest puhtalt staatiline, mis tähendab et seda omab mõtet ainult sealkohas välja kutsuda kus muutujaid vahetada peab. Parandasin näidet. Oleks JSil mingi ilus viis dünaamiliselt lokaalsele skoobile ligi pääseda...

(Nov 11 '09 at 10:00) kt ♦♦

See eval(swap('a','b')) variant on kaval. Muutuja t tuleks ümber nimetada mingi ebatõenäolise nimega ja kindlasti lisada ette var - see peaks suuremalt jaolt kindlustama, et mõnda kohalikku muutujat üle ei kirjutata.

Iseasi on muidugi see, et eval-i kasutamine raskendab JavaScripti minimiseerijate tööd - selle funktsiooni muutujate nimesid, milles eval-i kasutatakse, ei saa lühendada.

(Nov 11 '09 at 13:02) Rene Saarsoo ♦♦
Sinu vastus
lülita eelvaade

Jälgi seda küsimust

By Email:

Pärast sisselogimist saad tellida muudatuse teavitusi siit

By RSS:

Answers

Answers and Comments

Markdown Basics

  • *kaldkiri* või __kaldkiri__
  • **paks kiri** või __paks kiri__
  • link:[tekst](http://url.com/ "pealkiri")
  • pilt?![alt tekst](/path/img.jpg "pealkiri")
  • nummerdatud nimekiri: 1. Foo 2. Bar
  • to add a line break simply add two spaces to where you would like the new line to be.
  • põhilised HTML märgendid on samuti toetatud

Pinu tööpakkumised

kõik pakkumised »

Küsimuse sildid:

×18
×1
×1

küsitud: Nov 05 '09 at 20:27

nähtud: 4,120 korda

viimati uuendatud: Aug 03 '11 at 22:53

Litsents: Creative Commons Attribution License | Kontakt: info@pinu.ee