JavaScript för Javautvecklare

139
JavaScript för Javautvecklare John Wilander, Handelsbanken @johnwilander Jfokus 2012

description

My Jfokus 2012 tutorial "JavaScript för Javautvecklare". Natural language parts are in Swedish.

Transcript of JavaScript för Javautvecklare

Page 1: JavaScript för Javautvecklare

JavaScript för JavautvecklareJohn Wilander, Handelsbanken

@johnwilanderJfokus 2012

Page 3: JavaScript för Javautvecklare

Typer

Primitiva:string, number, boolean, function, undefined

Resten är object

Primitiva:byte, short, int, long, float, double, boolean, char

Resten är objekt, s.k. referenstyper

Java

JavaScript

Page 4: JavaScript för Javautvecklare

Typer

Primitiva:string, number, boolean, function, undefined

Resten är object

Primitiva:byte, short, int, long, float, double, boolean, char

Resten är objekt, s.k. referenstyper

Java

JavaScript

Page 5: JavaScript för Javautvecklare

Typer

Primitiva:string, number, boolean, function, undefined

Resten är object

Primitiva:byte, short, int, long, float, double, boolean, char

Resten är objekt, s.k. referenstyper

Java

JavaScript

Strängar är inte generella objekt utan en egen typ

Page 6: JavaScript för Javautvecklare

Typer

Primitiva:string, number, boolean, function, undefined

Resten är object

Primitiva:byte, short, int, long, float, double, boolean, char

Resten är objekt, s.k. referenstyper

Java

JavaScript

Det finns bara en typ för tal,

oavsett om det är heltal eller

decimaltal

Page 7: JavaScript för Javautvecklare

Typer

Primitiva:string, number, boolean, function, undefined

Resten är object

Primitiva:byte, short, int, long, float, double, boolean, char

Resten är objekt, s.k. referenstyper

Java

JavaScript

Funktioner är fullödiga objekt

med en egen typ

Page 8: JavaScript för Javautvecklare

Typer

Primitiva:string, number, boolean, function, undefined

Resten är object

Primitiva:byte, short, int, long, float, double, boolean, char

Resten är objekt, s.k. referenstyper

Java

JavaScript

JavaScripts version av

oinitialiserad är undefined

Page 9: JavaScript för Javautvecklare

Låt oss testatypeof 10typeof 10.3typeof Math.LN2typeof Infinitytypeof NaN

typeof ”tutorial”typeof ””typeof (typeof 10)

JavaScript

Page 10: JavaScript för Javautvecklare

Låt oss testatypeof 10typeof 10.3typeof Math.LN2typeof Infinitytypeof NaNtypeof Number(10)

typeof ”tutorial”typeof ””typeof (typeof 10)typeof String(”tutorial”)

JavaScript

Page 11: JavaScript för Javautvecklare

Låt oss testatypeof undefinedtypeof tutorial

typeof {}typeof []typeof [4, 6, 2]typeof new Date()

JavaScript

Page 12: JavaScript för Javautvecklare

Låt oss testatypeof undefinedtypeof tutorial

typeof {}typeof []typeof [4, 6, 2]typeof new Date()

typeof new Boolean(true)typeof new Number(10)typeof new String(”tutorial”)

JavaScript

Page 13: JavaScript för Javautvecklare

Statisk vs dynamisk typning

Dynamisk typning:var name; Variabler har inga typername = ”John”; Värden har typername = 34; Variabler byter typ dynamiskt

Statisk typning:String name; Variabler har typername = ”John”; Värden har typername = 34; Variabler kan inte byta typ

Java

JavaScript

Page 14: JavaScript för Javautvecklare

Dynamisk typning

var name = ”John”;

JavaScript

Värden har typerVariabler haringa typer

Page 15: JavaScript för Javautvecklare

Stark vs svag typning

Page 16: JavaScript för Javautvecklare

Stark vs svag typning

Stark !== braSvag !== dålig

Page 17: JavaScript för Javautvecklare

Stark vs svag typning

var dynVar = 4; Mycket svag typningdynVar + ””; Implicit typkonverteringdynVar + null; Implicit typkonverteringdynVar + []; Implicit typkonverteringdynVar + [0]; Implicit typkonvertering

int intVar = 4; Ganska stark typningintVar + ””; Implicit typkonverteringintVar + 0.0; Implicit, breddande typkonv.intVar + (int)0.0; Explicit typkonverteringintVar + null; Inte tillåtet

Java

JavaScript

Page 18: JavaScript för Javautvecklare

Typsäkert≈

inga typfel vid körning

Page 19: JavaScript för Javautvecklare

Johns slutsats

Java är ett statiskt, starkt typat språk med hyfsat god typsäkerhet

JavaScript är ett dynamiskt, svagt typat språk med hyfsat god typsäkerhet

Page 20: JavaScript för Javautvecklare

Objektorientering

Page 21: JavaScript för Javautvecklare

Java: Klasser och objekt

Klass

Objekt

Objekt

Objekt

Klass Singleton-instans

KällkodExekverande

kod

Page 22: JavaScript för Javautvecklare

JavaScript: Funktioner, objekt och prototyper

