ΠžΡΠ½ΠΎΠ²Π½Ρ‹Π΅ опрСдСлСния

Π€ΡƒΠ½ΠΊΡ†ΠΈΠΎΠ½Π°Π»ΡŒΠ½ΠΎΠ΅ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ (ЀП) - это такая ΠΆΠ΅, ΠΊΠ°ΠΊ ΠΈ ООП, ΠΏΠ°Ρ€Π°Π΄ΠΈΠ³ΠΌΠ° Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ. Она прСдписываСт ΠΊΠΎΠ½Ρ†Π΅ΠΏΡ†ΠΈΠΈ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΌΠΈ ΠΌΡ‹ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒΡΡ Π²ΠΎ врСмя Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ.

ЀП Π½Π΅ построСно ΠΏΠΎΠ²Π΅Ρ€Ρ… Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΉ - ΠΌΡ‹ ΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌΡΡ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ½Ρ‹ΠΌ ΠΊΠΎΠ΄ΠΎΠΌ, ΠΊΠ°ΠΊ матСматичСскими функциями

Π Π°ΡΠΏΡ€ΠΎΡΡ‚Ρ€Π°Π½Ρ‘Π½Π½ΠΎΡΡ‚ΡŒ

Π•ΡΡ‚ΡŒ языки, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ находятся Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Π² Ρ€Π°ΠΌΠΊΠ°Ρ… ΠΎΠ΄Π½ΠΎΠΉ ΠΏΠ°Ρ€Π°Π΄ΠΈΠ³ΠΌΡ‹:

  • ООП
    • Java
    • C#
  • ЀП
    • Haskell
    • Lisp
    • F#

Но Ρ‚Π°ΠΊ ΠΆΠ΅ Π΅ΡΡ‚ΡŒ ΠΈ ΠΌΡƒΠ»ΡŒΡ‚ΠΈΠΏΠ°Ρ€Π°Π΄ΠΈΠ³ΠΌΠ΅Π½Π½Ρ‹Π΅ языки, ΠΊΠ°ΠΊ JS

JS - это ΠΌΡƒΠ»ΡŒΡ‚ΠΈΠΏΠ°Ρ€Π°Π΄ΠΈΠ³ΠΌΠ΅Π½Π½Ρ‹ΠΉ ЯП, ΠΊΠΎΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΈΠ²Π°Π΅Ρ‚ ΠΊΠ°ΠΊ ΠΈΠΌΠΏΠ΅Ρ€Π°Ρ‚ΠΈΠ²Π½Ρ‹ΠΉ, Ρ‚Π°ΠΊ ΠΈ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΎΠ½Π°Π»ΡŒΠ½Ρ‹ΠΉ стили.


Π‘Π°Π·ΠΎΠ²Ρ‹Π΅ ΠΊΠΎΠ½Ρ†Π΅ΠΏΡ†ΠΈΠΈ ЀП

ΠŸΡ€ΠΎΡ†Π΅Π΄ΡƒΡ€Π° - это Π±Π»ΠΎΠΊ ΠΊΠΎΠ΄Π°, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ выполняСт Π½Π°Π±ΠΎΡ€ Π·Π°Π΄Π°Π½Π½Ρ‹Ρ… дСйствий.

Ѐункция - это Π±Π»ΠΎΠΊ ΠΊΠΎΠ΄Π°, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚. ΠžΠ±Ρ‹Ρ‡Π½ΠΎ, это Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ ΠΊΠ°ΠΊΠΈΡ…-Ρ‚ΠΎ вычислСний. Π’Π½ΡƒΡ‚Ρ€ΡŒ ΠΌΡ‹ ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‘ΠΌ Π΄Π°Π½Π½Ρ‹Π΅ ΠΈ ΠΏΠΎΠ»ΡƒΡ‡Π°Π΅ΠΌ Π½Π΅ΠΈΠ·ΠΌΠ΅Π½Π½Ρ‹ΠΉ ΠΎΡ‚ Ρ€Π°Π·Π° ΠΊ Ρ€Π°Π·Ρƒ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚.

Π”Π΅ΠΊΠ»Π°Ρ€Π°Ρ‚ΠΈΠ²Π½ΠΎΡΡ‚ΡŒ

Π•ΡΡ‚ΡŒ Π² ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠΈ глобально Π΄Π²Π° ΠΏΠΎΠ΄Ρ…ΠΎΠ΄Π°:

  • Π˜ΠΌΠΏΠ΅Ρ€Π°Ρ‚ΠΈΠ²Π½Ρ‹ΠΉ β†’ Как Ρ…ΠΎΡ‚ΠΈΠΌ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ? β†’ ΠžΠΏΠΈΡΡ‹Π²Π°Π΅ΠΌ дСйствия
  • Π”Π΅ΠΊΠ»Π°Ρ€Π°Ρ‚ΠΈΠ²Π½Ρ‹ΠΉ β†’ Π§Ρ‚ΠΎ Ρ…ΠΎΡ‚ΠΈΠΌ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ? β†’ ΠžΠΏΠΈΡΡ‹Π²Π°Π΅ΠΌ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚

Π’ основС всСго всСгда стоит ΠΈΠΌΠΏΠ΅Ρ€Π°Ρ‚ΠΈΠ²Π½Ρ‹ΠΉ ΠΏΠΎΠ΄Ρ…ΠΎΠ΄, Π½Π° Π±Π°Π·Π΅ ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ³ΠΎ ΡΠΎΠ·Π΄Π°ΡŽΡ‚ΡΡ Π΄Π΅ΠΊΠ»Π°Ρ€Π°Ρ‚ΠΈΠ²Π½Ρ‹Π΅

Π˜ΠΌΠΏΠ΅Ρ€Π°Ρ‚ΠΈΠ²Π½Π°Ρ функция

const arr = [1, 2, 3, 4, 5, 6];
 
function getEvens(arr) {
	const evens = [];
	
	for (let i = 0; i < arr.length; i++) {
	  if (arr[i] % 2 === 0) {
	    evens.push(arr[i]);
	  }
	}
	
	return evens;
}
 
 
console.log(getEvens(arr)); // [2, 4, 6]

А ΡƒΠΆΠ΅ ΠΏΠΎΠ²Π΅Ρ€Ρ… ΠΈΠΌΠΏΠ΅Ρ€Π°Ρ‚ΠΈΠ²Π½Ρ‹Ρ… Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΉ, ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ ΡΡ‚Ρ€ΠΎΠΈΡ‚ΡŒ Π΄Π΅ΠΊΠ»Π°Ρ€Π°Ρ‚ΠΈΠ²Π½Ρ‹Π΅, Π² ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Ρ… ΠΌΡ‹ просто Π±ΡƒΠ΄Π΅ΠΌ ΠΎΠΏΠΈΡΡ‹Π²Π°Ρ‚ΡŒ дСйствия, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Π΄ΠΎΠ»ΠΆΠ΅Π½ Π²Ρ‹ΠΏΠΎΠ»Π½ΡΡ‚ΡŒ ΠΊΠΎΠ΄

const arr = [1, 2, 3, 4, 5, 6];
const evens = getEvens(arr)
console.log(evens); // [2, 4, 6]

