JavaScript för Javautvecklare
-
Upload
johnwilander -
Category
Technology
-
view
2.273 -
download
0
description
Transcript of JavaScript för Javautvecklare
JavaScript för JavautvecklareJohn Wilander, Handelsbanken
@johnwilanderJfokus 2012
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
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
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
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
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
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
Låt oss testatypeof 10typeof 10.3typeof Math.LN2typeof Infinitytypeof NaN
typeof ”tutorial”typeof ””typeof (typeof 10)
JavaScript
Låt oss testatypeof 10typeof 10.3typeof Math.LN2typeof Infinitytypeof NaNtypeof Number(10)
typeof ”tutorial”typeof ””typeof (typeof 10)typeof String(”tutorial”)
JavaScript
Låt oss testatypeof undefinedtypeof tutorial
typeof {}typeof []typeof [4, 6, 2]typeof new Date()
JavaScript
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
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
Dynamisk typning
var name = ”John”;
JavaScript
Värden har typerVariabler haringa typer
Stark vs svag typning
Stark vs svag typning
Stark !== braSvag !== dålig
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
Typsäkert≈
inga typfel vid körning
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
Objektorientering
Java: Klasser och objekt
Klass
Objekt
Objekt
Objekt
Klass Singleton-instans
KällkodExekverande
kod
JavaScript: Funktioner, objekt och prototyper
Prototyp
Funktion Funktion
KällkodExekverande
kod
Objekt
Objekt
Objekt
Prototyp
Funktion
Funktion
KällkodExekverande
kod
Objekt
Objekt
Objekt
Moduler
Anonyma closures
JavaScript: Funktioner, objekt och prototyper
Java: Utökning med arv
Subklass
Superklass
extends
Java: Subtypning med arv
Supertyp
Subtyp
extends
Javaklasser blir funktionsmässigt större
ochtypmässigt mindre
(mer specifika)via arv
I JavaScript så ärutökning
ochsubtypningskilda saker
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
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
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
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
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
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
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
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
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.
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
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.
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
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
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
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
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
Varför vill vi subtypa?Jo, för att vi tänker istatisk typning och
is-a-relationer
Statisk typning och subtypning
public void doPurchase(List<Item> items)
Java
Kan ta emot en lista av Itemseller subtyper till Item
Dynamisk typning
public void doPurchase(List<Item> items)
JavaScript
Dynamisk typning
public void doPurchase(List<Item> items)
JavaScript
Dynamisk typning
public void doPurchase(List<Item> items)
JavaScript
Dynamisk typning
public void doPurchase(List<Item> items)
JavaScript
Dynamisk typning
function doPurchase(items)
JavaScript
Kan ta emot vad som helst... eller ingenting
Dynamisk typning
function doPurchase(items)
JavaScript
Kan returnera vad som helst... eller ingenting
Vad är sant och falskt i JavaScript?
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
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
Hur kan denna falskhet drabba oss?
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
Först ett par saker …
o = JW.obj;o.toString; // Finnso.hasOwnProperty(”drinks”) ?o.hasOwnProperty(”toString”) ?
JavaScript
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
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
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
Hur startar man ett JavaScript-program?
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>
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>
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>
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>
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>
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>
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>
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
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
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
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
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
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);}());
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
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
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
OK, men hur startar vi?
In the Beginning
(function(){}());
window.someGlobalFunction();
public static void main(String[] args)
Java
JavaScript
Självinvokerande funktioner
Anonym, självinvokerande med parameter(function myFunc(me) { // Kod}('John'));
Anonym, självinvokerande utan parameter(function myFunc() { // Kod}());
Självinvokerande funktioner
Anonym, namnlös och självinvokerande(function() { // Kod}());
Namngiven, självinvokerande, icke-anropsbarvar myFunc = function(me) { // Kod}('John');
Variabler
Scopevar GLOB = {};
GLOB.func = function(array) { var local = …; … for (var i=0; i<array.length; i++){ … var temp = array[i]; }};
JavaScript
Scopevar GLOB = {};
GLOB.func = function(array) { var local = …, i, temp; … for (i=0; i<array.length; i++){ … temp = array[i]; }};
JavaScript
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).
Statiska variabler?Medlemsvariabler?
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
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
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
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
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
Closure (hölje)(function(array) { var i, temp; … for (i=0; i<array.length; i++){ … temp = array[i]; }}([1, 2, 3]));
JavaScript
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”.
Closure-exempelfor(i=0; i<pages.length; i++) { var page = pages[i]; pageElement.load(page.url, function() { launchForm(page.form); });}
JavaScript
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
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
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
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.
Closure-exempelvar page;for(i=0; i<pages.length; i++) { page = pages[i]; pageElement.load(page.url, function() { launchForm(page.form); });}
JavaScript
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
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
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 :)
Crockford-moduleneller
Module Pattern
Med självinvokerande funktioner,scope och closures är vi redo för
det viktigaste designmönstret:
JW.cache = (function(){}());
JavaScript
JW.cache = (function(){ return {};}());
JavaScript
JW.cache = (function(){ return { getPatient: function(personnummer) {
} };}());
JavaScript
JW.cache = (function(){ var cache = {}; return { getPatient: function(personnummer) {
} };}());
JavaScript
JW.cache = (function(){ var cache = {}; return { getPatient: function(personnummer) { var res=cache[personnummer]; // Check if fresh // Return } };}());
JavaScript
JW.cache = (function(){ var cache = {}; return { getPatient: function(personnummer) { var res=cache[personnummer]; if(_isValid(res)) { return res.patient; } else { // Handle cache miss } } };}());
JavaScript
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
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
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
Crockford = (function(initParam) { var privVar1, privVar2, _privFunc1 = function() {
}, _privFunc2 = function() {
}; return { pubVar1: ”value”, pubFunc1: function() {
} };}(initParam));
JavaScript
RevealingModule Pattern
För att möjliggöra enhetstesteranvänder man någon form av
Crockford = (function(initParam) { var _privFunc = function() {
}; return { unitTestHandle: { privFunc: _privFunc } };}(initParam));
JavaScript
Crockford = (function(initParam) { var _privFunc = function() {
}; return { unitTestHandle: { privFunc: function() { log(”Only use in unit test”); return _privFunc(); } } };}(initParam));
JavaScript
Namngivna parametrar
Metodsignaturer
function execPurchase(price, item, discountCode, wantsSpam, user)
public void execPurchase(int, String, String, boolean, User)
Java
JavaScript
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
Vad innebär ett JavaScript-bygge?
JavaScript-bygge
• Hantering av ramverk och bibliotek
• Beroendehantering egna filer/moduler/klasser
• Enhetstester och statisk analys
• Konkatenering och minifiering
• final.html
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
Beroendehantering egen kod
• AMD – Asynchronous Module Definition
• Bundlat i större ramverk såsom YUI och Ext JS
• Fristående require.js m.fl.
Enhetstester ochstatisk analys
• Enhetstester med Jasmine, JSTestDriver etc.
• phantom.js – webbläsare utan GUI
• sinon.js – mockramverk
• Statisk analys med JSHint eller JSLint
Konkatenering och minifiering
• Google Closure Compiler
• YUI Compressor
• uglify.js
• require.js utför konkatenering och minifiering med Closure Compiler och uglify.js
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
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
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:
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
Några extras
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;”)
seal (ES5)JW = {name: "John"};
JW.name = "Joe";JW.job = "coder";
console.log(JW.name + ", " + JW.job);
JavaScript
seal (ES5)JW = {name: "John"};
Object.seal(JW);
JW.name = "Joe";JW.job = "coder";
console.log(JW.name + ", " + JW.job);
JavaScript
freeze (ES5)JW = {name: "John"};
Object.freeze(JW);
JW.name = "Joe";JW.job = "coder";
console.log(JW.name + ", " + JW.job);
JavaScript
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.
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
Referensdokumentation
Alltiddeveloper.mozilla.org
Aldrigwww.w3schools.com
Varför?w3fools.com
jsfiddle.net
Att följahttp://javascriptweekly.com/
@javascript_news@BrendanEich @littlecalculist@addy_osmani @addyosmani
@paul_irish @badass_js@rwaldron @slicknet
@kangax @unscriptable@sthlmjs