JavaScript
Børre Stenseth
Moduler>JavaScript>Litt om språket

Litt om JavaScript

Hva
Noen egenskaper ved Javascript

Dette er ikke noe forsøk på en mer eller mindre komplett lærebok i eller beskrivelse av JavaScript. Hensikten er bare å peke på noen mekanismer som erfaringsmessig er litt vanskelige å få tak og som skaper litt forvirring.

Denne modulen fokuserer på selve språket og trekker ikke inn objekter eller mekanismer nyttet til omgivelsene som browser og document.

Variable

Globale variable i Javascript er rett fram og enkelt. Alt vi definerer utenom funksjoner er tilgjengelig i alle funksjoner. Et enkelt eksempel, myNumber er global:

var myNumber;

function setMyNumber(nr)
{
    myNumber=nr;
}

function showMyNumber()
{
    alert('My number is: '+myNumber);
}

Ved å bruke var foran en variable sikrer vi oss at variabelen er definert for den blokken (scope) vi er i. Det er en god vane å bruke var for å unngå å bruke globale variable med samme navn ved en misforståelse.

var myNumber=123;

function setMyNumber(nr)
{
    myNumber=nr;
}

function showMyNumber()
{
    var myNumber=13;
    setMyNumber(24);
    // will allways display 13
    alert('My number is: '+myNumber);
}

Tekst

Mye av det vi ønsker å handtere i JavaScript er typisk tekst. Tekst, string, er en klasse i Javascript. Det finnes en del standardfunksjoner for å arbeide med stringer. Siden JavaScript ikke har typer så må vi selv sørge for at det objektet vi anvender metoden på er en string.

 S='Hallo alle sammen';
  • c=S.charAt(0)
    -->c:'H'
    
  • L=S.length()
    -->L:17
    
  • i=S.indexOf('a')
    -->i:1
    
  • i=S.lastIndexOf('a')
    -->i:12
    
  • ordliste=S.split(' ')
    -->ordlist[0]:'Hallo'
       ordlist[1]:'alle'
       ordlist[2]:'sammen'
       ordlist.length: 3
    
  • T=S.substring(6,9)
    -->T:'alle'
    T=S.substring(10)
    -->T:'sammen'
    
  • t=S.toLowerCase()
    -->t: 'hallo alle sammen'
    
  • T=S.toUpperCase()
    -->T: 'HALLO ALLE SAMMEN'
    

Vi kan dessuten slå sammen, concatenere, stringer med en enkel +. Dette er fleksibelt men litt farlig siden JavaScript ikke har typer og samtidig er veldig imøtekommende med andre ting en stringer.

a='Hallo';
b='alle';
i=3
j=4
T=a+b;
-->T:'Halloalle'
T=a+' '+b+' sammen';
-->T:'Hallo alle sammen'
T=a+' 'b+' '+i;
-->T:'Hallo alle 3'
T=a+' 'b+' '+i+j;
-->T:'Hallo alle 34'
T=a+' 'b+' '+(i+j);
-->T:'Hallo alle 7'

String har metodene

  anchor,
  big,
  blink,
  bold,
  charAt,
  fixed,
  fontColor,
  fontSize,
  indexOf,
  italics,
  lastIndexOf,
  link,
  small,
  split,
  strike,
  sub,
  substring,
  sup,
  toLowerCase,
  toUpperCase,
  replace

replace krever litt spesiell oppmerksomhet.

  var T='alle forstår alle';
  T=T.replace('alle','noen');
  -->T:'noen forstår alle'
 

Altså: bare en replace, den første forekomsten av alle byttes. For å få til en global erstatning, alle forekomster, kan vi skrive:

  var T='alle forstår alle';
  T=T.replace(/alle/g,'noen');
  -->T:'noen forstår noen'
 

Vi har da brukt regulær uttrykk, vi har skrevet / is tedet for '. g angir at vi vil ha global replace. Mer om regulære uttrykk i JavaScript i [1] .

Utvidelser

Det er lett å lage utvidelser, flere metoder, i en string. String som alle andre klasser har en superklasse som betegnes som prototype. Dersom vi gir egenskaper til String.prototype, vil disse egenskapene arves av alle String-objekter. En slik egenskap kan være en funksjon.

