javascript / ecmascript

Vít Jouda,
Dev Center Hradec Králové,

Česká Pojišťovna

O DCHK

vývojové centrum ČP v HK (od r. cca 2003)

vývoj interních aplikací, webů, zahraniční projekty

nový framework založený na moderních technologiích

Java 8, Spring Boot, Gradle, React, Redux, Webpack, Babel, Ramda...

SOAP a REST WS, Webové aplikace, portál pro sjednání pojištění, systém správy pohledávek...

mladý kolektiv programátorů se zaměřením na adaptaci nových technologií a metodiky vývoje

JavaScript vs. ECMAScript?

JavaScript - představen spol. Sun Microsystems v r. 1995

  

součást prohlížeče Netscape

ECMAScript - standardizovaná verze napříč výrobci, první verze v r. 1997

  

Následovaly dialekty různých výrobců, např. JScript (MS, IE 3.0)

European Computer Manufacturers Association 

Témata

Webová aplikace, SPA

ECMAScript 6+

 

Devstack (Node.js, Webpack...)
 

React (Facebook UI library)

 

Model management (Redux)

Webová aplikace

Definice

 

Technologie

 

 

Evoluce webových aplikací

(z pohledu DCHK)

JSP scriptlet - mix UI a aplikační logiky

Java Server Faces - komponentní FW

Spring MVC, JSPX, jQuery, Mustache.js

Spring (portlet) MVC, Angular 1.#, semi SPA

Spring Boot, React - Redux SPA, REST

Stavební bloky moderní spa

Package manager (NPM, Yarn, ...)

 

Transpiler (Babel, ...)

 

Module bundler (Webpack, Browserify, Rollup, ...)

 

Application FW / view layer (React, AngularJS, Vue, Ember, ...)

 

Model management (Redux, Flux, RxJS, ...)

 

CSS management (JSS, CSS modules, Sass...)

 

Test FW (Jest, Jasmine, Mocha, ...)

Základní charakteristiky ES

dynamicky typovaný

imperativní s deklarativními prvky

multi-paradigm

 

(skoro) vše je objekt

single-thread (event loop)

asynchronní (callback, Promise)

pass by value

prototypální, funkcionální, OOP

časté omyly

JS je pouze FE záležitost

JS je pomalý

s JS se nesetkám při vývoji BE aplikací

JS není modulární

Testování JS kódu

Test-Driven Development   

Behaviour-Driven development

metodika vývoje SW iterační metodou     založená na neprocházejících testech

metodika testování založená na specifikaci chování aplikačního kódu

Jest - BDD framework pro JS (Jasmine)

může zastávat dokumentaci

Základní konstrukce jazyka

//variable declaration
var a;
//variable definition
var b = 10;
//variable definitions can be chained
var myStr = 'abc', myNumber = 1;

//object creation
var car = new Object();
car.speed = 180;
car.color = 'blue';

//with object literal
var secondCar = {
    speed: 200,
    color: 'red'
};

//object properties have descriptors
Object.defineProperty(secondCar , 'type', {
    enumerable: false,
    get: function() {
        return this._type;
    },
    set: function(value) {
        console.log(value);
        this._type = value;
    }
});

secondCar.type = 'roadster';
//funtion statement, evaluated when VM resolves file
function add(a, b){
    return a + b;
}

//function expression, evaluated at runtime
var add = function(a, b){
    return a + b;
};

//functions are ALSO objects with operator()
add.param = 'some parameter';

//function cannot have overloaded parameters
function add(a, b){};
//ERROR - redefinition
function add(a, b, c){};

//function has implicit arguments[] parameter
function add(){
    return arguments[0] + arguments[1];
};

//function can return another function
function curriedAdd(a){
    return function(b) {
        return a + b;
    };
}

//function can also be passed as a parameter
function callMyName(getMyName){
    alert(getMyName());
}

callMyName(function(){
    return 'Mr. Mock';
})

//any variable can hold function
var car = {
    vendor: 'Audi',
    makeSound: function(){
        alert('sound');
    }
}
car.makeSound();

porovnání hodnot v js

Speciální operátory

typeof - vrací základní typ proměnné

instanceof - testuje přítomnost konstruktoru v prototypálním řetězci proměnné

logické hodnoty a operátory

rozlišujeme tzv. truthy a falsy hodnoty

hodnota proměnné v booleanovském kontextu (podmínky, kontruktor new Boolean(), logické operátory)

logické operátory || a && mají návratovou hodnotu

var falsyValue = 0, truthyValue = 'truthy';
var truthy = falsyValue || truthyValue;
var falsy = falsyValue && truthyValu;

lze použít pro defaultování hodnot (use with caution)

trik pro převod mezi truthy a falsy hodnotami na boolean

var falsyValue = '';

var booleanValue = !!falsyValue;

alert(typeof booleanValue);

Základní datové typy

existuje několik základních primitiv

string, number, boolean, null, undefined, symbol

všechna primitiva jsou immutable

vyjma null a undefined má každé primitivum svůj wrapper

String, Number, Boolean - vulueOf() vrací obalené primitivum

všechna čísla jsou 64b floating-point

pole a deklarativní prvky

//define array
var arrayObject = new Array();
var arrayLiteral = [];

//add to the end of an array
arrayLiteral.push('value');
//remove from the end of an array
var lastElement = arrayLiteral.pop();

//add to the beginning of an array
arrayLiteral.unshift('value');
//remove from the beginning of an array
var firstElement = arrayLiteral.shift();

//shallow copy array
var shallowCopy = iterableArray.slice();
iterableArray.pop();
alert(shallowCopy.length);

//iterate over array
var iterableArray = [0, 1, 2];
for(var i = 0; i < iterableArray.length; i++){
    alert(iterableArray[i]);
}