Π”Π΅ΠΊΠ»Π°Ρ€Π°Ρ‚ΠΈΠ²Π½ΠΎΡΡ‚ΡŒ - это свойство любого Ρ…ΠΎΡ€ΠΎΡˆΠ΅Π³ΠΎ ΠΊΠΎΠ΄Π°. НуТно ΡΡ‚Ρ€Π΅ΠΌΠΈΡ‚ΡŒΡΡ Ρ€Π΅Π°Π»ΠΈΠ·ΠΎΠ²Ρ‹Π²Π°Ρ‚ΡŒ максимум абстракций Π½Π°Π΄ Π½ΠΈΠ·ΠΊΠΎΡƒΡ€ΠΎΠ²Π½Π΅Π²Ρ‹ΠΌΠΈ опСрациями.

ЧистыС Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ

Чистая функция β€” это такая функция, которая всСгда Π²Π΅Π΄Π΅Ρ‚ сСбя прСдсказуСмо ΠΈ Π½Π΅ влияСт Π½Π° внСшнСС ΠΎΠΊΡ€ΡƒΠΆΠ΅Π½ΠΈΠ΅.

ΠžΡΠ½ΠΎΠ²Π½Ρ‹Π΅ ΠΏΡ€ΠΈΠ·Π½Π°ΠΊΠΈ чистых Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΉ:

  • Π΄Π΅Ρ‚Π΅Ρ€ΠΌΠΈΠ½ΠΈΡ€ΠΎΠ²Π°Π½Π½ΠΎΡΡ‚ΡŒ - ΠΏΡ€ΠΈ ΠΎΠ΄Π½ΠΈΡ… ΠΈ Ρ‚Π΅Ρ… ΠΆΠ΅ Π²Ρ…ΠΎΠ΄Π½Ρ‹Ρ… Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚Π°Ρ… всСгда Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ ΠΎΠ΄ΠΈΠ½ ΠΈ Ρ‚ΠΎΡ‚ ΠΆΠ΅ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚
  • отсутствиС сайд-эффСктов - Π½Π΅ измСняСт внСшниС ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Π΅, Π½Π΅ Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚ с ΡΠ΅Ρ‚ΡŒΡŽ/Ρ„Π°ΠΉΠ»Π°ΠΌΠΈ, Π½Π΅ ΠΏΠΈΡˆΠ΅Ρ‚ Π² консоль, Π½Π΅ влияСт Π½Π° состояниС Π²Π½Π΅ самой Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ
  • Π½Π΅ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ ΠΈ Π½Π΅ измСняСт состояния Π²Π½Π΅ своих Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚ΠΎΠ² - Π½Π΅ опираСтся Π½Π° Π³Π»ΠΎΠ±Π°Π»ΡŒΠ½Ρ‹Π΅ ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Π΅, Π½Π΅ ΠΌΡƒΡ‚ΠΈΡ€ΡƒΠ΅Ρ‚ ΠΈΡ…

Π­Ρ‚ΠΈ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ ΠΏΡ€ΠΈ ΠΎΠ΄Π½ΠΈΡ… ΠΈ Ρ‚Π΅Ρ… ΠΆΠ΅ значСниях всСгда Π±ΡƒΠ΄ΡƒΡ‚ Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Ρ‚ΡŒ ΠΎΠ΄ΠΈΠ½Π°ΠΊΠΎΠ²Ρ‹ΠΉ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚

function add(a, b) {
	return a + b;
}
 
function multiplyBy2(arr) {
	return arr.map(x => x * 2);
}
 
function isEven(n) {
	return n % 2 === 0;
}

А ΡƒΠΆΠ΅ эта функция зависит ΠΎΡ‚ внСшнСго состояния ΠΈ Π½Π΅ являСтся чистой

let counter = 0;
 
function increment() {
	counter += 1;
	return counter;
}

Π˜ΠΌΠΌΡƒΡ‚Π°Π±Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΡŒ

Π˜ΠΌΠΌΡƒΡ‚Π°Π±Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΡŒΒ (Π½Π΅ΠΈΠ·ΠΌΠ΅Π½ΡΠ΅ΠΌΠΎΡΡ‚ΡŒ) β€” концСпция, согласно ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΉ Π΄Π°Π½Π½Ρ‹Π΅ послС создания Π½Π΅ ΠΈΠ·ΠΌΠ΅Π½ΡΡŽΡ‚ΡΡ.

ВмСсто измСнСния ΠΎΡ€ΠΈΠ³ΠΈΠ½Π°Π»ΡŒΠ½ΠΎΠ³ΠΎ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π° создаСтся Π΅Π³ΠΎ новая копия с Π½ΡƒΠΆΠ½Ρ‹ΠΌΠΈ измСнСниями.

ΠŸΡ€Π΅ΠΈΠΌΡƒΡ‰Π΅ΡΡ‚Π²Π° Ρ‚Π°ΠΊΠΎΠ³ΠΎ ΠΏΠΎΠ΄Ρ…ΠΎΠ΄Π°:

  • ΠŸΡ€Π΅Π΄ΡΠΊΠ°Π·ΡƒΠ΅ΠΌΠΎΡΡ‚ΡŒ -Β Π½Π΅Ρ‚ скрытых ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠΉ Π² Π΄Ρ€ΡƒΠ³ΠΈΡ… частях ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹
  • Π£ΠΏΡ€ΠΎΡ‰Π°Π΅Ρ‚ ΠΎΡ‚Π»Π°Π΄ΠΊΡƒ ΠΈ тСстированиС
  • Π›Π΅Π³Ρ‡Π΅ Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ с историСй ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠΉ (Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, undo)

ΠŸΡ€ΠΎΠ±Π»Π΅ΠΌΡ‹ ΠΌΡƒΡ‚Π°Π±Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ:

  • Π΄Π°Π½Π½Ρ‹Π΅ Π±ΡƒΠ΄ΡƒΡ‚ нСсогласованными Π² Ρ€Π°Π·Π½Ρ‹Ρ… мСстах ΠΊΠΎΠ΄Π°
  • Π±ΡƒΠ΄ΡƒΡ‚ ΠΏΡ€ΠΎΠΈΡΡ…ΠΎΠ΄ΠΈΡ‚ΡŒ нСявныС ΠΏΠΎΠ±ΠΎΡ‡Π½Ρ‹Π΅ эффСкты
  • услоТнится Π΄Π΅Π±Π°Π³ ΠΈ тСстированиС ΠΊΠΎΠ΄Π°

ΠŸΡ€ΠΈΠΌΠ΅Ρ€Ρ‹

Если Π½Π°ΠΌ Π½ΡƒΠΆΠ½ΠΎ ΠΈΠ·ΠΌΠ΅Π½ΠΈΡ‚ΡŒ массив ΠΏΠΎ своим критСриям, Ρ‚ΠΎ Π»ΡƒΡ‡ΡˆΠΈΠΌ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚ΠΎΠΌ Π±ΡƒΠ΄Π΅Ρ‚ ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ Π½ΠΎΠ²Ρ‹ΠΉ массив

const arr = [1, 2, 3];
const plusOne = arr.map(x => x + 1); // [2, 3, 4], arr нС измСнился

Если Π½Π°ΠΌ Π½ΡƒΠΆΠ½ΠΎ Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ Π² массив, Ρ‚ΠΎ Ρ‚Π°ΠΊ ΠΆΠ΅ Π»ΡƒΡ‡ΡˆΠΈΠΌ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚ΠΎΠΌ Π±ΡƒΠ΄Π΅Ρ‚ ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ копию ΠΏΡ€ΠΎΡˆΠ»ΠΎΠ³ΠΎ ΠΈ Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ ΡƒΠΆΠ΅ Π² Π½Π΅Π³ΠΎ Π½ΠΎΠ²ΠΎΠ΅ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅

const arr = [1, 2, 3];
arr.push(4); // arr Ρ‚Π΅ΠΏΠ΅Ρ€ΡŒ [1, 2, 3, 4] β€” ΠΎΡ€ΠΈΠ³ΠΈΠ½Π°Π»ΡŒΠ½Ρ‹ΠΉ массив измСнился!
 
const arr = [1, 2, 3];
const newArr = [...arr, 4]; // arr остался ΠΏΡ€Π΅ΠΆΠ½ΠΈΠΌ, newArr β€” [1, 2, 3, 4]

ΠŸΡ€ΠΎΠ±Π»Π΅ΠΌΡ‹

Π’ JS ΠΌΡ‹ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ ссылки Π½Π° ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Ρ‹ ΠΈ массивы, поэтому ΠΏΡ€ΠΈ ΠΎΠ±Ρ€Π°Ρ‰Π΅Π½ΠΈΠΈ ΠΊ Π½ΠΈΠΌ, ΠΌΡ‹ воздСйствуСм с ΠΊΠΎΡ€Π½Π΅Π²Ρ‹ΠΌ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠΌ, Π° Π½Π΅ с Π΅Π³ΠΎ ΠΊΠΎΠΏΠΈΠ΅ΠΉ

Опасно ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹:

  • sort
  • splice

НуТно ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ:

  • toSorted, ΠΊΠΎΠΏΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ старый массив ΠΈ ΡΠΎΡ€Ρ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ Π΅Π³ΠΎ [...arr].sort
  • immer / immutable js
  • map, filter, reduce

Π€ΡƒΠ½ΠΊΡ†ΠΈΠΈ ΠΏΠ΅Ρ€Π²ΠΎΠ³ΠΎ класса ΠΈ Π²Ρ‹ΡΡˆΠ΅Π³ΠΎ порядка

Π’ JS всё являСтся ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠΌ: массивы, Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ ΠΈ сами ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Ρ‹. ΠŸΡ€ΠΈΠΌΠΈΡ‚ΠΈΠ²Π½Ρ‹Π΅ Ρ‚ΠΈΠΏΡ‹ Π΄Π°Π½Π½Ρ‹Ρ… ΠΈΠΌΠ΅ΡŽΡ‚ Π²Ρ€Π°ΠΏΠΏΠ΅Ρ€-ΠΎΠ±ΡŠΠ΅ΠΊΡ‚, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ прСдоставляСт доступ ΠΊ ΠΌΠ΅Ρ‚ΠΎΠ΄Π°ΠΌ связанным с этим Ρ‚ΠΈΠΏΠΎΠΌ Π΄Π°Π½Π½Ρ‹Ρ….

ΠœΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ:

  1. ΠŸΠ΅Ρ€Π΅Π΄Π°Π²Π°Ρ‚ΡŒ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚Π°ΠΌΠΈ Π² Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ
  2. Π’ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Ρ‚ΡŒ Π΄Ρ€ΡƒΠ³ΡƒΡŽ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ ΠΈΠ· Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ
  3. ΠŸΡ€ΠΈΡΠ²ΠΎΠΈΡ‚ΡŒ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ Π² ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½ΡƒΡŽ

ΠœΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒΡΡ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠ΅ΠΉ, ΠΊΠ°ΠΊ ΠΎΠ±Ρ‹Ρ‡Π½Ρ‹ΠΌ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠΌ, Π½ΠΎ с Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡ‚ΡŒΡŽ Π²Ρ‹Π·Ρ‹Π²Π°Ρ‚ΡŒ Π΅Π³ΠΎ.

Π’Π°ΠΊΠΈΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ получаСтся, Ρ‡Ρ‚ΠΎ ΠΊΠΎΠ³Π΄Π° ΠΌΡ‹ Ρ€Π°Π±ΠΎΡ‚Π°Π΅ΠΌ с функциями Ρ‚Π°ΠΊΠΈΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ, Ρ‚ΠΎ ΠΎΠ½ΠΈ Π±ΡƒΠ΄ΡƒΡ‚ ΡΠ²Π»ΡΡ‚ΡŒΡΡ функциями ΠΏΠ΅Ρ€Π²ΠΎΠ³ΠΎ класса

Π€ΡƒΠ½ΠΊΡ†ΠΈΠΈ Π²Ρ‹ΡΡˆΠ΅Π³ΠΎ порядка - это Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΊΠ°ΠΊΠΈΠΌ-Π»ΠΈΠ±ΠΎ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ Ρ€Π°Π±ΠΎΡ‚Π°ΡŽΡ‚ с Π΄Ρ€ΡƒΠ³ΠΈΠΌΠΈ функциями:

  • ΠΏΡ€ΠΈΠ½ΠΈΠΌΠ°ΡŽΡ‚ ΠΈΡ… Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚ΠΎΠΌ
  • Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°ΡŽΡ‚ Π΄Ρ€ΡƒΠ³ΡƒΡŽ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ

ΠŸΡ€ΠΈΠΌΠ΅Ρ€Ρ‹: map, reduce, filter, замыкания, мСмоизация, debounce/throttle


ЧастныС случаи

ΠšΠΎΠΌΠΏΠΎΠ·ΠΈΡ†ΠΈΡ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΉ

ΠšΠΎΠΌΠΏΠΎΠ·ΠΈΡ†ΠΈΡ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΉ β€” это ΠΏΡ€ΠΈΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ ΠΎΠ΄Π½ΠΎΠΉ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ ΠΊ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Ρƒ Π΄Ρ€ΡƒΠ³ΠΎΠΉ, Π² Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Π΅ Ρ‡Π΅Π³ΠΎ создаётся новая функция

ΠšΠΎΠΌΠΏΠΎΠ·ΠΈΡ†ΠΈΡ Π½Π°ΠΌ Π½ΡƒΠΆΠ½Ρ‹ для поддСрТания дСкларативности систСмы

Π’ ΠΎΠ±Ρ‹Ρ‡Π½ΠΎΠΉ ΠΆΠΈΠ·Π½ΠΈ, ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ ΠΏΡ€ΠΈΠΌΠ΅Π½ΡΡ‚ΡŒ Π΄Π΅Ρ„ΠΎΠ»Ρ‚Π½ΠΎ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ ΠΏΠΎΡΠ»Π΅Π΄ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎ Π΄Ρ€ΡƒΠ³ Π·Π° Π΄Ρ€ΡƒΠ³ΠΎΠΌ

fn1(fn2(fn3(fn4('hello'))));

