Javascript.RU

Создать новую тему Ответ
 
Опции темы Искать в теме
  #1 (permalink)  
Старый 12.05.2020, 19:05
Аватар для nastya97core
Аспирант
Отправить личное сообщение для nastya97core Посмотреть профиль Найти все сообщения от nastya97core
 
Регистрация: 04.04.2020
Сообщений: 60

Как сделать короткую функцию для forEach?
Здравствуйте.
1. Я не хочу использовать jQuery, но мне нужна от туда фишка с применением параметров на массив объектов (простите, если неправильно использовала термины).

Я имею в виду это $(".block").addClass("red")
И если есть несколько объектов с классом block, то применится addClass для всех объектов. В чистом JS я делаю это так:

document.querySelectorAll(".block").forEach((el)=> {
	el.classList.add("red");
});


Подскажите, как быть с функцией, которая бы делала forEach?

Я просто не совсем могу сообразить, как такое сделать. Вот так не работает (ну и не должно)
function qsf(e) {
        return
	document.querySelectorAll(e).forEach((el)=> {
		el
	})
}

2. На данный момент я себе сделала 2 функции
function q(e){return document.querySelector(e)}
function qs(e){return document.querySelectorAll(e)}

И теперь обращаюсь через q и qs соответсвенно. Так на много удобнее и короче получается.
Вопрос: насколько это правильное решение? Не замедляю ли я таким образом код? Ведь я заставляю его постоянно вызывать функцию. Может быть это как-то сказывается на ОЗУ?

3. Почему раньше, когда я видела js код, постоянно писали getElementById или getElementsByClassName, а не использовали querySelector, ведь так намного проще? Там же можно обратиться и по ID и по Class. Просто для меня, когда я первый раз столкнулась с кодом, лет 5 назад, это было аргументом для того, чтобы использовать jquery. Там только знак доллара, а здесь пипец какой-то. А теперь оказывается, что есть querySelector.

P.S.
getElementsByClassName я видела как раз в таком виде:
document.getElementsByClassName("block").forEach((el)=> {
	el.classList.add("red");
});

и меня это пугало, так как можно было сделать $(".block").addClass("red");
Ответить с цитированием
  #2 (permalink)  
Старый 12.05.2020, 19:13
Аватар для рони
Профессор
Отправить личное сообщение для рони Посмотреть профиль Найти все сообщения от рони
 
Регистрация: 27.05.2010
Сообщений: 33,109

Сообщение от nastya97core
Вот так не работает
работает, только сам forEach никогда ничего не возвращает.
Ответить с цитированием
  #3 (permalink)  
Старый 12.05.2020, 19:35
Аватар для nastya97core
Аспирант
Отправить личное сообщение для nastya97core Посмотреть профиль Найти все сообщения от nastya97core
 
Регистрация: 04.04.2020
Сообщений: 60

рони,
как сделать, чтоб возвращало и работало?
я classList имела в виду для примера. На деле я хочу именно иметь возможность что-то делать с массивом. То есть получить способности того же $("element").что-то
Ответить с цитированием
  #4 (permalink)  
Старый 12.05.2020, 19:48
Аватар для рони
Профессор
Отправить личное сообщение для рони Посмотреть профиль Найти все сообщения от рони
 
Регистрация: 27.05.2010
Сообщений: 33,109

forEach со встроенным списком элементов
nastya97core,

<!doctype html>
<html lang="ru">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style type="text/css">
    div{
        height: 100px;
        width: 100px;
        margin: 5px;
        text-align: center;
        line-height: 100px;
    }
    body{
         display: flex;
         justify-content: center;
    }
    .red{
        background-color: #FF0000;
    }

    </style>
 </head>
<body>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>

<script>
function qs(e){return document.querySelectorAll(e)};
function qsf(e){
const fn = callback => (NodeList.prototype.forEach.bind(qs(e))(callback), fn);
return fn};
qsf('div')
(el => el.classList.add("red"))
((el,i) => el.textContent = i)
(({style}) => style.color = '#fff');
</script>
</body>
</html>
Ответить с цитированием
  #5 (permalink)  
Старый 12.05.2020, 20:37
Аватар для рони
Профессор
Отправить личное сообщение для рони Посмотреть профиль Найти все сообщения от рони
 
