Библиотеки чрез затваряния в JavaScript

Често в JavaScript се създават библиотеки, които представляват колекции от функции за използване от други програмисти.

Такива библиотеки обикновено се опаковат в модули чрез затваряния. Това се прави, така че при свързване на библиотеката във външния свят да се появяват възможно най-малко функции.

Като правило всяка библиотека се стреми да създава във външния свят само една променлива - обект с функциите на библиотеката. В същото време вътре в кода на библиотеката част от функциите са основни, а част - спомагателни. Очевидно е, че във външния свят искаме да експортираме само необходимите функции, без да затрупваме експортирания обект със спомагателни функции.

Нека разгледаме пример. Да предположим, че имаме следния набор от функции, които бихме искали да превърнем в библиотека:

math.jsfunction square(num) {
  return num ** 2;
}
function cube(num) {
  return num ** 3;
}
function avg(arr) {
  return sum(arr, 1) / arr.length;
}
function digitsSum(num) {
  return sum(String(num).split(''));
}

// спомагателна функция
function sum(arr) {
  let res = 0;
  
  for (let elem of arr) {
    res += +elem;
  }
  
  return res;
}

Нека оформим нашите функции като модул:

math.js;(function() {
  function square(num) {
    return num ** 2;
  }
  function cube(num) {
    return num ** 3;
  }
  function avg(arr) {
    return sum(arr, 1) / arr.length;
  }
  function digitsSum(num) {
    return sum(String(num).split(''));
  }
  
  // спомагателна функция
  function sum(arr) {
    let res = 0;
    
    for (let elem of arr) {
      res += +elem;
    }
    
    return res;
  }
})();

А сега нека експортираме всички функции, с изключение на спомагателната:

math.js;(function() {
  function square(num) {
    return num ** 2;
  }
  function cube(num) {
    return num ** 3;
  }
  function avg(arr) {
    return sum(arr, 1) / arr.length;
  }
  function digitsSum(num) {
    return sum(String(num).split(''));
  }
  
  // спомагателна функция
  function sum(arr) {
    let res = 0;
    
    for (let elem of arr) {
      res += +elem;
    }
    
    return res;
  }
  
  window.math = {square, cube, avg, digitsSum};
})();

Да предположим, че имаме HTML страница index.html:

index.html<html>
  <head>
    <script>
      
    </script>
  </head>
</html>

Нека свържем нашата библиотека с нея:

index.html<html>
  <head>
    <script src="math.js"></script>
    <script>
      
    </script>
  </head>
</html>

Нека използваме функциите от нашата библиотека:

index.html<html>
  <head>
    <script src="math.js"></script>
    <script>
      alert(math.avg([1, 2, 3]) + math.square());
    </script>
  </head>
</html>
Задание 1

Даден е следният код:

javascriptfunction avg1(arr) {
  return sum(arr, 1) / arr.length;
}

function avg2(arr) {
  return sum(arr, 2) / arr.length;
}

function avg3(arr) {
  return sum(arr, 3) / arr.length;
}

// спомагателна функция
function sum(arr, pow) {
  let res = 0;
  
  for (let elem of arr) {
    res += elem ** pow;
  }
  
  return res;
}

Оформете този код като модул. Експортирайте навън всички функции, с изключение на спомагателната.

Задание 2

Изучете библиотеката underscore. Направете ваша собствена аналогична библиотека, като повторите в нея 5-10 функции от оригиналната библиотека.