// Take a DOM element and wrap it in a list item element. function itemise(el) { const li = document.createElement('li'); li.appendChild(el); return li; }
const itemise = function(el) { const li = document.createElement('li'); li.appendChild(el); return li; }
const itemise = (el) => { const li = document.createElement('li'); li.appendChild(el); return li; }
document.querySelectorAll()
, then the answer is not an array, but NodeList
. NodeList
no .map()
method, like arrays, so let's write this: // Apply a given function to every item in a NodeList and return an array. function elListMap(transform, list) { // list might be a NodeList, which doesn't have .map(), so we convert // it to an array. return [...list].map(transform); } // Grab all the spans on the page with the class 'for-listing'. const mySpans = document.querySelectorAll('span.for-listing'); // Wrap each one inside an <li> element. We re-use the // itemise() function from earlier. const wrappedList = elListMap(itemise, mySpans);
elListMap
function. But we can use elListMap
not only to create lists. For example, with its help you can add a class to a set of elements: function addSpinnerClass(el) { el.classList.add('spinner'); return el; } // Find all the buttons with class 'loader' const loadButtons = document.querySelectorAll('button.loader'); // Add the spinner class to all the buttons we found. elListMap(addSpinnerClass, loadButtons);
elLlistMap
takes another function as a parameter and converts it. That is, we can use elListMap
to solve different problems.li
elements and wrap in ul
. Easy: function wrapWithUl(children) { const ul = document.createElement('ul'); return [...children].reduce((listEl, child) => { listEl.appendChild(child); return listEl; }, ul); }
div
? No problem, we will write another function for this: function wrapWithDiv(children) { const div = document.createElement('div'); return [...children].reduce((divEl, child) => { divEl.appendChild(child); return divEl; }, div); }
function createListWrapperFunction(elementType) { // Straight away, we return a function. return function wrap(children) { // Inside our wrap function, we can 'see' the elementType parameter. const parent = document.createElement(elementType); return [...children].reduce((parentEl, child) => { parentEl.appendChild(child); return parentEl; }, parent); } }
elementType
parameter. And then, when we call the returned function, it already knows which element to create. Therefore, you can create wrapWithUl
and wrapWithDiv
: const wrapWithUl = createListWrapperFunction('ul'); // Our wrapWithUl() function now 'remembers' that it creates a ul element. const wrapWithDiv = createListWreapperFunction('div'); // Our wrapWithDiv() function now 'remembers' that it creates a div element.
.addEventListener()
method. We use it when we want to perform actions in response to some events. For example, I want to make a button that issues a warning: function showAlert() { alert('Fallacies do not cease to be fallacies because they become fashions'); } document.body.innerHTML += `<button type="button" class="js-alertbtn"> Show alert </button>`; const btn = document.querySelector('.js-alertbtn'); btn.addEventListener('click', showAlert);
showAlert()
function as an argument to btn.addEventListener()
..map()
, .filter()
and .reduce()
. As in the elListMap()
function: function elListMap(transform, list) { return [...list].map(transform); }
setTimeout()
and setInterval()
functions help control when functions are executed. For example, if you need to remove the highlight
class after 30 seconds, you can do it like this: function removeHighlights() { const highlightedElements = document.querySelectorAll('.highlighted'); elListMap(el => el.classList.remove('highlighted'), highlightedElements); } setTimeout(removeHighlights, 30000);
function maybe(fn) return function _maybe(...args) { // Note that the == is deliberate. if ((args.length === 0) || args.some(a => (a == null)) { return undefined; } return fn.apply(this, args); } }
elListMap()
function: // Apply a given function to every item in a NodeList and return an array. function elListMap(transform, list) { // list might be a NodeList, which doesn't have .map(), so we convert // it to an array. return [...list].map(transform); }
elListMap()
null or undefined value? We get a TypeError and drop the current operation, whatever it is. You can avoid this by using the maybe()
function: const safeElListMap = maybe(elListMap); safeElListMap(x => x, null); // ← undefined
undefined
. And if we passed it to another function protected by maybe()
, then in response we would get undefined
again. With maybe()
you can protect any number of functions, it is much easier to write a billion if
.connect()
..sort()
method. Yes, he has flaws. It changes the array instead of returning a new one. But let's forget about it for now. The .sort()
method is a higher order function; it takes another function as one of the parameters. function compareNumbers(a, b) { if (a === b) return 0; if (a > b) return 1; /* else */ return -1; }
let nums = [7, 3, 1, 5, 8, 9, 6, 4, 2]; nums.sort(compareNumbers); console.log(nums); // 〕[1, 2, 3, 4, 5, 6, 7, 8, 9]
let typeaheadMatches = [ { keyword: 'bogey', weight: 0.25, matchedChars: ['bog'], }, { keyword: 'bog', weight: 0.5, matchedChars: ['bog'], }, { keyword: 'boggle', weight: 0.3, matchedChars: ['bog'], }, { keyword: 'bogey', weight: 0.25, matchedChars: ['bog'], }, { keyword: 'toboggan', weight: 0.15, matchedChars: ['bog'], }, { keyword: 'bag', weight: 0.1, matchedChars: ['b', 'g'], } ];
function compareTypeaheadResult(word1, word2) { return -1 * compareNumbers(word1.weight, word2.weight); } typeaheadMatches.sort(compareTypeaheadResult); console.log(typeaheadMatches); // 〕[{keyword: "bog", weight: 0.5, matchedChars: ["bog"]}, … ]
.sort()
method helps us: “If you give me a comparison function, I will sort out any array. Do not worry about its contents. If you give a sort function, I will sort it out. ” Therefore, we do not need to write the sorting algorithm ourselves; we will focus on a much simpler problem of comparing two elements..sort()
method. We will have to write a new sort function every time we need to sort an array of a different kind. Or you have to reinvent the same with function pointers or objects. In any case, it will be very awkward..sort()
to use a faster algorithm. Then your code will benefit, regardless of what is inside the sorted arrays. And this scheme is true for a whole set of higher-order array functions ..sort()
method abstracts the sorting task from the contents of an array. This is called separation of concerns. Higher-order functions allow you to create abstractions that would be very cumbersome or even impossible without them. And the creation of abstractions accounts for 80% of the work of software engineers.Source: https://habr.com/ru/post/458896/
All Articles