SlideShare ist ein Scribd-Unternehmen logo
1 von 139
Downloaden Sie, um offline zu lesen
JavaScript för
Javautvecklare
John Wilander, Handelsbanken
      @johnwilander
         Jfokus 2012
shouldilearnjavascript.com
Java
                       Typer
Primitiva:
byte, short, int, long, float, double,
boolean, char

Resten är objekt, s.k. referenstyper
JavaScript

 Primitiva:
 string, number, boolean, function,
 undefined

 Resten är object
Java
                       Typer
Primitiva:
byte, short, int, long, float, double,
boolean, char

Resten är objekt, s.k. referenstyper
JavaScript

 Primitiva:
 string, number, boolean, function,
 undefined

 Resten är object
Java
                    Typer
Primitiva:
byte, short, int, long, float, double,
boolean, charinte
       Strängar är
       generella objekt
Resten är objekt, s.k.typ
      utan en egen referenstyper
JavaScript

 Primitiva:
 string, number, boolean, function,
 undefined

 Resten är object
Java
                    Typer
Primitiva: finns bara en
        Det
           typ för tal,
byte, short, int, long, float, double,
boolean, char det
         oavsett om
          är heltal eller
Resten är objekt, s.k. referenstyper
            decimaltal
JavaScript

 Primitiva:
 string, number, boolean, function,
 undefined

 Resten är object
Java
                     Typer
Primitiva:
byte, short, int, long, float, double,
boolean, char                         Funktioner är
                                     fullödiga objekt
Resten är objekt, s.k. referenstyper med en egen typ
JavaScript

 Primitiva:
 string, number, boolean, function,
 undefined

 Resten är object
Java
                    Typer
Primitiva:
byte, short, int, long, float, double,
boolean, charJavaScripts
             version av
Resten oinitialiserad är
           är objekt, s.k. referenstyper
JavaScript
           undefined
 Primitiva:
 string, number, boolean, function,
 undefined

 Resten är object
JavaScript
               Låt oss testa
 typeof      10
 typeof      10.3
 typeof      Math.LN2
 typeof      Infinity
 typeof      NaN


 typeof ”tutorial”
 typeof ””
 typeof (typeof 10)
JavaScript
               Låt oss testa
 typeof      10
 typeof      10.3
 typeof      Math.LN2
 typeof      Infinity
 typeof      NaN
 typeof      Number(10)

 typeof      ”tutorial”
 typeof      ””
 typeof      (typeof 10)
 typeof      String(”tutorial”)
JavaScript
               Låt oss testa
 typeof undefined
 typeof tutorial

 typeof      {}
 typeof      []
 typeof      [4, 6, 2]
 typeof      new Date()
JavaScript
               Låt oss testa
 typeof undefined
 typeof tutorial

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

 typeof new Boolean(true)
 typeof new Number(10)
 typeof new String(”tutorial”)
Statisk vs dynamisk typning
Java

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

JavaScript

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




             var name = ”John”;


               Variabler har   Värden har typer
                inga typer
Stark vs svag typning
Stark vs svag typning

    Stark !== bra
    Svag !== dålig
Java
             Stark vs svag typning
int intVar = 4;        Ganska stark typning
intVar + ””;           Implicit typkonvertering
intVar + 0.0;          Implicit, breddande typkonv.
intVar + (int)0.0;     Explicit typkonvertering
intVar + null;         Inte tillåtet
JavaScript

 var dynVar = 4;      Mycket svag typning
 dynVar + ””;         Implicit typkonvertering
 dynVar + null;       Implicit typkonvertering
 dynVar + [];         Implicit typkonvertering
 dynVar + [0];        Implicit typkonvertering
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
                  Objekt
          Klass    Objekt
                            Exekverande
Källkod              Objekt     kod


                   Singleton
          Klass
                    -instans
JavaScript: Funktioner,
     objekt och prototyper
                     Objekt
          Prototyp    Objekt
                               Exekverande
Källkod                 Objekt     kod


          Funktion    Funktion
JavaScript: Funktioner,
     objekt och prototyper
                       Objekt
            Prototyp

                        Objekt
                                 Exekverande
Källkod                   Objekt     kod
          Funktion
          Anonyma
           closures     Funktion
          Moduler
Java: Utökning med arv
         Subklass

                     extends


        Superklass
Java: Subtypning med arv
         Supertyp

                    extends


          Subtyp
Javaklasser blir
funktionsmässigt större
           och
   typmässigt mindre
     (mer specifika)
         via arv
I JavaScript så är
     utökning
        och
    subtypning
   skilda saker
JavaScript: Utökning via prototyp
JavaScript

 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: Utökning via prototyp
JavaScript

 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: Utökning via prototyp
JavaScript

 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: Utökning via prototyp
JavaScript

 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: Utökning via prototyp
JavaScript
           Användning av new innebär att:
 JW = {}; log = console.log;
           1) ett nytt objekt skapas med
 JW.Base = function(x,JW.Base och att
           prototypen för y) {
    this.x 2) funktionen JW.Base()
            = x; this.y = y;
 };        anropas med this pekandes på
 JW.Base.prototype.sum = function() {
           den nya instansen
    return this.x + this.y;
 }
 JW.instance = new JW.Base(1, 2);

 log(JW.instance instanceof JW.Base);
 log(JW.instance.sum());
