JavaScript® training

De Basics

Agenda

  • Coding standards
  • Implicit conversion
  • Scopes & IIFE
  • Closures
  • DOM
  • Event handling
  • Classes (ES5 version)

Coding standards

variabelen bovenaan, en één var statement per function

function f() {
  doSomething();

  var foo = 123;
  var bar = 456;

  if (true) {
    var baz = 7;
    
    foo = foo * baz;
  }

  return foo;
}

variabelen bovenaan, en één var statement per function

function f() {
  var foo = undefined;
  var bar = undefined
  var baz = undefined;

  doSomething();

  foo = 123;
  bar = 456;

  if (true) {
    baz = 7;
    
    foo = foo * baz;
  }

  return foo;
}

variabelen bovenaan, en één var statement per function

function f() {
  var foo = 123,
      bar = 456,
      baz = 7;

  doSomething();

  if (true) {    
    foo = foo * baz;
  }

  return foo;
}

Gebruik altijd een semicolon aan het eind van een statement

a = b + c
(d + e).print()
a = b + c(d + e).print()
a = b + c;
(d + e).print();
a = b + c;(d + e).print();

en altijd maximaal één statement per regel

altijd === en !==

'' == '0';           // false
0 == '';             // true
0 == '0';            // true

false == 'false';    // false
false == '0';        // true

false == undefined;  // false
false == null;       // false
null == undefined;   // true

' \t\r\n ' == 0;     // true
'            ' == 0; // true

altijd === en !==

'' === '0';           // false
0 === '';             // false
0 === '0';            // false

false === 'false';    // false
false === '0';        // false

false === undefined;  // false
false === null;       // false
null === undefined;   // false

' \t\r\n ' == 0;      // false
'            ' == 0;  // false

Implicit conversion

Implicit conversion

"truthy" & "falsy" waardes

undefined
null
false
-0
0
+0
NaN
''
var foo = undefined;

if (foo == null) {
  // code runs
}
var x = '5';

2 * x = ???;

2 + x = ???;

Implicit conversion

string -> number

var x = '5';

2 * x = 10;

2 + x = ???;

var x = '5';

2 * x = 10;

2 + x = '25';

[2] + '5';

Implicit conversion

Hoe het werkt

  1. Convert values to primitive
     
  2. If either primitive is a string, convert both to string and return concatenation
  3. Otherwise, convert both to number and return the sum

JS REGEL: Je kan alleen nummers en strings samenvoegen

Primitives: undefined, null, booleans, numbers, and strings

[2] + '5';

Implicit conversion

Hoe het werkt - omzetten naar primitive

prim1 := ToPrimitive([2])
prim2 := ToPrimitive('5')
  1. If input is primitive, return it as is.
  2. Otherwise, input is an object. Call obj.valueOf(). If the result is primitive, return it.
  3. Otherwise, call obj.toString(). If the result is a primitive, return it.
  4. Otherwise, throw a TypeError.
ToPrimitive(input, PreferredType?)
prim1 := ToPrimitive([2])

Implicit conversion

Hoe het werkt - omzetten naar primitive

  1. If input is primitive, return it as is.
  2. Otherwise, input is an object. Call obj.valueOf(). If the result is primitive, return it.
  3. Otherwise, call obj.toString(). If the result is a primitive, return it.
  4. Otherwise, throw a TypeError.
[2].valueOf(); // [2]
[2].toString(); // '2'
[2] + '5';
'2' + '5'; // '25'
[] + [];

Implicit conversion

verwachte en onverwachte resultaten

