Kirjautuminen

Haku

Tehtävät

Keskustelu: Nettisivujen teko: JS OOP timerin teko >:|

Sivun loppuun

Matso [06.08.2008 20:10:07]

#

Miten hemmetis tehään timeri JS luokan sisään?

function Timer(){
	var millis = 20;

	this.tick = tick;
	this.start = start

	function start(){
		//Ei toimi
		setInterval("this.tick();", millis);

		//Toimii
		this.tick(); this.tick(); this.tick(); this.tick(); this.tick(); this.tick(); this.tick();
	}

	function tick(){
		//tiktaktoe
	}
}

Toi ei tietty toimi ku se kutsuu jtn ulkosta funktiota "setInterval()" ja antaa sille parametrina ton kutsuttavan metodin ym.. mut saisko sen sit jotenki toimimaan?

Startti [06.08.2008 20:34:56]

#

Menisiköhän näillä pienillä muutoksilla?

<html>
<head>
<script type="text/javascript">
function Timer(){
    var millis = 1000;
    this.tick = tick;
    this.start = start;

    function start(){

        //Ei toimi
        setInterval(this.tick, this.millis);


        //Toimii
        //this.tick(); this.tick(); this.tick(); this.tick(); this.tick(); this.tick(); this.tick();
    }

    function tick(){
        //tiktaktoe
        document.write("hou<br>");

    }

}
function go() {
	var testi = new Timer();
	testi.start();
}
</script>
</head>
<body onload="go()">

</body>
</html>

Testasin Operalla ja Safarilla.

Pekka Karjalainen [06.08.2008 20:35:24]

#

EDIT: Hidas, mutta eri tapa.

Älä pistä koodia lainausmerkkeihin, paitsi ehkä body-tägin onload kentässä. Käytä nimetöntä funktiota. Katso, että olet määritellyt nimen ennen kuin viittaat siihen.

<html>
<script type="text/javascript">

function Timer(mark, millis) {
  var elem = document.getElementById("ruksit")
  var count = 0;

  function tick (tgt) {
    tgt.value += mark;
    if (++count == 10) {
      count = 0;
      tgt.value += '\n';
    }
  }

  function start () {
    setInterval (function() { tick(elem); }, millis);
  }

  this.tick = tick;
  this.start = start;
  this.count = count;
}

function init () {
  var timer=new Timer('x',100);
  timer.start();
  var timer2=new Timer('X',400);
  timer2.start();
}

</script>
<body onload="init();">
<textarea id="ruksit" rows="20" cols="60"></textarea>
</body>
</html>

Suotavaa on myös käyttää erillisiä js-tiedostoja. Esimerkin vuoksi yhdessä pompsissa. Toimi mun Operalla.

Merri [06.08.2008 20:48:05]

#

Vielä erilainen, kommentoitu versio:

<html>
	<head>
		<title></title>
		<script type="text/javascript">
function Timer() {
	// arvot jotka ovat paikallisia tälle objektille
	var timer = null;

	// julkisia muuttujia
	this.function = null;
	this.interval = 0;

	this.start = function () {
		// tuhoa aiempi asetus jos sellainen on, emme halua monta päällekkäistä kutsua
		if(timer != null) { clearInterval(timer); }
		// tarkista aikaväli
		if( (this.interval > 0) && (typeof this.function == 'function') ) {
			// nyt luo kutsu funktioon
			timer = setInterval(this.function, this.interval);
			// palautetaan true onnistuessa
			return true;
		}
	}

	this.stop = function () {
		// onko alustettu?
		if(timer != null) {
			// puhdista
			clearInterval(timer);
			// nollaa timer
			timer = null;
			// palautetaan true onnistuessa
			return true;
		}
	}
}

// ulkoinen testifunktio jota kutsumme
function tick() {
	// emme voi käyttää += koska se luokiteltaisiin merkkijonolisäykseksi
	document.getElementById('ticker').innerHTML-=-1;
}

// toinen testifunktio
function tick2() {
	document.getElementById('ticker2').innerHTML-=1;
}