JavaScript: Utökning via prototyp
JavaScript

 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: Utökning via prototyp
JavaScript

 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: Utökning via prototyp
JavaScript

 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: Utökning via prototyp
JavaScript

 JW = {}; log = console.log;

 JW.Base = function(x, y) {
    this.x = x; this.y = y;
 };
 JW.instance vi inte har skapat någon ny subtyp.
    Notera att = new JW.Base(1, 2);
 JW.Base.prototype.sumbefintliga (proto-)typen.
    Vi har bara utökat den = function() {
    return this.x + this.y;
 }

 log(JW.instance instanceof JW.Base);
 log(JW.instance.sum());
JavaScript
             JavaScript: Subtypning
 JW.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: Subtypning
 JW.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; ju bara programmera Java
    Nu försöker vi
 }; i JavaScript. Ni ser ju själva vilket elände det blir.
 JW.Extension.prototype =
    Nåja, låt oss gå igenom det i alla fall.
        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: Subtypning
 JW.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: Subtypning
 JW.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: Subtypning
 JW.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: Subtypning
 JW.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: Subtypning
 JW.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);
Varför vill vi subtypa?
 Jo, för att vi tänker i
  statisk typning och
     is-a-relationer
Statisk typning och
           subtypning
Java




  public void doPurchase(List<Item> items)




                   Kan ta emot en lista av Items
                      eller subtyper till Item
Dynamisk typning
JavaScript




   public void doPurchase(List<Item> items)
Dynamisk typning
JavaScript




   public void doPurchase(List<Item> items)
Dynamisk typning
JavaScript




   public void doPurchase(List<Item> items)
Dynamisk typning
JavaScript




   public void doPurchase(List<Item> items)
Dynamisk typning
JavaScript




             function doPurchase(items)




                        Kan ta emot vad som helst
                             ... eller ingenting
Dynamisk typning
JavaScript




             function doPurchase(items)




                       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
JavaScript
             Låt oss testa
 log = 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("{}");          }
Hur kan denna falskhet
     drabba oss?
Först ett par saker …
JavaScript



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

             Objekts properties (≈medlemsvariabler)
             går att komma åt som array-referenser
Först ett par saker …
JavaScript


 o = JW.obj;
 o.toString;     // Finns
 o.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});
Hur startar man ett
JavaScript-program?
<html>
          JavaScript och webb
<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>
<html>
          JavaScript och webb
<head>                                 Skript från fil i <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>
<html>
          JavaScript och webb
<head>                                 Skript från fil i <head>
  <script src=”js/main.js”></script>
  <script>
         var JW = {};                  Inline:at skript i <head>
         // 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>
<html>
          JavaScript och webb
<head>                                 Skript från fil i <head>
  <script src=”js/main.js”></script>
  <script>
         var JW = {};                  Inline:at skript i <head>
         // Mer kod
  </script>
</head>                                  Skript, direkt i HTML
<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>
<html>
          JavaScript och webb
<head>                                 Skript från fil i <head>
  <script src=”js/main.js”></script>
  <script>
         var JW = {};                  Inline:at skript i <head>
         // Mer kod
  </script>
</head>                                  Skript, direkt i HTML
<body>
  <button onclick="document.getElementById('field2').value=
