Callback-функції, call та apply
Метод forEach
Давайте спробуємо самі створити функцію forEach, щоб детально розібратися як працює метод масива .forEach().
Завдання:
- створити функцію перебору елементів масива;
- у якості першого аргумента виступає масив, який необхідно перебрати;
- у якості другого аргумента виступає callback-функція, якою буде здійснено обробку кожного елемента масива.
В першу чергу створіть call-back функцію, що виводить в консоль квадрат переданого елемента та всі передані в функцію аргументи.
Функція може приймати 1, 2, або 3 аргумента: елемент, ітератор та сам масив.
Метод sort
Давайте спробуємо самі створити функцію Sort, щоб детально розібратися як працює метод масива .sort().
Завдання:
- створити функцію сортування елементів масива;
- у якості першого аргумента виступає масив, який необхідно відсортувати;
- у якості другого аргумента виступає callback-функція, якою буде здійснено обробку елементів масива попарно.
В першу чергу створіть 3 call-back функції, які сортують числа по зростанню, спаданню та в першу чергу виводять непарні, а потім - парні значення.
Функції повинні приймати по 2 аргумента, які будуть порівнювати між собою.
Методи call та apply
https://learn.javascript.ru/call-apply.
Методи call та apply застосовуються до будь-яких функцій чи методів.
function blabla() { ... } // створення функції
var glagla = function() { ... } // створення функції
blabla(); // виклик функції
glagla(); // виклик функції
blabla.call(); // виклик метода call для функції
glagla.apply(); // виклик метода apply для функції
Ці два метода "по-своєму" запускають функцію.
Уявіть, що авто - це функція. Коли ви сідаєте за кермо та їдете - це прямий виклик функції.
Тепер уявіть, що в авто посадили робота. Робот - це метод call (чи apply), ви керуєте роботом, а робот керує автомобілем.
У такого способа керування автомобілем є свої недоліки та переваги.
.call();
Виклик здійснюється так:
func.call(context, arg1, arg2, arg3);
Даний метод задає функції контекст (this, батька).
Виконайте наступний код:
function aaa(a, b, c) {
console.log(this);
console.log(a, b, c);
}
aaa(5, 8, 42);
var masha = {
'name': 'Маша',
age: 17,
bbb: aaa
};
var petya = {
'name': 'Петя',
age: 22,
};
aaa.call(masha, 5, 8, 42);
masha.bbb(8, 8, 42);
masha.bbb.call(petya, 8, 8, 42);
Тобто, за допомогою call можна застосувати будь-яку функцію ніби-то як метод до будь-якого елемента (контекста).
Метод call підміняє контекст ("батька") для функції чи метода.
Ще один варіант практичного застосування:
var p = document.getElementsByTagName('p');
Хочемо перебрати всі пешки і щось з ними зробити.
У змінній p у нас не масив, а HTMLCollection, у нього немає метода forEach, тому доведеться використати цикл.
Або... скористатися методом call, викликавши forEach з прототипа чи іншого масива.
Це є можливим тому, що метод forEach не перевіряє - що ми йому підсовуємо як this: чи справжній масив, чи щось, що просто має елементи та властивість length.
var p = document.getElementsByTagName('p'),
k = [];
console.log('------------------------------');
k.forEach.call(p, function(e, i){
console.log(i, e.innerText.slice(0, 20));
});
Більш коректний варіант - звернення до прототипа, не потребує іншого масива:
Array.prototype.forEach.call(p, function(e, i){
console.log(i, e.innerText.slice(0, 20));
});
Звісно, якщо в якості контекста підсунути число чи об'єкт, то метод не спрацює.
.apply();
Метод .apply() дуже схожий на метод call, але зручніший для роботи з динамічною кількістю аргументів.
func.apply(context, arg_arr);
func.apply(context, [arg1, arg2, arg3]);
Тобто, ви можете передати всі аргументи у вигляді масива.
Це часто потрібно при виклику callback-функцій з довільною кількістю аргументів, детальніше розглянемо далі на методах max та min.
Функції бібліотеки Math.max та Math.min
Для кращого розуміння теми давайте самі створимо функції max та min, які є в бібліотеці Math.
Дані функції приймають довільну кількість аргументів (потрібно передбачити дії коли буде передано 0 або 1 аргумент та якщо є нечислові аргументи).
Серед усіх аргументів відбувається пошук найбільшого чи найменшого значення і повертається це значення.
Домашнє завдання
- Самостійно розберіться з методом .bind()
- Закінчіть функції min, max, протестуйте на різноманітних масивах.
- Посортуйте всі абзаци лекції, використовуючи функцію сортування масива .sort().
- Перевірте, чи хоч в одному заголовку h2 є літера "ї". Використайте відповідні методи.
-
Створіть базовий об'єкт "гарбуз", задайте йому колір, сорт, ціну за кілограм, нульову вагу, а також метод виводу в консоль інормації про вартість гарбуза.
На основі цього базового об'єкта створіть 5 гарбузів тільки з властивостями, без методів, задавайте кожному випадкову вагу в межах 5-15 кг.
Скористайтесь методом базового об'єкта для вивода інформації про вартість кожного створеного гарбуза. - Перевірте, чи спрацює метод масивів .forEach() для строк.
Мінотавр в лабіринті.
Мінотавра якось треба позначити. Можна знову перебрати весь лабіринт в пошуках вільних клітин, випадковій вільній клітині задати клас minotaur і запам'ятати координати, наприклад, у mx та my.
Кожен свій хід мінотавр повинен рекурсивно перебрати всі доступні шляхи. Наш лабіринт не є великим, рекурсія не буде дуже глибокою, тому про пам'ять поки не будемо тубруватися.
Створюємо рекурсію, яка з поточної клітини хоче піти вгору, вниз, вліво, вправо.
Ходи рекурсії можна записувати послідовно у масив.
Кожен хід рекурсії треба перевірити:
- чи є вільний прохід на нову клітину;
- чи ми ще не були на тій клітині;
- чи ми знайшли шукача скарбів.
Якщо знайшли шукача скарбів - цю гілку варто зберегти як потенційний шлях до жертви.
В кінці рекурсії потрібно перебрати всі збережені гілки, знайти найкоротшу і зробити крок по її перших координатах: забрати клас у поточної клітини, передати його наступній та змінити mx чи my.
Ну і перевірити - чи не наздогнали ми шукача скарбів. Якщо встали на його клітину - game over.
Один ньюанс: якщо шукач скарбів перейде на клітину з мінотавром - гра повинна завершитися. Чи мінотавр в свій хід повинен перевірити в першу чергу - чи не став шукач скарбів на його клітину.