// luo objektit joita voimme kutsua mistä vaan
var t = new Timer();
var t2 = new Timer();
// pistä asetuksia
t.function = tick;
t.interval = 500;
t2.function = tick2;
t2.interval = 100;

		</script>
	</head>
	<body>
		<div id="ticker">0</div>
		<p><input type="button" onclick="t.start()" value="Start"></p>
		<p><input type="button" onclick="t.stop()" value="Stop"></p>

		<div id="ticker2">0</div>
		<p><input type="button" onclick="t2.start()" value="Start"></p>
		<p><input type="button" onclick="t2.stop()" value="Stop"></p>
	</body>
</html>

Matso [06.08.2008 20:52:31]

#

Aha joo se toimiki siis ihan täl muutoksella:

setInterval("this.tick()", millis);
->
setInterval(this.tick, millis);

Mut ongelmana on, ku pitäs päästä käsiks niihin luokan muuttujiin, siis muutenki ku vaan antaa ne parametrina. Mites muutan tuolta tickin sisältä nyt noita luokan ominaisuuksia?

function Timer(){

    this.foo = 1;

    //...
    function tick(){
        this.foo += 2;
    }
    //...
}

Tässä se ongelma :/


Btw. Te jaksatte tota koodia vääntää, tajusin jo ekasta ton ensimmäisen ongelman :D

Merri [06.08.2008 21:37:29]

#

Millaisen objektin yrität nyt rakentaa? Ainakin se näyttäisi siltä, että se olisi vain yhtä tiettyä hommaa tekevä objekti. Omassa esimerkissäni (jonka jonku tovi sitten päivitin) oleva objekti on yleiskäyttöisempi kapistus.


Lisäksi koodi jonka postitin jo aiemmin ei pyrkinyt vastaamaan pelkästään ensimmäiseen kysymykseesi, vaan huomioimaan useita eri asioita jotka ongelmaasi liittyvät. Päivitetty koodi muuttaa objektia aavistuksen oliomaisemmaksi (tosin nyt ongelmaksi jää vielä se, että miten voi huomioida intervalin muutoksen).


Muoks!
En voi enää muokata koodia, joten lisäystä tähän:

<html>
	<head>
		<title></title>
		<script type="text/javascript">
function Timer() {
	// arvot jotka ovat paikallisia tälle objektille
	var timer = null;

	// julkisia muuttujia
	this.function = null;
	this.interval = 0;

	this.start = function () {
		// tuhoa aiempi asetus jos sellainen on, emme halua monta päällekkäistä kutsua
		if(timer != null) { clearInterval(timer); }
		// tarkista aikaväli
		if( (this.interval > 0) && (typeof this.function == 'function') ) {
			// nyt luo kutsu funktioon
			timer = setInterval(this.function, this.interval);
			// palautetaan true onnistuessa
			return true;
		}
	}

	this.stop = function () {
		// onko alustettu?
		if(timer != null) {
			// puhdista
			clearInterval(timer);
			// nollaa timer
			timer = null;
			// palautetaan true onnistuessa
			return true;
		}
	}
}

// ulkoinen testifunktio jota kutsumme
function tick(foo) {
	if(typeof tick.foo == 'undefined') tick.foo = 0;
	tick.foo += 1;
	document.getElementById('ticker').innerHTML = tick.foo;
}

// toinen testifunktio
function tick2(foo) {
	if(typeof tick2.foo == 'undefined') tick2.foo = 0;
	tick2.foo -= 1;
	document.getElementById('ticker2').innerHTML = tick2.foo;
}

// luo objektit joita voimme kutsua mistä vaan
var t = new Timer();
var t2 = new Timer();
// pistä asetuksia
t.function = tick;
t.interval = 500;
t2.function = tick2;
t2.interval = 100;

		</script>
	</head>
	<body>
		<div id="ticker">0</div>
		<p><input type="button" onclick="t.start()" value="Start"></p>
		<p><input type="button" onclick="t.stop();alert(tick.foo);" value="Stop"></p>

		<div id="ticker2">0</div>
		<p><input type="button" onclick="t2.start()" value="Start"></p>
		<p><input type="button" onclick="t2.stop();alert(tick2.foo);" value="Stop"></p>
	</body>
