Design Pattern

λ„€μž„μŠ€νŽ˜μ΄μŠ€ νŒ¨ν„΄ (Namespace Pattern)

지역/μ „μ—­ 객체λ₯Ό μ„ μ–Έν•˜μ—¬ κ·Έ μ•ˆμ— 값을 μ‚½μž…ν•˜μ—¬ μ‚¬μš©ν•˜λŠ” 것

ꢌμž₯ νŒ¨ν„΄

var App = App || {};
App.Parent = function () {};
App.Child = function () {};

App.container = 1;
App.module = {
    module_1: {
        data: {a: 1, b: 2}
    },
    module_2: {}
};

μ•ˆν‹° νŒ¨ν„΄

function Parent() {}
function Child() {}

var some_var = 1;

var module1 = {};

module.data = {a : 1, b : 2};

var module2 = {}

λͺ¨λ“ˆ νŒ¨ν„΄ (Module Pattern)

Common JS

μ‚¬μš©μ΄ λŒ€μ²΄μ μœΌλ‘œ κ°„νŽΈν•˜λ©° λŒ€λΆ€λΆ„μ˜ 둜컬 λ””μŠ€ν¬μ— μœ„μΉ˜ν•΄ λ°”λ‘œ λΆˆλŸ¬μ„œ μ‚¬μš©ν•œλ‹€.

μ„œλ²„μ‚¬μ΄λ“œ λ°©μ‹μ—μ„œ 많이 μ‚¬μš©ν•˜λ©° κ·Έ λŒ€ν‘œμ μΈ μ˜ˆκ°€ Node JS 이닀.

const $ = require('jquery');

module.exports = {
    jQuery: $
}

ν—Œλ° λͺ¨λ“ νŒŒμΌμ΄ λ‹€ λ‘œλ“œλ λ•Œ κΉŒμ§€ μ‚¬μš©ν•  수 μ—†μœΌλ©° νŒŒμΌλ‹¨μœ„μ˜ μŠ€μ½”ν”„κ°€ μ—†μ–΄ 기타 μ‚¬μ΄λ“œμ΄νŒ©νŠΈλ„ λ°œμƒν•œλ‹€.

AMD (Asynchronous Moudle Definition)

비동기적 λͺ¨λ“ˆ μ„ μ–Έ 으둜 λŒ€ν‘œμ μΈκ²Œ Require JS 이닀.

define(['a', 'b', 'c'], function (a, b, c) {
    /* statement */
});

Common JS λ³΄λ‹€λŠ” 비동기 ν™˜κ²½μ—μ„œ 맀우 잘 λ™μž‘ν•˜λ©° μ„œλ²„μ‚¬μ΄λ“œμ—μ„œλ„ 문제 없이 λ™μž‘λœλ‹€.

μ΄λŠ” Lazy-Load 기법을 μ‘μš©ν•˜μ—¬ λ”μš± 더 μœ μ—°ν•œ μ‚¬μš©μ΄ κ°€λŠ₯ν•˜λ‹€.

UMD (Universal Module Definition)

AMD 와 Common JS 방식을 λͺ¨λ‘ μ‚¬μš©κ°€λŠ₯ν•˜κ²Œ ν˜Έν™˜λ˜λŠ” 방식을 UMD 라고 ν•œλ‹€.

(function (root, factory) {
  if (typeof define === 'function' && define.amd) {
    // AMD. Register as an anonymous module.
    define(['b'], factory);
  } else if (typeof module === 'object' && module.exports) {
    // Node. Does not work with strict CommonJS, but
    // only CommonJS-like environments that support module.exports,
    // like Node.
    module.exports = factory(require('b'));
  } else {
    // Browser globals (root is window)
    root.returnExports = factory(root.b);
  }
}(this, function (b) {
  //use b in some fashion.

  // Just return a value to define the module export.
  // This example returns an object, but the module
  // can return a function as the exported value.
  return {};
}));

κΈ°λ³Έ λͺ¨λ“ˆ νŒ¨ν„΄

public κ³Ό private 의 μ ‘κ·Ό κΆŒν•œμ„ κ°€λŠ₯ν•˜κ²Œ ν•œλ‹€.

(function () {
    // private λ³€μˆ˜λ“€κ³Ό ν•¨μˆ˜λ“€μ„ μ„ μ–Έ

    return {
        // public λ³€μˆ˜λ“€κ³Ό ν•¨μˆ˜λ“€μ„ μ„ μ–Έ
    };
}());
var HTMLChanger = (function() {
    var contents = 'contents';

    var changeHTML = function () {
        var element = document.getElementById('attribute-to-change');
        element.innerHTML = contents;
    }

    return {
        callChangeHTML: function () {
            changeHTML();
            console.log(contents);
        }
    };
}());