Но Ρ‚Π°ΠΊΠΎΠΉ ΠΏΠΎΠ΄Ρ…ΠΎΠ΄ Π±ΡƒΠ΄Π΅Ρ‚ ΠΊΡ€Π°ΠΉΠ½Π΅ Π½Π΅ΡƒΠ΄ΠΎΠ±Π½Ρ‹ΠΌ.

Для Ρ€Π΅ΡˆΠ΅Π½ΠΈΡ этой ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΡ‹ со скрытиСм ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΉ, сущСствуСт функция compose, которая позволяСт ΠΏΠΎΡΠ»Π΅Π΄ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎ Π²Ρ‹ΠΏΠΎΠ»Π½ΡΡ‚ΡŒ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ ΠΈ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚

// функция-ΠΊΠΎΠΌΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€
const compose = (...funcs) => (initialValue) =>
  funcs.reduceRight((acc, fn) => fn(acc), initialValue);
 
// ΠΏΡ€ΠΈΠΌΠ΅Ρ€
const upperCase = str => str.toUpperCase();
const exclaim = str => str + '!';
const repeat = str => `${str} `.repeat(2);
 
const getResult = compose(repeat, exclaim, upperCase);
 
console.log(getResult('hello')); // HELLO! HELLO! 

Π’Π°ΠΊΠΎΠΉ ΠΏΠΎΠ΄Ρ…ΠΎΠ΄ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ Π² Π΄Π΅ΠΊΠΎΡ€Π°Ρ‚ΠΎΡ€Π°Ρ…

ΠšΠΎΠ½Π²Π΅ΠΉΠ΅Ρ€

Ѐункция-ΠΊΠΎΠ½Π²Π΅ΠΉΠ΅Ρ€ (pipe) β€” это Π°Π½Π°Π»ΠΎΠ³ ΠΊΠΎΠΌΠΏΠΎΠ·ΠΈΡ†ΠΈΠΈ, Π½ΠΎ ΠΎΠ½Π° выполняСт Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ слСва Π½Π°ΠΏΡ€Π°Π²ΠΎ: Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ ΠΏΠ΅Ρ€Π²ΠΎΠΉ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ пСрСдаётся Π²Ρ‚ΠΎΡ€ΠΎΠΉ, Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ Π²Ρ‚ΠΎΡ€ΠΎΠΉ Π² Ρ‚Ρ€Π΅Ρ‚ΡŒΡŽ ΠΈ Ρ‚Π°ΠΊ Π΄Π°Π»Π΅Π΅.

const pipe = 
	(...functions) => 
	(x) => functions.reduce((value, func) => func(value), x);

ΠŸΠ΅Ρ€Π΅Π΄Π°Π½Π½Ρ‹Π΅ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ Π±ΡƒΠ΄ΡƒΡ‚ Π²Ρ‹Π·Ρ‹Π²Π°Ρ‚ΡŒΡΡ ΠΏΠΎΡΠ»Π΅Π΄ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎ

const double = x => x * 2;
const increment = x => x + 1;
const square = x => x * x;
 
const getResult = pipe(double, increment, square); 
 
console.log(getResult(3)); // ((3 * 2) + 1) ^ 2 = 49

ЧастичноС ΠΏΡ€ΠΈΠΌΠ΅Π½Π΅Π½ΠΈΠ΅

ЧастичноС ΠΏΡ€ΠΈΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ β€” это Ρ‚Π΅Ρ…Π½ΠΈΠΊΠ°, ΠΏΠΎΠ·Π²ΠΎΠ»ΡΡŽΡ‰Π°Ρ Ρ„ΠΈΠΊΡΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ Ρ‡Π°ΡΡ‚ΡŒ Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚ΠΎΠ² Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ ΠΈ ΡΠΎΠ·Π΄Π°Π²Π°Ρ‚ΡŒ Π½ΠΎΠ²ΡƒΡŽ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ, которая ΠΎΠΆΠΈΠ΄Π°Π΅Ρ‚ ΠΎΡΡ‚Π°Π²ΡˆΠΈΠ΅ΡΡ Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚Ρ‹.

Π’Π°ΠΊΠΎΠΉ ΠΏΠΎΠ΄Ρ…ΠΎΠ΄ ΠΏΠΎΠ·Π²ΠΎΠ»ΠΈΡ‚ Π½Π°ΠΌ Π½Π΅ ΠΈΡΠΊΠ°Ρ‚ΡŒ, Π½Π΅ ΠΈΠΌΠΏΠΎΡ€Ρ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ ΠΈ Π½Π΅ ΠΏΠ΅Ρ€Π΅ΠΏΠΈΡΡ‹Π²Π°Ρ‚ΡŒ Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚Ρ‹ Π·Π°Π½ΠΎΠ²ΠΎ ΠΏΡ€ΠΈ ΠΊΠ°ΠΆΠ΄ΠΎΠΌ Π²Ρ‹Π·ΠΎΠ²Π΅ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ. Π’ΡƒΡ‚ ΠΌΡ‹ скрываСм ΠΎΠΏΡ€Π΅Π΄Π΅Π»Ρ‘Π½Π½ΡƒΡŽ Ρ‡Π°ΡΡ‚ΡŒ повторяСмых Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚ΠΎΠ²

Π˜ΡΡ…ΠΎΠ΄Π½Π°Ρ функция

const userHasRole = (user, role) => user.roles.includes(role);
 
const operator = { name: 'Анна', roles: ['USER', 'ADMIN'] };
userHasRole(operator, 'ADMIN'); // true

ЀиксируСм ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ

const clientHasRole = role => userHasRole(operator, role);
 
clientHasRole('ADMIN'); // true
clientHasRole('USER');  // true
clientHasRole('MANAGER'); // false

Но Ρ‚Π°ΠΊ ΠΆΠ΅ ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ Ρ„ΠΈΠΊΡΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚Ρ‹ Ρ‡Π΅Ρ€Π΅Π· bind, Ρ‡Ρ‚ΠΎ являСтся Π±ΠΎΠ»Π΅Π΅ Π½Π°Ρ‚ΠΈΠ²Π½ΠΎΠΉ Ρ€Π΅Π°Π»ΠΈΠ·Π°Ρ†ΠΈΠ΅ΠΉ

const clientHasRole = userHasRole.bind(null, operator);
 
console.log(clientHasRole('ADMIN'));   // true
console.log(clientHasRole('USER'));    // true
console.log(clientHasRole('MANAGER')); // false

ЀиксируСм ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ ΠΈ Ρ€ΠΎΠ»ΡŒ

const isClientAdmin = () => clientHasRole('ADMIN');
 
isClientAdmin(); // true

Π’ ΠΈΡ‚ΠΎΠ³Π΅, ΠΌΡ‹ сократили ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΡŽ с Π΄Π²ΡƒΡ… Π΄ΠΎ нуля Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚ΠΎΠ²

userHasRole(operator, 'ADMIN');
// >
clientHasRole('ADMIN');
// >
isClientAdmin();

ΠšΠ°Ρ€Ρ€ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅

ΠšΠ°Ρ€Ρ€ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅Β β€” это ΠΏΡ€Π΅ΠΎΠ±Ρ€Π°Π·ΠΎΠ²Π°Π½ΠΈΠ΅ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ с нСсколькими Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚Π°ΠΌΠΈ Π² ΠΏΠΎΡΠ»Π΅Π΄ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΡŒ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΉ, каТдая ΠΈΠ· ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Ρ… ΠΏΡ€ΠΈΠ½ΠΈΠΌΠ°Π΅Ρ‚ свои Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚Ρ‹

const userHasRoleCurried = user => role => user.roles.includes(role);
const operator = { name: 'Анна', roles: ['USER', 'ADMIN'] };
 
const clientHasRole = userHasRoleCurried(operator);
 
console.log(clientHasRole('ADMIN')); // true
console.log(clientHasRole('MANAGER')); // false

ΠšΠ°Ρ€Ρ€ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ часто ΠΌΠΎΠΆΠ΅Ρ‚ ΠΏΡ€ΠΈΠ³ΠΎΠ΄ΠΈΡ‚ΡŒΡΡ, ΠΊΠΎΠ³Π΄Π° Π½Π°ΠΌ Π½ΡƒΠΆΠ½ΠΎ ΠΎΠ±Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°Ρ‚ΡŒ ΠΏΠΎΡΡ‚ΡƒΠΏΠΈΠ²ΡˆΠΈΠ΅ Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚Ρ‹ ΠΈ ΠΏΠ΅Ρ€Π΅Π΄Π°Π²Π°Ρ‚ΡŒ ΠΈΡ… Π² ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΡƒΡŽ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ. Π­Ρ‚ΠΎ Ρ‚Π°ΠΊ ΠΆΠ΅ ΠΏΠΎΠΌΠΎΠ³Π°Π΅Ρ‚ ΡΠΎΡ…Ρ€Π°Π½ΡΡ‚ΡŒ Π΄Π΅ΠΊΠ»Π°Ρ€Π°Ρ‚ΠΈΠ²Π½ΠΎΡΡ‚ΡŒ ΠΊΠΎΠ΄Π° Π·Π° счёт Π±ΠΎΠ»Π΅Π΅ простого создания ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ΄Π½Ρ‹Ρ… Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΉ

АвтокаррированиС

Π’Π°ΠΊ ΠΆΠ΅ ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ, которая Π±ΡƒΠ΄Π΅Ρ‚ сама Ρ€Π΅Π°Π»ΠΈΠ·ΠΎΠ²Ρ‹Π²Π°Ρ‚ΡŒ ΠΊΠ°Ρ€Ρ€ΠΈΡ€ΠΎΠ²Π°Π½Π½Ρ‹Π΅ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ

function curry(fn) {
  return function curried(...args) {
    // Если ΠΏΠ΅Ρ€Π΅Π΄Π°Π½ΠΎ достаточно Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚ΠΎΠ² β€” Π²Ρ‹Π·Ρ‹Π²Π°Π΅ΠΌ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ
    if (args.length >= fn.length) {
      return fn.apply(this, args);
    } else {
      // Π˜Π½Π°Ρ‡Π΅ Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅ΠΌ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ, ΠΎΠΆΠΈΠ΄Π°ΡŽΡ‰ΡƒΡŽ ΠΎΡΡ‚Π°Π²ΡˆΠΈΠ΅ΡΡ Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚Ρ‹
      return function (...nextArgs) {
        return curried.apply(this, args.concat(nextArgs));
      };
    }
  };
}

РСализация каррирования с этой Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠ΅ΠΉ-ΠΎΠ±Ρ‘Ρ€Ρ‚ΠΊΠΎΠΉ

const curriedUserHasRole = curry(userHasRole);
 
const operator = { name: 'Анна', roles: ['USER', 'ADMIN'] };
 
const clientHasRole = curriedUserHasRole(operator);
console.log(clientHasRole('ADMIN'));    // true
console.log(clientHasRole('MANAGER'));  // false
 
// ΠΈΠ»ΠΈ Ρ‚Π°ΠΊ:
console.log(curriedUserHasRole(operator, 'USER')); // true

Chaining

ChainingΒ β€” это ΠΏΠΎΡΠ»Π΅Π΄ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎΠ΅ Π²Ρ‹Π·ΠΎΠ²Ρ‹ ΠΌΠ΅Ρ‚ΠΎΠ΄ΠΎΠ² ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π° (Ρ†Π΅ΠΏΠΎΡ‡ΠΊΠ° Π²Ρ‹Π·ΠΎΠ²ΠΎΠ²), ΠΏΡ€ΠΈ ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΉ ΠΊΠ°ΠΆΠ΄Ρ‹ΠΉ ΠΌΠ΅Ρ‚ΠΎΠ΄ Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚, ΠΏΠΎΠ·Π²ΠΎΠ»ΡΡŽΡ‰ΠΈΠΉ ΠΏΡ€ΠΎΠ΄ΠΎΠ»ΠΆΠΈΡ‚ΡŒ Ρ†Π΅ΠΏΠΎΡ‡ΠΊΡƒ

const result = new Array(10)
  .fill(1)           // [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
  .map((x, i) => x + i) // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
  .filter(x => x % 2 === 0) // [2, 4, 6, 8, 10]
  .join(', ');          // "2, 4, 6, 8, 10"
 
console.log(result); // "2, 4, 6, 8, 10"
fetch('https://jsonplaceholder.typicode.com/users/1')
  .then(response => response.json())
  .then(data => data.name)
  .then(name => name.toUpperCase())
  .then(console.log) // Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€: "LEANNE GRAHAM"
  .catch(console.error);

Π’ Ρ‚Π°ΠΊΠΎΠΌ случаС, функция Π΄ΠΎΠ»ΠΆΠ½Π° ΠΊΠ°ΠΆΠ΄Ρ‹ΠΉ Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Ρ‚ΡŒ this ΠΈΠ»ΠΈ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ смоТСт ΠΏΡ€ΠΎΠ΄ΠΎΠ»ΠΆΠΈΡ‚ΡŒ Ρ‡Π΅ΠΉΠ½

ΠšΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€Ρ‹

ΠšΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€Β β€” это ΠΎΠ±ΡŠΠ΅ΠΊΡ‚-ΠΎΠ±Ρ‘Ρ€Ρ‚ΠΊΠ°, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ β€œΠΎΠ±Π΅ΡΠΏΠ΅Ρ‡ΠΈΠ²Π°Π΅Ρ‚β€ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ ΠΈ позволяСт бСзопасно ΠΈ Π΄Π΅ΠΊΠ»Π°Ρ€Π°Ρ‚ΠΈΠ²Π½ΠΎ Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ с Π½ΠΈΠΌ Ρ‡Π΅Ρ€Π΅Π· ΡΠΏΠ΅Ρ†ΠΈΠ°Π»ΡŒΠ½Ρ‹Π΅ ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹ (Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, map, flatMap)

class Box<T> {
  // ΠŸΡ€ΠΈΠ²Π°Ρ‚Π½ΠΎΠ΅ свойство с Ρ‚ΠΈΠΏΠΎΠΌ T
  private value: T;
 
  // ΠŸΡ€ΠΈΠ²Π°Ρ‚Π½Ρ‹ΠΉ конструктор
  private constructor(value: T) {
    this.value = value;
  }
 
