7 Základní funkce JavaScriptu

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!