новая_координата = Math.max(
минимальное_допустимое_значение,
Math.min(
максимальное_допустимое_значение,
текущая_координата + изменение_координаты
)
);
const getSrc = img => img.getAttribute('src');
// или
const getSrc = img => img.attributes.src.value;
const relativeOnly = f => img => {
const src = getSrc(img);
if (!/^https?:\/\//.test(src)) {
f(img, src);
}
};
document.querySelectorAll('img').forEach(relativeOnly((img, src) =>
img.outerHTML = `
<picture>
<source srcset="${src}" type="image/svg+xml">
${img.outerHTML}
</picture>`
));
const wrapImages = relativeOnly((img, src) => {
const picture = document.createElement('picture');
const source = document.createElement('source');
source.srcset = src;
source.type = 'image/svg+xml';
img.replaceWith(picture);
picture.append(source, img);
});
for (const n of document.getElementsByTagName('img')) {
wrapImages(n);
}
// или
Array.prototype.forEach.call(document.images, wrapImages);
const count = 10;
.const result = Array
.from({ length: count }, (n, i) => `"${-~i}"`)
.join(', ');
// или
const result = [...Array(count).keys()].reduce((acc, n) => {
return acc.concat(acc && ', ', '"', ++n, '"');
}, '');
// или
const result = (function xxx(n) {
return n > 0 ? xxx(n - 1) + (n === 1 ? '' : ', ') + '"' + n + '"' : '';
})(count);
// или
const result = Array(count)
.fill()
.map((n, i) => JSON.stringify((i + 1).toString()))
.toString()
.replace(/,/g, '$& ');
const buttonSelector = '.class2';
const classesToToggle = [ 'class3', 'class4' ];
$(buttonSelector).click(e => {
$(e.currentTarget).next().toggleClass(classesToToggle.join(' '));
});
document.querySelectorAll(buttonSelector).forEach(n => {
n.addEventListener('click', onClick);
});
function onClick() {
classesToToggle.forEach(n => this.nextElementSibling.classList.toggle(n));
}
document.addEventListener('click', e => {
const button = e.target.closest(buttonSelector);
if (button) {
for (const n of classesToToggle) {
button.parentNode.lastElementChild.classList.toggle(n);
}
}
});
const el = document.querySelector('#box');
const colors = [ 'red', 'green', 'blue' ];
let index = -1;
el.addEventListener('mouseenter', function() {
index = (index + 1) % colors.length;
this.style.backgroundColor = colors[index];
});
el.addEventListener('mouseleave', function() {
this.style.backgroundColor = '';
});
подскажите, что мне нужно подправить
function makeRequests(urls, max) {
return new Promise(resolve => {
const results = Array(urls.length).fill(null);
const groupedUrls = urls.reduce((acc, n, i) => ((acc[n] ??= []).push(i), acc), {});
const uniqueUrls = Object.keys(groupedUrls);
let countRequests = 0;
let countResponses = 0;
for (let i = 0; i < Math.max(1, Math.min(max, uniqueUrls.length)); i++) {
request();
}
function request() {
if (countResponses === uniqueUrls.length) {
resolve(results);
} else if (countRequests < uniqueUrls.length) {
const url = uniqueUrls[countRequests++];
fetch(url)
.then(result => result.json())
.catch(error => error)
.then(result => {
groupedUrls[url].forEach(n => results[n] = result);
countResponses++;
request();
});
}
}
});
}
$('form').on('input', function() {
$('.button').prop('disabled', $('input', this).get().some(n => !n.value));
}).trigger('input');
// или
const form = document.querySelector('form');
const button = document.querySelector('.button');
const inputs = [...form.querySelectorAll('input')];
form.addEventListener('input', () => button.disabled = !inputs.every(n => n.value));
form.dispatchEvent(new Event('input'));
function makeRandomizer([ min, max ]) {
const numbers = [...Array(max - min + 1).keys()];
return () => numbers.length
? min + numbers.splice(Math.random() * numbers.length | 0, 1)[0]
: null;
}
function makeRandomizer([ min, max ]) {
const numbers = Array.from({ length: max - min + 1 }, (n, i) => min + i);
for (let i = numbers.length; --i > 0;) {
const j = Math.random() * (i + 1) | 0;
[ numbers[i], numbers[j] ] = [ numbers[j], numbers[i] ];
}
return () => numbers.pop() ?? null;
}
$('#sel1').change(function() {
const min = +$(this).val();
$('#sel2')
.val((i, v) => Math.max(v, min))
.children()
.show()
.filter((i, n) => +n.value < min)
.hide();
}).change();
const select1 = document.querySelector('#sel1');
const select2 = document.querySelector('#sel2');
select1.addEventListener('change', e => {
const min = +e.target.value;
select2.value = Math.max(select2.value, min);
for (const n of select2.children) {
n.hidden = +n.value < min;
}
});
select1.dispatchEvent(new Event('change'));
filterInput.addEventListener('keyup',...
пусть будетfilterInput.addEventListener('input', function() {
const value = this.value.toLowerCase();
filterResult.innerHTML = resultArr
.filter(n => n.toLowerCase().includes(value))
.map(n => `<li>${n}</li>`)
.join('');
});
filterInput.addEventListener('input', e => {
const value = e.target.value.toLowerCase();
filterResult.replaceChildren(...resultArr.reduce((acc, n) => {
if (n.toLowerCase().indexOf(value) !== -1) {
(acc[acc.length] = document.createElement('li')).textContent = n;
}
return acc;
}, []));
});
arr1.filter(n => arr2.includes(n)).length !== 0
// или
arr1.some(Set.prototype.has.bind(new Set(arr2)))
// или
new Set(arr1).size + new Set(arr2).size > new Set([ ...arr1, ...arr2 ]).size
function intersection(data1, data2, key = n => n) {
const getKey = key instanceof Function ? key : n => n[key];
const keys = new Set(Array.from(data2, getKey));
const result = [];
for (const n of data1) {
if (keys.has(getKey(n))) {
result.push(n);
}
}
return result;
}
// как применять в вашем случае
!!intersection(arr1, arr2).length
// другие примеры использования
intersection(Array(5).keys(), Array(3).keys()) // [0, 1, 2]
intersection('abcDe', 'cd', n => n.toLowerCase()) // ['c', 'D']
intersection([{id: 1}, {id: 2}, {id: 3}], [{id: 2}, {id: 4}], 'id') // [{id: 2}]
value=""
. Соответственно, проверять надо будет value на пустоту, а не равенство тексту. Это и проще, и код не придётся переписывать, если вдруг завтра вам потребуется изменить текст по умолчанию..element
), а не каждому элементу индивидуально. Не придётся вписывать новый обработчик или удалять существующий, если изменится количество элементов в форме.button.disabled = ![
inputMail.value,
inputPhone.value,
select.value,
checkbox.checked,
].every(Boolean);
str.match(/(?<=\{{2}).*?(?=\}{2})/g) ?? []
// или
Array.from(str.matchAll(/\{\{(.*?)\}\}/g), n => n[1])
const className = 'cart__counter';
.const remove = el => el.innerText = parseInt(el.innerText);
// или
const remove = el => el.innerHTML = el.innerHTML.match(/\d+/)[0];
// или
const remove = el => el.textContent = el.textContent.replace(/\D/g, '');
// или
const remove = el => [ el.firstChild.data ] = el.firstChild.data.split(' ');
// или
const remove = el => el.childNodes[0].nodeValue = parseFloat(el.childNodes[0].nodeValue);
document.querySelectorAll(`.${className}`).forEach(remove);
// или
for (const n of document.getElementsByClassName(className)) {
remove(n);
}
const arr = Object
.entries(obj)
.sort((a, b) => b[1] - a[1])
.map(n => n[0]);
const arr = Object
.values(Object.entries(obj).reduce((acc, n) => ((acc[n[1]] ??= []).push(n[0]), acc), {}))
.reverse()
.flat();
[...params.keys()].forEach(n => whiteList.includes(n) || params.delete(n));
childNodes
, который представляет собой динамический NodeList
и одновременно пытаетесь его модифицировать. Удаляя один узел, вы пропускаете следующий - т.е., если несколько текстовых узлов идут подряд, то удалён будет только каждый второй; а те нетекстовые узлы, которые расположены после текстовых, тут никакой рекурсии не случится, их содержимое вообще никак не будет обработано. Надо делать копию childNodes
, и перебирать её. Или вместо for...of
использовать цикл со счётчиком, при удалении узла счётчик увеличиваться не должен. Или перебирать childNodes
от конца к началу - тоже цикл со счётчиком или reduceRight
(да, это будет использование метода не совсем по назначению).nextElementSibling
, не знаю, как это комментировать. Надо было просто вызвать функцию, передав ей текущий элемент.const deleteTextNodes = node =>
node.nodeType === Node.TEXT_NODE
? node.remove()
: [...node.childNodes].forEach(deleteTextNodes);
// или
function deleteTextNodes(node) {
if (node instanceof Text) {
node.remove();
} else {
Array.prototype.reduceRight.call(node.childNodes, (_, n) => deleteTextNodes(n), null);
}
}