Треки
/
JavaScript
JavaScript
/
Вправи
/
Перетворення координат
Перетворення координат

Перетворення координат

Навчальна вправа

Вступ

Замикання - це програмний прийом у JavaScript, який дозволяє використовувати змінні із зовнішньої лексичної області видимості всередині вкладеного блоку коду. JavaScript підтримує замикання прозоро, і ми часто користуємося ними, навіть не знаючи, що це таке.

// Top-level declarations are global-scope
const dozen = 12;

{
  // Braces create a new block-scope
  // Referencing the outer variable is a closure.
  const twoDozen = dozen * 2;
}

// Because of the block-scope declaration, twoDozen is not available here.
twoDozen;
// => Uncaught ReferenceError: twoDozen is not defined

Крім фігурних дужок {}, функції (і класи) також створюють нові області видимості та можуть замикати в собі значення:

const dozen = 12;

// Functions create a new function-scope and block-scope.
// Referencing the outer variable here is a closure.
function nDozen(n) {
  // This is declared inside the function scope, and uses the top-level scope.
  // This works, and encloses the value 12.
  const twoDozen = dozen * 2;

  // This only uses the locally declared variable and the passed argument to the parameter `n`
  return (twoDozen / 2) * n;
}

// Because of the function-scope declaration, twoDozen is not available here.
twoDozen;
// => Uncaught ReferenceError: twoDozen is not defined

Як показують приклади з twoDozen, значення можна замкнути у вкладеній області видимості (функції, блоці тощо), але не можна витягти з цього контексту. У більшості випадків у сучасному JavaScript задумано так, щоб значення не витікало за межі області видимості.

Замикання для збереження стану й передавання значень

Використання оголошення змінної, яку можна змінювати (як let чи var), дозволяє зберегти певний стан:

let counter = 0;

// This function closure increments the counter's state in the outer lexical context.
// This way the counter can be shared between many calling contexts.
export function increment() {
  counter += 1;
  return counter;
}

increment();
// => 1

counter;
// => 1

Замикати значення й не давати стану витекти

Поєднавши дві ідеї: замикання значення для збереження стану та те, що замкнуті значення не витікають назовні, можна створити приватні значення.

Найпоширеніший метод - створити функцію, яка повертає функцію, що замикає в собі певний стан.

export function makeCounter() {
  let counter = 0;

  // This returns a new function that encloses the local variable counter
  return function increment() {
    counter += 1;
    return counter;
  };
}

// Counter did not leak
counter;
// => Uncaught ReferenceError: counter is not defined

// This creates a new counter.
// This assigns the increment function to the variable myFirstCounter.
const myFirstCounter = makeCounter();

typeof myFirstCounter;
// => function

myFirstCounter.name;
// => increment

myFirstCounter();
// => 1
myFirstCounter();
// => 2

// This creates new counter (with new, separate local state / enclosed counter variable)
const mySecondCounter = makeCounter();

mySecondCounter();
// => 1

// It does not affect the first counter.

myFirstCounter();
// => 3
Note

Багато програмістів вважають замикання складною концепцією, а повернення функції з функції є незвичним, а в деяких мовах програмування навіть неможливим. Якщо потрібно більше матеріалу для читання, посібник MDN про замикання досить вичерпний.

Вказівки

Наша компанія з дизайну переважно працювала з CSS-трансформаціями, створюючи вебсторінки. Після деяких обговорень ми вирішили почати використовувати JavaScript, щоб виконувати частину обчислень динамічно. Деякі з наших колег мають менший досвід роботи з JavaScript, тож ми вирішуємо використати замикання функції, щоб створити багаторазову трансформацію для пар координат {x, y}.

1. Перенести координати

Реалізуйте функцію translate2d, яка повертає функцію, що використовує замикання для багаторазового двовимірного перенесення пари координат.

У геометрії перенесення означає переміщення точок, векторів або фігур на однакову відстань в одному напрямку. Його можна тлумачити як додавання сталої до кожної точки.

const moveCoordinatesRight2Px = translate2d(2, 0);
const result = moveCoordinatesRight2Px(4, 8);
// result => [6, 8]

2. Масштабувати координати

Реалізуйте функцію scale2d, яка повертає функцію, що використовує замикання для багаторазового двовимірного масштабування пари координат.

У геометрії рівномірне масштабування означає збільшення або зменшення векторів чи фігур в одному напрямку. Його можна тлумачити як множення кожної точки на сталу (коефіцієнт масштабування).

Для цієї вправи вважаймо, що значення масштабу лише додатні.

const doubleScale = scale2d(2, 2);
const result = doubleScale(6, -3);
// result => [12, -6]

3. Компонувати функції трансформації

Поєднайте дві функції трансформації, щоб виконувати багаторазову трансформацію. Це часто називають композицією функцій, де результат першої функції 'f(x)' використовується як вхідні дані для другої функції 'g(x)'.

const moveCoordinatesRight2Px = translate2d(2, 0);
const doubleCoordinates = scale2d(2, 2);
const composedTransformations = composeTransform(
  moveCoordinatesRight2Px,
  doubleCoordinates,
);
const result = composedTransformations(0, 1);
// result => [4, 2]

4. Зберегти результати функцій

Реалізуйте функцію memoizeTransform. Вона приймає функцію, яку потрібно запамʼятати, а потім повертає нову функцію, що запамʼятовує вхідні дані переданої функції, тож останнє повернене значення можна «запамʼятати» й обчислити лише раз, якщо функцію викличуть знову з тими самими аргументами.

Мемоізацію іноді використовують у динамічному програмуванні. Вона дозволяє виконувати дорогі операції лише один раз, адже їхні результати запамʼятовуються. Зауважте, що в цій вправі запамʼятовується лише останній результат, на відміну від деяких розвʼязків у динамічному програмуванні, які запамʼятовують усі результати.

const tripleScale = scale2d(3, 3);
const memoizedScale = memoizeTransform(tripleScale);

memoizedScale(4, 3); // => [12, 9], this is computed since it hasn't been computed before for the arguments
memoizedScale(4, 3); // => [12, 9], this is remembered, since it was computed already
Редагувати через GitHub Посилання відкривається в новому вікні або вкладці
JavaScript Exercism

Час розпочати Перетворення координат?

Зареєструйтеся на Exercism, щоб вивчати й опановувати JavaScript, а також 37 концепцій159 вправ та справжнє наставництво від людей, і все це безкоштовно.