Advanced JavaScript
Jussi Pohjolainen
Agenda • Short Recap of JS • About EcmaScript 5 • JavaScript Best Prac>ces and Pa?erns • JavaScript Object Oriented Programming • HTML5 and JavaScript • JS – libraries – JQuery, YUI Library -‐> AngularJS
• Asynchronous Module Defini>on (AMD) • Designing JS Libraries • Tes>ng & Op>mizing
Recommended Reading
• Recommended reading – JavaScript: The Good Parts by Douglas Crockford – JavaScript: The Definite Guide by David Flanagan – JavaScript Pa?erns: Stoyan Stefanov
• And Google.. • Lot of good presenta>ons – http://yuilibrary.com/theater/
Rise of the Responsive Single Page App
Image: h?p://johnpolacek.github.io/scrolldeck.js/decks/responsive/
Single-‐page Applica>ons (SPA)
• Web app that fits on a single web page – Fluid UX, like desktop app – Examples like Gmail, Google maps
• Html page contains mini-‐views (HTML Fragments) that can be loaded in the background
• No reloading of the page, be5er UX • Requires handling of browser history, naviga<on and bookmarks
JavaScript
• SPAs are implemented using JavaScript and HTML
• ECMAScript is a scrip>ng language, standardized by Ecma Interna>onal
• In Browsers, ECMAScript is commonly called JavaScript – JavaScript = Na<ve (EcmaScript) + Host objects (browser)
Not just Web!
• Mobile Applica>ons • Windows 8/10 apps • Desktop widgets • Server side JS
<!DOCTYPE html> <html> <head> <title> Title </title> <meta charset="UTF-8" /> </head> <body> <script> document.write("hello world!"); </script> <script src="somefile.js"></script> </body> </html>
PROGRAMMING WITH JS
Basic Types
• JavaScript is loosely typed language! • Seven data types – Boolean – null – Undefined – Number
• 64 bit floa>ng point, also available Number.MAX_VALUE, Number.MIN_VALUE
– String – Object
About Numbers • Number(value), converts en>re string
– var i = Number("12"); • parseInt(value[, radix]), converts start of the string – var i = parseInt("12px", 10); – Radix?
• 10 => integer number, 8 => octal number, 16 => hexadecimal • While this parameter is op>onal, always specify it to eliminate reader confusion and to guarantee predictable behavior. Different implementa<ons produce different results when a radix is not specified.
• NaN (Not a Number) – Result of erroneous opera>ons
var integer1 = Number("12"); var integer2 = parseInt("12", 10); print(integer1 + integer2); // 24 var a = parseInt("12foobar", 10); print(a); // 12 var b = parseInt(" 12 ", 10); print(b); // 12 var c = parseInt("foobar12", 10); print(c); // Don't do this if(c == NaN) { print("A) It's Nan!"); } if(isNaN(c)) { print("B) It's NaN!"); }
Math Object
• All proper>es and methods are "sta>c", just like in Java – abs – acos – atan – … – sin – sqrt
• var value = Math.sqrt(4);
Strings • Sequences of 0 – n of 16-‐bit chars • Example
var s1 = "Hello"; var s2 = "Hello"; if(s1 === s2) { print("the same!"); } print(s1.length); print("hello" + 12); print(12 + "hello"); print("hello".toUpperCase());
True or false? var myArray1 = [false, null, undefined, "", 0, NaN]; // EcmaScript 5 feature! // Iterate the array myArray1.forEach(function(entry) { if(entry) { print(entry); // Here? } });
True or false? var myArray1 = ["false", "0", "undefined", "NaN"];
// EcmaScript 5 feature!
// Iterate the array
myArray1.forEach(function(entry)
{
if(entry)
{
print(entry);
}
});
True or false? var value = 0;
if(value = 0)
{
print("A");
}
if(value == 0)
{
print("B");
}
if("0" == 0)
{
print("C");
}
if("0" === 0)
{
print("D");
}
Statements
• Same than in other languages – If – Switch/case – While – Do/while – For – Break – Con>nue – Return – Try/throw/catch
Rhino (JavaScript Engine)
• Open Source JS Engine developed in Java – Mozilla Founda>on
• No built in support for web browser objects • Has Rhino shell for running JS in command line • Is bundled in Java SE 6 • Supports EcmaScript 5
EXERCISE 1
ABOUT ECMASCRIPT 5
EcmaScript
• Ecma Standard is based on JavaScript (Netscape) and JScript (Microsom)
• Development of the standard started in 1996 • First edi>on 1997 • Support – http://kangax.github.com/es5-compat-table/
• Newest version: EcmaScript 5.1 – http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf
Recap: object types
• Na>ve (Core Javascript) – ECMAScript standard: Array, Date..
• Host – The host environment, for example browser: window, DOM objects
EcmaScript
• Goal – Fix “bad” parts of JS while maintaining compa>ble with EcmaScript 5
• Introduces Strict mode – Removes features from the language! Raises errors that were okay in non strict mode
– Backward compa>ble – Add “use strict”, in func>on or global scope
• EcmaScript supports non-‐strict mode, but it’s depricated!
Strict “mode”
• Detec>on of bad/dangerous programming prac>ces – with() statement prevented – Assignment to non-‐declared variables prevented (i = 3)
– Eval is prohibited – Lot of other issues..
• See ES5 specifica>on page 235
Enable strict mode > cat strictmode.js
// This is just a string, backward compatible!
"use strict";
i = 0;
> rhino strictmode.js
js: uncaught JavaScript runtime exception: ReferenceError: Assignment to undefined "i" in strict mode
Global and local // GLOBAL, everything is strict: "use strict"; //.. strict program // LOCAL, function is strict function foo() { "use strict"; //.. strict function }
Other Main Changes
• Na>ve JSON object added – For parsing/stringifying JSON
• Changes to Array object, nine new methods – indexOf, lastIndexOf, every, some, forEach, map, filter, reduce, reduceRight
• Changes to Object – Can define ge?ers and se?ers – Objects can be sealed (no new proper>es can be added) and frozen (values cannot be changed)
JSON and Weather Underground myObject = JSON.parse(httpObj.responseText);
city = myObject.location.city;
now = myObject.forecast.txt_forecast.forecastday[0].fcttext_metric;
icon = myObject.forecast.txt_forecast.forecastday[0].icon_url;
forEach var arr = ["apple", "banana", "carrot", "apple"];
print(arr.indexOf("apple")); // 0
print(arr.indexOf("daikon")); // -1
print(arr.lastIndexOf("apple")); // 3
arr.forEach(function (entry)
{
print(entry)
}
);
every and some // Checks all the values, if one of them does not // match with given condition, return value is false. var returnValue = arr.every(function (value, index, array) { return value.length > 1; } ); print(returnValue); // true // Checks all the values, if one of them matches with // given condition, return value is true. var returnValue = arr.some(function (value, index, array) { return value === "apple"; } ); print(returnValue); // true
map and filter // Adds Hello to the end of the array values var newArray = arr.map(function (value, index, array) { return value + " Hello"; }); newArray.forEach(function (entry) { print(entry) } ); // Keep only Apples. var newArray2 = arr.filter(function (value, index, array) { return value === "apple"; }); newArray2.forEach(function (entry) { print(entry) } );
reduce var value = [10, 20, 30, 40, 50].reduce(function (previousValue, currentValue, index, array) {
print("previousValue = " + previousValue);
print("currentValue = " + currentValue);
return previousValue + currentValue;
}, 0);
print("result = " + value);
/*
previousValue = 0
currentValue = 10
previousValue = 10
currentValue = 20
previousValue = 30
currentValue = 30
previousValue = 60
currentValue = 40
previousValue = 100
currentValue = 50
result = 150
*/
reduceRight var value = [10, 20, 30, 40, 50].reduceRight(function (previousValue, currentValue, index, array) {
print("previousValue = " + previousValue);
print("currentValue = " + currentValue);
return previousValue + currentValue;
}, 0);
print("result = " + value);
/*
previousValue = 0
currentValue = 50
previousValue = 50
currentValue = 40
previousValue = 90
currentValue = 30
previousValue = 120
currentValue = 20
previousValue = 140
currentValue = 10
result = 150
*/
Prevent Extensions "use strict"; var obj = {}; obj.name = "John"; print(obj.name); // "John" print(Object.isExtensible(obj)); // true Object.preventExtensions(obj); // Should be exception in strict mode obj.url = "http://www.something.com"; print(Object.isExtensible(obj));
Proper>es and Descriptors
• It’s possible to define proper>es for object – Property descriptor • Value • Get and Set methods • Writable • Enumerable • Configurable
Example var obj = {};
obj.name = "something";
Object.defineProperty( obj, "name", {
value: "something", // Notice: you cannot have value and get + set
get: someFunction,
set: someOtherFunction,
writable: false, // property cannot be changed
enumerable: true, // will be iterated in for in
configurable: true // can be deleted
});
print( obj.name )
Sealing and Frozing
• Sealing prevents other code from dele>ng or adding descriptors – Object.seal(obj) – Object.isSealed(obj)
• Frozing is almost iden>cal to sealing, but addi>on of making the proper>es uneditable – Object.freeze(obj) – Object.isFrozen(obj)
EcmaScript 5 -‐ Overview
• Strict Mode • JSON parsing now standard • New Array methods • New Object methods
EXERCISE 2
JS BEST PRACTISES AND PATTERNS
Tools
• IDEs – Visual Studio, Aptana, Webstorm, IxEdit … – Or just text editor
• JS Engines: V8, Rhino .. • Quality: JSLint • Lot of frameworks available!
JS and OO
• JavaScript supports object-‐oriented language! • Only five primi>ve types: number, string, boolean, null, undefined – Object wrappers for number, string and boolean available
• Object is just a collec>on of named proper>es, a list of key-‐value pairs – Some of the proper>es can be func>ons!
• No classes! Let’s look at OO later in more carefully.
JS and Command Line
• It’s possible to run your js apps in command line.
• Several JS engines – SpiderMonkey (c++) or Rhino (java) (Firefox) – SquirrelFish (Apple’s Webkit) – V8 (Google Chrome)
• It’s possible to install these as command line apps, although the process can be li?le difficult
Rhino (JavaScript Engine)
• Open Source JS Engine developed in Java – Mozilla Founda>on
• No built in support for web browser objects • Has Rhino shell for running JS in command line • Is bundled in Java SE 6 – In Java 8 a new JS engine called Nashorn
V8
• Open source JS engine developed by Google • Compiles JS to na>ve code • Wri?en in C++, runs on Windows, OS X and Linux
• Can be used in browser and standalone engine
• You need to build the V8 – h?p://code.google.com/p/v8/ – h?ps://developers.google.com/v8/build
V8 running on Mac OS X
Any problems in the code? function sum (a, b) { s = a + b; return s; } x = sum(5,5); // Rhino's way to print to console print (x);
JSLint • JSLint is JS code quality tool made by Douglas Crockford – h?p://jslint.com
• Inspects and warns about poten>al problems • “Will hurt your feelings” • Excepts that your code is in “strict mode” • Can be used via website or command line (installa>on required)
• Command line tool (Java wrapper for JSLint) – h?p://code.google.com/p/jslint4java/
JSLint in Command Line
• JSLint4java – Java wrapper for the JSLint – h?p://code.google.com/p/jslint4java/
• To use it: – java -‐jar jslint4java-‐2.0.3.jar applica>on.js
Amer some modifica>ons function sum(a, b) { "use strict"; var s = a + b; return s; } var x = sum(5, 5); // Rhino's way to print to console print(x);
Prin>ng to Console
• Debugging in Browsers: use console – object • Firefox – Firebug extension
• Safari – Enable developer mode
• How? – console.log(“Hello World!”);
Global Variables
• Every JS environment has a global object • Every global variable becomes a property of the global object – In browser environment: window is the global object itself
Declaring Global variable // global object, window, will get a new property! variable = "hi there!"; console.log(variable); // And different ways to access the variable console.log(window.variable); console.log(window.variable); console.log(window["variable"]); console.log(this.variable); console.log(window);
Window proper>es
Problems
• Global variables shared among all the code • What if you use some third party JavaScript Library like JQuery or Modernizr? Name collision!
• Avoid Globals!
Problem 1 function something() {
// window object now has variable property!
variable = "hi there!";
}
something();
// prints "hi there!"
console.log(variable);
Problem 2 function something() {
// window object now has z property!
var x = z = "hello";
}
something();
// prints "hello"
console.log(z);
Difference when using var var x = 20; y = 21;
console.log(window.x); // 20 console.log(window.y); // 21
delete x; // does not delete anything
delete y; // removes the y from window
console.log(window.x); // 20 console.log(window.y); // undefined
Using var
• Use always var! • In strict mode, assignments to undeclared variables will throw an error!
Func>ons and Variable Declaring var x = 10; function test() { console.log(x); // outputs what? if(true) { var x = 5; } } test();
What really happens var x = 10; function test() { var x; console.log(x); // outputs “undefined” if(true) { x = 5; } } test();
Variable Hois>ng
• When you declare a variable inside a func>on, it acts like it was declared at the top of the func>on!
• Declare always your variables at the top!
Single Var Pa?ern function test() { var a = 1, b = 2, …; // rest of the function } test();
FD, FE, NFE
• It gets harder when a variable is – Func>on declara>on (FD) – Func>on expression (FE)
• Rules – Func<on declara<on is not hoisted – Func<on expression is hoisted
Func>on Declara>on: this works!
function testC()
{
print(foo());
function foo()
{
return 5;
}
}
<=>
function testD()
{
function foo()
{
return 5;
}
print(foo());
}
Func>on Expression: this does not work!
function testA()
{
print(foo());
var foo = function()
{
return 5;
}
}
<=>
function testB()
{
var foo;
print(foo());
foo = function()
{
return 5;
}
}
Named Func>on Expression
// Named function expression for recursion or debugging
var somethingFoo = function somethingBar()
{
print("do something");
// Recursion, does not end well here.
somethingBar();
}
somethingFoo();
// this does not work
somethingBar();
Func>ons in if-‐statements
• In strict mode code, func:ons can only be declared at top level or immediately within another func:on.
• So what happens in non-‐strict mode?
Func>ons in if-‐statements
function init()
{
if(true)
{
function foo() { return 1; }
}
else
{
function foo() { return 2; }
}
return foo();
}
print(init()); // 1 or 2?
Use this!
function init2()
{
var foo;
if(true)
{
foo = function() { return 1; }
}
else
{
foo = function() { return 2; }
}
return foo();
}
print(init2());
For loops for(var i = 0; i < somearray.length; i++) {
doSomething();
}
<=>
var max = somearray.length;_for(var i = 0; i < max; i++) {
doSomething()
}
Comparison
false == 0 => true
“” == 0 => true
Use
false === 0 => false
“” === 0 => false
eval()
• eval() func>on takes JS (string) and executes it.
• Security issues: don’t use it! • To parse JSON objects, use JSON.parse();
with // Instead of doing this, you could… myobj.prop.subprop.subsubprop.a = true; myobj.prop.subprop.subsubprop.b = false; // .. Use shortcut using with.. But DON’T! with(myobj.prop.subprop.subsubprop) { a = true; b = true; } // It’s confusing, just use var s = myobj.prop.subprop.subsubprop; s.a = true; s.b = true;
Constructors function Person(name) {
this.name = name;
}
// Should be used
var jaska = new Person("Jaska");
// Don't! Now this is bound to global object
var jeppe = Person("Jeppe");
Be?er version function Person(name) {
// If this refers not to Person (for example global object)
if(!(this instanceof Person))
{
// Let's then use the new word
return new Person(name);
}
else
{
this.name = name;
}
}
// Now both work
var vilma = new Person("Vilma");
var jaska = Person(”Jaska");
Code Style
• Indenta>on: 4 spaces (default for JSLint) • Use always curly braces • Naming conven>ons: – Use capital le?er in constructor func>ons: – var jack = new Person();
Documen>ng your code
• It’s possible to generate documenta>on from your comments (like Javadoc in Java)
• Free tools like – JSDoc3 • h?p://usejsdoc.org/about-‐gezng-‐started.html
Minimizing your code
• The Closure Compiler is a tool for making JavaScript download and run faster
• Google Closure Compiler – h?ps://developers.google.com/closure/compiler/
• Can be user by command line or web – h?p://closure-‐compiler.appspot.com/home
EXERCISE 3
HTML5 AND JS
HTML5
• Fimh version of HTML standard by W3C • S>ll under development but lot of browsers support the proposal of the standard
• Simple markup that can be wri?en either in HTML or XHTML syntax
• Poten>al candidate for cross plahorm mobile apps • Mostly about seman<cs, most of the cool parts are implemented using JavaScript
• JS APIs are not part of HTML5, developed separately
New Syntax
• <video> • <audio> • <canvas> • <section>, <article>, <header>, <nav>
New JS APIs • Web Storage
– The ability to store data locally in browser – Session storage and local storage
• Geoloca<on API – Fetching GPS loca>on
• File API – Reading local files – See: h?p://www.html5rocks.com/en/tutorials/file/dndfiles/ or – h?ps://developer.mozilla.org/en-‐US/docs/Using_files_from_web_applica>ons
• Web Workers – Asynchronous methods
• Web Sockets – Connec>ng in real>me between client and server. Mul>player games, chat, real>me
upda>ng. Needs server support – h?p://www.developerfusion.com/ar>cle/143158/an-‐introduc>on-‐to-‐websockets/
• Canvas
Geoloca>on API
• Geoloca>on API Specifica>on – h?p://dev.w3.org/geo/api/spec-‐source.html
• To detect the loca>on of the client • In mobile: GPS, in desktop IP-‐address or Wi-‐Fi loca>on
function setText(val, e) { document.getElementById(e).value = val; } function insertText(val, e) { document.getElementById(e).value += val; } var nav = null; function requestPosition() { if (nav == null) { nav = window.navigator; } if (nav != null) { var geoloc = nav.geolocation; if (geoloc != null) { geoloc.getCurrentPosition(successCallback); } else { alert("geolocation not supported"); } } else { alert("Navigator not found"); } } function successCallback(position) { alert("" + position.coords.latitude + ", " + position.coords.longitude); }
Showing Map on Google API
• h?p://maps.googleapis.com/maps/api/sta>cmap?center=<la>tude>,<longitude>&zoom=10&size=200x200&maptype=roadmap
• See: – h?ps://developers.google.com/maps/documenta>on/sta>cmaps/
Wunderground + Geoloca>on + Google sta>c map
• Wunderground provides JSON API for weather informa>on
• Get loca>on of the browser and AJAX request to wunderground
• Amer receiving the result, parse it and show results in html.
• Problem: AJAX does not work cross site.. You can implement middleware (PHP)
Mobile App (iPhone)
Web app!
Mobile App (iPhone)
Canvas
• “The canvas element a resolu:on-‐dependent bitmap canvas, which can be used for dynamically rendering of images such as game graphics, graphs, or other images”
• Image is drawn in JavaScript using typical vector graphics drawing primi>ves – drawImage(), lineTo(), arcTo(), bezierCurveTo(), fillRect(), scale(), rotate(), translate(), createLinearGradient(), shadowBlur(), …
Simple Drawing using Canvas and JS
<canvas id="mycanvas" width="200" height="200">
</canvas>
<script>
var canvas= document.getElementById('mycanvas');
var context = canvas.getContext('2d');
context.fillRect(60,30,80,120);
</script>
Possibili>es • Simple shapes (Rectangles) • Complex shapes (Paths) • Lines • Shadows • Text • Images • Pixel manipula>on • Colors and styles • Composi>ng • Transforma>ons • Canvas state
Implemen>ng a Game
main function main() { createCanvas(); // Original position reset(); // Millisecs elapsed since 1970. then = Date.now(); loadImages(); setEventListeners(); //The setInterval() method calls a function or evaluates an expression at //specified intervals (in milliseconds). setInterval(gameLoop, 1); } window.onload=function(){ main(); }
Game Objects and Global Variables var keysDown = {}; var bgImage = null; var canvas = null; var ctx = null; var then; var monstersCaught = 0; // Game objects var hero = {
speed: 256, x: 0, y: 0, myImage: null
}; var monster = {
x: 0, y: 0, myImage: null
};
Game Loop function gameLoop () {
var now = Date.now();
var delta = now - then;
update(delta / 1000);
render();
then = now;
};
Create Canvas function createCanvas() { // Create canvas element canvas = document.createElement("canvas"); // Get the canvas object that you can use to draw ctx = canvas.getContext("2d"); // Set size for the canvas object canvas.width = 512; canvas.height = 480; document.getElementById("here").appendChild(canvas); }
Star>ng point function reset() {
hero.x = canvas.width / 2;
hero.y = canvas.height / 2;
// Throw the monster somewhere on the screen randomly
monster.x = 32 + (Math.random() * (canvas.width - 64));
monster.y = 32 + (Math.random() * (canvas.height - 64));
};
Load Image function loadImage(imageSrc) {
var image = new Image();
image.src = imageSrc;
return image;
}
function loadImages() {
hero.myImage = loadImage("lib/hero.png");
monster.myImage = loadImage("lib/monster.png");
bgImage = loadImage("lib/background.jpg");
}
Key Listeners function setEventListeners() {
// If keydown, then add the key to the array and set it true
addEventListener("keydown", function (e) {
keysDown[e.keyCode] = true;
}, false);
// If keyup, remove it from the array
addEventListener("keyup", function (e) {
delete keysDown[e.keyCode];
}, false);
}
Update function update (modifier) {
if (38 in keysDown) { // Player holding up hero.y -= hero.speed * modifier; } if (40 in keysDown) { // Player holding down hero.y += hero.speed * modifier; } if (37 in keysDown) { // Player holding left hero.x -= hero.speed * modifier; } if (39 in keysDown) { // Player holding right hero.x += hero.speed * modifier; }
// Are they touching? if ( hero.x <= (monster.x + 32) && monster.x <= (hero.x + 32) && hero.y <= (monster.y + 32) && monster.y <= (hero.y + 32) ) { ++monstersCaught; reset(); }
};
Render function render() {
ctx.drawImage(bgImage, 0, 0);
ctx.drawImage(hero.myImage, hero.x, hero.y);
ctx.drawImage(monster.myImage, monster.x, monster.y);
// Score
ctx.fillStyle = "rgb(250, 250, 250)";
ctx.font = "12px Helvetica";
ctx.textAlign = "left";
ctx.textBaseline = "top";
ctx.fillText("FB Monsters caught: " + monstersCaught, 20, 20);
};
EXERCISE 4
JS AND OO
About Objects
• Everything (except basic types) are objects – Including func>ons and arrays
• Object contains proper>es and methods – Collec>on of name-‐value pairs – Names are strings, values can be anything – Proper>es and methods can be added at run>me
• Objects can inherit other objects
Object Literal var mystring = "hello!";
var myarray = ["element1", "element2"];
var circle1 = {radius: 9, getArea : someFunction };
var circle2 = {
radius: 9,
getRadius: function() {
return this.radius;
}
}
No Classes!
• One of the simplest way to create object – var obj = new Object(); – obj.x = 10; – obj.y = 12; – obj.method = function() { … }
• This adds dynamically two proper>es to the obj – object!
• Object is built – in data type
“Class”
• To define a class, define a func>on function Foo() {
this.x = 1; this.y = 1;
}
• var obj = new Foo(); • Internally a Object is created
Example function Circle(radius) {
this.radius = radius; this.getArea = function() {
return (this.radius * this.radius) * Math.PI; };
}
var myobj = new Circle(5); document.write(myobj.getArea());
About Namespaces
• Avoid pollu>ng global scope – Use namespaces! – Helps avoid clashes between your code and third-‐party libraries
• Namespaces don’t have dedicated syntax built into the language
• It’s possible to get same benefits by crea>ng single global object and add all other objects and func>ons to this object
Example about Namespaces "use strict"; // If first operand is truthy, then the result is // first operand, else the result is second operand // By convention namespaces are written in capitals var MYSPACE = MYSPACE || {}; MYSPACE.Dog = function (name) { this.name = name; this.getName = function () { return name; }; }; var spot = new MYSPACE.Dog("Spot"); print(spot.getName());
Arrays
• Arrays in JS are dynamic, content can be added and removed
• Arrays are also objects (Array “class” inherit Object) – concat(), join(), pop(), push(), slice(), sort(), splice()
Example "use strict"; var array1 = []; // or new Array() var array2 = ['a', 'b', 'c']; print(array2.length); delete array2[1]; for(var i = 0; i<array2.length; i++) { print(array2[i]); }
Func>ons • Every func>on in JS is Func>on object – Can be passed as arguments – Can store name / value pairs – Can be anonymous or named
• Usage (Don’t use this, it’s not efficient) – var myfunction = new Function("a","b", "return a+b;");
– print(myfunction(3,3)); • Only func>ons have scope, regular {blocks) don’t • Inner func>on can have access to outer func>on’s proper>es and parameters
Func>on Arguments
• The arguments object is a local object available within all func>ons
• Each func>on has access to special parameter called arguments – Contains the func<on arguments
• It’s an array like object (but not an array) – Only arguments.length available
Example "use strict"; function myConcat(separator) { var result = ""; // iterate through non-separator arguments for (var i = 1; i < arguments.length; i++) { result += arguments[i] + separator; } return result; } // returns "red, orange, blue, " print(myConcat(", ", "red", "orange", "blue")); // returns "elephant; giraffe; lion; cheetah; " print(myConcat("; ", "elephant", "giraffe", "lion", "cheetah")); // returns "sage. basil. oregano. pepper. parsley. " print(myConcat(". ", "sage", "basil", "oregano", "pepper", "parsley"));
Func>onal Scoping "use strict"; function init() { // local variable name var name = "Hello World"; // inner function function displayName() { // uses outer functions variable print(name); } displayName(); } init();
Returning a Inner Func>on "use strict";
function makeFunc() { var name = "Hello World"; function displayName() { print(name);
}
return displayName; }
// Is “Hello World” printed?
var myFunc = makeFunc(); myFunc();
About Closures
• myFunc is a closure • Special kind of object that combines – A func>on – Environment in which func>on was created • Environment consists of any local variables that were in-‐scope at the >me closure was created • myFunc is a closure that has displayName and name
Private members with Closures "use strict"; function getPerson(name) { var privateMember = "hello world!", obj; obj = { shout: function () { print(name + " shouts " + privateMember); }, say: function () { print(name + " say " + privateMember); } }; return obj; }; var person = getPerson("Jack"); // Does not work! print(person.privateMember); person.shout(); person.say();
Private methods with Closures "use strict"; var person = (function(name) { var privateMember = "hello world!", obj; obj = { setName: function(myName) { name = myName; }, shout: function () { print(name + " shouts " + privateMember); }, say: function () { print(name + " say " + privateMember); } }; return obj; })(); person.setName("Jack"); person.shout(); person.say();
this function foo() {
// adds prop to global object
this.prop = 12;
}
var obj = {
method: function() {
// goes to obj
this.prop = 12;
}
};
obj.method();
function Dog(name) {
// Refers to object being created!
this.name = name;
this.sayHello = function() {
print(this.name + " says hello!");
};
}
var dog = new Dog("Spot");
dog.sayHello();
EXERCISE 5
INHERITANCE
About Inheritance
• Code reuse is important – Inheritance can help
• JavaScript does not have classes, so no special keyword for extending – This can be very confusing for Java/C# developers – Objects inherit objects
Understanding JS Inheritance
• JS is not class based, it’s prototype-‐based! • Object inherit from another object • JS contains syntax and features that make it seem class based
Understanding Prototypes
• Prototype is an object from which other objects inherit proper>es
• Any object can be a prototype • Every object has internal __proto__ property
Example var parent = {
method1: function() { print("A"); }
}
var child = {
__proto__: parent,
method2: function() { print("B"); }
}
// If method1 is not found in child, look it from
// prototype!
child.method1(); // A
child.method2(); // B
__proto__
• __proto__ is depricated and should not be used (but it works)
• To get the prototype, use – Object.getPrototypeOf(object) • It’s read only!
• How to set? – Proposal: Object.setPrototypeOf(obj, prototype)
• Not possible to change the __proto__ ..!
Func>on Object
• When wri>ng – function Animal() { }
• Lot of things happens! – Two objects created: • 1) Animal • 2) Animal.prototype
– Animal.prototype has a property constructor, that points to Animal
Func>on Object // This is just a function. Dog is Function object! function Dog (name) { this.name = (name); } var spot = new Dog("Spot"); // true print(spot instanceof Object); // true print(Dog instanceof Function); // true print(Dog instanceof Object);
Func>on Object function sum1(a, b) {
return a + b;
}
// =>
var sum2 = new Function("a","b", "return a+b;");
print(sum1(2,2)); // 4
print(sum2(2,2)); // 4
print(sum2.length); // number of args = 2
print(sum2.toString());
The “new” Operator
function Person() {
this.name = “Jack”;
}
// Normal function call
Person();
// Object creation
var p = new Person();
Example function Cat() { } // c.__proto__ points to Cat.prototype! var c = new Cat(); // true print(c.__proto__ === Cat.prototype); // c inherites Cat.prototype! Cat.prototype.age = 12; // 12! print(c.age);
Example function Cat() { this.name = "Jack"; } var c = new Cat(); // true print(c.__proto__ === Cat.prototype); // c inherites Cat.prototype! Let's add stuff. Cat.prototype.age = 12; Cat.prototype.saySomething = function() { print(this.name + ": hello!"); } // 12! print(c.age); // "Jack: hello!" c.saySomething();
/** PERSON **/
function Person() { }
var jack = new Person();
// jack inherites Person.prototype!
print(jack.__proto__ === Person.prototype);
Person.prototype.age = 18;
print(jack.age); // 18;
//** STUDENT **/
function Student() { }
// Let's now change the prototype of Student.
// Now Student.prototype points to Person.
var temp = new Person();
Student.prototype = temp;
var tina = new Student();
// tina inherites Student.prototype.. which is now temp!
print(tina.__proto__ === Student.prototype); // true
print(tina.__proto__ === temp); // true
// Now tina inherites Student.prototype, which is
// Person object, which inherites the Person.prototype..
print(tina.age); // 18!
Example /** Person **/ function Person() { this.name = "Jack"; } // Adding functionality to the prototype.. Person.prototype.say = function() { print(this.name + ”: hello!"); } /** Student **/ function Student() { } // Inheritance Student.prototype = new Person(); /** Test **/ var student = new Student(); student.say(); // Jack: Hello
Person.prototype
say()
new Person()
name = “Jack”
__proto__
Example /** Person **/ function Person() { this.name = "Jack"; } // Adding functionality to the prototype.. What is this?? Person.prototype.say = function() { print(this.name + ”: hello!"); } /** Student **/ function Student() { } // Inheritance Student.prototype = new Person(); /** Test **/ var student = new Student(); student.say(); // Jack: Hello
Person.prototype
say()
new Person()
name = “Jack”
__proto__
new Student()
__proto__
Func>on Object
• Every func>on in JS is a Func>on object • When – var spot = new Dog(“spot”);
• Then spot’s __proto__ points to Dog.prototype!
• If a property cannot be found in an object, it is searched for in that object's prototype.
Example // here's the constructor: function Point() { } var a = new Point(); print (a.x); // undefined // set up the prototype object to have some values: Point.prototype = { x: 10, y: 20 }; // or you could do this: Point.prototype.z = 30; // make a new Point object // (a object gets an implicit reference to Point.prototype object) var a = new Point(); // Since a does not hold a property, let's look it from Point.prototype print (a.x);
Example // here's the constructor: function Point() { this.x = 10; this.y = 20; } // set up the prototype object to have some values: Point.prototype.z = 40; // make a new Point object // (a object gets an implicit reference to Point.prototype object) var a = new Point(); // Since a does not hold a property, let's look it from Point.prototype print (a.z);
//** POINT ** function Point() { } // set up the prototype object to have some values: Point.prototype = { x: 10, y: 20 }; /** PIXEL **/ function Pixel() { } Pixel.prototype = new Point(); Pixel.prototype.color = "red"; // make a new Point object // (a object gets an implicit reference to Point.prototype object) var a = new Pixel(); var b = new Pixel(); a.color = "blue"; // Since a does not hold a property, let's look it from Point.prototype print (a.color); print (b.color);
About constructors
• Prototype proper>es of Func>ons have a constructor property: – var dog = new Dog(); – dog.constructor == Dog; // TRUE
• This will break when doing inheritance!
/** Person **/ function Person() { } Person.prototype.name = "Jack"; /** Student **/ function Student() { this.id = "12345"; } // Inheritance Student.prototype = new Person(); Student.prototype.id = "12345"; /** Test **/ var student = new Student(); student.age = 22; print(student.age) print(student.name); print(student.id); var person = new Person(); print(person.constructor === Person); // TRUE var student = new Student(); print(student.constructor === Student); // FALSE
/** Person **/
function Person() {
}
Person.prototype.name = "Jack";
/** Student **/
function Student() {
this.id = "12345";
}
// Inheritance
Student.prototype = new Person();
Student.prototype.id = "12345";
// FIX
Student.prototype.constructor = Student;
/** Test **/
var student = new Student();
student.age = 22;
print(student.age)
print(student.name);
print(student.id);
var person = new Person();
print(person.constructor === Person); // TRUE
var student = new Student();
print(student.constructor === Student); // FALSE
Inheritance: Prototypal
• In EcmaScript 5 a protypal inheritance pa?ern is part of the language – var child = Object.create(parent);
• The create-‐func>on function create(o) { function F() {} f.prototype = o; return new F(); }
Example function Point(x,y) { this.x = x; this.y = y; } var pixel = Object.create(new Point(12,0)); pixel.color = "red"; print(pixel.x); print(pixel.color);
EXERCISE 6
JS LIBRARIES
Intro
• Number of open source JS libraries – Assist frequent JS programming tasks – Hide browser differences
• Lot of possibili>es – Google Web Toolkit – JQuery – AngularJS – YUI3 (not developed anymore) – Modernizr – …
h?p://en.wikipedia.org/wiki/Comparison_of_JavaScript_frameworks
JQuery
• Mo>va>on – Simple things may require lot of coding – Common browsers are different and implementa>on varies
• Solu>on, use a framework – jQuery is a fast and concise JavaScript Library that simplifies HTML document traversing, event handling, anima>ng, and Ajax interac>ons for rapid web development.
How?
• Download JQuery file (h?p://jquery.com/) – h?p://code.jquery.com/jquery-‐1.8.3.min.js
• Make your (x)html page and reference to the file in script block
• Make your code and use JQuery func>ons!
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript">
//<![CDATA[
// When document is ready to be manipulated
jQuery(document).ready( pageReadyToBeManipulated );
function pageReadyToBeManipulated() {
// If link is clicked
jQuery("a").click( linkClick );
}
function linkClick(event) {
alert("Thanks for visiting!");
// Prevent the default action
event.preventDefault();
}
//]]>
</script>
Some Basic Syntax
• JQuery can be used in two ways: – JQuery() – Or – $()
• $ is an alias to JQuery()! $ more commonly used
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript">
//<![CDATA[
// When document is ready to be manipulated
$(document).ready( pageReadyToBeManipulated );
function pageReadyToBeManipulated() {
// If link is clicked
$("a").click( linkClick );
}
function linkClick(event) {
alert("Thanks for visiting!");
// Prevent the default action
event.preventDefault();
}
//]]>
</script>
// USING ANONYMOUS FUNCTIONS
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript">
//<![CDATA[
$(document).ready(function(){
$("a").click(function(event){
alert("Thanks for visiting!");
event.preventDefault();
});
});
//]]>
</script>
// EVEN SHORTER SYNTAX, FORGET THE DOCUMENT PARAMETER
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript">
//<![CDATA[
$().ready(function(){
$("a").click(function(event){
alert("Thanks for visiting!");
event.preventDefault();
});
});
//]]>
</script>
Ge?ers in the Tradi>onal Way
• getElementsById
• getElementsByTagName
• getAttribute
JQuery and Selectors
• Select all h1 elements – $(“h1”)
• Select the first one – $(“h1”)[0]
• Add contents – $(“????”)[0].innerHTML = “hello!”;
• Lot of different selectors – h?p://api.jquery.com/category/selectors/
Crea>ng Elements in Tradi>onal Way
• createElement • createTextNode • setAttribute • appendChild • removeChild
JQuery Insert $().ready(function(){
$("a").click(function(event){
// Insert the new element after element with id here
$("<p>New Element</p>").insertAfter("#here");
event.preventDefault();
});
});
Manipula>on Func>ons
• .addClass() • .amer() • .append() • .css() • … • See: h?p://api.jquery.com/category/manipula>on/
EXERCISE 7
ANGULARJS
Angular JS • Single Page App Framework for JavaScript • Implements client-‐side Model-‐View-‐Whatever pa?ern – Some call it MVC, some MVVM, it does not ma?er: – Separa<on of presenta>on from business logic and presenta<on state
• No direct DOM manipula>on, less code • Support for all major browsers • Supported by Google • Large and fast growing community
First Example – Template <!DOCTYPE html>
<html ng-app>
<head>
<title>
Title
</title>
<meta charset="UTF-8" />
<style media="screen"></style>
<script src="angular.min.js"></script>
</head>
<body>
<!-- initialize the app -->
<div>
<!-- store the value of input field into a variable name -->
<p>Name: <input type="text" ng-model="name"></p>
<!-- display the variable name inside (innerHTML) of p -->
<p ng-bind="name"></p>
</div>
</body>
</html>
Download this file from: https://angularjs.org/
Direc>ve
Direc>ve
Template
Basic Concepts
• 1) Templates – HTML with addi>onal markup, direc>ves, expressions, filters ...
• 2) Direc<ves – Extend HTML using ng-app, ng-bind, ng-model
• 3) Filters – Filter the output: filter, orderBy, uppercase
• 4) Data Binding – Bind model to view using expressions {{ }}
Lot of Built in Direc>ves
• ngApp • ngClick • ngController • ngModel • ngRepeat • ngSubmit
• ngDblClick • ngMouseEnter • ngMouseMove • ngMouseLeave • ngKeyDown • ngForm
2) Expressions
• Angular expressions are JavaScript-‐like code snippets that are usually placed in bindings – {{ expression }}.
• Valid Expressions – {{ 1 + 2 }} – {{ a + b }} – {{ items[index] }}
• Control flow (loops, if) are not supported! • You can use filters to format or filter data
Example <!DOCTYPE html>
<html ng-app>
<head>
<title>Title</title>
<meta charset="UTF-8" />
<style media="screen"></style>
<script src="../angular.min.js"></script>
</head>
<body>
<div>
<p>Number 1: <input type="number" ng-model="number1"></p>
<p>Number 2: <input type="number" ng-model="number2"></p>
<!-- expression -->
<p>{{ number1 + number2 }}</p>
</div>
</body>
</html>
Direc>ve Direc>ve
Expression
ng-‐init and ng-‐repeat direc>ves
<html data-ng-app=""> <head> <title>Title</title> <meta charset="UTF-8" /> <script src="../angular.min.js" type="text/javascript"> </script> </head> <body> <div data-ng-init="names = ['Jack', 'John', 'Tina']"> <h1>Cool loop!</h1> <ul> <li data-ng-repeat="name in names">{{ name }}</li> </ul> </div> </body> </html>
3) Filter
• With filter, you can format or filter the output • Formanng – currency, number, date, lowercase, uppercase
• Filtering – filter, limitTo
• Other – orderBy, json
Using Filters -‐ Example <!DOCTYPE html>
<html data-ng-app="">
<head>
<title>Title</title>
<meta charset="UTF-8">
<script src="../angular.min.js" type="text/javascript">
</script>
</head>
<body>
<div data-ng-init="customers = [{name:'jack'}, {name:'tina'}]">
<h1>Cool loop!</h1>
<ul>
<li data-ng-repeat="customer in customers | orderBy:'name'">
{{ customer.name | uppercase }}</li>
</ul>
</div>
</body>
</html>
Filter
Filter
Using Filters -‐ Example <!DOCTYPE html>
<html data-ng-app="">
<head>
<title>Title</title>
<meta charset="UTF-8">
<script src="../angular.min.js" type="text/javascript">
</script>
</head>
<body>
<div data-ng-init=
"customers = [{name:'jack'}, {name:'tina'}, {name:'john'}, {name:'donald'}]">
<h1>Customers</h1>
<ul>
<li data-ng-repeat="customer in customers | orderBy:'name' | filter:'john'">{{
customer.name | uppercase }}</li>
</ul>
</div>
</body>
</html>
Using Filters – User Input Filters the Data <!DOCTYPE html>
<html data-ng-app="">
<head>
<title>Title</title>
<meta charset="UTF-8">
<script src="../angular.min.js" type="text/javascript">
</script>
</head>
<body>
<div data-ng-init=
"customers = [{name:'jack'}, {name:'tina'}, {name:'john'}, {name:'donald'}]">
<h1>Customers</h1>
<input type="text" data-ng-model="userInput" />
<ul>
<li data-ng-repeat="customer in customers | orderBy:'name' | filter:userInput">{{
customer.name | uppercase }}</li>
</ul>
</div>
</body>
</html>
EXERCISE 8 + 9
VIEWS, CONTROLLERS, SCOPE
Model – View -‐ Controllers
• Controllers provide the logic behind your app. – So use controller when you need logic behind your UI
• Use ng-‐controller to define the controller • Controller is a JavaScript Object, created by standard JS object constructor
View, Controller and Scope
View (html fragment)
Controller (view agnos>c!)
$scope
$scope is an object that can be used to communicate between
View and Controller
Model
controller.js
// Angular will inject the $scope object, you don't have to
// worry about it! By using $scope, you can send data to
// view (html fragment)
function NumberCtrl ($scope) {
// $scope is bound to view, so communication
// to view is done using the $scope
$scope.number = 1;
$scope.showNumber = function showNumber() {
window.alert( "your number = " + $scope.number );
};
}
Warning, this will not work from AngularJS 1.3. We will see later on how this is done using module
<!DOCTYPE html>
<html data-ng-app="">
<head>
<title>Title</title>
<meta charset="UTF-8" />
<style media="screen"></style>
<script src="../angular.min.js"></script>
<script src="controller.js"></script>
</head>
<body>
<div>
<div data-ng-controller="NumberCtrl">
<p>Number: <input type="number" ng-model="number"></p>
<p>Number = {{ number }}</p>
<button ng-click="showNumber()">Show Number</button>
</div>
</div>
</body>
</html>
Define the Controller implemented in controller.js
Access $scope.number Access $scope.showNumber()
When to use Controllers
• Use controllers – set up the ini>al state of $scope object – add behavior to the $scope object
• Do not – Manipulate DOM (use data-‐binding, direc<ves) – Format input (use form controls) – Filter output (use filters) – Share code or state (use services)
MODULES, ROUTES, SERVICES
Modules
• Module is an reusable container for different features of your app – Controllers, services, filters, direc>ves...
• All app controllers should belong to a module! – More readability, global namespace clean
• Modules can be loaded in any order • We can build our own filters and direc<ves!
Example: Own Filter // declare a module
var myAppModule = angular.module('myApp', []);
// configure the module.
// in this example we will create a greeting filter
myAppModule.filter('greet', function() {
return function(name) {
return 'Hello, ' + name + '!';
};
});
HTML using the Filter
// We will use module myApp
<div ng-app="myApp"> <div> {{ 'World' | greet }}
</div> </div>
angular.module
• The angular.module is a global place for crea>ng, registering and retrieving Angular modules
• Crea>ng a new module – var myModule = angular.module('myMod', []);
• The second argument ([]) defines dependent modules – which modules should be loaded first before this
Template for Controllers // Create new module 'myApp' using angular.module method.
// The module is not dependent on any other module
var myModule = angular.module('myModule', []);
myModule.controller('MyCtrl', function ($scope) { // Your controller code here!
});
Crea>ng a Controller in Module var myModule = angular.module('myModule',
[]);
myModule.controller('MyCtrl', function ($scope) {
var model = { "firstname": "Jack",
"lastname": "Smith" };
$scope.model = model;
$scope.click = function() {
alert($scope.model.firstname);
};
});
<!DOCTYPE html>
<html>
<head>
<title>Title</title>
<meta charset="UTF-8" />
<style media="screen"></style>
<script src="../angular.min.js"></script>
<script src="mymodule.js"></script>
</head>
<body>
<div ng-app="myModule"
<div ng-controller="MyCtrl">
<p>Firstname: <input type="text" ng-model="model.firstname"></p>
<p>Lastname: <input type="text" ng-model="model.lastname"></p>
<p>{{model.firstname + " " + model.lastname}}</p>
<button ng-click="click()">Show First name</button>
</div>
</div>
</body>
</html>
This is now the model object from MyCtrl. Model object is shared with view
and controller
EXERCISE 10 -‐ 11
AMD
AMD • JavaScript does not have "classes" or "packages" or "import" • Asynchronous Module Defini<on (AMD) is a JS specifica>on
that defines API for defining code in modules – Load smaller JS files, only when needed – Allow developers define dependencies – Encapsula>on
• Specifica>on is implemented by RequireJS and ScriptManJS • Specifica>on:
– https://github.com/amdjs/amdjs-api/blob/master/AMD.md • Different JS libraries support AMD spec
– RequireJS, curl, lsjs and Dojo
Problem
• Gezng mul>ple files onto a page is to include script tags <script src="file1.js"></script>
<script src="file2.js"></script>
<script src="file3.js"></script>
• All is loaded to global namespace • Some scripts depend each other -‐> order is important.
• Download >me!
Defining Modules
• Use define func>on of RequireJS • Each module in separate file (.js) – File name will be a module ID.
• Modules are dependent on others – Module declares a list of other modules for dependency
– No more includes in right order, modules interact with each other without global namespace
• Module is defined as "factory" – Can be object or func>on that returns a value
Defining and using Modules
Different modules // modules/number.js
define('numberModule', 7);
// modules/album.js
define('album', {
title: 'Haavemaa',
artist: 'Tauski Peltonen',
year: 1997
});
// modules/counter.js
define('counter', function() {
var counter = 0;
return {
increment: function() {
counter++;
},
getValue: function() {
return counter;
}
};
});
Using module require(['album'], function(album) {
console.log(album.title);
});
RequireJS: How to Use?
1. Download file script for Browser or Command line – http://requirejs.org/docs/start.html#get
2. Add RequireJS to your web page (if using browser) <script data-main="scripts/main" src="scripts/require.js">
</script>
3. Use predefined directory structure
<!DOCTYPE html>
<html>
<head>
<title>Title</title>
<meta charset="UTF-8" />
<style media="screen"></style>
<!--
Define single entry-point to your app.
data-main attribute tells require.js to load
scripts/main.js after require.js loads.
js is appended by default main -> main.js
www/index.html
scripts/require.js
main.js
modules/module1.js
module2.js
-->
<script data-main="scripts/main" src="scripts/require.js"></script>
</head>
<body>
</body>
</html>
main.js
// Load modules and use them
// require() function has two arguments
// 1) array of dependencies
// 2) callback function to execute once all the dependencies have loaded.
// function arguments are the specified dependencies!
require(['modules/number', 'modules/counter', 'modules/album'], function(number, counter, album){
// do something with the loaded modules
console.log(number)
console.log(album.title)
counter.increment();
counter.increment();
console.log(counter.getValue())
});
main.js
// Load modules and use them
// require() function has two arguments
// 1) array of dependencies
// 2) callback function to execute once all the dependencies have loaded.
// function arguments are the specified dependencies!
require(['modules/module1', 'modules/module2'], function(Module1, Module2){
// do something with the loaded modules
var module1 = new Module1();
var module2 = new Module2();
console.log(module1.getName())
console.log(module2.getName())
});
modules/module1+2.js
module1.js define([], function () {
function returnedModule() {
var name = 'Module 1';
this.getName = function () {
return name;
}
};
return returnedModule;
});
module2.js define(['modules/module1'], function (Module1) {
var module1 = new Module1()
function returnedModule() {
var name = 'Module 2: ';
this.getName = function () {
return name + module1.getName();
}
};
return returnedModule;
});
JQuery and RequireJS
• JQuery is AMD compa>ble • Download jquery – file and name it as "jquery.js"
• Amer this you can use it like any other module!
JQuery and RequireJS require(['jquery'], function(jquery){
// do something with the loaded modules
jquery( "#myform" ).submit(function( event ) {
...
event.preventDefault();
});
});
EXERCISE 12
LIBRARY DESIGN
Designing Libraries
• Designing JS libraries are hard – Dynamic nature of the language – Difficult to keep things truly private / sandboxed
• Let’s look at some general principals about designing libraries
• When possible, see how exis>ng libraries have done things..
API Design
• Consistent – Easy to learn when each module have a similar API
• Clean • Well documented • Consider plugin architecture
Sandbox pa?ern
Anonymous Closures
• Create anonymous func>on and execute it immediately
(function () {
// ... all vars and functions are in this
// scope only
// still maintains access to all globals
}());
Defining Modules
• Closures provide handy way of keeping module code sandboxed – Less pollu>on to global namespace – Avoid modules breaking each other – Modules can access globals
• In-‐depth tutorial – h?p://www.adequatelygood.com/2010/3/JavaScript-‐Module-‐Pa?ern-‐In-‐Depth
Defining Modules var MODULE1 = function() {
// Place module implementation here.
// All vars and functions declared here are private to
// this scope.
// Can access globals if needed.
}();
var MODULE1 = function() { // Private stuff (notice the single var pattern) var privateVar1 = "", privateVar2 = "moi", privateFunc1 = function() { /* ... */ }, privateFunc2 = function() { /* ... */ }; function privateFunc3() { /* ... */ } // Public stuff exported as part of an object. Due to the // closure, the public functions can access all the private // vars and functions as well. return { foo: function() { return "Hello World"; }, bar: function() { privateVar1 = "Hello!" }, publicVar1: "", publicVar2: 12 } }(); console.log(MODULE1.foo()); // “Hello World” console.log(MODULE1.publicVar2); // 12 console.log(MODULE1.privateVar1); undefined
About Globals // - Code should not rely on certain global objects to
// be available...
// - Local variables are more efficient
// - Shorter lookup paths for objects
// - Can be minified to reduce file size
var MODULE2 = function(globalWindowObject, documentObject) {
var width = globalWindowObject.innerWidth;
return { prop: width };
}(this, this.document);
console.log(MODULE2.prop);
UNIT TESTING
Test-‐driven development
• Each new feature begins with wri<ng a test! – Test will fail since the produc>on code does not exist yet
• Write the code • Run automated tests to see if if test cases pass
• Automated tests? – We need a framework…
JS Unit Tes>ng Frameworks
• Lot of op>ons – JSUnit, YUI Test, QUnit, Google Closure Tools
QUnit
• QUnit is a JS unit tes>ng framework • Can be used in client and also in server (Node.js) • Was originally developed as part of JQuery – Extracted its own project and became known as "QUnit"
• How? – Download qunit.js and qunit.css – Write a simple HTML page to run the tests – Write the tests
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>QUnit Example</title>
<link rel="stylesheet" href="qunit-1.18.0.css">
<script src="qunit-1.18.0.js"></script>
</head>
<body>
<div id="qunit"></div>
<script type="text/javascript">
function calculate(a, b) {
return a + b;
}
QUnit.test( "calculate test", function(assert) {
assert.ok( calculate(5,5) === 10, "Ok!" );
assert.ok( calculate(5,0) === 5, "Ok!" );
assert.ok( calculate(-5,5) === 0, "OK!" );
});
</script>
</body>
</html>
Three Asser>ons
• Basic – ok( boolean [, message]);
• If actual == expected – equal( actual, expected [, message]);
• if actual === expected – deepEqual( actual, expected [, message));
• Other – http://qunitjs.com/cookbook/#automating-unit-testing
EXERCISE 13
JAVASCRIPT OPTIMIZING
Brief look of Op>mizing
• Script deployment • Code op>miza>on – Loops, strings, DOM access and data access
• Mul>threading with Web Workers • Performance tools
Script Deployment
• Group to have as few files as possible! – Loading one file is much be?er than ten files, HTTP overhead!
• Can be done at build >me or at run >me • Run >me grouping – src=“h?p://site.com/combine?foo.js&bar.js”
Script Deployment
• Minify or gzip your scripts (for example: closure compiler) – Reduces the size – Code gets obfuscated – Some older browsers do not support gzipped files
Code Op>miza>on
• Do not op<mize your code! – Unreadable code – Concentrate on maintainable
• If you have to op<mize – Concentrate code that executed most omen
• Check string and DOM opera<ons – These are slow in JS!
Data and Property Access
• Data and property access may be expensive – document.getElementById(“a”).appendChild(child1); – document.getElementById(“a”).appendChild(child2);
• Cache frequently used objects – var x = document.getElementById(“a”); – x.appendChild(child1); – x.appendChild(child2);
Strings
• Avoid – mystring += “first” + “second” – Creates temporary string in memory
• Use – mystring += “first”; – mystring += “second”;
• Or use Array.join() – myArray = [“first”, “second”]; – var str = myArray.join();
Loops
• Don’t use for-‐in in arrays, requires addi>onal property lookups
• Cache variables! var len = myarray.length; var element = document.getElementById(“id”); for(var i = 0; i<len; i++) {
// Use element
}
Web Workers • Web worker is a JS way of doing things in background. W3C recommenda:on. – “API that allows Web applica>on authors to spawn background workers running scripts in parallel to their main page.”
– Web worker spec is separate spec from HTML5 • Bring mul>threading to your app
– Heavy calcula>ons or long-‐running tasks in the background – Keep UI responsive
• No need to use Web Workers in AJAX (mul>-‐threading on by default)
• Cannot manipulate UI (DOM)!
<!DOCTYPE HTML> <html> <head> <title>Big for loop</title> <script> function sayHello(){ var worker = new Worker('worker.js'); worker.onmessage = function (event) { alert("Completed " + event.data + " iterations" ); }; worker.postMessage(50000); } </script> </head> <body> <input type="button" onclick="sayHello();" value="Say Hello"/> </body> </html>
onmessage = function(event) {
var number = event.data;
for (var i = 0; i <= number; i += 1){
var j = i;
}
postMessage(j);
}
Check Web Worker support
if (typeof(Worker)!=="undefined”) {
}
EXERCISE 14
Top Related