JavaScript

Not only for Java Programmers

Heinrich Göbl

www.goebl.com

About me

  • Heinrich Göbl
  • IT-Freelancer (Architecture, Software-Development)
  • Focus on Java EE
  • “I like JavaScript ;-)”

What is JavaScript?

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


JavaScript


Why JavaScript?

Where JavaScript?

Object Literals

var obj = {
    name: "String",
    "while": "keyword as property name",
    flag: true,
    root2: 1.414213562,
    method: function () {
        return new Date();
    },
    lines: [ 1, 2, "abc" ]
};

Objects

Objects are associative arrays

var obj = {};     // new Object() no longer used
obj.prop = 'Jason';
obj['prop'] = 'Bourne';
'prop' in obj;    // true
obj.prop = null;
'prop' in obj;    // true
delete obj.prop;
'prop' in obj;    // false
obj.prop;         // undefined

JSON

[ 30, 10, "Jason" ]


{ "prop1": "value", "prop2": 1.414213562,
  "prop3": null,    "prop4": true,
  "prop5": [ 30, 10, "Jason" ],
  "prop6": { "x": 10, "y": -1 }
}


true

Arrays

var array = [ 30, 10, "Jason", new Date() ];

array.push({ prop: "Bourne" });
// equiv. w/ push
array[array.length] = "Last Element";
array.length;        // 6
array[100];          // undefined -> no Exception!
array[1000] = true;
array.length;        // 1001
typeof array;        // 'object'

Boolean Expressions

Function Declaration (1)

function add(arg1, arg2) {
  var result = arg1 + arg2;
  return result;
}

add(3, 7);               // 10
add('Jason', ' Bourne'); // 'Jason Bourne'
add([1, 3], [7, 5]);     // '1,37,5'
add.length;              // 2
typeof add;              // 'function'

Function Declaration (2)

function add() {
  var i, len, result = 0;
  for (i = 0, len = arguments.length; i < len; ++i) {
    result += arguments[i];
  }
  return result;
}

add(3, 7, 4, 6);         // 20
add.length;              // 0

Function Expression (1)

typeof max;     // 'undefined'
typeof min;     // 'function'

var max = function (a, b) {
  return a > b ? a : b;
};

typeof max;     // 'function'

function min(a, b) { return a < b ? a : b; }

Functions: 1st-Class Objects

function jQuery() { /* ... */ }
jQuery.browser = { /* ... */ };

// used as function
var $info = jQuery('#info');

// used as object (holds ref to trim-function)
jQuery.trim('  hi  ');

// click-function gets a function reference
jQuery('#btnOk').click(function () { /* ... */ });

Scopes


“In JavaScript there's no curly braces local scope; in other words, blocks don't create scope.”
JavaScript Patterns, Stoyan Stefanov, O'Reilly, 2010

Module Pattern

var MYKA = {}; // MYKA = my killer app

MYKA.helper = function () { /* ... */ };

// defining a new module (sub-namespace)
MYKA.module1 = {
  init: function () { /* ... */ },
  reload: function () {}
};

MYKA.module1.Customer = function (){
  // a constructor function
};

IIFE

(function() {
  var local; // not visible outside

  function helper() { /* I'm private */ }

  // do something
})();


(function() { /* ... */ })();
(function() { /* ... */ }());

Late Binding of 'this'

 var obj1 = {
     name: 'Bourne',
     getName: function () {return this.name;}
   },
   obj2 = {
     name: 'Wombosi'
   },
   getName = obj1.getName;

 obj1.getName();     // Bourne
 getName.call(obj2); // Wombosi
 getName();          // undefined

Inheritance

Inheritance Patterns/Types

Many ways - too many ways to fall...


  • Constructor Pattern
  • Prototype Pattern
  • Combination Constructor/ Prototype Pattern
  • Dynamic Prototype Pattern
  • Parasitic Constructor Pattern
  • Durable Constructor Pattern
  • Prototype Chaining
  • Constructor Stealing
  • Combination Inheritance
  • Prototypal Inheritance
  • Parasitic Inheritance
  • Parasitic Combination Inheritance

see "Professional JavaScript for Web Developers", Wrox Press

Constructor Function

function LatLng(lat, lng) {
  this.lat = lat;
  this.lng = lng;
}

var myHome = new LatLng(47.8239, 12.0946);

console.log(myHome);
// { lat: 47.8239, lng: 12.0946 }

Member Functions

LatLng.prototype.toString = function () {
  return 'LatLng: ' + this.lat + ';' + this.lng;
};

LatLng.prototype.getLat = function () {
  return this.lat;
};

LatLng.prototype.getLng = function () {
  return this.lng;
};

Subtype

Combination Inheritance

function POI(lat, lng, name) {
  // Constructor Stealing
  LatLng.call(this, lat, lng);
  this.name = name;
}

POI.prototype = new LatLng(); // not the best way!

// correct constructor pointer
POI.prototype.constructor = POI;

