En Javascript-primer
For at alle skal kunne ha glede av årets JavaScript-kalender starter vi med en rask gjennomgang av grunnleggende syntaks, primitive typer og kontrollsetninger.
Forutsetninger
Jeg går idag gjennom syntaksen til språket, men forutsetter at du har noe programmeringsbakgrunn. Etter noen innledende artikler vil det også dukke opp stoff som jeg håper er interessante selv for erfarne JavaScript-programmerere. Målet er å dekke et bredt spekter av teknikker for moderne JavaScript-utvikling.
Grunnleggende syntaks
JavaScript-syntaks ligner mye på Java-syntaks, men ikke la deg lure! Det er en del subtile forskjeller som er viktige. Objektprototyper har JavaScript lånt fra Self.
Datatyper
- tall ("number") - JavaScript har bare én talltype ("number"). Disse representeres som double-verdier. Dette betyr at JavaScript ikke egentlig har en egen heltallstype.
- strenger
- booleans
- objekter
- arrayer
- funksjoner
Det finnes også regulære uttrykk, datoer og noen error-typer. En mer detaljert beskrivelse av objekter, funksjoner og arrayer kommer i morgen. null og undefined deretter.
Variabler
- Deklareres med
var - Er typeløse (kan skifte type)
- Har leksikalsk skop
- Kan deklareres flere i slengen:
var a, b, c; - Kan deklareres med verdi:
var a = 1, b, c;
Typesjekk
Du kan til enhver tid sjekke typen på en variabel med typeof-operatoren:
typeof "JavaScript"; //=> "string"
typeof 1; //=> "number"
typeof 23.45; //=> "number"
typeof [2, 3, "hei"]; //=> "object", ikke så nyttig som det kunne ha vært
typeof true; //=> "boolean"
typeof { mitt: "Objekt" }; //=> "object"
typeof function() {}; //=> "function"
JavaScript er et objektorientert språk. Alle verdier er objekter. Alle objekter har en constructor-egenskap som gir deg konstruktøren til objektet (selve metoden, ikke navnet).
"JavaScript".constructor == String; //=> true
(1).constructor == Number; //=> true
(23.45).constructor == Number; //=> true
[2, 3, "hei"].constructor == Array; //=> true
true.constructor == Boolean; //=> true
({ mitt: "Objekt" }).constructor == Object; //=> true
(function() {}).constructor == Function; //=> true
Kontrollsetninger
if
if (<sannhetsuttrykk>) {
// Kode
} else if (<sannhetsuttrykk>) {
// ...kode
} else {
// ...og kode
}
switch
Som switch i Java, med unntak av at du kan switche på alle typer verdier - du kan tilogmed ha caser på forskjellige datatyper.
switch (yttrykk) {
case 2:
// Kode
break;
case "streng":
// Kode
// Ingen break - fallthrough
default:
// Enda mer kode
}
for
Som for-løkker i Java.
for (i = 0; i < length; i++) {
// Kode
}
for (i = 0, annen = null; (annen = minListe[i]); i++) {
// Kode
}
for in
for in kan brukes til å loope objekter.
var obj = { a: 1, b: 2 };
for (var prop in obj) {
console.log(prop + ": " + obj[prop] + "\n");
}
// a: 1
// b: 2
Senere skal vi se at alle JavaScript-objekter har en prototype-kjede. For å loope egenskapene som er satt direkte på objektet, og skippe de som finnes på prototype-kjeden kan vi bruke hasOwnProperty:
var obj = { a: 1, b: 2 };
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
console.log(prop + ": " + obj[prop] + "\n");
}
}
// a: 1
// b: 2
I JavaScript kan man skippe klammeparantesene for blokker som kun har ett uttrykk. Derfor skrives eksempelet over ofte mer kompakt som:
var obj = { a: 1, b: 2 };
for (var prop in obj) if (obj.hasOwnProperty(prop)) {
console.log(prop + ": " + obj[prop] + "\n");
}
// a: 1
// b: 2
...og representerer et av ekstremt få tilfeller hvor jeg syns det er greit å skippe klammeparantesene.
while
while (expression) {
// Kode
}
do {
// Kode
} while (expression);
Exceptions
try (expression) {
// Kode
} catch (error) {
// Noe gikk galt, håndter
} finally {
// Denne kjøres enten noe feiler eller ikke
}
catch eller finally kan kuttes, men én av dem må være med.
Likhet
Likhet sjekkes med == og !=. Obs! Disse operatorene gjør implisitt casting av verdier:
"" == false // true
0 == "" // true
Bruk heller === og !== som sjekker verdi og type
"" === false // false
0 === "" // false
Sannhetsverdier
Følgende verdier er "falsy" (evaluerer som false i sannhetsuttrykk):
-
false -
null -
undefined -
"" -
0 -
NaN(som er et spesielt tall, mer om det senere)
Alt annet er "thruthy" (evaluerer som true), inkludert tomme arrayer og det spesielle tallet Infinity
Ethvert uttrykk kan i JavaScript konverteres til en boolean enten ved Boolean(<uttrykk>); eller rett og slett !!<uttrykk> (tenk litt på den).
Verdien av et sannhetsuttrykk
Sannhetsuttrykk har to funksjoner i JavaScript: de evaluerer til enten "thruthy" eller "falsy" verdier. I tillegg returnerer de verdien av det siste evaluerte uttrykket:
function setName(name) {
return name || "John Doe"; // Slike uttrykk er ikke begrenset til kun to verdier
}
var name1 = setName(); // "John Doe"
var name2 = setName(null); // "John Doe"
var name3 = setName(""); // "John Doe"
var name4 = setName("Chris"); // "Chris
For || avbrytes evaluering ved første uttrykk som evaluerer som truthy. For && avbrytes evaluering for første uttrykk som evaluerer som falsy.
Operatorer
-
+- addisjon, strengekonkatenering -
- -
* -
/ -
%(modulus) -
++ -
-- -
= -
+= -
-= -
*= -
/= -
%= -
== -
!= -
=== -
!== -
< -
> -
<= -
>= -
&& -
|| -
! -
& -
| -
^ -
<< -
>> -
>>> -
~
De siste sju er bitvise operatorer. Du har også den tertiære operatoren: var a = (hvisUttrykk) ? saDenne : ellersDenne;
Angående +
Dersom du plusser noen tall med en streng får du en streng. Dersom du setter en pluss foran en streng (uten noe tall foran der igjen) får du et tall:
console.log("" + 2); // "2"
console.log(2 + 3 + 4 + "hei" + 6); // "9hei6" (!)
console.log(+ "6"); // 6
console.log(+"streng"); // NaN
Skop
Det finnes kun funksjonsskop og globalt skop.. Ikke noe blokkskop. La meg gjenta: ikke noe blokkskop:
function minFunk() {
var a = 2, b = 3;
if (b === 3) {
var a = "Hei";
}
console.log(a); // "Hei"
}
Å deklarere variabler inne i blokker på denne måten gir illusjonen av at JavaScript har blokkskop. Det har det ikke, så ikke gjør sånt. Deklarer variablene dine samlet i toppen av funksjonen.
Globalt skop
JavaScript har en ufin avhengighet til global skop. Dersom du ikke deklarerer variablene dine er de implisitt globale. Dette kan gi alle mulige slags katastrofale konsekvenser. Deklarer alle variable.
Redefiner implisitt skop (eller ikke!)
I JavaScript er det mulig å bruke with-strukturen for å sette et vilkårlig objekt til det implisitte skopet (skopet man opererer i når man ikke benytter lokale variabler og funksjoner). Dette er nesten aldri å anbefale fordi det maskerer hvor verdier kommer fra og går til:
var obj = { a: "Hei fra objekt" }
with (obj) {
console.log(a);
a = "Hei fra with"; // Er dette obj.a eller en global variabel?
console.log(a);
console.log(obj.a);
var a = "Hei fra lokal variabel"; // Hva med denne?
}
console.log(obj.a);
// Resultat:
// Hei fra objekt
// Hei fra with
// Hei fra with
// Hei fra lokal variabel
Bruk with med omhu og kun når du virkelig vet hva du driver med.
Semikolon
JavaScript-uttrykk kan, men må ikke avsluttes med semikolon. Dersom du ønsker flere uttrykk på samme linje må du ha semikolon etter hvert uttrykk, med unntak av det siste. Å utelate semikolon er dårlig praksis som gjør koden din skjørere (den slutter for eksempel å fungere i det øyeblikket linjeskift forsvinner - eksempelvis ved "minifisering").
That's it - en rask og gæern (men ikke fullstendig) innføring i basic JavaScript.
Mer, mer, mer!
Vel møtt til arrayer, funksjoner og objekter i morgen!
Kommentarer
Øyvind
1. desember, 09:22
Er det noe som heter base i switch statements? eller skulle det vært case?
Anders
(http://www.ixd.no)
1. desember, 10:31
Christian
1. desember, 10:34
Ole
1. desember, 11:28
Hein Haraldson Berg
(http://haraldsonberg.net/)
1. desember, 11:33
sfreud
1. desember, 19:17
En liten ting: stylingen av verdier/uttrykk gjør at de blir vanskelige å lese i Opera Mini. Siden css-filen din er skrevet på én linje ser jeg ikke hva som gjør det (og det er kanskje poenget?), men jeg tipper en liten CSS3 media query kan gjøre dette mer lesbart for oss som leser på mobilen:
div { // det du gjør } @media all and (max-width: 300px) { div { // noe som fungerer bedre for en liten skjerm } }(skjermskudd: http://photobucket.com/albums/r34...nshots_pilotprosjektet/cjohansen.png )
Christian
1. desember, 21:45
@sfreud: Takk for innspill. Jeg bruker Opera mini sjøl, og er egentlig klar over problemet. Jeg kan bare skylde på min egen latskap og Opera minis manglende forståelse for linjehøyde. Fikser det til i morgen!
Når det gjelder CSS-fila, så er den komprimert for ytelse, ikke for å skjule koden. Du kan se koden enten ved å bruke Firebug, eller CSSTidy (krever litt arbeid), eller ved å kikke på kilden: http://www.cjohansen.no/design/cjohansen/stylesheets/cjohansen.css
Ola
(http://lug00ber.m0f0.net/)
19. desember, 17:32
Er det korrekt oppfattet?
Christian
19. desember, 19:57
Det betyr at dersom du deler linja på en måte sånn at første deluttrykk/linje i seg selv er et gyldig uttrykk kan du ende opp med uforutsigbare resultater.
Når du deler linja bør du passe på å alltid dele etter en operator, slik at det ikke er noen tvil om at linja skal fortsette på neste.
Hvis du konsekvent avslutter uttrykk med semikolon utelater du all tvil om at et uttrykk er delt over flere linjer når semikolon mangler. Dette gjør koden din mer forståelig for andre.