document.getElementById('field1').value">Kopiera text</button>
  <div>
    Lite information
  </div>                               Inline:at skript i <body>
  <script>
         JW.calcPrice = function(price, vat) { //… };
  </script>
  <script src=”http://3rdparty.com/trackUsers.js”></script>
</body>
</html>
<html>
          JavaScript och webb
<head>                                 Skript från fil i <head>
  <script src=”js/main.js”></script>
  <script>
         var JW = {};                  Inline:at skript i <head>
         // Mer kod
  </script>
</head>                                  Skript, direkt i HTML
<body>
  <button onclick="document.getElementById('field2').value=
document.getElementById('field1').value">Kopiera text</button>
  <div>
    Lite information
  </div>                               Inline:at skript i <body>
  <script>
         JW.calcPrice = function(price, vat) { //… };
  </script>
  <script src=”http://3rdparty.com/trackUsers.js”></script>
</body>
</html>                                Skript från fil i <body>
<html>
         Laddning och körning
<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>
<html>
         Laddning och körning
<head>                           Synkron laddning och körning
  <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>
<html>
         Laddning och körning
<head>                           Synkron laddning och körning
  <script src=”js/main.js”></script>
  <script>
         var JW = {};                  Körs synkront, dvs innan
         // Mer kod
  </script>
                                        DOM:en har laddats
</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>
<html>
         Laddning och körning
<head>                           Synkron laddning och körning
  <script src=”js/main.js”></script>
  <script>
         var JW = {};                  Körs synkront, dvs innan
         // Mer kod
  </script>
                                        DOM:en har laddats
</head>
<body>                                   Körs vid klick-eventet
  <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>
<html>
         Laddning och körning
<head>                           Synkron laddning och körning
  <script src=”js/main.js”></script>
  <script>
         var JW = {};                  Körs synkront, dvs innan
         // Mer kod
  </script>
                                        DOM:en har laddats
</head>
<body>                                   Körs vid klick-eventet
  <button onclick="document.getElementById('field2').value=
document.getElementById('field1').value">Kopiera text</button>
  <div>
    Lite information
  </div>                          Körs när parsern kommit hit
  <script>
         JW.calcPrice = function(price, vat) { //… };
  </script>
  <script src=”http://3rdparty.com/trackUsers.js”></script>
</body>
</html>
<html>
         Laddning och körning
<head>                           Synkron laddning och körning
  <script src=”js/main.js”></script>
  <script>
         var JW = {};                  Körs synkront, dvs innan
         // Mer kod
  </script>
                                        DOM:en har laddats
</head>
<body>                                   Körs vid klick-eventet
  <button onclick="document.getElementById('field2').value=
document.getElementById('field1').value">Kopiera text</button>
  <div>
    Lite information
  </div>                          Körs när parsern kommit hit
  <script>
         JW.calcPrice = function(price, vat) { //… };
  </script>
  <script src=”http://3rdparty.com/trackUsers.js”></script>
</body>
</html>                               Laddas och körs synkront
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>
 Kör
Ladda
Html

Asynkron, icke-blockerande laddning
<script defer src=”js/script.js”></script>
 Kör
Ladda
Html

Asynkron, blockerande laddning
<script async src=”js/script.js”></script>
 Kör
Ladda
Html
Synkron, blockerande laddning
<script src=”js/script.js”></script>
 Kör
Ladda
Html

Asynkron, icke-blockerande laddning
<script defer src=”js/script.js”></script>
 Kör
Ladda
Html

Asynkron, blockerande laddning
<script async src=”js/script.js”></script>
 Kör
Ladda
Html
Synkron, blockerande laddning
<script src=”js/script.js”></script>
 Kör
Ladda
Html

Asynkron, icke-blockerande laddning
<script defer src=”js/script.js”></script>
 Kör
Ladda
Html

Asynkron, blockerande laddning
<script async src=”js/script.js”></script>
 Kör
Ladda
Html
OK, men hur startar vi?
Java
             In the Beginning

public static void main(String[] args)


JavaScript



 (function(){}());

 window.someGlobalFunction();
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-anropsbar
var myFunc = function(me) {
  // Kod
}('John');
Variabler
JavaScript
                  Scope
 var GLOB = {};

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

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

 GLOB.func = function(array) {
    var local = …, i, temp;
    …
    for (i=0; Det finns bara två variabel-scope:
               i<array.length; i++){
      …       Globalt eller lokalt funktions-scope.
      temp = array[i];
    }         Alla lokala variabler ”hissas” till
 };           toppen av funktionen (hoisting).
Statiska variabler?
Medlemsvariabler?
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

 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++){
     …     Ett closure håller sitt scope och sin
     temp =kontext under hela sin livslängd.
             array[i];
   }
 }([1, 2, 3]));
           En referens som kommit innanför
           höljet (array i exemplet) lever alltså
           kvar och håller sitt värde inom
           ”höljet”.
JavaScript
             Closure-exempel
 for(i=0; i<pages.length; i++) {
   var page = pages[i];
   pageElement.load(page.url,
     function() {
       launchForm(page.form);
     });
 }
JavaScript
             Closure-exempel
 for(i=0; i<pages.length; i++) {
   var page = pages[i];
   pageElement.load(page.url,
     function() {
       launchForm(page.form);
     });
                  Callback-funktion eftersom
 }
                  pageElement.load()
                  är asynkron
JavaScript
             Closure-exempel
 for(i=0; i<pages.length; i++) {
   var page = pages[i];
   pageElement.load(page.url,
     function() {
              page hissas och får alltså ett
       launchForm(page.form);
     });      nytt värde för varje iteration
 }
JavaScript
             Closure-exempel
 var page;
 for(i=0; i<pages.length; i++) {
   page = pages[i];
   pageElement.load(page.url,
              page hissas och får alltså ett
     function() {
              nytt värde för varje iteration
       launchForm(page.form);
     });
 }
JavaScript
             Closure-exempel
 var page;
 for(i=0; i<pages.length; i++) {
   page = pages[i];
   pageElement.load(page.url,
     function() {
       launchForm(page.form);
     });        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.
JavaScript
             Closure-exempel
 var page;
 for(i=0; i<pages.length; i++) {
   page = pages[i];
   pageElement.load(page.url,
     function() {
       launchForm(page.form);
     });
 }
JavaScript
             Closure-exempel
 var page;
 for(i=0; i<pages.length; i++) {
   page = pages[i];
   (function(page) {
     pageElement.load(page.url,
       function() {
           launchForm(page.form);
       }
     });
   })(page);
 }
JavaScript
             Closure-exempel
 var page;
 for(i=0; i<pages.length; i++) {
   page = pages[i];
   (function(page) {
     pageElement.load(page.url,
       function() {
           launchForm(page.form);
       }
              Vi binder page till ett nytt hölje
     });
   })(page); så att callbacken refererar rätt
 }
JavaScript
             Closure-exempel
 var page;
 for(i=0; i<pages.length; i++) {
   page = pages[i];
   (function(myPage) {
     pageElement.load(myPage.url,
       function() {
           launchForm(myPage.form);
       }         Om man mår dåligt av sånt
     });         så kan man döpa om höljets
   })(page);     variabel :)
 }
Med självinvokerande funktioner,
 scope och closures är vi redo för
   det viktigaste designmönstret:

Crockford-modulen
       eller
  Module Pattern
JavaScript

 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 { Vi kan alltså ha (closure-)privata
             variabler och funktioner
     getPatient:
       function(personnummer) {
         var res=cache[personnummer];
         if(_isValid(res)) {
           return res.patient;
         } else {
           // Handle cache miss
JavaScript

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

                 },
                 _privFunc2 = function() {

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

             }
   };
 }(initParam));
För att möjliggöra enhetstester
 använder man någon form av

   Revealing
 Module Pattern
JavaScript

 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));
Namngivna parametrar
Java
             Metodsignaturer
public void execPurchase(int, String,
String, boolean, User)



JavaScript

 function execPurchase(price, item,
 discountCode, wantsSpam, user)
Java
             Metodsignaturer
builder = new Purchase.Builder();
Purchase purchase =
     builder.setPrice(9900)
     .setItem(”keps”).wantsSpam(false)
     .setUser(user).build();
JavaScript

 function execPurchase(purchase) {
   purchase.price …
   purchase.item …
   purchase.wantsSpam …
   purchase.user …
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 och
       statisk 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
HTML
<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>
Med beroendehantering
HTML
<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>
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
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>
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”keps”,i objekt à la
  { item:
              duplikat
                          item: ”boll”}

•   Ingen skuggning via eval(”var x;”)
JavaScript
              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"};
     Men … obj.prototype kan
 Object.freeze(JW);
     fortfarande ändra på förseglade och frysta
 JW.name = "Joe";testat att frysa prototypen
     objekt. Jag har
 JW.job =det verkar fungera men det måste
     och "coder";
     förstås analyseras för sidoeffekter.
 console.log(JW.name + ", " + JW.job);
JavaScript
             arguments
 JW = 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]);
Referensdokumentation
            Alltid
     developer.mozilla.org
          Aldrig
     www.w3schools.com
           Varför?
         w3fools.com
jsfiddle.net
Att följa
 http://javascriptweekly.com/

    @javascript_news
@BrendanEich @littlecalculist
@addy_osmani @addyosmani
 @paul_irish @badass_js
  @rwaldron @slicknet
 @kangax @unscriptable
        @sthlmjs

Weitere ähnliche Inhalte

Mehr von johnwilander

JavaScript Beyond jQuery (Jfokus 2013)
JavaScript Beyond jQuery (Jfokus 2013)JavaScript Beyond jQuery (Jfokus 2013)
JavaScript Beyond jQuery (Jfokus 2013)johnwilander
 
Tre sårbarheter i webbappar
Tre sårbarheter i webbapparTre sårbarheter i webbappar
Tre sårbarheter i webbapparjohnwilander
 
Hotlinking is Too Hot for Comfort
Hotlinking is Too Hot for ComfortHotlinking is Too Hot for Comfort
Hotlinking is Too Hot for Comfortjohnwilander
 
Stateless Anti-Csrf
Stateless Anti-CsrfStateless Anti-Csrf
Stateless Anti-Csrfjohnwilander
 
Advanced CSRF and Stateless Anti-CSRF
Advanced CSRF and Stateless Anti-CSRFAdvanced CSRF and Stateless Anti-CSRF
Advanced CSRF and Stateless Anti-CSRFjohnwilander
 
Application Security for Rich Internet Applicationss (Jfokus 2012)
Application Security for Rich Internet Applicationss (Jfokus 2012)Application Security for Rich Internet Applicationss (Jfokus 2012)
Application Security for Rich Internet Applicationss (Jfokus 2012)johnwilander
 
RIPE: Runtime Intrusion Prevention Evaluator
RIPE: Runtime Intrusion Prevention EvaluatorRIPE: Runtime Intrusion Prevention Evaluator
RIPE: Runtime Intrusion Prevention Evaluatorjohnwilander
 

Mehr von johnwilander (7)

JavaScript Beyond jQuery (Jfokus 2013)
JavaScript Beyond jQuery (Jfokus 2013)JavaScript Beyond jQuery (Jfokus 2013)
JavaScript Beyond jQuery (Jfokus 2013)
 
Tre sårbarheter i webbappar
Tre sårbarheter i webbapparTre sårbarheter i webbappar
Tre sårbarheter i webbappar
 
Hotlinking is Too Hot for Comfort
Hotlinking is Too Hot for ComfortHotlinking is Too Hot for Comfort
Hotlinking is Too Hot for Comfort
 
Stateless Anti-Csrf
Stateless Anti-CsrfStateless Anti-Csrf
Stateless Anti-Csrf
 
Advanced CSRF and Stateless Anti-CSRF
Advanced CSRF and Stateless Anti-CSRFAdvanced CSRF and Stateless Anti-CSRF
Advanced CSRF and Stateless Anti-CSRF
 
Application Security for Rich Internet Applicationss (Jfokus 2012)
Application Security for Rich Internet Applicationss (Jfokus 2012)Application Security for Rich Internet Applicationss (Jfokus 2012)
Application Security for Rich Internet Applicationss (Jfokus 2012)
 
RIPE: Runtime Intrusion Prevention Evaluator
RIPE: Runtime Intrusion Prevention EvaluatorRIPE: Runtime Intrusion Prevention Evaluator
RIPE: Runtime Intrusion Prevention Evaluator
 