Add / Override Methods

// overrides LatLng::toString
POI.prototype.toString = function () {
  return 'POI: ' + this.name
};

// add new method
POI.prototype.getName = function () {
  return this.name
};

var saltys = new POI(47.587, -122.378, 'Saltys');

Prototype Chain

image/svg+xml LatLng.prototype __proto__constructorgetLnggetLattoString constructor Object.prototype [native] POI.prototype __proto__constructorgetNametoString saltys __proto__latlngname 47.5872-122.3777'Saltys' POI prototype LatLng prototype [Function][Function][Function] [Function][Function] latlng undefinedundefined

Inheritance Summary


Diff JavaScript - Java


See code-snippets/java


Pitfalls

Pitfall #1 - globals

for (i = 0; i < 10; ++i) { /* ... */ }


Guide

Pitfall #2 - hoisting

console.log(typeof a);  // 'undefined'
console.log(typeof c);  // 'undefined'

a = 'Wombosi';
console.log(typeof a);  // 'string'

if (false) {
  var a, b;             // (!) unreachable code (!)
}

console.log(b); // undefined
console.log(c); // ReferenceError: c is not defined

Pitfall #3 - type coercion

7 == "7"     // true
1 == true    // true



Solution: use strict equals === and !==

7 === "7"     // false
1 === true    // false

Pitfall #4 - this

var obj = {
  name: 'Jason Bourne',
  printLater: function () {
    setTimeout(function () {
      console.log(this.name);
    }, 1000);
  }
};
obj.printLater(); // logs undefined

this does not point to obj!

Pitfall #4 - this -> self

var obj = {
  name: 'Jason Bourne',
  printLater: function () {
    var self = this; // sometimes that | me

    setTimeout(function () {
      console.log(self.name);
    }, 1000);
  }
};
obj.printLater(); // logs Jason Bourne

Pitfall - Numbers

1/10 + 2/10            // 0.30000000000000004
1 / 0                  // Infinity
isFinite(1 / 0)        // false
Math.pow(2, 1023)      // 8.98846567431158e+307
Math.pow(2, 1024)      // Infinity
Number.MAX_VALUE       // 1.7976931348623157e+308

Pitfall - Number Parsing

parseInt('077')        // 63   (!) -> octal value
parseInt('080')        // 0    (!) -> parse error
parseInt('080', 10)    // 80
parseInt('80abc', 10)  // 80   (!)
Number('80abc')        // NaN
parseInt('Jason')      // NaN
isNaN(Number('Jason')) // true
parseInt('ZZ', 36) === 36 * 36 - 1    // true
Number(36 * 36 - 1).toString(36);     // 'zz'

Pitfall - ASI

return
{
   a: true
}

// behaves like ...
return; // = return undefined;
{
   a: true
}; // code not reachable -> garbage collected

Pitfall - forget new

jQuery.Event = function( src, props ) {
  // Allow instantiation without the 'new' keyword
  if ( !(this instanceof jQuery.Event) ) {
    return new jQuery.Event( src, props );
  }

  // ...
};

Other Pitfalls

Fighting Pitfalls

Tools

JetBrains IDEs


Demo?

Browser Tools

Integrated


Demo?

JSHint (Static Code Analysis)

/*jshint latedef:true, curly:true*/
a = 'Wombosi';
if (/bos/.test(a))
    a += '!';
var a;


JSLint global declaration

/*global jQuery*/

(function( $ ){

    // do something with $
    // ($ is local var for global jQuery)
    // BTW jQuery is a property of window

})( jQuery );

JSHint and Alternatives

JSHint in Java/Maven

<plugin>
    <groupId>ro.isdc.wro4j</groupId>
    <artifactId>wro4j-maven-plugin</artifactId>
    <executions><execution>
        <id>wro-lint</id>
        <phase>generate-resources</phase>
        <goals><goal>jshint</goal></goals>
        <configuration>...</configuration>
    </execution></executions>
</plugin>

JS[HL]int IDE Integration

Debugging Proxies

jsFiddle (Example)

jsFiddle

console

Poor man's debugger :-;


var a = [1, 9], b = {name: 'Bourne'};

console.log('a', a, 'b', b);
// a [ 1, 9 ] b { name: 'Bourne' }

console.error('No more beer');

Links DailyJS - Mastering Console Logging http://dailyjs.com/2012/02/02/console/ Mozilla Developer Network / console https://developer.mozilla.org/en/DOM/console

console: old browsers

if (typeof console === 'undefined') {
  (function(global) {
    var nop = function(){};
    global.console = {
      log: nop, info: nop, error: nop,
      dir: nop, time: nop, timeEnd: nop
    };
  }(window));
}

Testing

Either ...... or?
Real Browser TestsPhantom.js, Zombie.js, ...
synchronousasynchronous
Unit-TestIntegration-Test
Browser JSRhino, Node, ...
ManuallyAutomated


Testing-Tools

Integration Tests


Unit-Testing

