JS: Going deeper

Станислав Говоров, Яндекс

JS: Going deeper

Станислав Говоров,
Системный инженер

 

Объекты и наследование

Objects & Inheritance

Object

{
    key1 : value,
    key2 : value2,
}
//...and a bit magic

Object properties

Object properties

ES6 features:

//Calculated property names:
let calculated = 'doge';
let obj2 = {[calculated] : 'WOW'};

//ES5:
var calculated   = 'doge';
var obj2         = {};
obj2[calculated] = 'WOW';

Add some magic

Object property descriptors

Object.defineProperty(obj, prop, descriptor)

Descriptor:

Object property descriptors

Get and set

let obj = {};
Object.defineProperty(obj,'magicProp',{
    get: function(){
        console.log('getter invoked');
        return 42;
    },
    set: function(){
        console.log('setter invoked');
        this.magicProp = '21';
    },
});

 

Object.defineProperties(obj, descriptors)

Object.keys(obj),

Object.getOwnPropertyNames(obj)

Object.getOwnPropertyDescriptor(obj, prop)

Object.preventExtensions(obj)

Object.seal(obj)

Object.freeze(obj)

Object.isExtensible(obj)

Object.isSealed(obj)

Object.isFrozen(obj)

No classes in JS

WAT

Only prototypes

JavaScript classes introduced in ECMAScript 6 are syntactical sugar over JavaScript’s existing prototype-based inheritance. The class syntax is not introducing a new object-oriented inheritance model to JavaScript. JavaScript classes provide a much simpler and clearer syntax to create objects and deal with inheritance.

MDN

ECMA-262

“Classes” in JS

ES6 way:

class MyAwesomeClass {
    constructor(){
        this.importantProp = 'importantValue';
    }

    coolMethod(){
        console.log('coolMethod invoked');
    }

    static andStaticOne(){
        console.log('static method invoked');
    }
}

let instance = new MyAwesomeClass();

are just syntax sugar

Pre-ES6 way:

const MyAwesomeClass = function(){
    this.importantProp = 'importantValue';
}

MyAwesomeClass.prototype = {
    coolMethod: function(){
        console.log('coolMethod invoked');
    },
};
MyAwesomeClass.andStaticOne = function(){
    console.log('static method invoked');
};

let instance = new MyAwesomeClass();

Ok. What about inheritance?

Inheritance

ES6 way:

class AwesomeChildClass extends MyAwesomeClass {
    childMethod(){
        console.log('child method invoked');
    }
    coolMethod(){
        console.log('redeclared method');
    }
}

Inheritance

Pre-ES6 way:

const AwesomeChildClass.prototype = Object.create(MyAwesomeClass);

AwesomeChildClass.prototype.childMethod = function(){
    console.log('child method invoked');
}

AwesomeChildClass.prototype.coolMethod = function(){
    console.log('redeclared method');
}

Inheritance

:) Mix ES6 and pre-ES6:

const MyAwesomeClass = function(){
    this.importantProp = 'importantValue';
}

class ChildClass extends MyAwesomeClass();

let instance = new ChildClass();

How Inheritance Works

Prototype Chain

MDN

Prototype Chain and Performance

instanceOf

instanceOf

obj instanceof Constructor

Own properties and inherited properties

vs

??

hasOwnProperty!

Object.prototype.hasOwnProperty()

Own properties and inherited properties

To check whether an object has a property defined on itself and not somewhere on its prototype chain, it is necessary to use the hasOwnProperty method which all objects inherit from Object.prototype. hasOwnProperty is the only thing in JavaScript which deals with properties and does not traverse the prototype chain.

Note: It is not enough to check whether a property is undefined. The property might very well exist, but its value just happens to be set to undefined.

Extending native prototypes

(monkey patching)

is a bad idea

Prototype.js

JavaScript is a dynamic scripting language

very dynamic :)

 

class BigTastyPizza extends PepperoniPizza {
    size() {
        return '40cm';
    }
}

 

 

Warning: Changing the [[Prototype]] of an object is, by the nature of how modern JavaScript engines optimize property accesses, a very slow operation, in every browser and JavaScript engine. The effects on performance of altering inheritance are subtle and far-flung, and are not limited to simply the time spent in obj.__proto__ = ... statement, but may extend to any code that has access to any object whose [[Prototype]] has been altered. If you care about performance you should avoid setting the [[Prototype]] of an object. Instead, create a new object with the desired [[Prototype]] using Object.create().

new operator in a nutshell

let object = new Constructor(arguments);

MDN

ECMA-262

Цикл событий и модель исполнения

Concurrency model & Event loop

Concurrency model & Event loop

Runtime concepts

One thread

(web workers API)

Event Loop

Functions in Stack

Objects allocated in a Heap

Callback Queue

“Run-to-completion”

Runtime concepts

non-blocking

setTimeout, setInterval

setTimeout, setInterval

"turtle finished"
"horse finished"

setTimeout, setInterval

setTimeout, setInterval

setTimeout, setInterval

MDN

W3C

MDN

MDN

W3C

MDN

Асинхронное программирование в Javascript

Asynchronous Javascript