Noen metoder som finnes i en del andre språk er metoder for å fjerne blanke i begge ender av en string og sjekke starten og slutten på en string. Det finnes uttallige eksempler på slike implementasjoner. En enkel variant er slik:

String.prototype.trimBoth = function() 
{ return this.replace(/^\s+|\s+$/g, ''); }

String.prototype.trimLeft = function() 
{ return this.replace(/^\s+/,"");}

String.prototype.trimRight = function() 
{ return this.replace(/\s+$/,"");}

String.prototype.startsWith = function(str)
{return (this.match("^"+str)==str)}        

String.prototype.endsWith = function(str)
{return (this.match(str+"$")==str)}

Mer om 'prototype' i modulen Egne Objekter

Dersom vi kjører koden over, vil vi senere kunne skrive:

  var T='  du store alpakka  ';
  T=T.trimBoth();
  T.startsWith("du")
  -->true
  T.endsWith("alpakka")
  -->true
  

Tall

Vi har ofte behov for å konvertere fra tekst (string) til tall (integer eller float). JavaScript har to egnede funksjoner: parseInt() og parseFloat()

parseFloat(string)

Funksjonen tar en string som input og produserer et flytetall.

 	parseFloat('2.67') -> 2.67
 	parseFloat('2.67 meter') -> 2.67
 	parseFloat('0.2e6') -> 200000
 	parseFloat('jensen') -> NaN

Merk at ikke-numeriske verdier på slutten av en god begynnelse ignoreres, og at når funksjonen feiler returnerer den verdien NaN ("Not-a-Number"). Noen nettlesere kan levere 0 istedet for NaN. Vi kan teste om en verdi er NaN med funksjonen: isNaN(verdi), se nedenfor.

Du kan forsøke deg fram med noen konverteringer nedenfor (skriv inn en string og trykk på likhetstegnet)

parseFloat(' ') ?

parseInt(string[,base])

Funksjonen tar en string som input og produserer et heltall. Vi kan dessuten angi hvilket tallsystem vi vil ha svaret i. 10-tallsystemet er default.

 	parseInt('12') -> 12
 	parseInt('12.4') -> 12
 	parseInt('012') -> 10 
 	(verdier som starter på 0 tolkes som oktale)
 	parseInt('12',8) -> 10
 	parseInt('0x12') -> 18 
 	(verdier som starter på 0x tolkes som hexadesimale)
 	parseInt('12',16) -> 18
 	parseInt('jensen') -> NaN
 	parseInt('14jens',5) -> 9

Merk igjen at ikke-numeriske verdier på slutten av en god begynnelse ignoreres, og at når funksjonen feiler returnerer den verdien NaN. Vi kan teste om en verdi er Nan med funksjonen: isNaN(verdi), se nedenfor. Noen nettlesere kan levere 0 istedet for NaN.

Du kan forsøke deg fram med noen konverteringer nedenfor (skriv inn en string og eventuelt tallsystemet du vil bruke og trykk på likhetstegnet)

parseInt(' ', ) ?

isNaN(verdi)

isNaN står for "Not-a-Number". Denne funksjonen kan brukes for å teste om en verdi er et gyldig tall, flytetall eller heltall. Vi kan teste resultatet av en divisjon, for å se om vi har fått divisjon med null, eller vi kan teste resultatet av en konvertering som vist overfor.

Merk at parameteren til isNaN er en verdi, altså hva som helst, og resultatet er en boolsk verdi (true eller false). Det går dårlig å teste på om resultatet av en konvertering er lik stringen 'NaN'.

Begge de situasjonene vi har nevnt ovenfor, divisjon med 0 og mislykket konvertering, er situasjoner som vi i andre språk vanligvis ville identifisert ved unntaksprogrammering.

Array

Array er en klasse i Javascript. Arrayer i Javascript er fleksible. Det innebærer at vi kan ekspandere en array med å tilordne verdier. Noen eksempler på initialisering av array.

A=new Array('Ole','Hans','Peder')

A=new Array();
A=['Ole','Hans','Peder'];