Assertion Libraries


expect(window.r).to.be(undefined);
expect({ a: 'b' }).to.eql({ a: 'b' })
expect(5).to.be.a('number');
expect([]).to.be.an('array');
expect(window).not.to.be.an(Image);

Mock / Spy / Stubs


var callback = sinon.stub();
callback.withArgs(42).returns(1);
callback.withArgs(1).throws("TypeError");

callback(); // No return value, no exception
callback(42); // Returns 1
callback(1); // Throws TypeError

Demo: mocha / expect.js

see code-snippets/javascript/inheritance-test.js


$ npm install mocha -g



$ mocha inheritance-test.js
$ mocha --reporter spec *-test.js
$ mocha --watch --growl *-test.js

JavaScript in Facelets (1)




JavaScript in Facelets (2)

<script type="text/javascript">
// <![CDATA[

  if ($.browser.msie &&
      parseInt($.browser.version, 10) <= 11) {
    alert('Wrong browser!');
  }

// ]]>
</script>

Efficiency / Performance

Concatenate and minify js files!


Consider using AMD

The Asynchronous Module Definition (AMD) API specifies a mechanism for defining modules such that the module and its dependencies can be asynchronously loaded.

Example: uglify-js

(function (window, undefined) {
    var myString = 'Wombosi';
    if (/bos/.test(myString)) {
        myString += '!';
    }
    if (window.wom === undefined) {
        window.wom = myString;
    }
}(window));
(function(e,t){var n="Wombosi";/bos/.test(n) ↵
&&(n+="!"),e.wom===t&&(e.wom=n)})(window);

jQuery Examples

From: jQuery Fundamentals by Rebecca Murphey
$('#menu li').hover(function() {
    $(this).toggleClass('hover');
});


$('div.funtimes').animate(
    {
        left : [ "+=50", "swing" ],
        opacity : [ 0.25, "linear" ]
    },
    300
);

jQuery Mobile - head

<!DOCTYPE html>
<html lang="en">
<head>
    <link href="jquery.mobile-1.1.0.css"
          rel="stylesheet"/>
    <script src="jquery-1.7.1.js"></script>
    <script src="jquery.mobile-1.1.0.js"></script>
    <script src="my-application.js"></script>
</head>

jQuery Mobile - body

<section id="home" data-role="page">
  <header data-role="header">
    <h1>nerdshow rc</h1>
  </header>
  <div data-role="content">
    <a data-role="button" href="#"
       data-icon="arrow-r" id="btn-next">
      Next</a>
  </div>
</section>
<section id="help" data-role="page">
...
</section>

jQuery Mobile - code

$('#home').live('pagebeforecreate', function() {
    $.mobile.showPageLoadingMsg();
    myapp.load(function (error) {
        $.mobile.hidePageLoadingMsg();
        if (error) {alert(error);}
    });
    // ...
});
// connect behavior to form elements
$(function () {
    $('#btn-next').click(function () {
        myapp.nextSlide();
    });
});

Reading

Internet


Books

Questions?

Thank you!

// my mail address
'hgoebl+goebl.com'.replace('+', '@')

Backup

image/svg+xml
taken from: http://rationalwiki.org/ (Creative Commons Licensed)

switch - not like Java!

var i, c = 3,
    f = function() { return 2; };

for (i = 1; i <= 3; ++i) {
  switch (i) {
    case 1:   console.log('1'); break;
    case f(): console.log('2'); break;
    case c:   console.log('3'); break;
    default:  console.log('?'); break;
  }
}

Exception Handling (1)

try {
  fn();           // fn is not defined anywhere
}
catch (e) {
  console.log(e); // [ReferenceError: fn is not defined]
  console.log(e.type);     // not_defined
  console.log(e.message);  // fn is not defined
}
finally {
  console.log('finally');
}

Exception Handling (2)

throw {
  type: '...',
  message: '...'
};

throw Error('Bei mia is ois kabutt');

console: measuring time

var i;
console.time('myHeavyLoop');
for (i = 0; i < 100000; i++) {
  ;
}
console.timeEnd('myHeavyLoop');
// myHeavyLoop: 12ms

Pitfall - function in loop

var i, nums = [];
for (i = 0; i < 10; i++) {
  nums[i] = function (j) {
    return i + j;
  };
}

nums[0](2); // Prints 12 instead of 2
// example from www.jshint.com/options/

Pitfall - function in loop

Solution: copy the value of i

var i, nums = [];
for (i = 0; i < 10; i++) {
  (function (i) {
    nums[i] = function (j) {
      return i + j;
    }
  }(i));
}
// example from www.jshint.com/options/

Documentation

Content Delivery Networks

Boolean Expressions (2)

function f(o) {
  if (o && o.prop) {
    // use o.prop
  }
}

Java is type-safe but more verbose:

public void f(MyObj o) {
  if (o != null && o.getProp() != null) {
    // use it
  }
}

Conclusions (1)

Conclusions (2)