Callbacks

//...
http.get(
    'cat.gif',
    onComplete(cat){
        console.log(cat);
    },
    onError(e){
        console.error('details');
    }
);
//...

Callbacks

askServiceOne(
    param,
    onCompleteOne(),
    onErrorOne(),
);

Callbacks

askServiceOne(
    param,
    function onCompleteOne(){
        doSomething();
        askServiceTwo();
    },
    function onErrorOne(){
        //error handling one
    },
);

Callbacks

askServiceOne(
    param,
    function onCompleteOne(){
        doSomething();
        askServiceTwo('param',
            function onCompleteTwo(){
                doSomethingTwo();
            },
            function onErrorTwo(){
                //error handling two
            },
        });
    }),
    function onErrorOne(){
        //error handling one
    }),
);

Callbacks

askServiceOne(
    param,
    onCompleteOne(function(){
        doSomething();
        askServiceTwo('param',
            function onCompleteTwo(){
                doSomethingTwo();
                askService100500({
                    'param100500',
                    function onComplete100500(){
                        console.log('OH GOD WHY??');
                    },
                    function onError100500(){
                        //error handling logic
                    },
                });
            }),
            function onErrorTwo(){
                //error handling two
            }),
        });
    }),
    onErrorOne(function(){
        //error handling one
    }),
);

Callbacks

                                },
                            },
                        },
                    },
                },
            },
        },
    },
},

Callbacks

Callback hell

Events

Promises

.. .. ..

http://callbackhell.com/

Callbacks vs Events

Callbacks vs Events

askService('param');

listener.on('service:success', function(){
});

listener.on('service:pending', function(){
});

listener.on('service:fail', function(){
});

listener.on('service:done', function(){
});

listener.on('service:accessDenied', function(){
});

Promises

askServiceOne(
    param,
    onCompleteOne(function(){
        doSomething();
        askServiceTwo('param',
            function onCompleteTwo(){
                doSomethingTwo();
                askService100500({
                    'param100500',
                    function onComplete100500(){
                        console.log('OH GOD WHY??');
                    },
                    function onError100500(){
                        //error handling logic
                    },
                });
            }),
            function onErrorTwo(){
                //error handling two
            }),
        });
    }),
    onErrorOne(function(){
        //error handling one
    }),
);

Promises

let flags = [];

askServiceOne(
    param,
    onCompleteOne(function(){
        doSomething();
        flags.push('one');
        askServiceTwo('param',
            function onCompleteTwo(){
                doSomethingTwo();
                flags.push('two');
                askService100500({
                    'param100500',
                    function onComplete100500(){
                        flags.push('100500');
                        console.log('OH GOD WHY??');
                    },
                    function onError100500(){
                        //error handling logic
                    },
                });
            }),
            function onErrorTwo(){
                //error handling two
            }),
        });
    }),
    onErrorOne(function(){
        //error handling one
    }),
);

Promises

askService(param)
    .then(callback1)
    .catch(handler1)
    .then(callback2)
    .catch(handler2)
    .then(callback3)
    .catch(handler3)
    .then(callback4)
    .catch(handler4)

Chaining

Asynchronous catch

Promises

jQuery ajax()

fetch()

jQuery deffered spec

Promises

Promises

var promise = new Promise(function(resolve, reject) {
    //business logic
    //call resolve(result) or reject(error) when you need it
});

promise.then(onResolve,onReject);

Promises

let monkey = new Promise(function(resolve,reject){
    let r = Math.round(Math.random());
    if (r === 0){
        resolve('OK');
    }
    else {
        reject('o0');
    }
});

Promises

//async one
let asyncMonkey = new Promise(function(resolve,reject){

    let res = Math.round(r);
    let r   = Math.random();

    setTimeout(function(){
        if (res === 0){
            resolve('OK');
        }
        else {
            reject('o0');
        }
    },r*10000);
});

Promises

asyncMonkey.then(
    function(result){
        console.log(result); //OK
    },
    function(error){
        console.error(error); //o0
    }
);

Promises

{
    PromiseState            : "pending", //rejected/resolved
    PromiseResult           : undefined,
    PromiseFulFillReactions : [],
    PromiseRejectReactions  : [],
}

Promises

 

Q

Promises A

Promises A+

bluedird

MDN

learn.javascript.ru

Reactive Programming

Reactive Programming

Reactive Programming

Reactive Programming

It’s like an asynchronous immutable array

underscore for events

Reactive Programming

Reactive Programming

//assume we have rxjs-based http service
//this.requestSubscription;

this.inputField.onValueChange()
    .debounce(400)
    .distinctUntilChanged()
    .subscribe((value)=>{
        requestSubscription = this.http.get('/url')
            .subscribe((data)=>{
                //callback
            });
    });


this.requestSubscription.unsubscribe(); //will cancel automatically!

Reactive Programming

Reactive Programming

ReactiveX

Introduction to reactive programming

Rx Marbles

Rx Book

Useful resources

Style Guide 1

Style Guide 2

google.com :)

stack overflow

MDN

learn.javascript.ru

Eloquent Javascript

You don’t know JS