niedziela, 18 września 2011

Co zmienia var?

Tematem tego posta będzie znaczenie słówka "var" występującego w JavaScript. Otóż wielu z programistów traktuje po macoszemu deklarację zmiennej, bo wszak w większości przypadków dodanie tych 3 literek nic nie zmienia. Jednak są takie momenty, gdy to słowo kluczowe decyduje o tym, czy skrypt będzie działał poprawnie, czy też będzie skrycie psuł nam krew.
Generalnie problemy z inicjacją zmiennych w JavaScript pojawiają się gdy zaczynamy tworzyć równolegle wykonywane fragmenty kodu, czyli używamy window.setTimeout() oraz window.setInterval(). Szkopuł tkwi w tym, że zmienna utworzona bez użycia "var" zachowuje się jak zmienna statyczna, a dopiero dodanie wspomnianego słówka powoduje, że będzie się ona zachowywać jak normalna zmienna lokalna.

Może jednak pokażę na przykładzie o co mi chodzi :) Przykład będzie trywialny, ot mamy dwa guziki z liczbami, z których pierwszy po kliknięciu ma dodawać "0.1" co 1/10 sekundy, a drugi ma "0.1" odejmować. Oczywiście te 0.1 nie mogą być na sztywno zapisane wewnątrz funkcji.

<script type="text/javascript">

function __countNoVar(node, finalValue)
{
delta = finalValue - Number(node.innerHTML);
delta = Number(Number(delta / 10 ).toFixed(1));

var intervalIdent = self.setInterval(function(){
	    node.innerHTML = (Number(node.innerHTML)+delta).toFixed(1);
	},100);
}

</script>
<button onclick="__countNoVar(this, 1);">0</button>
<button onclick="__countNoVar(this, -1);">0</button>
Dodaje: Odejmuje:

Jak widać jeśli pojedynczo wciśniemy guziki to działają bez problemu, ale w momencie wciśnięcia drugiego buttona nagle również pierwszy zaczyna liczyć w tym samym "kierunku" co ostatnio wciśnięty. Dzieje się tak właśnie z powodu braku "var" przed deklaracją zmiennej "delta", czego wynikiem jest używanie nowej wartości tej zmiennej tak w ostatnio utworzonym "wątku" jak i we wszystkich poprzednich utworzonych za pomocą funkcji "__countNoVar".

Wersja z "varem", która w wyglądzie różni się dosłownie 3 literami działa już jednak poprawnie:
<script type="text/javascript">

function __countWithVar(node, finalValue)
{
var delta = finalValue - Number(node.innerHTML);
delta = Number(Number(delta / 10 ).toFixed(1));

var intervalIdent = self.setInterval(function(){
	    node.innerHTML = (Number(node.innerHTML)+delta).toFixed(1);
	},100);
}

</script>
<button onclick="__countWithVar(this, 1);">0</button>
<button onclick="__countWithVar(this, -1);">0</button>
Dodaje: Odejmuje:

2 komentarze:

  1. http://download.oracle.com/docs/cd/E19957-01/816-6408-10/stmt.htm#1066604

    Nikt nie czyta manuali, przez co PHP, JS i inne 'łatwe' języki mają opinie złych, topornych, wolnych etc.

    OdpowiedzUsuń
  2. Sytuacji jednak zapewne nie poprawia fakt, że manuale są tak przejrzyste i czytelne, że hej :P

    Poza tym nie nazwałbym PHP czy JS łatwymi. One po prostu są zubożone względem pierwowzorów.

    OdpowiedzUsuń