M03 - JavaScript - part 2
Object
JavaScript object is a collection of properties.
| let person = {name: 'Arska', age: 49}
|
You can access object properies using . (dot) and/or [] chars.
| console.log(person.name); // Arska <- BETTER use dot notation!
console.log(person['age']); // 49
|
You can add more properties later to your object.
| person.id = "123345-1212";
console.log(person.id); // 123345-1212
|
Object Oriented Programming
- You can use a functions inside your object, then they are called methods
- Method can access properties using
this
keyword
- Developer can use JavaScript build-in objects like
Math
, Date
, String
, Array
and Object
- Also HTML objects are available
window
, document
, form
, etc...
- Developer can create his/her own objects
- Developer can't use keywords like
public
, protected
, private
which are common in real OOP languages
- Developer need to use
new
keyword to reserve memory for object
- Function is used to define own class with properties and methods (ES5)
- Developer will use
constructor
keyword in ES6
Example: OOP with function
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 | function Car(model) {
// public property
this.model = model;
// private variable (available only inside Car scope)
let color = "Red";
// public setter and getter methods with anonymous functions
this.getColor = function() {
return color;
}
this.setColor = function(newColor) {
color = newColor;
}
}
// create a new car instance
var car = new Car("Ford");
console.log(car.model); // Ford
console.log(car.getColor()); // Red
car.setColor("Blue");
console.log(car.getColor()); // Blue
// test access to private variable
console.log(car.color); // undefined
// test access to car color with global scope
console.log(color); // color is not defined
|
Prototype
Developer can add more properties or methods to object when app is running and instance has been created already.
| car.speed = 165;
car.getSpeed = function(){return this.speed;};
console.log(car.getSpeed()); // 165
|
Developer can use prototype
to add more properties and methods to all object instances.
| Car.prototype.pa = 'diesel';
Car.prototype.getPa = function(){return this.pa;};
console.log(car.getPa()); // diesel
// create another Car instance
var audi = new Car("Audi");
console.log(audi.getPa()); // diesel
|
Example: OOP with classes ES6. ES6 provides specific syntax for defining the getter and setter using the get and set keywords. Properties are changed to _property to avoid the property collision with the getter and setter.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36 | class Person {
// constructor
constructor(name, height, weight) {
this._name = name;
this._height = height;
this._weight = weight;
}
// getter
get bmi() {
return this.calcBmi();
}
// setter
set name(newName) { this._name = newName; }
set height(newHeight) { this._height = newHeight; }
set weight(newWeight) { this._weight = newWeight; }
// getter
get name() { return this._name; }
get height() { return this._height; }
get weight() { return this._weight; }
// method
calcBmi() {
return this._weight/(this._height/100 * this._height/100);
}
}
// create one instance
const person = new Person("Alainen Kim", 290, 90);
console.log (person.name, person.height, person.weight, person.bmi);
// modify instance
person.name = "Teppo Testaaja";
person.height = 1000;
person.weight = 2000;
console.log (person.name, person.height, person.weight, person.bmi);
|
Will display following data:
| "Alainen Kim"
290
90
10.70154577883472
"Teppo Testaaja"
1000
2000
20
|
Callback functions
- callback function are given to another function as a parameter
- another function can then call a callback function when needed
- callback function are heavily used with eventhandling and asynchronous programming
Example with JavaScript setTimeout
function:
| function fn() {
console.log("Haloo");
}
// will print "Haloo" after one second
setTimeout(fn, 1000);
|
Example with own made functions:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 | function fn1(name) {
alert('Hello ' + name);
}
function fn2(name) {
console.log('Hello ' + name);
}
function askName(callback) {
// ask name
let name = prompt('Write your name');
// call callback function with name
callback(name);
}
askName(fn1);
// askName(fn2); // remember test this too!
|
Arrow functions
- Developer can use arrow functions in ES6
- It is easy way to define function
A few examples
| // traditional way to define a named function
function fn(a) { return a; }
|
| // traditional way to define anonymous function
let afn = function(a) { return a; }
|
| // arrow function
let lfn1 = (a) => a;
|
| // arrow function, without () parenthesis, if there are only one parameter
let lfn2 = a => a;
|
| // arrow function without parameters
let lfn3 = () => { console.log("From lfn3"); };
|
| // arrow function with multiple parameters
let lfn4 = (a, b) => a + b;
console.log(lfn4(-1, 5)); // prints: 4
|
| // arrow function with multiple lines of code
let lfn5 = () => {
console.log("From lfn5 row 1");
console.log("From lfn5 row 2");
};
|
| // arrow function as callbacks
setTimeout(() => console.log("Haloo"), 1000);
|
Arrow function and this keyword:
| <body>
<button>Click Me!</button>
</body>
|
| let btn = document.querySelector('button');
const anofn = function () {
return console.log(this);
}
var arfn = () => console.log(this);
// 1.
btn.addEventListener('click', anofn);
// 2.
//btn.addEventListener('click', arfn);
|
- In 1.
this
keyword will point to [object HTMLButtonElement]
-> a button object it self
- In 2.
this
keyword will point to [object Window]
-> object which defines arrow function
One common problem with traditional function and this
keyword is visible in below code. You will need to define one more variable (like self
) which points to function variables.
| <body>
<h3 id="count">0</h3>
</body>
|
| function Counter() {
this.number = 0;
let self = this;
setInterval(function() {
self.number++;
document.getElementById("count").innerHTML = self.number;
}, 500);
}
let counter = new Counter();
|
You can avoid above problem using a arrow function instead of traditional named or anonymous function.
| function Counter() {
this.number = 0;
setInterval(() => {
this.number++;
document.getElementById("count").innerHTML = this.number;
}, 500);
}
let counter = new Counter();
|
Function parameters
- A JavaScript function does not perform any checking on parameter values (arguments)
- Function parameters are the names listed in the function definition
- Function arguments are the real values passed to (and received by) the function
- JavaScript function definitions do not specify data types for parameters
- JavaScript functions do not check the number of arguments received
If a function is called with missing arguments (less than declared), the missing values are set to undefined
.
| function myFunction(x, y) {
if (y === undefined) {
y = 2;
}
}
|
ES6 allows default parameter values in the function declaration.
| function fn1(n1, n2 = 2) {
return n1 == n2;
}
console.log(fn1(3)); // false
console.log(fn1(2)); // true
|
| function fn2(n1, n2 = n1) {
console.log(n1); // 4
console.log(n2); // 5
return n1 == n2;
}
console.log(fn2(4, 5)); // false, because n2 = n1 doesn't happen, two parameters
console.log(fn2(4)); // true, because n2 = n1 will be called (only one parameter)
|
Template Literals
Template Literals use back-ticks (``) rather than the quotes ("") to define a string.
| let firstname = 'Pekka';
let lastname = "Pouta";
let multiline = `
ES5 is ok,
ES6 rules ok
`;
console.log(multiline);
let hello = `Helou, I'm ${lastname} ${firstname}`;
console.log(hello);
|
Will print:
| "
ES5 is ok,
ES6 rules ok
"
"Helou, I'm Pouta Pekka"
|
Object literals
Variables can have default values to object fields.
1
2
3
4
5
6
7
8
9
10
11
12
13 | let name = "John";
let age = 50;
let object = {
name : 'Ari',
age,
fn() {
console.log(this.name + ', ' + this.age)
}
}
console.log(object);
object.fn();
|
Will print:
| [object Object] {
age: 50,
fn: fn() {
window.runnerWindow.proxyConsole.log(this.name + ', ' + this.age)
},
name: "Ari"
}
"Ari, 50"
|
Developer can write it more easily:
| let name = 'Ari';
let age = 50;
let object = {name, age};
console.log(object.name); // "Ari"
|
Dynamic fields
Object field names can be created dynamically using [].
1
2
3
4
5
6
7
8
9
10
11
12
13 | let counter = 0;
let getId = () => ++counter;
let object1 = {
['id_' + getId()]: counter
};
let object2 = {
['id_' + getId()]: counter
};
console.log(object1); // [object Object]{id_1: 1}
console.log(object2.id_2); // "2"
|
Rest operator ...array
Function parameters (list) are moved to array.
| function calculateSum(...values) { // array in here
console.log(values);
let sum = 0;
for(let i = 0; i < values.length; i++) {
sum += values[i];
}
return sum;
}
console.log(calculateSum(10,20,30)); // list in here
|
Spread operator ...list
Array in function parameters are moved to list.
| let values = [1,2,3];
console.log(...values); // 1
// 2
// 3
console.log(values); // [1,2,3]
// Math requires a list, convert array to list with spread operator
console.log(Math.max(...values)); // 3
|
Array items to variables
Array values can be moved to varibles.
| let numbers = [1, 2, 3];
let [n1, n2, n3] = numbers;
console.log(n1); // 1
console.log(n2); // 2
console.log(n3); // 3
|
| let numbers = [1,2,3]
let [a,...b] = numbers;
console.log(a); // 1
console.log(b); // [2, 3]
|
1
2
3
4
5
6
7
8
9
10
11
12 | let object = {
name: 'Ari',
age: 53
};
// nimi-field renaming to name
let { name: firstname, age } = object; // firstname is a new alias
console.log(firstname); // "Ari"
console.log(age); // "53"
console.log(name); // "error"
|