[] + []; // ''
[] + {};
[] + {}; // '[object Object]'
6 + { valueOf: function () { return 2; };
6 + { valueOf: function () { return 2; }; // 8
{} + {}; // NaN
+{}
Number({})
Number({}.toString()) 
  // {}.valueOf() isn’t primitive
Number("[object Object]")
NaN
{} + [];
{} + []; // 0

Scopes & IIFE

function foo() {

  function baz() {
    console.log(a);
  }

  var a = 42;

  fn = baz;
}

function bar() {
  fn();
}

var fn;

foo();

bar(); // 42

Scopes

global scope

var globalVar = 42;

Scopes

function scope

function doSomething() {
  var inner = 5 * 5;
}

Scopes

function scope

var globalVar = 'global';

function fn() { 
  var localVar = 'local';
}
fn();

console.log(globalVar); // 'global'
console.log(localVar); // reference error

Scopes

nested scopes

function foo(a) {
  console.log(a + b);
}

var b = 2;

foo(2); // 4

Scopes

nested scopes

function foo(a) {
  var b = a * 2;

  function bar(c) {
    console.log( a, b, c );
  }

  bar(b * 3);
}

foo( 2 ); // 2 4 12

Scopes

nested scopes

  • Bubble 1 encompasses the global scope, and has just one identifier in it: foo.
  • Bubble 2 encompasses the scope of foo, which includes the three identifiers: 
    a, bar and b.
  • Bubble 3 encompasses the scope of bar, and it includes just one identifier: c.

Scopes

hoisting

function foo() {
  for (var i = 0; i < 10; i++) {
    bar(i * 2); 
  }

  function bar(a) {
    i = 3;
    console.log(a + i);
  }
}

foo();
function foo() {
  var i;

  function bar(a) {
    i = 3;
    console.log(a + i);
  }

  for (i = 0; i < 10; i++) {
    bar(i * 2); 
  }
}

foo();

Scopes

hoisting

function foo() {
  var i;

  function bar(a) {
    var i = 3;
    console.log(a + i);
  }

  for (i = 0; i < 10; i++) {
    bar(i * 2); 
  }
}

foo();

Scopes

hoisting

foo();

var foo;

function foo() {
  console.log(1);
}

foo = function() {
  console.log(2);
};

Scopes

hoisting

foo();

function foo() {
  console.log(1);
}

var foo = function() {
  console.log(2);
};

function foo() {
  console.log(3);
}

Scopes

hoisting

foo();

var bar = true;

foo();

if (bar) {
  function foo() { console.log('a'); }
} else {
  function foo() { console.log('b'); }
}

Quiz!

function thisIsWeird() {
  function secret() {
    var unused3;
  }
  var result;
  function secret() {
    var unused1;
  }
  
  result = secret;
  function secret() {
    var unused2;
  }
  return result;
}
console.log(thisIsWeird()); // ?

Opdracht!

http://bit.ly/rnlHoist

http://bit.ly/rnlHoist2

Scopes

IIFE

(function() {
  // the code here is executed immediately, 
  // in its own scope
})();

immediately-invoked function expression

Scopes

IIFE

var a = 1;

(function() {
  var b = 2;

  console.log(a + b); // 3
})();

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

immediately-invoked function expression

Scopes

IIFE

function foo() {
  console.log(4);
}
foo() // 4
var foo = function () {
  console.log(8);
};
foo(); // 8
function () {
  console.log(15);
}();
function () { // SyntaxError: Unexpected token (
  console.log(15);
}();

Scopes

IIFE

function () { // SyntaxError: Unexpected token (
  console.log(15);
}();

When the parser encounters the function keyword in the global scope or inside a function, it treats it as a function declaration (statement), and not as a function expression, by default.

(function () { 
  console.log(15);
})(); // 15

Scopes

IIFE

function () { // SyntaxError: Unexpected token (
  console.log(15);
}();

When the parser encounters the function keyword in the global scope or inside a function, it treats it as a function declaration (statement), and not as a function expression, by default.

(function () { 
  console.log(15); // 15
})();

Scopes

IIFE

var a = 16;

(function (x) {
  x = x * 2;
  console.log(x); // 32
})(a);

console.log(a); // 16
var a = 16;

(function (x) {
  var a = x * 2;
  console.log(a); // 32
})(a);

console.log(a); // 16

Opdracht!

http://bit.ly/rnlIIFE

Scopes

execution context

function foo() { 
  console.debug(this); 
}
foo();

JavaScript uses the this keyword to get a reference to the current execution context

this

Scopes

execution context

var myObject = { 
  go: function() {
    console.log(this);
  } 
};
myObject.go(); // reference to myObject

Scopes

execution context

function MyClass() {
  this.go = function() {
    console.log(this);
  }
}

var instance1 = new MyClass();
var instance2 = new MyClass();

instance1.go(); // reference to the MyClass instance1
instance2.go(); // reference to the MyClass instance2

Closures

Closures are functions that refer to independent (free) variables. In other words, the function defined in the closure 'remembers' the environment in which it was created.

function init() {
  // name is a local variable created by init
  var name = 'Randstad'; 

  // displayName() is the inner function, a closure
  function displayName() { 

    // displayName() uses variable declared in the parent function
    console.log(name); 
  }
  displayName();    
}
init();
function init() {
  var name = 'Randstad'; 

  function displayName() {
    console.log(name); 
  }
  return displayName;    
}
var fn = init();
fn(); // 'Randstad';
function makeAdder(x) {
  return function(y) {
    return x + y;
  };
}

var add5 = makeAdder(5);
var add10 = makeAdder(10);

console.log(add5(2));  // 7
console.log(add10(2)); // 12
var counter = (function() {
  var privateCounter = 0;
  function changeBy(val) {
    privateCounter += val;
  }
  return {
    increment: function() {
      changeBy(1);
    },
    decrement: function() {
      changeBy(-1);
    },
    value: function() {
      return privateCounter;
    }
  };   
})();

console.log(counter.value()); // logs 0
counter.increment();
counter.increment();
console.log(counter.value()); // logs 2
counter.decrement();
console.log(counter.value()); // logs 1
var myElements = document.getElementsByTagName('button');
 
for (var i = 0; i < myElements.length; ++i) {
    myElements[i].onclick = function() {
        console.log( 'You clicked on: ' + i );
    };
}

Opdracht!

http://bit.ly/rnlClosures

DOM

Document Object Model

window;   // the window containing the DOM, the browser
document; // the DOM tree, also window.document

window

document

node

event target

window

  • window.innerWidth;
  • window.outerHeight;
  • window.localStorage; 
  • window.parent;
  • window.scrollY;
  • window.location;
  • window.self.window.window.self.window.self.self;

window

  • window.alert(message);
  • window.onload();
  • window.close();
  • window.open(url);
  • window.scrollTo(x, y)
  • window.setInterval(func, delay); 
  • window.setTimeout(func, delay);
  • window.matchMedia(mediaQueryString);

document

var paragraphs = document.getElementsByTagName('p');
// paragraphs[0] is the first <p> element
// paragraphs[1] is the second <p> element, etc.

console.log(paragraphs[0].nodeName); // "P"

paragraphs is een HTMLCollection

paragraphs[0] is een HTMLParagraphElement

Alle properties, methods en events in de DOM zijn objecten met een speciale DOM interface.

  • document.getElementById(id)
  • element.getElementsByTagName(name)
  • document.createElement(name)
  • parentNode.appendChild(node)
  • element.innerHTML
  • element.style.left
  • element.setAttribute
  • element.getAttribute
  • element.addEventListener
    

Creating a new element

document.body.onload = addElement;

function addElement () { 
  // create a new div element 
  // and give it some content 
  var newDiv = document.createElement('div'),
      newContent = document.createTextNode('Hoi Jeffrey!');

  // add the text node to the newly created div. 
  newDiv.appendChild(newContent); 

  // add the newly created element and its content into the DOM 
  var currentDiv = document.getElementById('div1'); 
  document.body.insertBefore(newDiv, currentDiv); 
}
<body>
  <div id="div1"></div>
</body>

DOM event handlers

<button onclick="return handleClick(event);"></button>
document.getElementById("mybutton").onclick = function(event) { ... }
document.getElementById("mybutton").addEventListener('click', 
  function(event) { ... }
);

Registering events

function Interface() {
  var button = document.getElementById('myButton');

  button.addEventListener('click', function () {
    this.handleClick();
  });
}

Interface.prototype.handleClick = function () { ... };

new Interface();
function Interface() {
  var self = this;
  var button = document.getElementById('myButton');

  button.addEventListener('click', function () {
    self.handleClick();
  });
}

Interface.prototype.handleClick = function () { ... };

new Interface();

Classes

var Person = function () {};

Class definieren

var person1 = new Person();
var person2 = new Person();

Nieuw object

var Person = function () {
  console.log('person created');
};

De constructor

var Person = function (firstName) {
  this.firstName = firstName;
};

var person1 = new Person('Maarten');
var person2 = new Person('Mats');

console.log('person1 is ' + person1.firstName); 
// logs "person1 is Maarten"

console.log('person2 is ' + person2.firstName); 
// logs "person2 is Mats"

Properties toevoegen

var Person = function (firstName) {
  this.firstName = firstName;
};

Person.prototype.sayHello = function() {
  console.log('Hallo, ik ben ' + this.firstName);
};

var person1 = new Person('Wouter');
var person2 = new Person('Eric');

person1.sayHello(); // logs "Hallo, ik ben Wouter"
person2.sayHello(); // logs "Hallo, ik ben Eric"

Methods

http://bit.ly/rnlCarousel

Opdracht!

Made with Slides.com