Vzpomínám si na rané dny JavaScriptu, kdy jste potřebovali jednoduchou funkci téměř na všechno, protože dodavatelé prohlížečů implementovali funkce jinak, a ne pouze okrajové funkce, základní funkce, jako je addEventListener
a attachEvent
. Doba se změnila, ale stále existuje několik funkcí, které by každý vývojář měl mít ve svém arzenálu, pro výkon pro účely funkční jednoduchosti.
debounce
Funkce debounce může změnit hru, pokud jde o výkon nabitý událostmi. Pokud nepoužíváte funkci debouncing s scroll
, resize
, key*
pravděpodobně to děláte špatně. Zde je debounce
funkce pro udržení účinnosti kódu:
// Returns a function, that, as long as it continues to be invoked, will not // be triggered. The function will be called after it stops being called for // N milliseconds. If `immediate` is passed, trigger the function on the // leading edge, instead of the trailing. function debounce(func, wait, immediate) { var timeout; return function() { var context = this, args = arguments; var later = function() { timeout = null; if (!immediate) func.apply(context, args); }; var callNow = immediate && !timeout; clearTimeout(timeout); timeout = setTimeout(later, wait); if (callNow) func.apply(context, args); }; }; // Usage var myEfficientFn = debounce(function() { // All the taxing stuff you do }, 250); window.addEventListener('resize', myEfficientFn);
debounce
funkce neumožní použít zpětné volání více než jednou za daný časový rámec. To je důležité zejména při přiřazování funkce zpětného volání k často se spouštějícím událostem.
poll
Jak jsem zmínil u debounce
Někdy se vám nepodaří zapojit se do události, která označí požadovaný stav – pokud událost neexistuje, musíte požadovaný stav v určitých intervalech kontrolovat:
// The polling function function poll(fn, timeout, interval) { var endTime = Number(new Date()) + (timeout || 2000); interval = interval || 100; var checkCondition = function(resolve, reject) { // If the condition is met, we're done! var result = fn(); if(result) { resolve(result); } // If the condition isn't met but the timeout hasn't elapsed, go again else if (Number(new Date()) < endTime) { setTimeout(checkCondition, interval, resolve, reject); } // Didn't match and too much time, reject! else { reject(new Error('timed out for ' + fn + ': ' + arguments)); } }; return new Promise(checkCondition); } // Usage: ensure element is visible poll(function() { return document.getElementById('lightbox').offsetWidth > 0; }, 2000, 150).then(function() { // Polling done, now do something else! }).catch(function() { // Polling timed out, handle the error! });
Dotazování je na webu užitečné již dlouho a bude i v budoucnu!
once
Jsou chvíle, kdy dáváte přednost tomu, aby daná funkce proběhla pouze jednou, podobně jako byste použili onload
událost. Tento kód poskytuje vámi uvedenou funkci:
function once(fn, context) { var result; return function() { if(fn) { result = fn.apply(context || this, arguments); fn = null; } return result; }; } // Usage var canOnlyFireOnce = once(function() { console.log('Fired!'); }); canOnlyFireOnce(); // "Fired!" canOnlyFireOnce(); // nada
once
Funkce zajišťuje, že daná funkce může být volána pouze jednou, čímž se zabrání duplicitní inicializaci!
getAbsoluteUrl
Získání absolutní adresy URL z proměnného řetězce není tak snadné, jak si myslíte. Je tam URL
konstruktor, ale může fungovat, pokud neposkytnete požadované argumenty (což někdy nemůžete). Zde je zdvořilý trik pro získání absolutní adresy URL a zadání řetězce:
var getAbsoluteUrl = (function() { var a; return function(url) { if(!a) a = document.createElement('a'); a.href = url; return a.href; }; })(); // Usage getAbsoluteUrl('/something'); // https://davidwalsh.name/something
Prvek "vypálit" href
manipulace a nesmyslné adresy URL za vás a na oplátku poskytují spolehlivou absolutní adresu URL.
isNative
Vědět, zda je daná funkce nativní nebo ne, může signalizovat, zda jste ochotni ji přepsat. Tento praktický kód vám může dát odpověď:
;(function() { // Used to resolve the internal `[[Class]]` of values var toString = Object.prototype.toString; // Used to resolve the decompiled source of functions var fnToString = Function.prototype.toString; // Used to detect host constructors (Safari > 4; really typed array specific) var reHostCtor = /^\[object .+?Constructor\]$/; // Compile a regexp using a common native method as a template. // We chose `Object#toString` because there's a good chance it is not being mucked with. var reNative = RegExp('^' + // Coerce `Object#toString` to a string String(toString) // Escape any special regexp characters .replace(/[.*+?^${}()|[\]\/\\]/g, '\\$&') // Replace mentions of `toString` with `.*?` to keep the template generic. // Replace thing like `for ...` to support environments like Rhino which add extra info // such as method arity. .replace(/toString|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$' ); function isNative(value) { var type = typeof value; return type == 'function' // Use `Function#toString` to bypass the value's own `toString` method // and avoid being faked out. ? reNative.test(fnToString.call(value)) // Fallback to a host object check because some environments will represent // things like typed arrays as DOM methods which may not conform to the // normal native pattern. : (value && type == 'object' && reHostCtor.test(toString.call(value))) || false; } // export however you want module.exports = isNative; }()); // Usage isNative(alert); // true isNative(myCustomFunction); // false
Funkce není hezká, ale svou práci zvládne!
insertRule
Všichni víme, že můžeme získat NodeList ze selektoru (přes document.querySelectorAll
) a každému z nich přiřaďte styl, ale efektivnější je nastavení tohoto stylu na selektor (jako to děláte v šabloně stylů):
var sheet = (function() { // Create the <style> tag var style = document.createElement('style'); // Add a media (and/or media query) here if you'd like! // style.setAttribute('media', 'screen') // style.setAttribute('media', 'only screen and (max-width : 1024px)') // WebKit hack :( style.appendChild(document.createTextNode('')); // Add the <style> element to the page document.head.appendChild(style); return style.sheet; })(); // Usage sheet.insertRule("header { float: left; opacity: 0.8; }", 1);
To je užitečné zejména při práci na dynamickém webu s vysokým obsahem AJAX. Pokud nastavíte styl na selektor, nemusíte zohledňovat styling každého prvku, který se tomuto selektoru může shodovat (nyní nebo v budoucnu).
matchesSelector
Často před pokračováním ověřujeme vstup; zajištění pravdivé hodnoty, zajištění platnosti údajů ve formulářích atd. Jak často ale zajistíme, aby se prvek kvalifikoval pro posun vpřed? Můžete použít matchesSelector
funkce pro ověření, zda prvek odpovídá dané selektorové shodě:
function matchesSelector(el, selector) { var p = Element.prototype; var f = p.matches || p.webkitMatchesSelector || p.mozMatchesSelector || p.msMatchesSelector || function(s) { return [].indexOf.call(document.querySelectorAll(s), this) !== -1; }; return f.call(el, selector); } // Usage matchesSelector(document.getElementById('myDiv'), 'div.someSelector[some-attribute=true]')
Tady to máte: sedm funkcí JavaScriptu, které by měl mít každý vývojář ve svém panelu nástrojů. Máte nějakou funkci, kterou jsem vynechal? Prosím sdílejte to!