A=new Array();
A[0]='Ole';A[1]='Hans';A[2]='Peder';

Merk at:

A=new Array();
A[0]='Ole';A[1]='Hans';A[2]='Peder';
A[4]='Marit';

Vil gi innholdet: Ole, Hans, Peder, undefined, Marit
Arrayen har altså fått tilstrekkelig mange elementer, men ett av dem er ikke definert.

Array har egenskapen length, og metodene: join, reverse, shift, pop, push og sort

Metoden sort krever en kommentar. Hvis vi skriver følgende:

Liste=new Array(1,3,5,2,4,11,33);
Liste.sort();

Ender vi med følgende rekkefølge:
1,11,2,3,33,4,5
altså som om heltallene skulle vært stringer. Dersom vi ønsker å sortere numerisk kan vi gjøre slik:

function sequenceNumber(a,b)
{
  return a - b
}
Liste=new Array(1,3,5,2,4,11,33);
Liste.sort(sequenceNumber);

Dette gir oss:
1,2,3,4,5,11,33

Anta følgende oppsett:

var list1=[];
list1.push('jens');
list1.push('ole');
var list2=new Array('kari','marit');
var list3=['pedersen','hansen']
var list=null;

Følgende:

list=list1.concat(list2,list3);
var T=list.join(',');

vil gi T: jens,ole,kari,marit,pedersen,hansen

Hvis vi fortsetter med

list=list.reverse();
var T=list.join(',');

får vi T:hansen,pedersen,marit,kari,ole,jens

Ddrsom vi ønsker å randomisere en array, kan vi gjøre dette på flere måter. F.eks. slik:


function shuffle(list) {
  var i, j, t;
  for (i = 1; i < list.length; i++) {
	j = Math.floor(Math.random()*(1+i));  // j in [0..i]
	if (j != i) {
	  //swap
	  t = list[i];          
	  list[i] = list[j];
	  list[j] = t;
	}
  }
}

Tidsstyring

Vi kan lett lage tidsbestemte begivenheter i JavaScript, ved å sette en forsinkelse på kall til en funksjon, setTimeout(minfunksjon,tidsforsinkelse). Tidsforsinkelsen i millisekunder.

0

HTMLkoden er slik:

<button onclick="Count()">Start en teller</button>
<div style="font-size:24px" id="counter">0
</div>

JavaScriptkoden er slik (her bruker vi document-objektet):

function Count()
{
	elt=document.getElementById('counter');
	x=parseInt(elt.innerHTML);
	elt.innerHTML=(x+1)%10000;
	setTimeout(Count,500);
}

Merk at telleren øker tempo hvis vi klikker flere ganger. Du ser kanskje hvorfor ?

Vi har ikke laget noen mekanisme for å stoppe telleren. Vi har selvsagt mulighet for dette, enten ved å sette et egetdefinert flag eller ved å bruke funksjonen: clearTimeout. Denne funksjonen og funksjonene setInterval og clearInterval forutsetter at vi tar vare på en returverdi, en timer ID, fra setTimeout.

Tid og dato

JavaScript har en nyttig klasse som heter Date. Dette kan hjelpe oss å holde styr på ukedager, tidsdifferanser osv. Nedenfor finner du et eksempel på bruk av noen funksjoner i Date:

klikk her

Skriptet er slik:

function visFullTime(eltID){
  var today=new Date();
  var T=prettyTime(today)+'  '+norwegianDate(today);
  document.getElementById(eltID).innerHTML=T;
}


function prettyTime(dt){
  var h=dt.getHours();
  var m=dt.getMinutes();
  var s=dt.getSeconds();
  var hs=''+h;
  var ms=''+m;
  var ss=''+s;
  if (h <10) hs='0'+hs;
  if (m <10) ms='0'+ms;
  if (s <10) ss='0'+ss;
  return hs+':'+ms+':'+ss;
}


function norwegianDate(dt){
  var weekday=new Array("Søndag","Mandag","Tirsdag",
                        "Onsdag","Torsdag","Fredag","Lørdag");
  var monthName=new Array("Januar","Februar","Mars","April",
                          "Mai","Juni","Juli","August",
                          "September","Oktober","November","Desember");
  return weekday[dt.getDay()]+' '+dt.getDate()+
         '. '+monthName[dt.getMonth()]+' '+dt.getFullYear();
}