JavaScript för Javautvecklare

  • 1. JavaScript för Javautvecklare John Wilander, Handelsbanken @johnwilander Jfokus 2012
  • 3. Java Typer Primitiva: byte, short, int, long, float, double, boolean, char Resten är objekt, s.k. referenstyper JavaScript Primitiva: string, number, boolean, function, undefined Resten är object
  • 4. Java Typer Primitiva: byte, short, int, long, float, double, boolean, char Resten är objekt, s.k. referenstyper JavaScript Primitiva: string, number, boolean, function, undefined Resten är object
  • 5. Java Typer Primitiva: byte, short, int, long, float, double, boolean, charinte Strängar är generella objekt Resten är objekt, s.k.typ utan en egen referenstyper JavaScript Primitiva: string, number, boolean, function, undefined Resten är object
  • 6. Java Typer Primitiva: finns bara en Det typ för tal, byte, short, int, long, float, double, boolean, char det oavsett om är heltal eller Resten är objekt, s.k. referenstyper decimaltal JavaScript Primitiva: string, number, boolean, function, undefined Resten är object
  • 7. Java Typer Primitiva: byte, short, int, long, float, double, boolean, char Funktioner är fullödiga objekt Resten är objekt, s.k. referenstyper med en egen typ JavaScript Primitiva: string, number, boolean, function, undefined Resten är object
  • 8. Java Typer Primitiva: byte, short, int, long, float, double, boolean, charJavaScripts version av Resten oinitialiserad är är objekt, s.k. referenstyper JavaScript undefined Primitiva: string, number, boolean, function, undefined Resten är object
  • 9. JavaScript Låt oss testa typeof 10 typeof 10.3 typeof Math.LN2 typeof Infinity typeof NaN typeof ”tutorial” typeof ”” typeof (typeof 10)
  • 10. JavaScript Låt oss testa typeof 10 typeof 10.3 typeof Math.LN2 typeof Infinity typeof NaN typeof Number(10) typeof ”tutorial” typeof ”” typeof (typeof 10) typeof String(”tutorial”)
  • 11. JavaScript Låt oss testa typeof undefined typeof tutorial typeof {} typeof [] typeof [4, 6, 2] typeof new Date()
  • 12. JavaScript Låt oss testa typeof undefined typeof tutorial typeof {} typeof [] typeof [4, 6, 2] typeof new Date() typeof new Boolean(true) typeof new Number(10) typeof new String(”tutorial”)
  • 13. Statisk vs dynamisk typning Java Statisk typning: String name; Variabler har typer name = ”John”; Värden har typer name = 34; Variabler kan inte byta typ JavaScript Dynamisk typning: var name; Variabler har inga typer name = ”John”; Värden har typer name = 34; Variabler byter typ dynamiskt
  • 14. Dynamisk typning JavaScript var name = ”John”; Variabler har Värden har typer inga typer
  • 15. Stark vs svag typning
  • 16. Stark vs svag typning Stark !== bra Svag !== dålig
  • 17. Java Stark vs svag typning int intVar = 4; Ganska stark typning intVar + ””; Implicit typkonvertering intVar + 0.0; Implicit, breddande typkonv. intVar + (int)0.0; Explicit typkonvertering intVar + null; Inte tillåtet JavaScript var dynVar = 4; Mycket svag typning dynVar + ””; Implicit typkonvertering dynVar + null; Implicit typkonvertering dynVar + []; Implicit typkonvertering dynVar + [0]; Implicit typkonvertering
  • 18. Typsäkert ≈ inga typfel vid körning
  • 19. 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
  • 21. Java: Klasser och objekt Objekt Klass Objekt Exekverande Källkod Objekt kod Singleton Klass -instans
  • 22. JavaScript: Funktioner, objekt och prototyper Objekt Prototyp Objekt Exekverande Källkod Objekt kod Funktion Funktion
  • 23. JavaScript: Funktioner, objekt och prototyper Objekt Prototyp Objekt Exekverande Källkod Objekt kod Funktion Anonyma closures Funktion Moduler
  • 24. Java: Utökning med arv Subklass extends Superklass
  • 25. Java: Subtypning med arv Supertyp extends Subtyp
  • 26. Javaklasser blir funktionsmässigt större och typmässigt mindre (mer specifika) via arv
  • 27. I JavaScript så är utökning och subtypning skilda saker
  • 28. JavaScript: Utökning via prototyp JavaScript 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());
  • 29. JavaScript: Utökning via prototyp JavaScript 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());
  • 30. JavaScript: Utökning via prototyp JavaScript 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());
  • 31. JavaScript: Utökning via prototyp JavaScript 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());
  • 32. JavaScript: Utökning via prototyp JavaScript Användning av new innebär att: JW = {}; log = console.log; 1) ett nytt objekt skapas med JW.Base = function(x,JW.Base och att prototypen för y) { this.x 2) funktionen JW.Base() = x; this.y = y; }; anropas med this pekandes på JW.Base.prototype.sum = function() { den nya instansen return this.x + this.y; } JW.instance = new JW.Base(1, 2); log(JW.instance instanceof JW.Base); log(JW.instance.sum());
  • 33. JavaScript: Utökning via prototyp JavaScript 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());
  • 34. JavaScript: Utökning via prototyp JavaScript 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());
  • 35. JavaScript: Utökning via prototyp JavaScript 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());
  • 36. JavaScript: Utökning via prototyp JavaScript JW = {}; log = console.log; JW.Base = function(x, y) { this.x = x; this.y = y; }; JW.instance vi inte har skapat någon ny subtyp. Notera att = new JW.Base(1, 2); JW.Base.prototype.sumbefintliga (proto-)typen. Vi har bara utökat den = function() { return this.x + this.y; } log(JW.instance instanceof JW.Base); log(JW.instance.sum());
  • 37. JavaScript JavaScript: Subtypning JW.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);
  • 38. JavaScript JavaScript: Subtypning JW.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; ju bara programmera Java Nu försöker vi }; i JavaScript. Ni ser ju själva vilket elände det blir. JW.Extension.prototype = Nåja, låt oss gå igenom det i alla fall. 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);
  • 39. JavaScript JavaScript: Subtypning JW.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);
  • 40. JavaScript JavaScript: Subtypning JW.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);
  • 41. JavaScript JavaScript: Subtypning JW.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);
  • 42. JavaScript JavaScript: Subtypning JW.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);
  • 43. JavaScript JavaScript: Subtypning JW.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);
  • 44. Varför vill vi subtypa? Jo, för att vi tänker i statisk typning och is-a-relationer
  • 45. Statisk typning och subtypning Java public void doPurchase(List<Item> items) Kan ta emot en lista av Items eller subtyper till Item
  • 46. Dynamisk typning JavaScript public void doPurchase(List<Item> items)
  • 47. Dynamisk typning JavaScript public void doPurchase(List<Item> items)
  • 48. Dynamisk typning JavaScript public void doPurchase(List<Item> items)
  • 49. Dynamisk typning JavaScript public void doPurchase(List<Item> items)
  • 50. Dynamisk typning JavaScript function doPurchase(items) Kan ta emot vad som helst ... eller ingenting
  • 51. Dynamisk typning JavaScript function doPurchase(items) Kan returnera vad som helst ... eller ingenting
  • 52. Vad är sant och falskt i JavaScript?
  • 53. 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
  • 54. JavaScript Låt oss testa log = 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("{}"); }
  • 55. Hur kan denna falskhet drabba oss?
  • 56. Först ett par saker … JavaScript JW.obj = {drinks: "coffee"}; JW.obj.drinks; => "coffee" JW.obj["drinks"]; => "coffee" Objekts properties (≈medlemsvariabler) går att komma åt som array-referenser
  • 57. Först ett par saker … JavaScript o = JW.obj; o.toString; // Finns o.hasOwnProperty(”drinks”) ? o.hasOwnProperty(”toString”) ?
  • 58. 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'});
  • 59. 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'});
  • 60. 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});
  • 61. Hur startar man ett JavaScript-program?
  • 62. <html> JavaScript och webb <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>
  • 63. <html> JavaScript och webb <head> Skript från fil i <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>
  • 64. <html> JavaScript och webb <head> Skript från fil i <head> <script src=”js/main.js”></script> <script> var JW = {}; Inline:at skript i <head> // 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>
  • 65. <html> JavaScript och webb <head> Skript från fil i <head> <script src=”js/main.js”></script> <script> var JW = {}; Inline:at skript i <head> // Mer kod </script> </head> Skript, direkt i HTML <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>
  • 66. <html> JavaScript och webb <head> Skript från fil i <head> <script src=”js/main.js”></script> <script> var JW = {}; Inline:at skript i <head> // Mer kod </script> </head> Skript, direkt i HTML <body> <button onclick="document.getElementById('field2').value= document.getElementById('field1').value">Kopiera text</button> <div> Lite information </div> Inline:at skript i <body> <script> JW.calcPrice = function(price, vat) { //… }; </script> <script src=”http://3rdparty.com/trackUsers.js”></script> </body> </html>
  • 67. <html> JavaScript och webb <head> Skript från fil i <head> <script src=”js/main.js”></script> <script> var JW = {}; Inline:at skript i <head> // Mer kod </script> </head> Skript, direkt i HTML <body> <button onclick="document.getElementById('field2').value= document.getElementById('field1').value">Kopiera text</button> <div> Lite information </div> Inline:at skript i <body> <script> JW.calcPrice = function(price, vat) { //… }; </script> <script src=”http://3rdparty.com/trackUsers.js”></script> </body> </html> Skript från fil i <body>
  • 68. <html> Laddning och körning <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>
  • 69. <html> Laddning och körning <head> Synkron laddning och körning <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>
  • 70. <html> Laddning och körning <head> Synkron laddning och körning <script src=”js/main.js”></script> <script> var JW = {}; Körs synkront, dvs innan // Mer kod </script> DOM:en har laddats </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>
  • 71. <html> Laddning och körning <head> Synkron laddning och körning <script src=”js/main.js”></script> <script> var JW = {}; Körs synkront, dvs innan // Mer kod </script> DOM:en har laddats </head> <body> Körs vid klick-eventet <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>
  • 72. <html> Laddning och körning <head> Synkron laddning och körning <script src=”js/main.js”></script> <script> var JW = {}; Körs synkront, dvs innan // Mer kod </script> DOM:en har laddats </head> <body> Körs vid klick-eventet <button onclick="document.getElementById('field2').value= document.getElementById('field1').value">Kopiera text</button> <div> Lite information </div> Körs när parsern kommit hit <script> JW.calcPrice = function(price, vat) { //… }; </script> <script src=”http://3rdparty.com/trackUsers.js”></script> </body> </html>
  • 73. <html> Laddning och körning <head> Synkron laddning och körning <script src=”js/main.js”></script> <script> var JW = {}; Körs synkront, dvs innan // Mer kod </script> DOM:en har laddats </head> <body> Körs vid klick-eventet <button onclick="document.getElementById('field2').value= document.getElementById('field1').value">Kopiera text</button> <div> Lite information </div> Körs när parsern kommit hit <script> JW.calcPrice = function(price, vat) { //… }; </script> <script src=”http://3rdparty.com/trackUsers.js”></script> </body> </html> Laddas och körs synkront
  • 74. 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); }());
  • 75. Synkron, blockerande laddning <script src=”js/script.js”></script> Kör Ladda Html Asynkron, icke-blockerande laddning <script defer src=”js/script.js”></script> Kör Ladda Html Asynkron, blockerande laddning <script async src=”js/script.js”></script> Kör Ladda Html
  • 76. Synkron, blockerande laddning <script src=”js/script.js”></script> Kör Ladda Html Asynkron, icke-blockerande laddning <script defer src=”js/script.js”></script> Kör Ladda Html Asynkron, blockerande laddning <script async src=”js/script.js”></script> Kör Ladda Html
  • 77. Synkron, blockerande laddning <script src=”js/script.js”></script> Kör Ladda Html Asynkron, icke-blockerande laddning <script defer src=”js/script.js”></script> Kör Ladda Html Asynkron, blockerande laddning <script async src=”js/script.js”></script> Kör Ladda Html
  • 78. OK, men hur startar vi?
  • 79. Java In the Beginning public static void main(String[] args) JavaScript (function(){}()); window.someGlobalFunction();
  • 80. Självinvokerande funktioner Anonym, självinvokerande med parameter (function myFunc(me) { // Kod }('John')); Anonym, självinvokerande utan parameter (function myFunc() { // Kod }());
  • 81. Självinvokerande funktioner Anonym, namnlös och självinvokerande (function() { // Kod }()); Namngiven, självinvokerande, icke-anropsbar var myFunc = function(me) { // Kod }('John');
  • 83. JavaScript Scope var GLOB = {}; GLOB.func = function(array) { var local = …; … for (var i=0; i<array.length; i++){ … var temp = array[i]; } };
  • 84. JavaScript Scope var GLOB = {}; GLOB.func = function(array) { var local = …, i, temp; … for (i=0; i<array.length; i++){ … temp = array[i]; } };
  • 85. JavaScript Scope var GLOB = {}; GLOB.func = function(array) { var local = …, i, temp; … for (i=0; Det finns bara två variabel-scope: i<array.length; i++){ … Globalt eller lokalt funktions-scope. temp = array[i]; } Alla lokala variabler ”hissas” till }; toppen av funktionen (hoisting).
  • 87. 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
  • 88. 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
  • 89. 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
  • 90. 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
  • 91. 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;
  • 92. JavaScript Closure (hölje) (function(array) { var i, temp; … for (i=0; i<array.length; i++){ … temp = array[i]; } }([1, 2, 3]));
  • 93. JavaScript Closure (hölje) (function(array) { var i, temp; … for (i=0; i<array.length; i++){ … Ett closure håller sitt scope och sin temp =kontext under hela sin livslängd. array[i]; } }([1, 2, 3])); En referens som kommit innanför höljet (array i exemplet) lever alltså kvar och håller sitt värde inom ”höljet”.
  • 94. JavaScript Closure-exempel for(i=0; i<pages.length; i++) { var page = pages[i]; pageElement.load(page.url, function() { launchForm(page.form); }); }
  • 95. JavaScript Closure-exempel for(i=0; i<pages.length; i++) { var page = pages[i]; pageElement.load(page.url, function() { launchForm(page.form); }); Callback-funktion eftersom } pageElement.load() är asynkron
  • 96. JavaScript Closure-exempel for(i=0; i<pages.length; i++) { var page = pages[i]; pageElement.load(page.url, function() { page hissas och får alltså ett launchForm(page.form); }); nytt värde för varje iteration }
  • 97. JavaScript Closure-exempel var page; for(i=0; i<pages.length; i++) { page = pages[i]; pageElement.load(page.url, page hissas och får alltså ett function() { nytt värde för varje iteration launchForm(page.form); }); }
  • 98. JavaScript Closure-exempel var page; for(i=0; i<pages.length; i++) { page = pages[i]; pageElement.load(page.url, function() { launchForm(page.form); }); 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.
  • 99. JavaScript Closure-exempel var page; for(i=0; i<pages.length; i++) { page = pages[i]; pageElement.load(page.url, function() { launchForm(page.form); }); }
  • 100. JavaScript Closure-exempel var page; for(i=0; i<pages.length; i++) { page = pages[i]; (function(page) { pageElement.load(page.url, function() { launchForm(page.form); } }); })(page); }
  • 101. JavaScript Closure-exempel var page; for(i=0; i<pages.length; i++) { page = pages[i]; (function(page) { pageElement.load(page.url, function() { launchForm(page.form); } Vi binder page till ett nytt hölje }); })(page); så att callbacken refererar rätt }
  • 102. JavaScript Closure-exempel var page; for(i=0; i<pages.length; i++) { page = pages[i]; (function(myPage) { pageElement.load(myPage.url, function() { launchForm(myPage.form); } Om man mår dåligt av sånt }); så kan man döpa om höljets })(page); variabel :) }
  • 103. Med självinvokerande funktioner, scope och closures är vi redo för det viktigaste designmönstret: Crockford-modulen eller Module Pattern
  • 104. JavaScript JW.cache = (function(){}());
  • 105. JavaScript JW.cache = (function(){ return {}; }());
  • 106. JavaScript JW.cache = (function(){ return { getPatient: function(personnummer) { } }; }());
  • 107. JavaScript JW.cache = (function(){ var cache = {}; return { getPatient: function(personnummer) { } }; }());
  • 108. JavaScript JW.cache = (function(){ var cache = {}; return { getPatient: function(personnummer) { var res=cache[personnummer]; // Check if fresh // Return } }; }());
  • 109. JavaScript JW.cache = (function(){ var cache = {}; return { getPatient: function(personnummer) { var res=cache[personnummer]; if(_isValid(res)) { return res.patient; } else { // Handle cache miss } } }; }());
  • 110. 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 } }
  • 111. 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
  • 112. JavaScript JW.cache = (function(){ var cache = {}, _isValid(res) { return !res ? false : (Date.now() - res.timestamp) <= 60000; // One minute } return { Vi kan alltså ha (closure-)privata variabler och funktioner getPatient: function(personnummer) { var res=cache[personnummer]; if(_isValid(res)) { return res.patient; } else { // Handle cache miss
  • 113. JavaScript Crockford = (function(initParam) { var privVar1, privVar2, _privFunc1 = function() { }, _privFunc2 = function() { }; return { pubVar1: ”value”, pubFunc1: function() { } }; }(initParam));
  • 114. För att möjliggöra enhetstester använder man någon form av Revealing Module Pattern
  • 115. JavaScript Crockford = (function(initParam) { var _privFunc = function() { }; return { unitTestHandle: { privFunc: _privFunc } }; }(initParam));
  • 116. JavaScript Crockford = (function(initParam) { var _privFunc = function() { }; return { unitTestHandle: { privFunc: function() { log(”Only use in unit test”); return _privFunc(); } } }; }(initParam));
  • 118. Java Metodsignaturer public void execPurchase(int, String, String, boolean, User) JavaScript function execPurchase(price, item, discountCode, wantsSpam, user)
  • 119. Java Metodsignaturer builder = new Purchase.Builder(); Purchase purchase = builder.setPrice(9900) .setItem(”keps”).wantsSpam(false) .setUser(user).build(); JavaScript function execPurchase(purchase) { purchase.price … purchase.item … purchase.wantsSpam … purchase.user …
  • 121. JavaScript-bygge • Hantering av ramverk och bibliotek • Beroendehantering egna filer/moduler/ klasser • Enhetstester och statisk analys • Konkatenering och minifiering • final.html
  • 122. 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
  • 123. Beroendehantering egen kod • AMD – Asynchronous Module Definition • Bundlat i större ramverk såsom YUI och Ext JS • Fristående require.js m.fl.
  • 124. Enhetstester och statisk analys • Enhetstester med Jasmine, JSTestDriver etc. • phantom.js – webbläsare utan GUI • sinon.js – mockramverk • Statisk analys med JSHint eller JSLint
  • 125. Konkatenering och minifiering • Google Closure Compiler • YUI Compressor • uglify.js • require.js utför konkatenering och minifiering med Closure Compiler och uglify.js
  • 126. Utan beroendehantering HTML <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>
  • 127. Med beroendehantering HTML <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>
  • 128. 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:
  • 129. final.html 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>
  • 131. 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”keps”,i objekt à la { item: duplikat item: ”boll”} • Ingen skuggning via eval(”var x;”)
  • 132. JavaScript seal (ES5) JW = {name: "John"}; JW.name = "Joe"; JW.job = "coder"; console.log(JW.name + ", " + JW.job);
  • 133. JavaScript seal (ES5) JW = {name: "John"}; Object.seal(JW); JW.name = "Joe"; JW.job = "coder"; console.log(JW.name + ", " + JW.job);
  • 134. JavaScript freeze (ES5) JW = {name: "John"}; Object.freeze(JW); JW.name = "Joe"; JW.job = "coder"; console.log(JW.name + ", " + JW.job);
  • 135. JavaScript freeze (ES5) JW = {name: "John"}; Men … obj.prototype kan Object.freeze(JW); fortfarande ändra på förseglade och frysta JW.name = "Joe";testat att frysa prototypen objekt. Jag har JW.job =det verkar fungera men det måste och "coder"; förstås analyseras för sidoeffekter. console.log(JW.name + ", " + JW.job);
  • 136. JavaScript arguments JW = 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]);
  • 137. Referensdokumentation Alltid developer.mozilla.org Aldrig www.w3schools.com Varför? w3fools.com
  • 139. Att följa http://javascriptweekly.com/ @javascript_news @BrendanEich @littlecalculist @addy_osmani @addyosmani @paul_irish @badass_js @rwaldron @slicknet @kangax @unscriptable @sthlmjs