//remove multiple elements from array
var toRemoveFrom = [0, 1, 2];
alert(toRemoveFrom.splice(1, 2));
alert(toRemoveFrom);
//iteration
var colors = ['red', 'green'];

colors.forEach(function(color){
    alert(color);
})

//filter
var filteredColors = colors.filter(function(color){
    return color === 'red';
})

//map
var mappedColors = colors.map(function(color){
    return {
        color: color
    };
})

//reduce
var allColors = colors.reduce(function(acc, next){
    return acc + next;
})

var numbers = [0, 1, 2, 3];
var oddNumbersSum = numbers
    .filter(function(number){
        return number % 2 === 1;
    })
    .reduce(function(acc, next){
        return acc + next;
    });
alert(oddNumbersSum);

Ne všechno je "pole"

existují array-like objekty

arguments[], DOM-method result

lze převést na Array

Array.prototype.slice.call(arguments);

cvičení

Vytvořte funkci (např. 'carFactory'), která na zavolání vrátí objekt reprezentující automobil.

 

Funkce přijímá 2 parametry - název automobilu a rychlost v km/h. Tyto parametry budou vloženy do objektu automobilu spolu s atributem id: integer, který bude inkrementační (obdobně jako v relační DB).

 

Vytvořte funkci, která přijímá N parametrů (jednotlivá vozidla tak, jak je vrací 'carFactory') a vrátí id automobilu s nejvyšší rychlostí.

 

Kód otestuje pomocí Jest BDD (min. 2 testy).

scope a closure

Context (this)

Prototypální dědičnost

každý objekt má svůj prototype

prototype je obyčejný JS objekt

výchozí prototyp je Object.prototype

prototypy objektu tvoří tzv. "prototype chain"

při přístupu k atributu je tento řetězec prohledáván odspoda nahoru

v devtools viditelný jako '__proto__'

protypální řetezec je vytvořen pomocí

operátoru 'new' při volání konstruktoru

metody Object.create()

konstruktor

obyčejná JS funkce, dle kovnvence začíná velkým písmenem

volá se přes operátor 'new'

za předpokladu volání 'new Foo()' se provedou následující operace

  1. vytvoří se prázdný objekt, jehož prototyp je nastaven na Foo.prototype
  2. zavolá se funkce Foo s tímto objektem jako kontext ('this')
  3. návratová hodnota této funkce je vrácena jako výsledek volání operátoru new (implicitně je vrácen objekt z bodu 1)

Object.create()

vytvoří nový objekt s prototypem nastaveným na první parametr

na rozdíl od 'new' nevolá žádný konstruktor

může vytvořit objekt bez prototypu - Object.create(null)

// samsungPhone
{
    systemVersion: '6.1',
    __proto__: phone
}
// phone
{
    displayType: 'AMOLED',
    cpu: {
        model: 'Snapdragon 821',
        cores: 8
    },
    __proto__: Object.prototype
}
// Object.prototype
{
    ...
}
var phone = {
    displayType: 'AMOLED',
    cpu: {
        model: 'Snapdragon 821',
        cores: 8
    }
};

function SamsungPhone(){
    this.systemVersion = '3.0';
}

SamsungPhone.prototype = phone;

var samsungPhone = new SamsungPhone();

OOP s využitím prototypální dědičnosti

function Animal(name) {
    this.name = name;
}

Animal.prototype.sayYourName = function() {
    console.log(this.name);
}

//older approach
function Doge(name) {
    Animal.call(this, name);
}
Doge.prototype = new Animal();
Doge.constructor = Doge;

Doge.prototype.makeSound = function() {
    console.log('Bark!')
}

var rex = new Doge('Rex');

//newer approach using object.create()
function Cate(name) {
    Animal.call(this, name);
}
Cate.prototype = Object.create(Animal.prototype);
Cate.constructor = Cate;

Cate.prototype.makeSound = function() {
    console.log('Moew!')
}

var garfield = new Cate('Garfield');

rex.sayYourName();
rex.makeSound();
console.log('-------')
garfield.sayYourName();
garfield.makeSound();

Promise

sync async
single value
multi-value

Result foo()

List<Result> foo()

Future<Result> foo()

src.subscribe(observer)

ES2015 promise

var promise = new Promise((resolve, reject) => {
    resolve(1);
});

promise
    .then((value) => {
        console.log(value);
        return value + 5;
    })
    .then(value => {
        console.log(value);
    });

var errPromise = new Promise((resolve, reject) => {
    reject('Error');
});

errPromise 
    .then((value) => console.log('You should not see this message'))
    .catch((err) => console.log(err));


callback hell

//example using fake API
function send(URL, data, onDone = function(responseData){}){};

send(calculateContract, formData, function(calculatedData ){
    send(saveToDB, calculatedData function(savedData){
            send(print, savedData, function(){
                console.log('Contract printed');
            });   
        });
});

//same example using ES2015 Promise
send(calculateContract, formData)
    .then(function(calculatedData ){
        return send(saveToDB, calculatedData );
    })
    .then(function(savedData){
        return send(print, savedData);
    })
    .then(function(){
        console.log('Contract printed');
    })
    .catch(function(err){
        //handle error
        console.log(err);
    });

//...and with arrow functions
send(calculateContract, formData)
    .then((calculatedData) => send(saveToDB, calculatedData))
    .then((savedData) => send(print, savedData))
    .then(() => console.log('Contract printed'))
    .catch((err) => console.log(err));

třídy

pouze syntactic sugar nad existující prototypální dědičností

es2017 (babel stage-0)

Rest, spread, destructuring

cvičení #2

ES FIM 2018

By Vít Jouda

ES FIM 2018

ECMAscript FIM presentation 2018

  • 152