Created
July 20, 2015 16:00
-
-
Save pbakondy/dd0a9c8b3e3c24db185e to your computer and use it in GitHub Desktop.
7 Essential JavaScript Functions
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// http://davidwalsh.name/essential-javascript-functions | |
/* | |
debounce | |
The debounce function can be a game-changer when it comes to event-fueled performance. | |
If you aren't using a debouncing function with a scroll, resize, key* event, you're | |
probably doing it wrong. Here's a debounce function to keep your code efficient: | |
*/ | |
// 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); | |
//The debounce function will not allow a callback to be used more than once per given time frame. | |
//This is especially important when assigning a callback function to frequently-firing events. | |
/* | |
poll | |
As I mentioned with the debounce function, sometimes you don't get to plug into an event | |
to signify a desired state -- if the event doesn't exist, you need to check for your | |
desired state at intervals: | |
*/ | |
function poll(fn, callback, errback, timeout, interval) { | |
var endTime = Number(new Date()) + (timeout || 2000); | |
interval = interval || 100; | |
(function p() { | |
// If the condition is met, we're done! | |
if(fn()) { | |
callback(); | |
} | |
// If the condition isn't met but the timeout hasn't elapsed, go again | |
else if (Number(new Date()) < endTime) { | |
setTimeout(p, interval); | |
} | |
// Didn't match and too much time, reject! | |
else { | |
errback(new Error('timed out for ' + fn + ': ' + arguments)); | |
} | |
})(); | |
} | |
// Usage: ensure element is visible | |
poll( | |
function() { | |
return document.getElementById('lightbox').offsetWidth > 0; | |
}, | |
function() { | |
// Done, success callback | |
}, | |
function() { | |
// Error, failure callback | |
} | |
); | |
// Polling has long been useful on the web and will continue to be in the future! | |
/* | |
once | |
There are times when you prefer a given functionality only happen once, similar to | |
the way you'd use an onload event. This code provides you said functionality: | |
*/ | |
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 | |
// The once function ensures a given function can only be called once, thus prevent duplicate initialization! | |
/* | |
getAbsoluteUrl | |
Getting an absolute URL from a variable string isn't as easy as you think. There's the URL constructor | |
but it can act up if you don't provide the required arguments (which sometimes you can't). Here's a | |
suave trick for getting an absolute URL from and string input: | |
*/ | |
var getAbsoluteUrl = (function() { | |
var a; | |
return function(url) { | |
if(!a) a = document.createElement('a'); | |
a.href = url; | |
return a.href; | |
}; | |
})(); | |
// Usage | |
getAbsoluteUrl('/something'); // http://davidwalsh.name/something | |
//The "burn" element href handles and URL nonsense for you, providing a reliable absolute URL in return. | |
/* | |
isNative | |
Knowing if a given function is native or not can signal if you're willing to override it. | |
This handy code can give you the answer: | |
*/ | |
;(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 | |
//The function isn't pretty but it gets the job done! | |
/* | |
insertRule | |
We all know that we can grab a NodeList from a selector (via document.querySelectorAll) and | |
give each of them a style, but what's more efficient is setting that style to a selector | |
(like you do in a stylesheet): | |
*/ | |
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); | |
//This is especially useful when working on a dynamic, AJAX-heavy site. If you set the style | |
//to a selector, you don't need to account for styling each element that may match that selector (now or in the future). | |
/* | |
matchesSelector | |
Oftentimes we validate input before moving forward; ensuring a truthy value, ensuring forms | |
data is valid, etc. But how often do we ensure an element qualifies for moving forward? | |
You can use a matchesSelector function to validate if an element is of a given selector match: | |
*/ | |
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]') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment