Делаем просто:
const result = [...str].reduce((acc, n) => (acc[n] = -~acc[n], acc), {});
Делаем сложно, решаем задачу в более общем виде - вот функция, считающая повторения произвольных значений:
function count(data, key = n => n) {
const getKey = key instanceof Function ? key : n => n[key];
const result = {};
for (const n of data) {
const k = getKey(n);
result[k] = (result[k] ?? 0) + 1;
}
return result;
}
В вашем случае применять так:
const result = count(str);.
Работать можно не только со строками, но и, например, с массивами:
count([{name: 'A'}, {name: 'B'}, {name: 'B'}, {name: 'B'}], 'name'); // {A: 1, B: 3}
Или коллекциями DOM-элементов:
<div data-country="USA">New York</div>
<div data-country="USA">Boston</div>
<div data-country="USA">Las Vegas</div>
<div data-country="Japan">Osaka</div>
<div data-country="Japan">Tokyo</div>
<div data-country="Japan">Kyoto</div>
<div data-country="Japan">Yokohama</div>
<div data-country="Germany">Munich</div>
<div data-country="Germany">Dresden</div>
const cities = document.querySelectorAll('[data-country]');
count(cities, n => n.dataset.country); // {USA: 3, Japan: 4, Germany: 2}
Вообще, с любыми итерируемыми объектами работать можно:
count(Array(9).keys(), n => [ 'чётные', 'нечётные' ][n & 1]) // {чётные: 5, нечётные: 4}