Как рациональнее всего создать разные счетчики?

Есть ли какой-то способ добавлять неограниченное количество таких же счетчиков без копипаста? Как-то не совсем красиво выйдет если будет много одинакового кода.

let buttonCountPlus = document.getElementById("buttonCountPlus");
    let buttonCountMinus = document.getElementById("buttonCountMinus");
    let count = document.getElementById("buttonCountNumber");
    const calculation = document.querySelector('#calculation');
    let price = 150;



   buttonCountPlus.addEventListener('click', () => {
       if (count.innerHTML < 4) {
           count.innerHTML++;
           calculation.innerHTML = count.innerHTML * price;
       }
   });

   buttonCountMinus.addEventListener('click', () => {
       if (count.innerHTML > 0) {
           count.innerHTML--;
           calculation.innerHTML = count.innerHTML * price;
       }
   })
 #counter {
            display: flex;
            justify-content: space-between;
            width: 80px;
        }
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
   
</head>
<body class="container">
<div id="counter">
    <input type="button" id="buttonCountPlus" value="+">
    <div id="buttonCountNumber">1</div>
    <input type="button" id="buttonCountMinus" value="-">
</div>

<div id="calculation">150</div>
</script>
</body>
</html>

Сделал таким образом. Можно копипастить дивы, без добавления лишнего кода. Спасибо в комментариях за наводку

 const plus = document.querySelectorAll('.plus');
    const minus = document.querySelectorAll('.minus');
    const result = document.querySelectorAll('.result');

    function min() {
        return function (ev) {
            if (ev.target.nextElementSibling.innerHTML > 0) {
                return --ev.target.nextElementSibling.innerHTML;
            }
        }
    }

    function pl() {
        return function (ev) {
            return ++ev.target.previousElementSibling.innerHTML;
        }
    }

    minus.forEach(function (dominus) {
        dominus.addEventListener('click', min());
    })

    plus.forEach(function (doplus) {
        doplus.addEventListener('click', pl());
    })
.counter {
            display: flex;
            justify-content: space-between;
            width: 80px;
            margin-bottom: 20px;
        }
<div class = "counter">
    <button class = "minus">-</button>
    <div class = "result">1</div>
    <button class = "plus">+</button>
</div>
<div class = "counter">
    <button class = "minus">-</button>
    <div class = "result">1</div>
    <button class = "plus">+</button>
</div>
<div class = "counter">
    <button class = "minus">-</button>
    <div class = "result">1</div>
    <button class = "plus">+</button>
</div>


Ответы (1 шт):

Автор решения: OPTIMUS PRIME

Можно организовать это дело с помощью Классов (а можете переписать то же самое в виде обычных функций (замыканий), вопрос удобства / вкуса):

class Counter {

  constructor(price, qty_max = 4) {
    this.root = this._create_element(price);

    this._qty = {
      curr: 1,
      max: qty_max,
    };
    
    this._price = price;

    this._elem = {
      qty: this.root.querySelector(".qty"),
      total: this.root.querySelector(".total"),
    };    
    
    this._apply_increment();
    this._apply_decrement();
  }

  _create_element(price) {
    let html = (`
      <div class="counter">
        <button class="minus">-</button>
        <div class="qty">1</div>
        <button class="plus">+</button>

        <div class="total">${ price }</div>
      </div>
    `);

    let div = document.createElement("div");
    div.innerHTML = html;

    return div.firstElementChild;
  }

  _count(delta) {
    this._qty.curr = Math.max(0, Math.min(this._qty.max, this._qty.curr + delta));

    this._elem.qty.textContent = this._qty.curr;
    this._elem.total.textContent = this._qty.curr * this._price;
  }

  _apply_increment() {
    let btn = this.root.querySelector(".plus");
    btn.addEventListener("click", () => this._count(+1));
  }

  _apply_decrement() {
    let btn = this.root.querySelector(".minus");
    btn.addEventListener("click", () => this._count(-1));
  }

}

document.body.appendChild(new Counter(150, 4).root);
document.body.appendChild(new Counter(200, 5).root);
document.body.appendChild(new Counter(250, 6).root);
.qty {
  display: inline-block;
  width: 50px;
  text-align: center;
}

.total {
  padding: 4px 0;
  font-size: 18px;
}

→ Ссылка