Date har metodene: getDate,

  getDay,
  getHours,
  getMinutes,
  getMonth,
  getSeconds,
  getTime,
  getTimeZoneoffset,
  getYear,
  parse,
  prototype,
  setDate,
  setHours,
  setMinutes,
  setMonth,
  setSeconds,
  setTime,
  setYear,
  toGMTString,
  toLocaleString,
  UTC

Math

Vi finner det vi forventer i objektet math. De vi oftest trenger er kanskje:

  abs(x)
  sin(x),cos(x),tan(x)
  max(x,y),min(x,y)
  ceil(x),floor(x),round(x)
  pow(x,y),exp(x),sqrt(x),log(x)
  random()

random-funksjonen returnerer et flytetall mellom 0 og 1. Hvis vi vil ha en funksjon som returnerer et heltall mellom to grenser a <= t <=b kan vi skrive en slik funksjon:

function randint(a,b){
  return (Math.floor(Math.random()*(b-a+1)))+a;
}

Testen ser slik ut:

function doRandomTest(n,a,b){
  T=''+n+ ' tester av randint('+a+','+b+'): ';
  for (var ix=0;ix < n; ix++)
    T=T+' '+randint(a,b);
  document.getElementById('randomresult').innerHTML=T;
}

function randint(a,b){
  return (Math.floor(Math.random()*(b-a+1)))+a;
}

Du kan inspisere en grafisk framstilling av en test av algoritmen:

Test randomhttp://www.it.hiof.no/~borres/dw/joms/histogram.html

null og undefined

Javascript definerer to konstanter, verdier, null og undefined.

null tilsvarer det vi kjenner fra andre språk, null i Java, None i Python, og sier oss at en referanse referer til ingenting. null oppfører seg som false i tester og vi kan skrive:

function test1()
{
   var T=null;
   if(T)
    alert(''+T.length);
   else
    alert('T er ikke satt');
}

test her

Dersom vi hadde forsøkt å spørre etter T.length når T er null ville vi fått feil.

undefined har en litt annen oppførsel. undefined gir ikke nødvendigvis feil, men rapporterer seg selv som, nettopp: "undefined". Vi kan skrive, der string objekterer altså ikke har noen egenskap value:

function test2()
{
   var T='something';
   alert(T.value);
}

test her

undefined oppfører seg også som false i tester og vi kan skrive:

function test3()
{
   var T='something';
   if(T.value)
    alert(T.value);
   else
    alert('T\'s value is undefined');
}

test her

Det betyr at vi kan lage følgende konstruksjon:

function arrayTester()
{
  liste=new Array();
  liste[0]='hans';
  liste[1]='jens';
  liste[4]='kari';
  var S=''
  for(var ix=0;ix<liste.length;ix++)
    if(liste[ix])
      S+=liste[ix]+'\n';
  alert(S);
}

test her

Det betyr også at vi kan bruke denne mekanismen til å teste om en nettleser har de egenskapene vi er ute etter. F.eks. er en typisk kodesnutt fra en AJAX-request slik:

function establishRequest()
{
    var theRequest=null;
    if (window.XMLHttpRequest)
        theRequest = new XMLHttpRequest();
    else if (window.ActiveXObject)
    {
        try { theRequest = new ActiveXObject("Msxml2.XMLHTTP");
        }
        catch(e) {
            try {theRequest= new ActiveXObject("Microsoft.XMLHTTP");
            }
            catch(e) {theRequest=null;}
        }
    }
    else
        theRequest=null;
    return theRequest;
}

Her bruker vi en kombinasjon av tester på undefined (window.XMLHttpRequest og window.ActiveXObject) og try - catch. Mer om AJAX i modulen AJAX

Referanser
  1. JavaScript,Pattern Matching and Regular Expressionswebreference.comwww.webreference.com/js/column5/14-03-2010
Vedlikehold

B.Stenseth revidert mai 2011

(Velkommen) Moduler>JavaScript>Litt om språket (Objekter)