Prototyp

Funktion Funktion

KällkodExekverande

kod

Objekt

Objekt

Objekt

Page 23: JavaScript för Javautvecklare

Prototyp

Funktion

Funktion

KällkodExekverande

kod

Objekt

Objekt

Objekt

Moduler

Anonyma closures

JavaScript: Funktioner, objekt och prototyper

Page 24: JavaScript för Javautvecklare

Java: Utökning med arv

Subklass

Superklass

extends

Page 25: JavaScript för Javautvecklare

Java: Subtypning med arv

Supertyp

Subtyp

extends

Page 26: JavaScript för Javautvecklare

Javaklasser blir funktionsmässigt större

ochtypmässigt mindre

(mer specifika)via arv

Page 27: JavaScript för Javautvecklare

I JavaScript så ärutökning

ochsubtypningskilda saker

Page 28: JavaScript för Javautvecklare

JavaScript: Utökning via prototyp

JW = {}; log = console.log;

JW.Base = function(x, y) { this.x = x; this.y = y;};JW.Base.prototype.sum = function() { return this.x + this.y;}JW.instance = new JW.Base(1, 2);

log(JW.instance instanceof JW.Base);log(JW.instance.sum());

JavaScript

Page 29: JavaScript för Javautvecklare

JavaScript: Utökning via prototyp

JW = {}; log = console.log;

JW.Base = function(x, y) { this.x = x; this.y = y;};JW.Base.prototype.sum = function() { return this.x + this.y;}JW.instance = new JW.Base(1, 2);

log(JW.instance instanceof JW.Base);log(JW.instance.sum());

JavaScript

Page 30: JavaScript för Javautvecklare

JavaScript: Utökning via prototyp

JW = {}; log = console.log;

JW.Base = function(x, y) { this.x = x; this.y = y;};JW.Base.prototype.sum = function() { return this.x + this.y;}JW.instance = new JW.Base(1, 2);

log(JW.instance instanceof JW.Base);log(JW.instance.sum());

JavaScript

Page 31: JavaScript för Javautvecklare

JavaScript: Utökning via prototyp

JW = {}; log = console.log;

JW.Base = function(x, y) { this.x = x; this.y = y;};JW.Base.prototype.sum = function() { return this.x + this.y;}JW.instance = new JW.Base(1, 2);

log(JW.instance instanceof JW.Base);log(JW.instance.sum());

JavaScript

Page 32: JavaScript för Javautvecklare

JavaScript: Utökning via prototyp

JW = {}; log = console.log;

JW.Base = function(x, y) { this.x = x; this.y = y;};JW.Base.prototype.sum = function() { return this.x + this.y;}JW.instance = new JW.Base(1, 2);

log(JW.instance instanceof JW.Base);log(JW.instance.sum());

JavaScriptAnvändning av new innebär att:1) ett nytt objekt skapas med prototypen för JW.Base och att2) funktionen JW.Base() anropas med this pekandes på den nya instansen

Page 33: JavaScript för Javautvecklare

JavaScript: Utökning via prototyp

JW = {}; log = console.log;

JW.Base = function(x, y) { this.x = x; this.y = y;};JW.Base.prototype.sum = function() { return this.x + this.y;}JW.instance = new JW.Base(1, 2);

log(JW.instance instanceof JW.Base);log(JW.instance.sum());

JavaScript

Page 34: JavaScript för Javautvecklare

JavaScript: Utökning via prototyp

JW = {}; log = console.log;

JW.Base = function(x, y) { this.x = x; this.y = y;};JW.Base.prototype.sum = function() { return this.x + this.y;}JW.instance = new JW.Base(1, 2);

log(JW.instance instanceof JW.Base);log(JW.instance.sum());

JavaScript

Page 35: JavaScript för Javautvecklare

JavaScript: Utökning via prototyp

JW = {}; log = console.log;

JW.Base = function(x, y) { this.x = x; this.y = y;};JW.instance = new JW.Base(1, 2);JW.Base.prototype.sum = function() { return this.x + this.y;}

log(JW.instance instanceof JW.Base);log(JW.instance.sum());

JavaScript

Page 36: JavaScript för Javautvecklare

JavaScript: Utökning via prototyp

JW = {}; log = console.log;

JW.Base = function(x, y) { this.x = x; this.y = y;};JW.instance = new JW.Base(1, 2);JW.Base.prototype.sum = function() { return this.x + this.y;}

log(JW.instance instanceof JW.Base);log(JW.instance.sum());

JavaScript

Notera att vi inte har skapat någon ny subtyp.Vi har bara utökat den befintliga (proto-)typen.

Page 37: JavaScript för Javautvecklare

JavaScript: SubtypningJW.Base = function(x, y) { this.x = x; this.y = y; };JW.Extension = function(x, y, z) { JW.Base.call(this, x, y); this.z = z;};JW.Extension.prototype = Object.create(JW.Base.prototype);JW.Extension.prototype.constructor = JW.Extension;JW.instance = new JW.Extension(1, 2, 3);log(JW.instance instanceof JW.Base);

JavaScript

Page 38: JavaScript för Javautvecklare