  // БтатичСский Ρ„Π°Π±Ρ€ΠΈΡ‡Π½Ρ‹ΠΉ ΠΌΠ΅Ρ‚ΠΎΠ΄
  static of<T>(value: T): Box<T> {
    return new Box(value);
  }
 
  // map с Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π΅Π½ΠΈΠ΅ΠΌ Π½ΠΎΠ²ΠΎΠ³ΠΎ ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€Π°
  map<U>(fn: (x: T) => U): Box<U> {
    return Box.of(fn(this.value));
  }
 
  // fold для раскрытия значСния
  fold<U>(fn: (x: T) => U): U {
    return fn(this.value);
  }
}
 
// ΠŸΡ€ΠΈΠΌΠ΅Ρ€ использования:
const result = Box
  .of(10)
  .map(x => x + 5)
  .map(x => x * 2)
  .fold(x => `Π Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚: ${x}`);
 
console.log(result); // 'Π Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚: 30'

Π­Ρ‚ΠΎ позволяСт Π½Π°ΠΌ ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ ΠΈΠΌΠΌΡƒΡ‚Π°Π±Π΅Π»ΡŒΠ½Ρ‹ΠΌ ΠΈ ΠΈΠ·ΠΌΠ΅Π½ΡΡ‚ΡŒ Π΅Π³ΠΎ Π΄Π΅ΠΊΠ»Π°Ρ€Π°Ρ‚ΠΈΠ²Π½ΠΎ Ρ‡Π΅Ρ€Π΅Π· доступныС ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹.

Π’Π°ΠΊΠΎΠΉ ΠΏΠΎΠ΄Ρ…ΠΎΠ΄ Ρ€Π΅Π°Π»ΠΈΠ·ΡƒΠ΅ΠΌ Ρ‚Π°ΠΊ ΠΆΠ΅ ΠΈ Ρ‡Π΅Ρ€Π΅Π· ΠΏΡ€ΠΎΡ‚ΠΎΡ‚ΠΈΠΏΡ‹, Π½ΠΎ ΠΏΡ€ΠΎΡ‰Π΅ ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ Ρ‡Π΅Ρ€Π΅Π· классы.

Π’Π°ΠΊ ΠΆΠ΅ ΠΌΡ‹ избавляСмся ΠΎΡ‚ Π»ΡƒΠΊΠΎΠ²ΠΈΡ†Ρ‹ Π²Ρ‹Π·ΠΎΠ²ΠΎΠ² Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΉ fn1(fn2(fn3(val)))

Π€ΡƒΠ½ΠΊΡ‚ΠΎΡ€Ρ‹

Π€ΡƒΠ½ΠΊΡ‚ΠΎΡ€Β β€” это структура-ΠΎΠ±Ρ‘Ρ€Ρ‚ΠΊΠ°, Ρƒ ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΉ Π΅ΡΡ‚ΡŒ ΠΌΠ΅Ρ‚ΠΎΠ΄Β map(fn), ΠΏΠΎΠ·Π²ΠΎΠ»ΡΡŽΡ‰ΠΈΠΉ ΠΏΡ€ΠΈΠΌΠ΅Π½ΠΈΡ‚ΡŒ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ ΠΊ Ρ…Ρ€Π°Π½ΠΈΠΌΠΎΠΌΡƒ Π·Π½Π°Ρ‡Π΅Π½ΠΈΡŽ ΠΈ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ Π½ΠΎΠ²ΡƒΡŽ ΠΎΠ±Ρ‘Ρ€Ρ‚ΠΊΡƒ Ρ‚Π°ΠΊΠΎΠ³ΠΎ ΠΆΠ΅ Ρ‚ΠΈΠΏΠ°.

// Π€ΡƒΠ½ΠΊΡ‚ΠΎΡ€: map Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ Π½ΠΎΠ²Ρ‹ΠΉ Box с Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ΠΎΠΌ fn(value)
const result = Box.of(2).map(x => x + 3).map(x => x * 10); // Box(50)

Π€ΡƒΠ½ΠΊΡ‚ΠΎΡ€ Π³Π°Ρ€Π°Π½Ρ‚ΠΈΡ€ΡƒΠ΅Ρ‚ сохранСниС структуры ΠΈ позволяСт бСзопасно β€œΡ‚Ρ€Π°Π½ΡΠ»ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒβ€ Π²Π½ΡƒΡ‚Ρ€ΠΈ Π½Π΅Ρ‘ значСния с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽΒ map, Ρ‡Ρ‚ΠΎ ΠΎΠ±Ρ‹Ρ‡Π½ΠΎ называСтся: Π·Π°ΠΊΠΎΠ½ΠΎΠΌ ΠΊΠΎΠΌΠΏΠΎΠ·ΠΈΡ†ΠΈΠΈ ΠΈ Π·Π°ΠΊΠΎΠ½ΠΎΠΌ идСнтичности.

Π€ΡƒΠ½ΠΊΡ‚ΠΎΡ€Π°ΠΌΠΈ Π² JS ΠΌΠΎΠΆΠ½ΠΎ Π½Π°Π·Π²Π°Ρ‚ΡŒ:

  • Array
  • Promise

АппликативныС Ρ„ΡƒΠ½ΠΊΡ‚ΠΎΡ€Ρ‹

Аппликативный Ρ„ΡƒΠ½ΠΊΡ‚ΠΎΡ€Β β€” Ρ€Π°ΡΡˆΠΈΡ€ΡΠ΅Ρ‚ идСю Ρ„ΡƒΠ½ΠΊΡ‚ΠΎΡ€Π°: Π² Π½Ρ‘ΠΌ ΠΌΠΎΠΆΠ½ΠΎ Ρ…Ρ€Π°Π½ΠΈΡ‚ΡŒ Π½Π΅ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ значСния, Π½ΠΎ ΠΈ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ, ΠΈ ΠΏΡ€ΠΈΠΌΠ΅Π½ΡΡ‚ΡŒ ΠΈΡ… ΠΊ значСниям Π²Π½ΡƒΡ‚Ρ€ΠΈ Π΄Ρ€ΡƒΠ³ΠΈΡ… ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€ΠΎΠ² с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ ΠΌΠ΅Ρ‚ΠΎΠ΄Π° Π½Π°ΠΏΠΎΠ΄ΠΎΠ±ΠΈΠ΅Β apΒ (apply).

class Box<T> {
  // ...
  ap<U>(b: Box<(x: T) => U>): Box<U> {
    return b.map(fn => fn(this.value));
  }
}
 
// 1 - box ΠΎΡ‚ value
const valueBox = Box.of(5);
// box ΠΎΡ‚ func
const fnBox = Box.of((n: number) => n * 3);
// примСняСт Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ
const result2 = valueBox.ap(fnBox); // Box(15)

Если map Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚ с функциями, Ρ‚ΠΎ ap Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚ с Π΄Ρ€ΡƒΠ³ΠΈΠΌΠΈ ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€Π°ΠΌΠΈ

ΠœΠΎΠ½Π°Π΄Ρ‹

ΠœΠΎΠ½Π°Π΄Π°Β β€” это структура, Π² ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΉ Π΅ΡΡ‚ΡŒ ΠΌΠ΅Ρ‚ΠΎΠ΄Β flatMapΒ (ΠΈΠ»ΠΈΒ chain, ΠΈΠ½ΠΎΠ³Π΄Π° Π½Π°Π·Ρ‹Π²Π°ΡŽΡ‚Β bind): Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΎΠ½ позволяСт β€œΡ€Π°Π·Π²ΠΎΡ€Π°Ρ‡ΠΈΠ²Π°Ρ‚ΡŒβ€ Π²Π»ΠΎΠΆΠ΅Π½Π½Ρ‹Π΅ ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€Ρ‹. Π’ΠΎ Π΅ΡΡ‚ΡŒ Π²Π½ΡƒΡ‚Ρ€ΠΈΒ mapΒ ΠΌΡ‹ ΠΏΠΎΠ»ΡƒΡ‡Π°Π΅ΠΌ Π½Π΅ просто Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅, Π° Ρ†Π΅Π»Ρ‹ΠΉ Π½ΠΎΠ²Ρ‹ΠΉ ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€ - ΠΈ этот ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€ Π½Π΅ Π±ΡƒΠ΄Π΅Ρ‚ Π²ΠΊΠ»Π°Π΄Ρ‹Π²Π°Ρ‚ΡŒΡΡ Π΄Ρ€ΡƒΠ³ Π² Π΄Ρ€ΡƒΠ³Π° бСсконСчно, Π° Π°ΠΊΠΊΡƒΡ€Π°Ρ‚Π½ΠΎ свёрнут ΠΎΠ±Ρ€Π°Ρ‚Π½ΠΎ Π² ΠΎΠ΄ΠΈΠ½ слой.

class Box<T> {
  // ..
  flatMap<U>(fn: (x: T) => Box<U>): Box<U> {
    return fn(this.value);
  }
}
 
const result3 = Box.of(8)
  .flatMap(x => Box.of(x * 2))      // Box(16)
  .flatMap(x => Box.of(`box:${x}`)); // Box('box:16')
  • ОсновноС ΠΎΡ‚Π»ΠΈΡ‡ΠΈΠ΅ ΠΎΡ‚Β map: Π²Π½ΡƒΡ‚Ρ€ΠΈΒ flatMap функция Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ ΡƒΠΆΠ΅ Box, Π° Π½Π΅ просто Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅, ΠΈ ΠΎΠ±Ρ‘Ρ€Ρ‚Ρ‹Π²Π°Π½ΠΈΠ΅ Π½Π΅ происходит ΠΏΠΎΠ²Ρ‚ΠΎΡ€Π½ΠΎ.
  • ΠœΠΎΠ½Π°Π΄Ρ‹ ΠΎΡ‡Π΅Π½ΡŒ ΡƒΠ΄ΠΎΠ±Π½Ρ‹ для построСния β€œΡ†Π΅ΠΏΠΎΡ‡Π΅ΠΊβ€ асинхронных, ΠΏΠΎΠ±ΠΎΡ‡Π½Ρ‹Ρ… ΠΈΠ»ΠΈ условных вычислСний Π±Π΅Π· Π²Π»ΠΎΠΆΠ΅Π½Π½Ρ‹Ρ… структур.

Π€ΡƒΠ½ΠΊΡ‚ΠΎΡ€Ρ‹ - это интСрфСйс Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ, Π° ΠΌΠΎΠ½Π°Π΄Ρ‹ - это рСализация интСрфСйса Ρ„ΡƒΠ½ΠΊΡ‚ΠΎΡ€ΠΎΠ²


БпСцификация Fantasy Land

Fantasy LandΒ β€” это спСцификация для алгСбраичСских структур Π² JS, которая описываСт Π½Π°Π±ΠΎΡ€ абстракций ΠΈ Ρ‚Ρ€Π΅Π±ΠΎΠ²Π°Π½ΠΈΠΉ ΠΊ Π½ΠΈΠΌ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Ρ€Π°Π·Π½Ρ‹Π΅ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ ΠΌΠΎΠ³Π»ΠΈ Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ совмСстно.

Π’ΠΎΡ‚ ΠΊΡ€Π°Ρ‚ΠΊΠΈΠΉ список основных сущностСй Fantasy Land ΠΈ ΠΈΡ… ΠΊΠ»ΡŽΡ‡Π΅Π²Ρ‹Π΅ ΠΈΠ΄Π΅ΠΈ:

  • Setoid
    • equals (fantasy-land/equals): опрСдСляСт ΡΠΊΠ²ΠΈΠ²Π°Π»Π΅Π½Ρ‚Π½ΠΎΡΡ‚ΡŒ; Π·Π°ΠΊΠΎΠ½Ρ‹ рСфлСксивности, симмСтрии, транзитивности.
    • Ord (Ρ‚Ρ€Π΅Π±ΡƒΠ΅Ρ‚ Setoid)
      • lte (fantasy-land/lte): Ρ‚ΠΎΡ‚Π°Π»ΡŒΠ½Ρ‹ΠΉ порядок; антисиммСтрия, Ρ‚Ρ€Π°Π½Π·ΠΈΡ‚ΠΈΠ²Π½ΠΎΡΡ‚ΡŒ.
  • Semigroup
    • concat (fantasy-land/concat): ассоциативноС объСдинСниС Π·Π½Π°Ρ‡Π΅Π½ΠΈΠΉ ΠΎΠ΄Π½ΠΎΠ³ΠΎ Ρ‚ΠΈΠΏΠ°.
    • Monoid (Ρ‚Ρ€Π΅Π±ΡƒΠ΅Ρ‚ Semigroup)
      • empty (fantasy-land/empty): Π½Π΅ΠΉΡ‚Ρ€Π°Π»ΡŒΠ½Ρ‹ΠΉ элСмСнт; Π»Π΅Π²Ρ‹Π΅/ΠΏΡ€Π°Π²Ρ‹Π΅ Π΅Π΄ΠΈΠ½ΠΈΡ†Ρ‹.
      • Group (Ρ‚Ρ€Π΅Π±ΡƒΠ΅Ρ‚ Monoid)
        • invert (fantasy-land/invert): ΠΎΠ±Ρ€Π°Ρ‚Π½Ρ‹ΠΉ элСмСнт; Π»Π΅Π²Ρ‹Π΅/ΠΏΡ€Π°Π²Ρ‹Π΅ инвСрсии.
  • Semigroupoid
    • compose (fantasy-land/compose): ассоциативная композиция ΠΌΠΎΡ€Ρ„ΠΈΠ·ΠΌΠΎΠ².
    • Category (Ρ‚Ρ€Π΅Π±ΡƒΠ΅Ρ‚ Semigroupoid)
      • id (fantasy-land/id): тоТдСствСнный ΠΌΠΎΡ€Ρ„ΠΈΠ·ΠΌ; Π»Π΅Π²Ρ‹Π΅/ΠΏΡ€Π°Π²Ρ‹Π΅ Π΅Π΄ΠΈΠ½ΠΈΡ†Ρ‹.
  • Functor
    • map (fantasy-land/map): ΠΎΡ‚ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ значСния, соблюдая identity ΠΈ composition.
    • Apply (Ρ‚Ρ€Π΅Π±ΡƒΠ΅Ρ‚ Functor)
      • ap (fantasy-land/ap): ΠΏΡ€ΠΈΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ Π²Π½ΡƒΡ‚Ρ€ΠΈ ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€Π° ΠΊ Π·Π½Π°Ρ‡Π΅Π½ΠΈΡŽ Π² ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€Π΅; ΠΊΠΎΠΌΠΏΠΎΠ·ΠΈΡ†ΠΈΠΎΠ½Π½Ρ‹ΠΉ Π·Π°ΠΊΠΎΠ½.
      • Applicative (Ρ‚Ρ€Π΅Π±ΡƒΠ΅Ρ‚ Apply)
        • of (fantasy-land/of): ΠΏΠΎΠ΄ΡŠΡ‘ΠΌ значСния Π² ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€; Π·Π°ΠΊΠΎΠ½Ρ‹ identity, homomorphism, interchange.
      • Chain (Ρ‚Ρ€Π΅Π±ΡƒΠ΅Ρ‚ Apply)
        • chain (fantasy-land/chain): монадичСская связка; Π°ΡΡΠΎΡ†ΠΈΠ°Ρ‚ΠΈΠ²Π½ΠΎΡΡ‚ΡŒ.
        • ChainRec (Ρ‚Ρ€Π΅Π±ΡƒΠ΅Ρ‚ Chain)
          • chainRec (fantasy-land/chainRec): стСк-бСзопасная рСкурсия Π² Ρ‚Π΅Ρ€ΠΌΠΈΠ½Π°Ρ… Chain.
        • Monad (Ρ‚Ρ€Π΅Π±ΡƒΠ΅Ρ‚ Applicative ΠΈ Chain)
          • of (fantasy-land/of): ΠΊΠ°ΠΊ Π² Applicative.
          • chain (fantasy-land/chain): Π·Π°ΠΊΠΎΠ½Ρ‹ Π»Π΅Π²ΠΎΠΉ/ΠΏΡ€Π°Π²ΠΎΠΉ Π΅Π΄ΠΈΠ½ΠΈΡ†Ρ‹.
  • Foldable
    • reduce (fantasy-land/reduce): свёртка структуры; ΡΠΊΠ²ΠΈΠ²Π°Π»Π΅Π½Ρ‚Π½ΠΎΡΡ‚ΡŒ спСцифицированной свёрткС.
  • Traversable (Ρ‚Ρ€Π΅Π±ΡƒΠ΅Ρ‚ Functor ΠΈ Foldable)
    • traverse (fantasy-land/traverse): ΠΏΡ€ΠΎΡ…ΠΎΠ΄ со сборкой эффСктов; naturality, identity, composition.
  • Contravariant
    • contramap (fantasy-land/contramap): ΠΏΡ€Π΅ΠΎΠ±Ρ€Π°Π·ΠΎΠ²Π°Π½ΠΈΠ΅ Π²Ρ…ΠΎΠ΄Π½ΠΎΠ³ΠΎ Ρ‚ΠΈΠΏΠ°; Π·Π°ΠΊΠΎΠ½Ρ‹ identity ΠΈ composition.
  • Bifunctor (Ρ‚Ρ€Π΅Π±ΡƒΠ΅Ρ‚ Functor)
    • bimap (fantasy-land/bimap): ΠΎΡ‚ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ ΠΏΠΎ Π΄Π²ΡƒΠΌ измСрСниям; identity ΠΈ composition.
  • Profunctor (Ρ‚Ρ€Π΅Π±ΡƒΠ΅Ρ‚ Functor)
    • promap (fantasy-land/promap): ΠΊΠΎΠ½Ρ‚Ρ€Π°-/ΠΊΠΎΠ²Π°Ρ€ΠΈΠ°Π½Ρ‚Π½ΠΎΠ΅ ΠΎΡ‚ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ Π²Ρ…ΠΎΠ΄Π°/Π²Ρ‹Ρ…ΠΎΠ΄Π°; identity ΠΈ composition.
  • Alt (Ρ‚Ρ€Π΅Π±ΡƒΠ΅Ρ‚ Functor)
    • alt (fantasy-land/alt): ассоциативная Π°Π»ΡŒΡ‚Π΅Ρ€Π½Π°Ρ‚ΠΈΠ²Π°; Π΄ΠΈΡΡ‚Ρ€ΠΈΠ±ΡƒΡ‚ΠΈΠ²Π½ΠΎΡΡ‚ΡŒ ΠΎΡ‚Π½ΠΎΡΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ map.
    • Plus (Ρ‚Ρ€Π΅Π±ΡƒΠ΅Ρ‚ Alt)
      • zero (fantasy-land/zero): Π½Π΅ΠΉΡ‚Ρ€Π°Π»ΡŒΠ½Ρ‹ΠΉ «пустой» элСмСнт для alt; Π·Π°ΠΊΠΎΠ½Ρ‹ left/right identity ΠΈ annihilation.
      • Alternative (Ρ‚Ρ€Π΅Π±ΡƒΠ΅Ρ‚ Applicative ΠΈ Plus)
        • alt (fantasy-land/alt)
        • zero (fantasy-land/zero)
        • of (fantasy-land/of): Π·Π°ΠΊΠΎΠ½Ρ‹ дистрибутивности ΠΈ уничтоТСния для ap с zero.
  • Extend (Ρ‚Ρ€Π΅Π±ΡƒΠ΅Ρ‚ Functor)
    • extend (fantasy-land/extend): построСниС значСния ΠΈΠ· ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€Π°; Π·Π°ΠΊΠΎΠ½ ΠΊΠ²Π°Π·ΠΈΠΌΠΎΠ½Π°Π΄Π½ΠΎΠΉ ассоциативности.
    • Comonad (Ρ‚Ρ€Π΅Π±ΡƒΠ΅Ρ‚ Extend)
      • extract (fantasy-land/extract): ΠΈΠ·Π²Π»Π΅Ρ‡Π΅Π½ΠΈΠ΅ значСния; Π»Π΅Π²Ρ‹Π΅/ΠΏΡ€Π°Π²Ρ‹Π΅ Π΅Π΄ΠΈΠ½ΠΈΡ†Ρ‹ для extend/extract.

Π˜Ρ‚ΠΎΠ³ΠΈ

  • Π”Π΅ΠΊΠ»Π°Ρ€Π°Ρ‚ΠΈΠ²Π½ΠΎΡΡ‚ΡŒ, чистота Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΉ, ΠΈΠΌΠΌΡƒΡ‚Π°Π±Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΡŒ ΠΈ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ Π²Ρ‹ΡΡˆΠ΅Π³ΠΎ порядка β€” основа гибкости ЀП.
  • Π’ JS доступны ΠΈ Π±Π°Π·ΠΎΠ²Ρ‹Π΅, ΠΈ ΠΏΡ€ΠΎΠ΄Π²ΠΈΠ½ΡƒΡ‚Ρ‹Π΅ ЀП-ΠΏΡ€Π°ΠΊΡ‚ΠΈΠΊΠΈ.