Регистрация: 27.05.2010
Сообщений: 33,109

nastya97core,
Rise библиотека в jQuery стиле
Ответить с цитированием
  #6 (permalink)  
Старый 13.05.2020, 08:17
Аватар для рони
Профессор
Отправить личное сообщение для рони Посмотреть профиль Найти все сообщения от рони
 
Регистрация: 27.05.2010
Сообщений: 33,109

вариант с контекстом
Rise,


<!doctype html>
<html lang="ru">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style type="text/css">
    div{
        height: 100px;
        width: 100px;
        margin: 5px;
        text-align: center;
        line-height: 100px;
    }
    body{
         display: flex;
         justify-content: center;
    }
    .red{
        background-color: #FF0000;
    }

    </style>
 </head>
<body>
<div class="item">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>

<script>
function qsa(selector, parent) {
    return (parent || document).querySelectorAll(selector)
}

function qsf(...e) {
    const fn = callback => (NodeList.prototype.forEach.bind(qsa(...e))(callback), fn);
    return fn
};
let parent = qsa('.item')[0];
qsf('div', parent)
    (el => el.classList.add("red"))
    ((el, i) => el.append(i))
    (({style}) => style.color = '#fff');
</script>
</body>
</html>

Последний раз редактировалось рони, 13.05.2020 в 08:40.
Ответить с цитированием
  #7 (permalink)  
Старый 13.05.2020, 13:22
Аватар для Malleys
Профессор
Отправить личное сообщение для Malleys Посмотреть профиль Найти все сообщения от Malleys
 
Регистрация: 20.12.2009
Сообщений: 1,714

Сообщение от nastya97core
И теперь обращаюсь через q и qs соответственно. Так на много удобнее и короче получается.
Вы можете использовать функции, которые есть в Command Line API:

function $(selector, startNode) {
	return (startNode || document).querySelector(selector);
}
function $$(selector, startNode) {
	var nodes = (startNode || document).querySelectorAll(selector);
	var length = nodes.length;
	Object.setPrototypeOf(nodes, Array.prototype);
	nodes.length = length;
	return nodes;
}
function $x(xpath, startNode) {
	var doc = startNode && startNode.ownerDocument || document;
	var result = doc.evaluate(xpath, startNode || doc, null, XPathResult.UNORDERED_NODE_ITERATOR_TYPE);
	var node, nodes = [];
	while(node = result.iterateNext()) nodes.push(node);
	return nodes;
}
Такие функции определены в консоли для разработчиков, почему бы их не воссоздать для использования в проекте? Обратите внимание, что $$ и $x возвращают массив, так что вы можете работать как с обычным массивом!

Сообщение от nastya97core
Вопрос: насколько это правильное решение? Не замедляю ли я таким образом код? Ведь я заставляю его постоянно вызывать функцию. Может быть это как-то сказывается на ОЗУ?
Ну если вам удобно работать с NodeList (например при помощи циклов), то OK. А что там должно замедлять код? Посмотрите на определение функции jQuery и ужаснитесь, насколько там замедляют код! Давайте посмотрим...
<script src="https://charm-launch.glitch.me/selectors.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>

<style>
.container {
	display: flex;
	justify-content: center;
}
.container > div {
	height: 100px;
	width: 100px;
	margin: 5px;
	text-align: center;
	line-height: 100px;
}
.red {
	background-color: #FF0000;
}

</style>

<div class="info"></div>
<script>
	var html = [], c = ["jQuery", "Command Line API"];
	for(var j = 0; j < c.length; j++) {
		html.push('<section id="' + c[j] + '">');
			html.push('<h1>' + c[j] + '</h1>');
			html.push('<div class="container">');
				for(var i = 0; i < 5; i++) {
					html.push('<div></div>');
				}
			html.push('</div>');
		html.push('</section>');
	}
	document.write(html.join(""));
</script>
 