HTMLChanger.callChangeHTML();         // 'contents'
console.log(HTMLChanger.contents);    // undefined

ꢌμž₯ λͺ¨λ“ˆ νŒ¨ν„΄

  1. Module Scope λ‚΄μ—μ„œ μ‚¬μš©ν•  λ³€μˆ˜ μž‘μ„±
  2. Utility Method μž‘μ„±
  3. DOM μ‘°μž‘ λ©”μ†Œλ“œ μž‘μ„±
  4. Event Handler μž‘μ„±
  5. Public Method μž‘μ„±
var module = (function () {
    // 1. Module Scope λ‚΄μ—μ„œ μ‚¬μš©ν•  λ³€μˆ˜ μž‘μ„±
    var scopeVal = {},
        utilMethod,
        manipulateDOM,
        eventHandler,
        initModule;

    // 2. Utility Method μž‘μ„±
    utilMethod = function () {
        /* μ‹€ν–‰ μ½”λ“œ */
    };

    // 3. DOM μ‘°μž‘ λ©”μ†Œλ“œ μž‘μ„±
    manipulateDOM = function () {
        /* μ‹€ν–‰ μ½”λ“œ */
    }

    // 4. Event Handler μž‘μ„±
    eventHandler = function () {
        /* μ‹€ν–‰ μ½”λ“œ */
    }

    // 5. Public Method μž‘μ„±
    return {
        init: initMethod
    };
}());

컀링 (Currying)

μ—¬λŸ¬κ°œμ˜ 인자λ₯Ό λ°›λŠ” ν•¨μˆ˜κ°€ μžˆμ„ 경우 μΌλΆ€μ˜ 인자만 λ°›λŠ” ν•¨μˆ˜λ₯Ό λ§Œλ“œλŠ” 기법

Currying Example

function volume(l, w, h) {
    return l * w * h;
}

function curry(fn) {
    var arity = fn.length;

    return (function resolver() {
        var memory = Array.prototype.slice.call(arguments);

        return function () {
            var local = memory.slice();

            Array.prototype.push.apply(local, arguments);

            var next = (local.length >= arity? fn : resolver);

            return next.apply(null, local);
        };
    }());
}

Example #1 : JS - ES5

var curried = curry(volume),
    length = curried(2),
    lengthAndWidth = length(3);

console.log(lengthAndWidth(4));

Example #2 : JS - ES5

var _curried = curry(volume);
console.log(_curried(2)(3)(4));

Case 2 κ°€ 10배정도 빠름

λ©”λͺ¨μ΄μ œμ΄μ…˜ (Memoization)

이전에 μ—°μ‚°λœ κ²°κ³Όλ₯Ό μ €μž₯ν•˜κ³  μ‚¬μš©ν•˜λŠ” νŒ¨ν„΄
λ©”λͺ¨λ¦¬ 상에 μž„μ‹œ μ €μž₯값을 μ €μž₯ν•˜μ—¬ μ‚¬μš©ν•  수 μžˆμ–΄ μ‹œκ°„ λ³΅μž‘λ„λ₯Ό 많이 쀄인닀.

일반적인 ν”Όλ³΄λ‚˜μΉ˜ 둜직

var count = 0;

var fibonacci = function (n) {
    count++;
    return n < 2 ? n : fibonacci(n - 1) + fibonacci(n - 2);
}

for (var i = 0; i <= 10; i++) {
    console.log(i + ' = ' + fibonacci(i));
}

console.log('count = ', count);

λ©”λͺ¨μ΄μ œμ΄μ…˜μ„ μ‚¬μš©ν•œ ν”Όλ³΄λ‚˜μΉ˜ 둜직 1

var fibonacci = function () {
    var memo = [0, 1];
    var count = 0;
    var fib = function (n) {
        count++;

        var result = meno[n];

        if (typeof result !== 'number') {
            result = fib(n - 1) + fib(n - 2);
            memo[n] = result;
        }
        return result;
    };
    return fib;
}

for (var i = 0; i <= 10; i++) {
    console.log(i, ' = ', fibonacci(i));
}

console.log('count : ', count);

λ©”λͺ¨μ΄μ œμ΄μ…˜μ„ μ‚¬μš©ν•œ ν”Όλ³΄λ‚˜μΉ˜ 둜직 2

var factorial = (function () {
    var save = {};
    var fact = function (number) {
        if (number > 0) {
            var saved = save[number - 1] || fact(number - 1);
            var result = number * saved;
            save[number] = result;
            console.log(saved, result);
            return result;
        } else {
            return 1;
        }
    }
    return fact;
}());

factorial(7);