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
- Convert values to primitive
- If either primitive is a string, convert both to string and return concatenation
- 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')
- If input is primitive, return it as is.
- Otherwise, input is an object. Call obj.valueOf(). If the result is primitive, return it.
- Otherwise, call obj.toString(). If the result is a primitive, return it.
- Otherwise, throw a TypeError.
ToPrimitive(input, PreferredType?)
prim1 := ToPrimitive([2])
Implicit conversion
Hoe het werkt - omzetten naar primitive
- If input is primitive, return it as is.
- Otherwise, input is an object. Call obj.valueOf(). If the result is primitive, return it.
- Otherwise, call obj.toString(). If the result is a primitive, return it.
- 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!
JavaScript training 1/4
By Paul Verbeek
JavaScript training 1/4
- 536