Moduly v Javascripte

10/2016 / Milan "perún" Herda / @moriquend / prezentacie.perunhq.org

Časť 1: Module Pattern

Úloha

Vytvorte v Javascripte objekt, ktorý bude mať privátnu premennú name, ku ktorej sa bude dať pristúpiť iba cez setter/getter.


// váš kód

var person = /* váš kód */;

person.setName('fero');

console.log(person.getName());
                    

Scope premenných

Scope je rozsah platnosti, tj. kde všade je možné k existujúcej premennej pristúpiť.

Je určený miestom a spôsobom deklarovania premennej.

Aký je scope v prípade, že tento kód je v top-level skripte?


a = 1;
var b = 2;

function foo () {
    c = 3;
    var d = 4;

    for (i = 5; i < 10; i++) {
        e = 6;
        var f = 7;
    }

    for (var j = 8; j < 10; j++) {
    }
}
                        

Aký je scope v prípade, že tento kód je v top-level skripte?


a = 1;     // globálna premenná
var b = 2;

function foo () {
    c = 3;
    var d = 4;

    for (i = 5; i < 10; i++) {
        e = 6;
        var f = 7;
    }

    for (var j = 8; j < 10; j++) {
    }
}
                        

Aký je scope v prípade, že tento kód je v top-level skripte?


a = 1;     // globálna premenná
var b = 2; // globálna premenná

function foo () {
    c = 3;
    var d = 4;

    for (i = 5; i < 10; i++) {
        e = 6;
        var f = 7;
    }

    for (var j = 8; j < 10; j++) {
    }
}
                        

Aký je scope v prípade, že tento kód je v top-level skripte?


a = 1;     // globálna premenná
var b = 2; // globálna premenná

function foo () {
    c = 3;     // globálna premenná
    var d = 4;

    for (i = 5; i < 10; i++) {
        e = 6;
        var f = 7;
    }

    for (var j = 8; j < 10; j++) {
    }
}
                        

Aký je scope v prípade, že tento kód je v top-level skripte?


a = 1;     // globálna premenná
var b = 2; // globálna premenná

function foo () {
    c = 3;     // globálna premenná
    var d = 4; // lokálna pre foo

    for (i = 5; i < 10; i++) {
        e = 6;
        var f = 7;
    }

    for (var j = 8; j < 10; j++) {
    }
}
                        

Aký je scope v prípade, že tento kód je v top-level skripte?


a = 1;     // globálna premenná
var b = 2; // globálna premenná

function foo () {
    c = 3;     // globálna premenná
    var d = 4; // lokálna pre foo

    for (i = 5; i < 10; i++) {   // globálna premenná
        e = 6;
        var f = 7;
    }

    for (var j = 8; j < 10; j++) {
    }
}
                        

Aký je scope v prípade, že tento kód je v top-level skripte?


a = 1;     // globálna premenná
var b = 2; // globálna premenná

function foo () {
    c = 3;     // globálna premenná
    var d = 4; // lokálna pre foo

    for (i = 5; i < 10; i++) {   // globálna premenná
        e = 6;                      // globálna premenná
        var f = 7;
    }

    for (var j = 8; j < 10; j++) {
    }
}
                        

Aký je scope v prípade, že tento kód je v top-level skripte?


a = 1;     // globálna premenná
var b = 2; // globálna premenná

function foo () {
    c = 3;     // globálna premenná
    var d = 4; // lokálna pre foo

    for (i = 5; i < 10; i++) {   // globálna premenná
        e = 6;                      // globálna premenná
        var f = 7;                  // lokálna pre foo
    }

    for (var j = 8; j < 10; j++) {
    }
}
                        

Aký je scope v prípade, že tento kód je v top-level skripte?


a = 1;     // globálna premenná
var b = 2; // globálna premenná

function foo () {
    c = 3;     // globálna premenná
    var d = 4; // lokálna pre foo

    for (i = 5; i < 10; i++) {   // globálna premenná
        e = 6;                      // globálna premenná
        var f = 7;                  // lokálna pre foo
    }

    for (var j = 8; j < 10; j++) { // lokálna pre foo
    }
}
                        

Spôsoby deklarácie v ES2015

  • var - bezo zmeny, deklaruje lokálne pre funkciu
  • let - platnosť iba vo svojom bloku
  • const - konštanta, platnosť iba vo svojom bloku

Closure

Closure je "obálka", ktorá v sebe obsahuje všetky premenné, ku ktorým má funkcia prístup.

Closure


var a = 1;

function foo () {
    var b = 2;

    return function () {
        var c = 3;

        return a + b + c;
    }
}

