const nestedToPlain = (obj, path = '') =>
Object.entries(obj).reduce((acc, [ k, v ]) => {
const newPath = `${path}${path ? '.' : ''}${k}`;
return Object.assign(acc, v instanceof Object
? nestedToPlain(v, newPath)
: { [newPath]: v }
);
}, {});
const plain = nestedToPlain(example, 'example');
const nestedToPlain = (obj, keys = []) =>
Object.entries(obj).reduce((acc, [ k, v ]) => (
keys.push(k),
Object.assign(acc, v instanceof Object
? nestedToPlain(v, keys)
: { [keys.join('.')]: v }
),
keys.pop(),
acc
), {});
const plain = nestedToPlain(example, [ 'example' ]);
const nestedToPlain = function(obj, keys = []) {
const result = {};
const [ push, pop ] = this;
for (const stack = [ obj ]; stack.length;) {
const n = stack.pop();
if (n instanceof Object) {
Object.entries(n).reverse().forEach(([ k, v ]) => stack.push(pop, v, k, push));
} else if (n === push) {
keys.push(stack.pop());
} else if (n === pop) {
keys.pop();
} else {
result[keys.join('.')] = n;
}
}
return result;
}.bind([ Symbol(), Symbol() ]);
const plain = nestedToPlain(example, [ 'example' ]);
const newArr = arr
.filter(function(n) {
return !(this[n.country] = this.hasOwnProperty(n.country));
}, {})
.map((n, i) => ({ id: i + 1, country: n.country }));
const newArr = Object.values(arr.reduce((acc, { country }) => {
acc[0][country] = acc[0][country] || { id: ++acc[1], country };
return acc;
}, [ {}, 0 ])[0]);
const newArr = Array.from(arr.reduce((acc, { country: n }) => (
acc.set(n, acc.get(n) || { id: -~acc.size, country: n })
), new Map).values());
state = {
active: null,
}
toggle = ({ target: { dataset: { name } } }) => {
this.setState(({ active }) => ({
active: active === name ? null : name,
}));
}
<button onClick={this.toggle} data-name="collapse_1"></button>
<button onClick={this.toggle} data-name="collapse_2"></button>
<button onClick={this.toggle} data-name="collapse_3"></button>
toggle = ({ target: { dataset: { name } } }) => {
this.setState(({ collapse }) => ({
collaple: {
...collapse,
[name]: !collapse[name],
},
}));
}
const keys = [ 'firstName', 'lastName' ];
const values = document.querySelector('input').value.toLowerCase().match(/\S+/g) || [];
const result = arr.filter(n => keys.some(k => values.some(v => n[k].toLowerCase().includes(v))));
Нетривиальная задача
<svg
data-color-index="-1"
data-color-attr="fill"
...
<span
data-color-index="-1"
data-color-attr="color"
...
$('svg, span').mouseenter(function() {
const colorIndex = (+this.dataset.colorIndex + 1) % colors.length;
$(this).css(this.dataset.colorAttr, colors[colorIndex]);
this.dataset.colorIndex = colorIndex;
}).mouseleave(function() {
$(this).css(this.dataset.colorAttr, '');
});
let index = -1;
$('.demo').mouseenter(function() {
index = (index + 1) % colors.length;
updateColor(this, colors[index]);
}).mouseleave(function() {
updateColor(this, '');
});
function updateColor(el, color) {
$('[data-color-attr]', el).each(function() {
$(this).css(this.dataset.colorAttr, color);
});
}
function sum(...values) {
const s = values.reduce((acc, n) => acc + n, 0);
const f = sum.bind(null, s);
f.valueOf = () => s;
return f;
}
Object.entries(Obj).reduce((acc, [ k, v ]) => ((acc[v] = acc[v] || []).push(k), acc), {})
- .popup.visible {
+ .item.visible .popup {
const container = document.querySelector('.container');
const itemSelector = '.item';
const activeClass = 'visible';
const toggleItem = (item, items) =>
items.forEach(n => n.classList[n === item ? 'toggle' : 'remove'](activeClass));
// делегирование, назначаем обработчик клика один раз для всех item'ов
container.addEventListener('click', function({ target: t }) {
if (t.matches(itemSelector)) {
toggleItem(t, this.querySelectorAll(itemSelector));
}
});
// или, каждому item'у назначаем обработчик клика индивидуально
const items = container.querySelectorAll(itemSelector);
items.forEach(n => n.addEventListener('click', onClick));
function onClick({ target: t }) {
if (this === t) {
toggleItem(t, items);
}
}
const itemSelector = '.accordion_item';
const buttonSelector = `${itemSelector} .title_block`;
const contentSelector = '.info';
const activeClass = 'active_block';
const toggleEffect = 'slideToggle'; // или fadeToggle, или toggle
const onClick = e => $(e.currentTarget)
.closest(itemSelector)
.toggleClass(activeClass)
.find(contentSelector)
[toggleEffect]();
// обработчик клика подключаем к заголовкам
$(buttonSelector).click(onClick);
// или, если предполагается добавление новых секций аккордеона уже после
// подключения обработчика, то лучше будет повесить его на документ,
// дополнительно указав, у каких элементов надо слушать событие;
// в этом случае клики по динамически добавляемым элементам будут
// обрабатываться так же, как и по тем, что существовали изначально
$(document).on('click', buttonSelector, onClick);
autoFocus={true}
и отключать редактирование по событию blur. Так проблема с ненужным срабатыванием обработчика клика решится сама собой.window.addEventListener('load', function() {
var ctx = document.getElementById('canvas').getContext('2d');
window.myLine = new Chart(ctx, config);
});
function connectInputs(selector) {
const onInput = e => $inputs.val(e.target.value);
const $inputs = $(selector).on('input', onInput);
return () => $inputs.off('input', onInput);
}
connectInputs('#input, #output');
function connectInputs([...inputs]) {
const onInput = e => inputs.forEach(n => n.value = e.target.value);
inputs.forEach(n => n.addEventListener('input', onInput));
return () => inputs.forEach(n => n.removeEventListener('input', onInput));
}
connectInputs(document.querySelectorAll('#input, #output'));