JavaScript: SubtypningJW.Base = function(x, y) { this.x = x; this.y = y; };JW.Extension = function(x, y, z) { JW.Base.call(this, x, y); this.z = z;};JW.Extension.prototype = Object.create(JW.Base.prototype);JW.Extension.prototype.constructor = JW.Extension;JW.instance = new JW.Extension(1, 2, 3);log(JW.instance instanceof JW.Base);

JavaScript

Nu försöker vi ju bara programmera Javai JavaScript. Ni ser ju själva vilket elände det blir.Nåja, låt oss gå igenom det i alla fall.

Page 39: JavaScript för Javautvecklare

JavaScript: SubtypningJW.Base = function(x, y) { this.x = x; this.y = y; };JW.Extension = function(x, y, z) { JW.Base.call(this, x, y); this.z = z;};JW.Extension.prototype = Object.create(JW.Base.prototype);JW.Extension.prototype.constructor = JW.Extension;JW.instance = new JW.Extension(1, 2, 3);log(JW.instance instanceof JW.Base);

JavaScript

Page 40: JavaScript för Javautvecklare

JavaScript: SubtypningJW.Base = function(x, y) { this.x = x; this.y = y; };JW.Extension = function(x, y, z) { JW.Base.call(this, x, y); this.z = z;};JW.Extension.prototype = Object.create(JW.Base.prototype);JW.Extension.prototype.constructor = JW.Extension;JW.instance = new JW.Extension(1, 2, 3);log(JW.instance instanceof JW.Base);

JavaScript

Page 41: JavaScript för Javautvecklare

JavaScript: SubtypningJW.Base = function(x, y) { this.x = x; this.y = y; };JW.Extension = function(x, y, z) { JW.Base.call(this, x, y); this.z = z;};JW.Extension.prototype = Object.create(JW.Base.prototype);JW.Extension.prototype.constructor = JW.Extension;JW.instance = new JW.Extension(1, 2, 3);log(JW.instance instanceof JW.Base);

JavaScript

Page 42: JavaScript för Javautvecklare

JavaScript: SubtypningJW.Base = function(x, y) { this.x = x; this.y = y; };JW.Extension = function(x, y, z) { JW.Base.call(this, x, y); this.z = z;};JW.Extension.prototype = Object.create(JW.Base.prototype);JW.Extension.prototype.constructor = JW.Extension;JW.instance = new JW.Extension(1, 2, 3);log(JW.instance instanceof JW.Base);

JavaScript

Page 43: JavaScript för Javautvecklare

JavaScript: SubtypningJW.Base = function(x, y) { this.x = x; this.y = y; };JW.Extension = function(x, y, z) { JW.Base.call(this, x, y); this.z = z;};JW.Extension.prototype = Object.create(JW.Base.prototype);JW.Extension.prototype.constructor = JW.Extension;JW.instance = new JW.Extension(1, 2, 3);log(JW.instance instanceof JW.Base);

JavaScript

Page 44: JavaScript för Javautvecklare

Varför vill vi subtypa?Jo, för att vi tänker istatisk typning och

is-a-relationer

Page 45: JavaScript för Javautvecklare

Statisk typning och subtypning

public void doPurchase(List<Item> items)

Java

Kan ta emot en lista av Itemseller subtyper till Item

Page 46: JavaScript för Javautvecklare

Dynamisk typning

public void doPurchase(List<Item> items)

JavaScript

Page 47: JavaScript för Javautvecklare

Dynamisk typning

public void doPurchase(List<Item> items)

JavaScript

Page 48: JavaScript för Javautvecklare

Dynamisk typning

public void doPurchase(List<Item> items)

JavaScript

Page 49: JavaScript för Javautvecklare

Dynamisk typning

public void doPurchase(List<Item> items)

JavaScript

Page 50: JavaScript för Javautvecklare

Dynamisk typning

function doPurchase(items)

JavaScript

Kan ta emot vad som helst... eller ingenting

Page 51: JavaScript för Javautvecklare

Dynamisk typning

function doPurchase(items)

JavaScript

Kan returnera vad som helst... eller ingenting

Page 52: JavaScript för Javautvecklare

Vad är sant och falskt i JavaScript?

Page 53: JavaScript för Javautvecklare

Truthiness is a ”truth” that a person claims to know intuitively ”from the gut” or because it ”feels right” without regard to evidence, logic, intellectual examination, or facts.

http://en.wikipedia.org/wiki/Truthiness

Page 54: JavaScript för Javautvecklare

Låt oss testalog = console.log;if(!false) { log("false"); }if(!"false") { log("\"false\""); }if(!0) { log("0"); }if(!-1) { log("-1"); }if(!"") { log("\"\""); }if(!null) { log("null"); }if(!undefined) { log("undefined"); }if(![]) { log("[]"); }if(!{}) { log("{}"); }

JavaScript

Page 55: JavaScript för Javautvecklare

Hur kan denna falskhet drabba oss?

Page 56: JavaScript för Javautvecklare

Först ett par saker …

JW.obj = {drinks: "coffee"};JW.obj.drinks; => "coffee"JW.obj["drinks"]; => "coffee"