var bar = foo();
bar();
                    

IIFE

Immediately Invoked Function Expression

IIFE


(function () {
    // kód
})();
                    

K čomu to je?

Nájdite rozdiel


var a = 1,
    b = 2,
    c;

c = a + b;

// versus

(function () {
    var a = 1,
        b = 2,
        c;

    c = a + b;
})();

                    

Module pattern

Spôsob, ako pomocou closure vieme vytvárať moduly/objekty s privátnymi premennými/funkciami

Module pattern


function () {
    var name;

    return {
        setName: function (newName) {
            if (newName !== 'fero') {
                name = newName;
            }
        },
        getName: function () {
            return name;
        }
    }
}
                        

Revealing module pattern


function () {
    var name,
        setName,
        getName;

    setName = function (newName) {
        // tu môžu byť rôzne validácie
        name = newName;
    };

    getName = function () {
        return name;
    };

    return {
        setName: setName,
        getName: getName
    }
}
                        

Vytvorenie inštancie


var person = (function () {
    var name,
        setName,
        getName;

    setName = function (newName) {
        // tu môžu byť rôzne validácie
        name = newName;
    };

    getName = function () {
        return name;
    };

    return {
        setName: setName,
        getName: getName
    }
})();
                    

Vytvorenie inštancie


var personFactory = function () {
    var name,
        setName,
        getName;

    setName = function (newName) {
        // tu môžu byť rôzne validácie
        name = newName;
    };

    getName = function () {
        return name;
    };

    return {
        setName: setName,
        getName: getName
    }
};

var personA = personFactory(),
    personB = personFactory();
                    

Pohrajte sa

Vytvorte modul reprezentujúci bojovú jednotku v hre s vlastnosťami:

  • názov
  • rýchlosť
  • sila
  • zdravie

var unitFactory = function () {
    var name,
        speed,
        strength,
        health,
        // methods
        setName,
        getName,
        setSpeed,
        getSpeed,
        setStrength,
        getStrength,
        setHealth,
        getHealth;

    setName = function (newName) {
        name = newName;
    };

    getName = function () {
        return name;
    };

    setSpeed = function (newSpeed) {
        speed = newSpeed;
    };

    getSpeed = function () {
        return speed;
    };

    setStrength = function (newStrength) {
        strength = newStrength;
    };

    getStrength = function () {
        return strength;
    };

    setHealth = function (newHealth) {
        health = newHealth;
    };

    getHealth = function () {
        return health;
    };

    return {
        setName: setName,
        getName: getName,
        setSpeed: setSpeed,
        getSpeed: getSpeed,
        setStrength: setStrength,
        getStrength: getStrength
    };
};

Pohrajte sa

Vytvorte inštanciu reprezentujúcu kopijníka, jazdca a lukostrelca


var pikeman = unitFactory(),
    horseman = unitFactory(),
    archer = unitFactory();

pikeman.setName('pikeman');
pikeman.setSpeed(1);
pikeman.setStrength(5);
pikeman.setHealth(10);

// ...

Pohrajte sa

Pridajte lukostrelcovi vlastnosť dostrel


archer.range = 5;

archer.setRange = function (newRange) {
    this.range = newRange;
};

archer.getRange = function () {
    return this.range;
};
                    

var extendByRange = function (unit) {
    var range,
        setRange,
        getRange;

    setRange = function (newRange) {
        range = newRange;
    };

    getRange = function () {
        return range;
    };

    unit.setRange = setRange;
    unit.getRange = getRange;

    return unit;
};
                    

var archer = unitFactory();

archer = extendByRange(archer);

archer.setRange(4);
                    

Využitie module patternu

  • skrývanie implementáčných detailov a privátnych vlastností
  • ochrana objektov pred narušením zvonka
  • umožňuje komponentové programovanie
  • ochrana pred zaprasením globálneho menného priestoru

Moduly nie sú iba module pattern

CommonJS a ES2015 dovoľujú mať pre skripty samostatné menné priestory a exportovať von iba želané premenné.

CommonJS


// index.js
var square = require('./square.js');

console.log('area is ' + square.area(5));

// square.js
var area = function (length) {
    return length * length;
};

module.exports = {
    area: area
};
                        

ES2015


// index.js
import square from './square';

console.log('area is ' + square.area(5));

// square.js
const area = (length) => {
    return length * length;
};

export default {
    area
};

                        

Nabudúce:

Ako pracovať s modulmi rôznych formátov

CommonJS, AMD, UMD a ES2015

Ďakujem za pozornosť

Otázky?