<script>
	
	var t = performance.now();
	/* сначала идёт пример на jQuery */
	$("[id='jQuery'] .container div")
		.addClass("red")
		.text(i => i)
		.css("color", "white")
	/* конец примера на jQuery */
	var dt1 = performance.now() - t;
	
	$("[id='jQuery'] h1").text(
		$("[id='jQuery'] h1").text() + " (" + dt1 + "ms)" 
	);
	
	jQuery.noConflict();
	
	t = performance.now();
	/* далее идёт пример, вдохновлённый Command Line API */
	$$("[id='Command Line API'] .container div").forEach((e, i) => {
		e.classList.add("red");
		e.textContent = i;
		e.style.color = "white";
	});
	/* конец примера */
	var dt2 = performance.now() - t;
	
	$("[id='Command Line API'] h1").textContent += " (" + dt2 + "ms)";
	/* jQuery обычно на полпорядка медленней, однако на некоторых сложных селекторах jQuery замедляется почти на 3 порядка (т. е. jQuery в 800 раз медленней) */
	$(".info").textContent = "jQuery работает в " + (dt1/dt2) + " раз медленней, чем вдохновление от Command Line API";
</script>


Сообщение от рони
qsf('div')
(el => el.classList.add("red"))
((el,i) => el.textContent = i)
(({style}) => style.color = '#fff');
Зачем такие странные конструкции? Почему каждый раз нужно перечислять элементы? Может стоит прочитать про итераторы?

Твой пример, но перечисление только один раз...
<html lang="ru">
<head>
    <style>
    div{
        height: 100px;
        width: 100px;
        margin: 5px;
        text-align: center;
        line-height: 100px;
    }
    body{
         display: flex;
         justify-content: center;
    }
    .red{
        background-color: #FF0000;
    }
    </style>
 </head>
<body>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>

<script>	
for(const [i, el] of document.querySelectorAll("div").entries()) {
	el.classList.add("red")
	el.textContent = i
	el.style.color = '#fff'
}
</script>
</body>
</html>


Твой второй пример с использованием кода, вдохновлённого Command Line API...
<!doctype html>
<html lang="ru">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style type="text/css">
    div {
        height: 100px;
        width: 100px;
        margin: 5px;
        text-align: center;
        line-height: 100px;
    }
    .item {
         display: flex;
         justify-content: center;
    }
    .red {
        background-color: #FF0000;
    }
    </style>
 </head>
<body>
<div class="item">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>

<script src="https://charm-launch.glitch.me/selectors.js"></script>
<script>	/* поиск с контекстом, как любит Rise */
$$("div", $(".item")).forEach((el, i) => {
	el.classList.add("red")
	el.append(i)
	el.style.color = '#fff'
});
</script>
</body>
</html>


Сообщение от nastya97core
Почему раньше, когда я видела js код, постоянно писали getElementById или getElementsByClassName, а не использовали querySelector, ведь так намного проще?
Вы и сейчас можете использовать метод getElementById, который возвращает первый попавшийся элемент с данным id. Не использовали метод querySelector, поскольку им вероятно нужна была поддержка в IE6-7, в которых такого метода нет. Просто сейчас особо никто и не делает сайты и для IE6-7 тоже!

Сообщение от nastya97core
Просто для меня, когда я первый раз столкнулась с кодом, лет 5 назад, это было аргументом для того, чтобы использовать jquery. Там только знак доллара, а здесь пипец какой-то. А теперь оказывается, что есть querySelector.
Ну 5 лет назад (в 2015 году) все браузеры уже поддерживали метод querySelector. Даже в 2009 году этот метод уже работал и в Firefox и в IE8 и в Safari (c 2008 года) и в Opera! https://caniuse.com/#feat=queryselector

Сообщение от nastya97core
getElementsByClassName я видела как раз в таком виде:
document.getElementsByClassName("block").forEach(el => {
    el.classList.add("red");
});


и меня это пугало, так как можно было сделать $(".block").addClass("red");
Не забывайте, чтобы сделать так $(".block").addClass("red");, вам нужно было подключить ещё намного больше кода, который должен пугать ещё больше!

Сообщение от nastya97core
Подскажите, как быть с функцией, которая бы делала forEach?
Можно вообще обойтись без функции! Используйте циклы.

for(const el of document.querySelectorAll(".block")) {
    el.classList.add("red");
}

С кодом, вдохновлённым Command Line API, вы можете написать даже так...
for(const el of $$(".block")) {
    el.classList.add("red");
}