JavaScript

Objekts properties (≈medlemsvariabler) går att komma åt som array-referenser

Page 57: JavaScript för Javautvecklare

Först ett par saker …

o = JW.obj;o.toString; // Finnso.hasOwnProperty(”drinks”) ?o.hasOwnProperty(”toString”) ?

JavaScript

Page 58: JavaScript för Javautvecklare

Vad gör koden?JW = {};JW.apply=function(applyTo,applyWith){ for(var prop in applyWith) { if(applyWith.hasOwnProperty(prop) && !applyTo[prop]) { applyTo[prop] = applyWith[prop]; } }}JW.obj = {preselected: 3};JW.apply(JW.obj,{country: 'Sweden'});

JavaScript

Page 59: JavaScript för Javautvecklare

Ser ni buggen?JW = {};JW.apply=function(applyTo,applyWith){ for(var prop in applyWith) { if(applyWith.hasOwnProperty(prop) && !applyTo[prop]) { applyTo[prop] = applyWith[prop]; } }}JW.obj = {preselected: 3};JW.apply(JW.obj,{country: 'Sweden'});

JavaScript

Page 60: JavaScript för Javautvecklare

Ser ni buggen?JW = {};JW.apply=function(applyTo,applyWith){ for(var prop in applyWith) { if(applyWith.hasOwnProperty(prop) && !applyTo[prop]) { applyTo[prop] = applyWith[prop]; } }}JW.obj = {preselected: 0};JW.apply(JW.obj,{preselected: 5});

JavaScript

Page 61: JavaScript för Javautvecklare

Hur startar man ett JavaScript-program?

Page 62: JavaScript för Javautvecklare

JavaScript och webb<html><head> <script src=”js/main.js”></script> <script> var JW = {}; // Mer kod </script></head><body> <button onclick="document.getElementById('field2').value=document.getElementById('field1').value">Kopiera text</button> <div> Lite information </div> <script> JW.calcPrice = function(price, vat) { //… }; </script> <script src=”http://3rdparty.com/trackUsers.js”></script></body></html>

Page 63: JavaScript för Javautvecklare

JavaScript och webb<html><head> <script src=”js/main.js”></script> <script> var JW = {}; // Mer kod </script></head><body> <button onclick="document.getElementById('field2').value=document.getElementById('field1').value">Kopiera text</button> <div> Lite information </div> <script> JW.calcPrice = function(price, vat) { //… }; </script> <script src=”http://3rdparty.com/trackUsers.js”></script></body></html>

Skript från fil i <head>

Page 64: JavaScript för Javautvecklare

JavaScript och webb<html><head> <script src=”js/main.js”></script> <script> var JW = {}; // Mer kod </script></head><body> <button onclick="document.getElementById('field2').value=document.getElementById('field1').value">Kopiera text</button> <div> Lite information </div> <script> JW.calcPrice = function(price, vat) { //… }; </script> <script src=”http://3rdparty.com/trackUsers.js”></script></body></html>

Skript från fil i <head>

Inline:at skript i <head>

Page 65: JavaScript för Javautvecklare

JavaScript och webb<html><head> <script src=”js/main.js”></script> <script> var JW = {}; // Mer kod </script></head><body> <button onclick="document.getElementById('field2').value=document.getElementById('field1').value">Kopiera text</button> <div> Lite information </div> <script> JW.calcPrice = function(price, vat) { //… }; </script> <script src=”http://3rdparty.com/trackUsers.js”></script></body></html>

Skript från fil i <head>

Skript, direkt i HTML

Inline:at skript i <head>

Page 66: JavaScript för Javautvecklare

JavaScript och webb<html><head> <script src=”js/main.js”></script> <script> var JW = {}; // Mer kod </script></head><body> <button onclick="document.getElementById('field2').value=document.getElementById('field1').value">Kopiera text</button> <div> Lite information </div> <script> JW.calcPrice = function(price, vat) { //… }; </script> <script src=”http://3rdparty.com/trackUsers.js”></script></body></html>

Skript från fil i <head>

Skript, direkt i HTML

Inline:at skript i <head>

Inline:at skript i <body>

Page 67: JavaScript för Javautvecklare

JavaScript och webb<html><head> <script src=”js/main.js”></script> <script> var JW = {}; // Mer kod </script></head><body> <button onclick="document.getElementById('field2').value=document.getElementById('field1').value">Kopiera text</button> <div> Lite information </div> <script> JW.calcPrice = function(price, vat) { //… }; </script> <script src=”http://3rdparty.com/trackUsers.js”></script></body></html>

Skript från fil i <head>

Skript, direkt i HTML

Inline:at skript i <head>

Skript från fil i <body>

Inline:at skript i <body>

Page 68: JavaScript för Javautvecklare

Laddning och körning<html><head> <script src=”js/main.js”></script> <script> var JW = {}; // Mer kod </script></head><body> <button onclick="document.getElementById('field2').value=document.getElementById('field1').value">Kopiera text</button> <div> Lite information </div> <script> JW.calcPrice = function(price, vat) { //… }; </script> <script src=”http://3rdparty.com/trackUsers.js”></script></body></html>

Page 69: JavaScript för Javautvecklare

Laddning och körning<html><head> <script src=”js/main.js”></script> <script> var JW = {}; // Mer kod </script></head><body> <button onclick="document.getElementById('field2').value=document.getElementById('field1').value">Kopiera text</button> <div> Lite information </div> <script> JW.calcPrice = function(price, vat) { //… }; </script> <script src=”http://3rdparty.com/trackUsers.js”></script></body></html>

Synkron laddning och körning

Page 70: JavaScript för Javautvecklare

Laddning och körning<html><head> <script src=”js/main.js”></script> <script> var JW = {}; // Mer kod </script></head><body> <button onclick="document.getElementById('field2').value=document.getElementById('field1').value">Kopiera text</button> <div> Lite information </div> <script> JW.calcPrice = function(price, vat) { //… }; </script> <script src=”http://3rdparty.com/trackUsers.js”></script></body></html>

Körs synkront, dvs innan DOM:en har laddats

Synkron laddning och körning

Page 71: JavaScript för Javautvecklare

Laddning och körning<html><head> <script src=”js/main.js”></script> <script> var JW = {}; // Mer kod </script></head><body> <button onclick="document.getElementById('field2').value=document.getElementById('field1').value">Kopiera text</button> <div> Lite information </div> <script> JW.calcPrice = function(price, vat) { //… }; </script> <script src=”http://3rdparty.com/trackUsers.js”></script></body></html>

Körs vid klick-eventet

Körs synkront, dvs innan DOM:en har laddats

Synkron laddning och körning

Page 72: JavaScript för Javautvecklare

Laddning och körning<html><head> <script src=”js/main.js”></script> <script> var JW = {}; // Mer kod </script></head><body> <button onclick="document.getElementById('field2').value=document.getElementById('field1').value">Kopiera text</button> <div> Lite information </div> <script> JW.calcPrice = function(price, vat) { //… }; </script> <script src=”http://3rdparty.com/trackUsers.js”></script></body></html>

Körs när parsern kommit hit

Körs vid klick-eventet

Körs synkront, dvs innan DOM:en har laddats

Synkron laddning och körning

Page 73: JavaScript för Javautvecklare

Laddning och körning<html><head> <script src=”js/main.js”></script> <script> var JW = {}; // Mer kod </script></head><body> <button onclick="document.getElementById('field2').value=document.getElementById('field1').value">Kopiera text</button> <div> Lite information </div> <script> JW.calcPrice = function(price, vat) { //… }; </script> <script src=”http://3rdparty.com/trackUsers.js”></script></body></html> Laddas och körs synkront

Körs när parsern kommit hit

Körs vid klick-eventet

Körs synkront, dvs innan DOM:en har laddats

Synkron laddning och körning

Page 74: JavaScript för Javautvecklare

Asynkron laddning(function(){ var oldFirstScript = document.getElementsByTagName('script')[0]; newScript = document.createElement('script'),

newScript.async = true; newScript.src = 'js/script.js';

oldFirstScript.parentNode.insertBefore( newScript, oldFirstScript);}());

Page 75: JavaScript för Javautvecklare

Synkron, blockerande laddning<script src=”js/script.js”></script>

Asynkron, icke-blockerande laddning<script defer src=”js/script.js”></script>

Asynkron, blockerande laddning<script async src=”js/script.js”></script>

HtmlLaddaKör

HtmlLaddaKör

HtmlLaddaKör

Page 76: JavaScript för Javautvecklare

Synkron, blockerande laddning<script src=”js/script.js”></script>

Asynkron, icke-blockerande laddning<script defer src=”js/script.js”></script>

Asynkron, blockerande laddning<script async src=”js/script.js”></script>

HtmlLaddaKör

HtmlLaddaKör

HtmlLaddaKör

Page 77: JavaScript för Javautvecklare

Synkron, blockerande laddning<script src=”js/script.js”></script>

Asynkron, icke-blockerande laddning<script defer src=”js/script.js”></script>

Asynkron, blockerande laddning<script async src=”js/script.js”></script>

HtmlLaddaKör

HtmlLaddaKör

HtmlLaddaKör

Page 78: JavaScript för Javautvecklare

OK, men hur startar vi?

Page 79: JavaScript för Javautvecklare

In the Beginning

(function(){}());

window.someGlobalFunction();

public static void main(String[] args)

Java

JavaScript

Page 80: JavaScript för Javautvecklare

Självinvokerande funktioner