</html>

Pekka Karjalainen [07.08.2008 08:48:35]

#

"Luokan ominaisuuksia" voi käyttää ihan suoraan sisemmissä funktioissa, koska ne näkyvät sinne. Ei tähän ole keksitty mitään mutkia, vaan niitä voi vain asettaa ja lukea. Tässä esimerkki, missä ajastimen voi käynnistää ja pysäyttää, ja jokaisella ajastimella on sisällä timerId-muuttuja, joka ei näy maailmalle.

Voit kokeilla, että näitä kahta erillistä ajastinta voi erikseen käynnistää ja pysäyttää napeista useita kertoja. Se vakuuttanee skeptisimmän JS-koodarinkin, että molemmilla on oma sisäinen timerId.

<html>
<script type="text/javascript">

var timers = [];

function Timer(elem, millis, action) {

  var timerId = undefined;

  function start () {
    if (timerId) return;
    timerId = setInterval(function() { action(elem); }, millis);
  }

  function stop () {
    if (timerId) {
      clearInterval(timerId);
      timerId = undefined;
    }
  }

  this.start=start;
  this.stop=stop;
}

function init () {
  var elem = document.getElementById("ruksit");
  timers.push(new Timer (elem, 100,
    function(tgt) { tgt.value += 'X'; }));
  timers.push(new Timer (elem, 1000,
    function(tgt) { tgt.value += '.\n'; }));
}

</script>
<body onload="init();">
<textarea id="ruksit" rows="20" cols="60"></textarea><br>
<button onclick="timers[0].start();">Ekan käynnistys</button>
<button onclick="timers[0].stop();">Ekan pysäytys </button>
<button onclick="timers[1].start();">Tokan käynnistys</button>
<button onclick="timers[1].stop();">Tokan pysäytys</button>
</body>
</html>

JavaScriptissä muuttujat elävät niin kauan kuin niihin on viittaus jossakin elävässä objektissa, esimerkiksi funktiossa.

P.S: Toisin kuin ylemmässä aivopieru-koodissa, nuo this-muuttujat kannattaa asettaa vain, jos ne kuuluvut olion julkiseen rajapintaan. Kapseloinnista lienee kyse. Kun jokin on kapseloinut minun viimeisen aivosoluni, niin enhän minä osaa :)

Metabolix [07.08.2008 15:34:07]

#

Koodi tulee suoraan päästä, mutta ajatus on testattu ja toimiva. Oikeastaan kyse on lähes samasta kuin yllä, mutta kutsu on eristetty ajastinluokasta (jota ei tässä edes ole).

// Taulukko kaikille kutsuobjekteille
var kutsut = new Array();

// Kutsuobjekti
function kutsu(objekti, metodi) {
  // Tiedot talteen
  this.objekti = objekti;
  this.metodi = metodi;

  // Lisätään taulukkoon
  this.index = kutsut.length;
  kutsut.push(this);

  // Kutsuntafunktio
  this.call = function () {
    this.objekti[this.metodi]();
  }

  // Funktio, joka luo tästä staattisen kutsun
  this.getStaticCall = function () {
    var func;
    // Luodaan funktio, joka viittaa globaaliin kutsutaulukkoon
    eval("func = function() {kutsut[" + this.index + "].call();};");
    return func;
  }
}

function objekti() {
  this.x = 1;
  this.nosta = function () {
    this.x += 1;
    alert("x = " + this.x);
  }
}

var o1 = new objekti();
var o2 = new objekti();
var k1 = new kutsu(o1, "nosta");
var k2 = new kutsu(o2, "nosta");

// Pannaan kutsu menemään
setInterval(k1.getStaticCall(), 3000);
setInterval(k2.getStaticCall(), 4000);

Sivun alkuun

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta