function parallel(tasks, onAllTasksComplete) {
const results = [];
let numCompleted = 0;
function onTaskComplete(index, result) {
results[index] = result;
if (++numCompleted === tasks.length) {
onAllTasksComplete(results);
}
}
for (let i = 0; i < tasks.length; i++) {
const onComplete = r => onTaskComplete(i, r);
const result = tasks[i](onComplete);
if (result !== undefined) {
onComplete(result);
}
}
}
const process = (funcs, initialArg) => funcs.reduce((arg, f) => f(arg), initialArg);
const getMonthNameInGenitiveCase = (date = new Date) =>
date.toLocaleString('ru', {
month: 'long',
day: 'numeric',
}).split(' ')[1];const getMonthNameInGenitiveCase = (date = new Date) =>
[
'января', 'февраля', 'марта', 'апреля', 'мая', 'июня',
'июля', 'августа', 'сентября', 'октября', 'ноября', 'декабря',
][date.getMonth()];
const openSelector = '[data-target]';
const closeSelector = '.modal__close';
const modalSelector = '.modal';
const activeClass = 'modal--active';document.addEventListener('click', ({ target: t }) => {
const open = t.closest(openSelector);
if (open) {
document.querySelector(`#${open.dataset.target}`).classList.add(activeClass);
} else {
t.closest(closeSelector)?.closest(modalSelector).classList.remove(activeClass);
}
});const onClick = (selector, handler) => document
.querySelectorAll(selector)
.forEach(n => n.addEventListener('click', handler));
onClick(openSelector, ({ currentTarget: { dataset: { target } } }) => {
document.querySelector(`#${target}`).classList.add(activeClass);
});
onClick(closeSelector, e => {
e.currentTarget.closest(modalSelector).classList.remove(activeClass);
});
const obj = {
val: 1,
valueOf() {
return this.val ^= 1;
},
};
// или
const obj = {
val: '1',
toString() {
return this.val = '1'.slice(this.val.length);
},
};
// или
const obj = {
val: true,
[Symbol.toPrimitive]() {
return this.val = !this.val;
},
};console.log(obj == false, obj == true); // true true
console.log(...Array.from({ length: 5 }, () => +obj)); // 0 1 0 1 0
function mustStay(n) {
for (const m of arr2) {
if (m.content.insuranceType === n.value) {
return false;
}
}
return true;
}
// или
const mustStay = n => arr2.every(m => m.content.insuranceType !== n.value);
// или
const mustStay = function(n) {
return !this.has(n.value);
}.bind(new Set(arr2.map(n => n.content.insuranceType)));
// или
const mustStay = n =>
(function next(i) {
return i >= arr2.length
? true
: arr2[i].content.insuranceType !== n.value && next(-~i);
})(0);for (let i = 0; i < arr1.length; i++) {
if (!mustStay(arr1[i])) {
for (let j = i--; ++j < arr1.length; arr1[j - 1] = arr1[j]) ;
arr1.pop();
}
}
// или
arr1.reduceRight((_, n, i, a) => mustStay(n) || a.splice(i, 1), null);
// или
arr1.splice(0, arr1.length, ...arr1.filter(mustStay));
// или
arr1.length -= arr1.reduce((acc, n, i, a) => (
a[i - acc] = n,
acc + !mustStay(n)
), 0);
const steps = [ /* ... */ ];
let iStep = 0;
const question = document.querySelector('.quiz__question');
const answers = document.querySelector('.quiz__answers');
const prev = document.querySelector('.quiz__button_prev');
const next = document.querySelector('.quiz__button_next');
prev.addEventListener('click', () => nextStep(-1));
next.addEventListener('click', () => nextStep(+1));
function nextStep(stepChange) {
iStep = Math.max(0, Math.min(steps.length - 1, iStep + stepChange));
prev.disabled = iStep === 0;
next.disabled = iStep === steps.length - 1;
question.innerHTML = steps[iStep].question;
answers.innerHTML = steps[iStep].answers.map(n => `<li>${n}</li>`).join('');
}
nextStep(0);
<div data-filter="service">
<div class="sign">Streaming service</div>
<div class="item">Netflix</div>
<div class="item">HBO Max</div>
<div class="item">Hulu</div>
</div>
<div data-filter="genre">
<div class="sign">Movie genre</div>
<div class="item">Comedy</div>
<div class="item">Action</div>
<div class="item">Horror</div>
<div class="item">Drama</div>
<div class="item">Fantasy</div>
</div><li class="card" data-service="Netflix" data-genre="Comedy">const cardSelector = '.card';
const hiddenCardClass = 'hidden';
const filterSelector = '[data-filter]';
const filterItemSelector = `${filterSelector} .item`;
const activeFilterItemClass = 'item_active';
document.querySelector('.filters').addEventListener('click', e => {
const item = e.target.closest(filterItemSelector);
if (!item) {
return;
}
item.closest(filterSelector).querySelectorAll(filterItemSelector).forEach(n => {
n.classList[n === item ? 'toggle' : 'remove'](activeFilterItemClass);
});
const values = Array.from(
e.currentTarget.querySelectorAll(`.${activeFilterItemClass}`),
n => [ n.closest(filterSelector).dataset.filter, n.innerText ]
);
document.querySelectorAll(cardSelector).forEach(n => {
n.classList.toggle(hiddenCardClass, values.some(m => n.dataset[m[0]] !== m[1]));
});
});
return getValue(objectValus[prop], property);const getValue = (obj, key) => Object
.values(obj ?? {})
.reduce((found, n) => found ?? getValue(n, key), obj?.[key]);
const result = Object.values(arr.reduce((acc, { id }) => (
(acc[id] ??= { id, count: 0 }).count++,
acc
), {}));function uniqueWithCount(data, key, countKey) {
const getKey = key instanceof Function ? key : n => n[key];
const unique = new Map;
for (const n of data) {
const k = getKey(n);
unique
.set(k, unique.get(k) ?? { ...n, [countKey]: 0 })
.get(k)[countKey]++;
}
return unique;
}const result = Array.from(
uniqueWithCount(arr, 'id', 'count').values(),
({ id, count }) => ({ id, count })
);
function solve(arr) {
const last = arr.reduce((acc, n, i) => (acc[n] = i, acc), {});
return arr.filter((n, i) => last[n] === i);
}function solve(arr) {
const last = new Map(arr.map((n, i) => [ n, i ]));
arr.length -= arr.reduce((acc, n, i, a) => (
a[i - acc] = n,
acc + (i !== last.get(n))
), 0);
return arr;
}const solve = arr => (
arr.splice(0, arr.length, ...[...new Set(arr.reverse())].reverse()),
arr
);
const merge = (arr1, arr2, step) => Array
.from(
{ length: Math.min(arr1.length, 1 + arr2.length / step | 0) },
(_, i) => [ ...arr2.slice(~-i * step, i * step), arr1[i] ]
)
.flat();const merge = (arr1, arr2, step) =>
[].concat(...Array.from(
{ length: Math.min(arr1.length, 1 + arr2.length / step | 0) },
(_, i) => [ arr1[i], ...arr2.slice(i * step, -~i * step) ]
));const merge = (arr1, arr2, step) =>
Array.prototype.flatMap.call(arr1, (n, i) => [
...Object.assign(
i ? Array(step).fill(null) : [],
arr2.slice((i - 1) * step, i * step)
),
n,
]);function merge(arr1, arr2, step) {
const len = arr2.length;
return Array.from(
{ length: len - (len % step) + 1 + len / step | 0 },
(_, i) => {
const j = i / (step + 1) | 0;
return i % (step + 1)
? arr2[i - j - 1]
: arr1[j] ?? null
});
}const c = merge(b, a, 5); - можете воспользоваться любой из этих функций, результаты выдадут одинаковые. Чего может и не быть с другими аргументами. Например:merge('ABCD', [ 1, 2, 3, 4, 5, 6, 7 ], 4)
// первая и четвёртая функции останавливаются на элементе первого массива,
// если во втором массиве не хватает элементов, на заполнение
// очередного промежутка между элементами первого массива
['A', 1, 2, 3, 4, 'B']
// вторая функция остановится после того,
// как отдаст все элементы второго массива
['A', 1, 2, 3, 4, 'B', 5, 6, 7]
// третья функция подставит дефолтные значения
// вместо недостающих элементов второго массива
['A', 1, 2, 3, 4, 'B', 5, 6, 7, null, 'C', null, null, null, null, 'D']merge('ABC', [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ], 2)
// 1, 3
['A', 1, 2, 'B', 3, 4, 'C']
// 2
['A', 1, 2, 'B', 3, 4, 'C', 5, 6]
// 4
['A', 1, 2, 'B', 3, 4, 'C', 5, 6, null, 7, 8, null]
(function() {
function func(arg) {
console.log(arg, this);
}
let arg = 1;
const f1 = () => func(arg);
const f2 = func.bind(this, arg);
arg = 2;
f1();
f2();
}).call('hello, world!!');
Array.from(str, n => n < 5 ? 0 : 1).join('')
// или
[...str].reduce((acc, n) => acc + +(n >= 5), '')
// или
''.concat(...str.split('').map(n => Math.floor(n / 5)))
// или
[].map.call(str, n => -~-~-~n >> 3).join``
// или
str.replace(/./g, m => Number('56789'.includes(m)))
// или
str.replace(/[1-4]/g, 0).replace(/[5-9]/g, 1)
const newArr = Array.from(
{ length: arr.length / 2 },
(n, i) => ({ ...arr[i], ...arr[i + arr.length / 2] })
);const numKeys = new Set(arr.flatMap(Object.keys)).size;
const newArr = arr.reduce((acc, n, i, a) => (
Object.assign(acc[i % (a.length / numKeys)] ??= {}, n),
acc
), []);
// или
const numKeys = Object.keys(Object.assign({}, ...arr)).length;
const numObjs = arr.length / numKeys;
const newArr = Array.from(
{ length: numObjs },
(n, i) => Object.assign({}, ...Array.from(
{ length: numKeys },
(m, j) => arr[j * numObjs + i]
))
);const newArr = arr.reduce((acc, n) => {
const [ [ k, v ] ] = Object.entries(n);
const i = acc[0][k] = (acc[0][k] ?? -1) + 1;
(acc[1][i] ??= {})[k] = v;
return acc;
}, [ {}, [] ])[1];
<a>. Соответственно, не будет и атрибута href. А у null не будет метода substr. О чём вы должны были узнать сами, из сообщения об ошибке - если бы открыли консоль.target следует использовать currentTarget.target к <a>, если таковой нашёлся, получать его href, начинается с решётки - выполнять плавную прокрутку к соответствующему элементу:document.addEventListener('click', e => {
const href = e.target.closest('a')?.getAttribute('href') ?? '';
if (href[0] === '#') {
e.preventDefault();
document.querySelector(href)?.scrollIntoView({
behavior: 'smooth',
});
}
});
const newUrl = url.match(/.+\//)[0];
// или
const newUrl = url.replace(/[^\/]+$/, '');
// или
const newUrl = url.slice(0, url.lastIndexOf('/') + 1);
// или
const newUrl = url.split(/(\/)/).slice(0, -1).join('');preg_match('/.+\//', $url, $match);
$newUrl = $match[0];
// или
$newUrl = preg_replace('/[^\/]+$/', '', $url);
// или
$newUrl = substr($url, 0, strrpos($url, '/') + 1);
// или
$newUrl = implode('', array_slice(preg_split('/(\/)/', $url, 0, PREG_SPLIT_DELIM_CAPTURE), 0, -1));