Anonym, självinvokerande med parameter(function myFunc(me) { // Kod}('John'));

Anonym, självinvokerande utan parameter(function myFunc() { // Kod}());

Page 81: JavaScript för Javautvecklare

Självinvokerande funktioner

Anonym, namnlös och självinvokerande(function() { // Kod}());

Namngiven, självinvokerande, icke-anropsbarvar myFunc = function(me) { // Kod}('John');

Page 82: JavaScript för Javautvecklare

Variabler

Page 83: JavaScript för Javautvecklare

Scopevar GLOB = {};

GLOB.func = function(array) { var local = …; … for (var i=0; i<array.length; i++){ … var temp = array[i]; }};

JavaScript

Page 84: JavaScript för Javautvecklare

Scopevar GLOB = {};

GLOB.func = function(array) { var local = …, i, temp; … for (i=0; i<array.length; i++){ … temp = array[i]; }};

JavaScript

Page 85: JavaScript för Javautvecklare

Scopevar GLOB = {};

GLOB.func = function(array) { var local = …, i, temp; … for (i=0; i<array.length; i++){ … temp = array[i]; }};

JavaScript

Det finns bara två variabel-scope:Globalt eller lokalt funktions-scope.

Alla lokala variabler ”hissas” tilltoppen av funktionen (hoisting).

Page 86: JavaScript för Javautvecklare

Statiska variabler?Medlemsvariabler?

Page 87: JavaScript för Javautvecklare

JW.Personnummer = function (personnummerStr) { this.personnummer = personnummerStr; var checksum = personnummerStr.substring(11,12); };JW.Personnummer.prototype.regexp = /[0-9]+/;JW.Personnummer.OLDEST_DATE = new Date(1880, 0, 1);JW.obj = new JW.Personnummer("191212121212");JW.obj.personnummer;JW.obj.checksum;JW.obj.regexp;JW.Personnummer.OLDEST_DATE

JavaScript

Page 88: JavaScript för Javautvecklare

JW.Personnummer = function (personnummerStr) { this.personnummer = personnummerStr; var checksum = personnummerStr.substring(11,12); };JW.Personnummer.prototype.regexp = /[0-9]+/;JW.Personnummer.OLDEST_DATE = new Date(1880, 0, 1);JW.obj = new JW.Personnummer("191212121212");JW.obj.personnummer;JW.obj.checksum;JW.obj.regexp;JW.Personnummer.OLDEST_DATE

JavaScript

Page 89: JavaScript för Javautvecklare

JW.Personnummer = function (personnummerStr) { this.personnummer = personnummerStr; var checksum = personnummerStr.substring(11,12); };JW.Personnummer.prototype.regexp = /[0-9]+/;JW.Personnummer.OLDEST_DATE = new Date(1880, 0, 1);JW.obj = new JW.Personnummer("191212121212");JW.obj.personnummer;JW.obj.checksum;JW.obj.regexp;JW.Personnummer.OLDEST_DATE

JavaScript

Page 90: JavaScript för Javautvecklare

JW.Personnummer = function (personnummerStr) { this.personnummer = personnummerStr; var checksum = personnummerStr.substring(11,12); };JW.Personnummer.prototype.regexp = /[0-9]+/;JW.Personnummer.OLDEST_DATE = new Date(1880, 0, 1);JW.obj = new JW.Personnummer("191212121212");JW.obj.personnummer;JW.obj.checksum;JW.obj.regexp;JW.Personnummer.OLDEST_DATE

JavaScript

Page 91: JavaScript för Javautvecklare

JW.Personnummer = function (personnummerStr) { this.personnummer = personnummerStr; var checksum = personnummerStr.substring(11,12); };JW.Personnummer.prototype.regexp = /[0-9]+/;JW.Personnummer.OLDEST_DATE = new Date(1880, 0, 1);JW.obj = new JW.Personnummer("191212121212");JW.obj.personnummer;JW.obj.checksum;JW.obj.regexp;JW.Personnummer.OLDEST_DATE;

JavaScript

Page 92: JavaScript för Javautvecklare

Closure (hölje)(function(array) { var i, temp; … for (i=0; i<array.length; i++){ … temp = array[i]; }}([1, 2, 3]));

JavaScript

Page 93: JavaScript för Javautvecklare

Closure (hölje)(function(array) { var i, temp; … for (i=0; i<array.length; i++){ … temp = array[i]; }}([1, 2, 3]));

JavaScript

Ett closure håller sitt scope och sinkontext under hela sin livslängd.

En referens som kommit innanförhöljet (array i exemplet) lever alltsåkvar och håller sitt värde inom”höljet”.

Page 94: JavaScript för Javautvecklare

Closure-exempelfor(i=0; i<pages.length; i++) { var page = pages[i]; pageElement.load(page.url, function() { launchForm(page.form); });}

JavaScript

Page 95: JavaScript för Javautvecklare

Closure-exempelfor(i=0; i<pages.length; i++) { var page = pages[i]; pageElement.load(page.url, function() { launchForm(page.form); });}

JavaScript

Callback-funktion eftersompageElement.load()är asynkron

Page 96: JavaScript för Javautvecklare

Closure-exempelfor(i=0; i<pages.length; i++) { var page = pages[i]; pageElement.load(page.url, function() { launchForm(page.form); });}

JavaScript

page hissas och får alltså ett nytt värde för varje iteration

Page 97: JavaScript för Javautvecklare

Closure-exempelvar page;for(i=0; i<pages.length; i++) { page = pages[i]; pageElement.load(page.url, function() { launchForm(page.form); });}

JavaScript

page hissas och får alltså ett nytt värde för varje iteration

Page 98: JavaScript för Javautvecklare

Closure-exempelvar page;for(i=0; i<pages.length; i++) { page = pages[i]; pageElement.load(page.url, function() { launchForm(page.form); });}

JavaScript

När väl callbacken anropas så kommer page referera till pages[pages.length-1] eller åtminstone ett annat element än det var tänkt.

Page 99: JavaScript för Javautvecklare

Closure-exempelvar page;for(i=0; i<pages.length; i++) { page = pages[i]; pageElement.load(page.url, function() { launchForm(page.form); });}

JavaScript

Page 100: JavaScript för Javautvecklare

Closure-exempelvar page;for(i=0; i<pages.length; i++) { page = pages[i]; (function(page) { pageElement.load(page.url, function() { launchForm(page.form); } }); })(page);}

JavaScript

Page 101: JavaScript för Javautvecklare

Closure-exempelvar page;for(i=0; i<pages.length; i++) { page = pages[i]; (function(page) { pageElement.load(page.url, function() { launchForm(page.form); } }); })(page);}

JavaScript

Vi binder page till ett nytt höljeså att callbacken refererar rätt

Page 102: JavaScript för Javautvecklare

Closure-exempelvar page;for(i=0; i<pages.length; i++) { page = pages[i]; (function(myPage) { pageElement.load(myPage.url, function() { launchForm(myPage.form); } }); })(page);}

JavaScript

Om man mår dåligt av såntså kan man döpa om höljetsvariabel :)

Page 103: JavaScript för Javautvecklare

Crockford-moduleneller

Module Pattern

Med självinvokerande funktioner,scope och closures är vi redo för

det viktigaste designmönstret:

Page 104: JavaScript för Javautvecklare

JW.cache = (function(){}());

JavaScript

Page 105: JavaScript för Javautvecklare

JW.cache = (function(){ return {};}());

JavaScript

Page 106: JavaScript för Javautvecklare

JW.cache = (function(){ return { getPatient: function(personnummer) {

} };}());

JavaScript

Page 107: JavaScript för Javautvecklare

JW.cache = (function(){ var cache = {}; return { getPatient: function(personnummer) {

} };}());

JavaScript

Page 108: JavaScript för Javautvecklare

JW.cache = (function(){ var cache = {}; return { getPatient: function(personnummer) { var res=cache[personnummer]; // Check if fresh // Return } };}());

JavaScript

Page 109: JavaScript för Javautvecklare

JW.cache = (function(){ var cache = {}; return { getPatient: function(personnummer) { var res=cache[personnummer]; if(_isValid(res)) { return res.patient; } else { // Handle cache miss } } };}());

JavaScript

Page 110: JavaScript för Javautvecklare

JW.cache = (function(){ var cache = {}, _isValid = function(res) {

} return { getPatient: function(personnummer) { var res=cache[personnummer]; if(_isValid(res)) { return res.patient; } else { // Handle cache miss } }

JavaScript

Page 111: JavaScript för Javautvecklare

JW.cache = (function(){ var cache = {}, _isValid(res) { return !res ? false : (Date.now() - res.timestamp) <= 60000; // One minute } return { getPatient: function(personnummer) { var res=cache[personnummer]; if(_isValid(res)) { return res.patient; } else { // Handle cache miss

JavaScript

Page 112: JavaScript för Javautvecklare

JW.cache = (function(){ var cache = {}, _isValid(res) { return !res ? false : (Date.now() - res.timestamp) <= 60000; // One minute } return { getPatient: function(personnummer) { var res=cache[personnummer]; if(_isValid(res)) { return res.patient; } else { // Handle cache miss

JavaScript

Vi kan alltså ha (closure-)privatavariabler och funktioner

Page 113: JavaScript för Javautvecklare

Crockford = (function(initParam) { var privVar1, privVar2, _privFunc1 = function() {

}, _privFunc2 = function() {

}; return { pubVar1: ”value”, pubFunc1: function() {

} };}(initParam));

JavaScript

Page 114: JavaScript för Javautvecklare

RevealingModule Pattern

För att möjliggöra enhetstesteranvänder man någon form av

Page 115: JavaScript för Javautvecklare

Crockford = (function(initParam) { var _privFunc = function() {

}; return { unitTestHandle: { privFunc: _privFunc } };}(initParam));

JavaScript

Page 116: JavaScript för Javautvecklare

Crockford = (function(initParam) { var _privFunc = function() {

}; return { unitTestHandle: { privFunc: function() { log(”Only use in unit test”); return _privFunc(); } } };}(initParam));

JavaScript

Page 117: JavaScript för Javautvecklare

Namngivna parametrar

Page 118: JavaScript för Javautvecklare

Metodsignaturer

function execPurchase(price, item, discountCode, wantsSpam, user)

public void execPurchase(int, String, String, boolean, User)

Java

JavaScript

Page 119: JavaScript för Javautvecklare

Metodsignaturer

function execPurchase(purchase) { purchase.price … purchase.item … purchase.wantsSpam … purchase.user …

builder = new Purchase.Builder();Purchase purchase = builder.setPrice(9900) .setItem(”keps”).wantsSpam(false) .setUser(user).build();

Java

JavaScript

Page 120: JavaScript för Javautvecklare

Vad innebär ett JavaScript-bygge?

Page 121: JavaScript för Javautvecklare

JavaScript-bygge

• Hantering av ramverk och bibliotek

• Beroendehantering egna filer/moduler/klasser

• Enhetstester och statisk analys

• Konkatenering och minifiering

• final.html

Page 122: JavaScript för Javautvecklare

Hantering av ramverk

• Vill ofta cache:a tredjepartsbibliotek hårt

• Ibland hotlink:a till CDN eller dylikt

• Därför sällan slå ihop med egen kod

• Vill sällan ha i sitt eget repo

Page 123: JavaScript för Javautvecklare

Beroendehantering egen kod

• AMD – Asynchronous Module Definition

• Bundlat i större ramverk såsom YUI och Ext JS

• Fristående require.js m.fl.

Page 124: JavaScript för Javautvecklare

Enhetstester ochstatisk analys

• Enhetstester med Jasmine, JSTestDriver etc.

• phantom.js – webbläsare utan GUI

• sinon.js – mockramverk

• Statisk analys med JSHint eller JSLint

Page 125: JavaScript för Javautvecklare

Konkatenering och minifiering

• Google Closure Compiler

• YUI Compressor

• uglify.js

• require.js utför konkatenering och minifiering med Closure Compiler och uglify.js

Page 126: JavaScript för Javautvecklare

Utan beroendehantering<head> <link rel="stylesheet" type="text/css" href="css/main.css"> <script src="js/lib/jquery-1.7.1.min.js"></script> <script src="js/lib/jquery-encoder-0.1.0.js"></script> <script src="js/base.js"></script> <script src="js/JW/util/util.js"></script> <script src="js/JW/personnummer/Personnummer.js"></script> <script src="js/JW/patient/Patient.js"></script> <script src="js/JW/cache/cache.js"></script> <script src="js/JW/proxy/proxy.js"></script> <script src="js/JW/gui/gui.js"></script></head>

HTML

Page 127: JavaScript för Javautvecklare

Med beroendehantering<head> <link rel="stylesheet" type="text/css" href="css/main.css"> <script data-main="js/base" src="js/lib/require-1.0.5/require.js"></script></head>

HTML

Page 128: JavaScript för Javautvecklare

java -classpath /path/to/rhino/js.jar:/path/to/Closure_Compiler/compiler.jar org.mozilla.javascript.tools.shell.Main ../../r.js -o name=base out=min.js baseUrl=. paths.jquery=empty: paths.jquery-encoder=empty:

Page 129: JavaScript för Javautvecklare

final.html<head> <link rel="stylesheet" type="text/css" href="css/main.css"> <script src="js/lib/require-1.0.5/require.js"></script> <script> require.config({ paths: { "base": "js/min", "jquery": "js/lib/jquery-1.7.1.min", "jquery-encoder": "js/lib/jquery-encoder-0.1.0" } }); require(["base"]); </script></head>

HTML

Page 130: JavaScript för Javautvecklare

Några extras

Page 131: JavaScript för Javautvecklare

Strict Mode (ES5)

• Inled JavaScript-fil eller funktions-scope med ”use strict”;

• Omöjliggör ofrivilliga globala variabler

• Inget läckage av globala objektet till this

• Omöjliggör duplikat i objekt à la{ item: ”keps”, item: ”boll”}

• Ingen skuggning via eval(”var x;”)

Page 132: JavaScript för Javautvecklare

seal (ES5)JW = {name: "John"};

JW.name = "Joe";JW.job = "coder";

console.log(JW.name + ", " + JW.job);

JavaScript

Page 133: JavaScript för Javautvecklare

seal (ES5)JW = {name: "John"};

Object.seal(JW);

JW.name = "Joe";JW.job = "coder";

console.log(JW.name + ", " + JW.job);

JavaScript

Page 134: JavaScript för Javautvecklare

freeze (ES5)JW = {name: "John"};

Object.freeze(JW);

JW.name = "Joe";JW.job = "coder";

console.log(JW.name + ", " + JW.job);

JavaScript

Page 135: JavaScript för Javautvecklare

freeze (ES5)JW = {name: "John"};

Object.freeze(JW);

JW.name = "Joe";JW.job = "coder";

console.log(JW.name + ", " + JW.job);

JavaScript

Men … obj.prototype kanfortfarande ändra på förseglade och frysta objekt. Jag har testat att frysa prototypenoch det verkar fungera men det måste förstås analyseras för sidoeffekter.

Page 136: JavaScript för Javautvecklare

argumentsJW = function() { console.log(arguments.length); for(var i=0; i<arguments.length; i++) { console.log(arguments[i]); } return "done";}

JW(1, "Joe", [2, 3, 4]);

JavaScript

Page 138: JavaScript för Javautvecklare

jsfiddle.net

Page 139: JavaScript för Javautvecklare

Att följahttp://javascriptweekly.com/

@javascript_news@BrendanEich @littlecalculist@addy_osmani @addyosmani

@paul_irish @badass_js@rwaldron @slicknet

@kangax @unscriptable@sthlmjs