Сообщение от nastya97core
На деле я хочу именно иметь возможность что-то делать с массивом
Вы можете использовать Array.from чтобы получить массив с элементами из NodeList... или же использовать три вспомогательных функции для работы с CSS- и XPath-селекторами — $ для поиска одного элемента по CSS-селектору, $$ — для поиска всех элементов (возвращает массив элементов) и $x — для поиска элементов по XPath-селектору (возвращает массив элементов). Код $, $$ и $x смотрите выше!
$$(".block").forEach(el => {
    el.classList.add("red");
});
Ответить с цитированием
  #8 (permalink)  
Старый 13.05.2020, 15:18
Аватар для рони
Профессор
Отправить личное сообщение для рони Посмотреть профиль Найти все сообщения от рони
 
Регистрация: 27.05.2010
Сообщений: 33,109

Сообщение от Malleys
Почему каждый раз нужно перечислять элементы?
не понимаю вашего вопроса или критики.
потому что это можно, и ничто не мешает сделать всё за один цикл или десять, была продемонстрирована возможность делать цикл за циклом.
Ответить с цитированием
  #9 (permalink)  
Старый 13.05.2020, 18:07
Аватар для Malleys
Профессор
Отправить личное сообщение для Malleys Посмотреть профиль Найти все сообщения от Malleys
 
Регистрация: 20.12.2009
Сообщений: 1,714

Сообщение от рони
и ничто не мешает сделать всё за один цикл или десять,
1. Время мешает! Вот, проверь в консоли на этой странице...
function qsa(selector, parent) {
    return (parent || document).querySelectorAll(selector)
}
function qsf(...e) {
    const fn = callback => (NodeList.prototype.forEach.bind(qsa(...e))(callback), fn);
    return fn
};

var TIMES = 1000, SELECTOR = "body td";
console.time("Длинное каррирование");
eval("qsf('" + SELECTOR + "')\n" + "(e => e.style.background = '#' + ('000000' + Math.floor(0xffffff * Math.random())).slice(-6))\n".repeat(TIMES) + "\n//# sourceURL=Длинное-каррирование")
console.timeEnd("Длинное каррирование");

console.time("Длинный цикл");
eval("for(const e of document.querySelectorAll('" + SELECTOR + "')) {\n" + "\te.style.background = '#' + ('000000' + Math.floor(0xffffff * Math.random())).slice(-6);\n".repeat(TIMES) + "}\n\n//# sourceURL=Длинный-цикл")
console.timeEnd("Длинный цикл");

console.time("Длинное jQuery");
eval("jQuery('" + SELECTOR + "')\n" + "\t.css('background', '#' + ('000000' + Math.floor(0xffffff * Math.random())).slice(-6))\n".repeat(TIMES) + "\n//# sourceURL=Длинное-jQuery")
console.timeEnd("Длинное jQuery");


2. Стиль кода.

qsf("#a .b")
(e => a)
(e => b)
(e => c)
(e => d)
против
for(const e of $$("#a .b")) {
    a;
    b;
    c;
    d;
}


3. Кто опишет этот сложный тип в JSDoc? Visual Studio Code, WebStorm и пр. понимают синтаксис JSDoc, что позволяет использовать автоматическое дополнение, подсказки и ранний анализ кода.
Ответить с цитированием
  #10 (permalink)  
Старый 13.05.2020, 18:32
Аватар для рони
Профессор
Отправить личное сообщение для рони Посмотреть профиль Найти все сообщения от рони
 
Регистрация: 27.05.2010
Сообщений: 33,109

Malleys,
1 мне сложно понять, при чём тут скорость ...
2 что вам мешает записать все изменения в одном цикле!!!
qsf("#a .b")(e => abcd)
3. увы , я не владею современными средствами разработки, туго как то с наукой и учителями.
Ответить с цитированием
Ответ



Опции темы Искать в теме
Искать в теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Как сделать спойлер для текста kos0760 Элементы интерфейса 11 27.03.2018 23:09
Расширение для Safari. Как вызвать функцию из popover в global page? housewm Opera, Safari и др. 0 21.12.2013 06:07
Как сделать для нескольких форм? j.r.r AJAX и COMET 8 08.09.2013 16:32
Как сделать выполнение ф-ции только для видимых объектов на экране? Randomizer jQuery 6 21.01.2013 16:06
Как сделать функцию типа toDataUrl для рисунка в ie6 ? Олег Общие вопросы Javascript 2 14.09.2008 00:06