Created
December 25, 2021 20:49
-
-
Save bgoonz/3db10bb662f66b0b564c7d748226153d to your computer and use it in GitHub Desktop.
This file has been truncated, but you can view the full file.
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
<!doctype html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8" /> | |
<meta name="viewport" content="width=device-width, initial-scale=1" /> | |
<link rel="profile" href="https://gmpg.org/xfn/11" /> | |
<title>Web Development Resources Site – webdevhub</title> | |
<meta name='robots' content='max-image-preview:large' /> | |
<link rel='dns-prefetch' href='//webdevhubcom.wordpress.com' /> | |
<link rel='dns-prefetch' href='//s0.wp.com' /> | |
<link rel='dns-prefetch' href='//wordpress.com' /> | |
<link rel='dns-prefetch' href='//fonts.googleapis.com' /> | |
<link rel="alternate" type="application/rss+xml" title="Web Development Resources Site » Feed" href="https://web-dev-hub.com/feed/" /> | |
<link rel="alternate" type="application/rss+xml" title="Web Development Resources Site » Comments Feed" href="https://web-dev-hub.com/comments/feed/" /> | |
<script type="text/javascript"> | |
/* <![CDATA[ */ | |
function addLoadEvent(func) { | |
var oldonload = window.onload; | |
if (typeof window.onload != 'function') { | |
window.onload = func; | |
} else { | |
window.onload = function () { | |
oldonload(); | |
func(); | |
} | |
} | |
} | |
/* ]]> */ | |
</script> | |
<script type="text/javascript"> | |
window._wpemojiSettings = {"baseUrl":"https:\/\/s0.wp.com\/wp-content\/mu-plugins\/wpcom-smileys\/twemoji\/2\/72x72\/","ext":".png","svgUrl":"https:\/\/s0.wp.com\/wp-content\/mu-plugins\/wpcom-smileys\/twemoji\/2\/svg\/","svgExt":".svg","source":{"concatemoji":"https:\/\/s0.wp.com\/wp-includes\/js\/wp-emoji-release.min.js?m=1625065786h&ver=5.8.2"}}; | |
!function(e,a,t){var n,r,o,i=a.createElement("canvas"),p=i.getContext&&i.getContext("2d");function s(e,t){var a=String.fromCharCode;p.clearRect(0,0,i.width,i.height),p.fillText(a.apply(this,e),0,0);e=i.toDataURL();return p.clearRect(0,0,i.width,i.height),p.fillText(a.apply(this,t),0,0),e===i.toDataURL()}function c(e){var t=a.createElement("script");t.src=e,t.defer=t.type="text/javascript",a.getElementsByTagName("head")[0].appendChild(t)}for(o=Array("flag","emoji"),t.supports={everything:!0,everythingExceptFlag:!0},r=0;r<o.length;r++)t.supports[o[r]]=function(e){if(!p||!p.fillText)return!1;switch(p.textBaseline="top",p.font="600 32px Arial",e){case"flag":return s([127987,65039,8205,9895,65039],[127987,65039,8203,9895,65039])?!1:!s([55356,56826,55356,56819],[55356,56826,8203,55356,56819])&&!s([55356,57332,56128,56423,56128,56418,56128,56421,56128,56430,56128,56423,56128,56447],[55356,57332,8203,56128,56423,8203,56128,56418,8203,56128,56421,8203,56128,56430,8203,56128,56423,8203,56128,56447]);case"emoji":return!s([10084,65039,8205,55357,56613],[10084,65039,8203,55357,56613])}return!1}(o[r]),t.supports.everything=t.supports.everything&&t.supports[o[r]],"flag"!==o[r]&&(t.supports.everythingExceptFlag=t.supports.everythingExceptFlag&&t.supports[o[r]]);t.supports.everythingExceptFlag=t.supports.everythingExceptFlag&&!t.supports.flag,t.DOMReady=!1,t.readyCallback=function(){t.DOMReady=!0},t.supports.everything||(n=function(){t.readyCallback()},a.addEventListener?(a.addEventListener("DOMContentLoaded",n,!1),e.addEventListener("load",n,!1)):(e.attachEvent("onload",n),a.attachEvent("onreadystatechange",function(){"complete"===a.readyState&&t.readyCallback()})),(n=t.source||{}).concatemoji?c(n.concatemoji):n.wpemoji&&n.twemoji&&(c(n.twemoji),c(n.wpemoji)))}(window,document,window._wpemojiSettings); | |
</script> | |
<style type="text/css"> | |
img.wp-smiley, | |
img.emoji { | |
display: inline !important; | |
border: none !important; | |
box-shadow: none !important; | |
height: 1em !important; | |
width: 1em !important; | |
margin: 0 .07em !important; | |
vertical-align: -0.1em !important; | |
background: none !important; | |
padding: 0 !important; | |
} | |
</style> | |
<link rel='stylesheet' id='all-css-0-1' href='https://s0.wp.com/_static/??-eJylUttuwjAM/aGloQghXqZ9Sy5eMeSmOAH693NbVkG5aNJeIh/b5/gSy3MSJoYCoUhfRXK1w0DynEz0gjw66BeoMUQf8jmNqiaTMRWMjL6jc/H8Ln8fT5CFrlo7YHbpHczpGIyrlt3skFbRHlmAGo/hMeVAsnD8qONlNh7q/hZVPol1s5KKCMokP7gm+VekrjLUkDuOZJCndt0MGrqis1K7aI7Coc4q94sx/iFU9uCf7IOH9WBRgePwsM8bkJzqeaMOOmX6l7u6o3PsFt+RXjc/dspiUJIaWlZ9rEV0Ge2f519IZFUwdMsrWNJNvNLWTbtrWkHokwNpkcocE88lbu5OWZ5SaJWvpz3jiYQyxDLew2y8Uxs+kv0+qcdtvqFNpbVOGYgEvx6rF+Onj+W+/Ge73aza3Xaz3R1+AJ7xXpc=?cssminify=yes' type='text/css' media='all' /> | |
<style id='wp-block-library-inline-css'> | |
.has-text-align-justify { | |
text-align:justify; | |
} | |
</style> | |
<style id='wpcom-admin-bar-inline-css'> | |
.admin-bar { | |
position: inherit !important; | |
top: auto !important; | |
} | |
.admin-bar .goog-te-banner-frame { | |
top: 32px !important | |
} | |
@media screen and (max-width: 782px) { | |
.admin-bar .goog-te-banner-frame { | |
top: 46px !important; | |
} | |
} | |
@media screen and (max-width: 480px) { | |
.admin-bar .goog-te-banner-frame { | |
position: absolute; | |
} | |
} | |
</style> | |
<style id='global-styles-inline-css'> | |
body{--wp--preset--color--black: #000000;--wp--preset--color--cyan-bluish-gray: #abb8c3;--wp--preset--color--white: #ffffff;--wp--preset--color--pale-pink: #f78da7;--wp--preset--color--vivid-red: #cf2e2e;--wp--preset--color--luminous-vivid-orange: #ff6900;--wp--preset--color--luminous-vivid-amber: #fcb900;--wp--preset--color--light-green-cyan: #7bdcb5;--wp--preset--color--vivid-green-cyan: #00d084;--wp--preset--color--pale-cyan-blue: #8ed1fc;--wp--preset--color--vivid-cyan-blue: #0693e3;--wp--preset--color--vivid-purple: #9b51e0;--wp--preset--color--primary: #CD2220;--wp--preset--color--secondary: #007AB7;--wp--preset--color--foreground: #303030;--wp--preset--color--background: #FFFFFF;--wp--preset--gradient--vivid-cyan-blue-to-vivid-purple: linear-gradient(135deg,rgba(6,147,227,1) 0%,rgb(155,81,224) 100%);--wp--preset--gradient--light-green-cyan-to-vivid-green-cyan: linear-gradient(135deg,rgb(122,220,180) 0%,rgb(0,208,130) 100%);--wp--preset--gradient--luminous-vivid-amber-to-luminous-vivid-orange: linear-gradient(135deg,rgba(252,185,0,1) 0%,rgba(255,105,0,1) 100%);--wp--preset--gradient--luminous-vivid-orange-to-vivid-red: linear-gradient(135deg,rgba(255,105,0,1) 0%,rgb(207,46,46) 100%);--wp--preset--gradient--very-light-gray-to-cyan-bluish-gray: linear-gradient(135deg,rgb(238,238,238) 0%,rgb(169,184,195) 100%);--wp--preset--gradient--cool-to-warm-spectrum: linear-gradient(135deg,rgb(74,234,220) 0%,rgb(151,120,209) 20%,rgb(207,42,186) 40%,rgb(238,44,130) 60%,rgb(251,105,98) 80%,rgb(254,248,76) 100%);--wp--preset--gradient--blush-light-purple: linear-gradient(135deg,rgb(255,206,236) 0%,rgb(152,150,240) 100%);--wp--preset--gradient--blush-bordeaux: linear-gradient(135deg,rgb(254,205,165) 0%,rgb(254,45,45) 50%,rgb(107,0,62) 100%);--wp--preset--gradient--luminous-dusk: linear-gradient(135deg,rgb(255,203,112) 0%,rgb(199,81,192) 50%,rgb(65,88,208) 100%);--wp--preset--gradient--pale-ocean: linear-gradient(135deg,rgb(255,245,203) 0%,rgb(182,227,212) 50%,rgb(51,167,181) 100%);--wp--preset--gradient--electric-grass: linear-gradient(135deg,rgb(202,248,128) 0%,rgb(113,206,126) 100%);--wp--preset--gradient--midnight: linear-gradient(135deg,rgb(2,3,129) 0%,rgb(40,116,252) 100%);--wp--preset--duotone--dark-grayscale: url('#wp-duotone-dark-grayscale');--wp--preset--duotone--grayscale: url('#wp-duotone-grayscale');--wp--preset--duotone--purple-yellow: url('#wp-duotone-purple-yellow');--wp--preset--duotone--blue-red: url('#wp-duotone-blue-red');--wp--preset--duotone--midnight: url('#wp-duotone-midnight');--wp--preset--duotone--magenta-yellow: url('#wp-duotone-magenta-yellow');--wp--preset--duotone--purple-green: url('#wp-duotone-purple-green');--wp--preset--duotone--blue-orange: url('#wp-duotone-blue-orange');--wp--preset--font-size--small: 16.6px;--wp--preset--font-size--medium: 20px;--wp--preset--font-size--large: 26.45px;--wp--preset--font-size--x-large: 42px;--wp--preset--font-size--normal: 20px;--wp--preset--font-size--huge: 30.4174px;}.has-black-color{color: var(--wp--preset--color--black) !important;}.has-cyan-bluish-gray-color{color: var(--wp--preset--color--cyan-bluish-gray) !important;}.has-white-color{color: var(--wp--preset--color--white) !important;}.has-pale-pink-color{color: var(--wp--preset--color--pale-pink) !important;}.has-vivid-red-color{color: var(--wp--preset--color--vivid-red) !important;}.has-luminous-vivid-orange-color{color: var(--wp--preset--color--luminous-vivid-orange) !important;}.has-luminous-vivid-amber-color{color: var(--wp--preset--color--luminous-vivid-amber) !important;}.has-light-green-cyan-color{color: var(--wp--preset--color--light-green-cyan) !important;}.has-vivid-green-cyan-color{color: var(--wp--preset--color--vivid-green-cyan) !important;}.has-pale-cyan-blue-color{color: var(--wp--preset--color--pale-cyan-blue) !important;}.has-vivid-cyan-blue-color{color: var(--wp--preset--color--vivid-cyan-blue) !important;}.has-vivid-purple-color{color: var(--wp--preset--color--vivid-purple) !important;}.has-primary-color{color: var(--wp--preset--color--primary) !important;}.has-secondary-color{color: var(--wp--preset--color--secondary) !important;}.has-foreground-color{color: var(--wp--preset--color--foreground) !important;}.has-background-color{color: var(--wp--preset--color--background) !important;}.has-black-background-color{background-color: var(--wp--preset--color--black) !important;}.has-cyan-bluish-gray-background-color{background-color: var(--wp--preset--color--cyan-bluish-gray) !important;}.has-white-background-color{background-color: var(--wp--preset--color--white) !important;}.has-pale-pink-background-color{background-color: var(--wp--preset--color--pale-pink) !important;}.has-vivid-red-background-color{background-color: var(--wp--preset--color--vivid-red) !important;}.has-luminous-vivid-orange-background-color{background-color: var(--wp--preset--color--luminous-vivid-orange) !important;}.has-luminous-vivid-amber-background-color{background-color: var(--wp--preset--color--luminous-vivid-amber) !important;}.has-light-green-cyan-background-color{background-color: var(--wp--preset--color--light-green-cyan) !important;}.has-vivid-green-cyan-background-color{background-color: var(--wp--preset--color--vivid-green-cyan) !important;}.has-pale-cyan-blue-background-color{background-color: var(--wp--preset--color--pale-cyan-blue) !important;}.has-vivid-cyan-blue-background-color{background-color: var(--wp--preset--color--vivid-cyan-blue) !important;}.has-vivid-purple-background-color{background-color: var(--wp--preset--color--vivid-purple) !important;}.has-primary-background-color{background-color: var(--wp--preset--color--primary) !important;}.has-secondary-background-color{background-color: var(--wp--preset--color--secondary) !important;}.has-foreground-background-color{background-color: var(--wp--preset--color--foreground) !important;}.has-background-background-color{background-color: var(--wp--preset--color--background) !important;}.has-black-border-color{border-color: var(--wp--preset--color--black) !important;}.has-cyan-bluish-gray-border-color{border-color: var(--wp--preset--color--cyan-bluish-gray) !important;}.has-white-border-color{border-color: var(--wp--preset--color--white) !important;}.has-pale-pink-border-color{border-color: var(--wp--preset--color--pale-pink) !important;}.has-vivid-red-border-color{border-color: var(--wp--preset--color--vivid-red) !important;}.has-luminous-vivid-orange-border-color{border-color: var(--wp--preset--color--luminous-vivid-orange) !important;}.has-luminous-vivid-amber-border-color{border-color: var(--wp--preset--color--luminous-vivid-amber) !important;}.has-light-green-cyan-border-color{border-color: var(--wp--preset--color--light-green-cyan) !important;}.has-vivid-green-cyan-border-color{border-color: var(--wp--preset--color--vivid-green-cyan) !important;}.has-pale-cyan-blue-border-color{border-color: var(--wp--preset--color--pale-cyan-blue) !important;}.has-vivid-cyan-blue-border-color{border-color: var(--wp--preset--color--vivid-cyan-blue) !important;}.has-vivid-purple-border-color{border-color: var(--wp--preset--color--vivid-purple) !important;}.has-primary-border-color{border-color: var(--wp--preset--color--primary) !important;}.has-secondary-border-color{border-color: var(--wp--preset--color--secondary) !important;}.has-foreground-border-color{border-color: var(--wp--preset--color--foreground) !important;}.has-background-border-color{border-color: var(--wp--preset--color--background) !important;}.has-vivid-cyan-blue-to-vivid-purple-gradient-background{background: var(--wp--preset--gradient--vivid-cyan-blue-to-vivid-purple) !important;}.has-light-green-cyan-to-vivid-green-cyan-gradient-background{background: var(--wp--preset--gradient--light-green-cyan-to-vivid-green-cyan) !important;}.has-luminous-vivid-amber-to-luminous-vivid-orange-gradient-background{background: var(--wp--preset--gradient--luminous-vivid-amber-to-luminous-vivid-orange) !important;}.has-luminous-vivid-orange-to-vivid-red-gradient-background{background: var(--wp--preset--gradient--luminous-vivid-orange-to-vivid-red) !important;}.has-very-light-gray-to-cyan-bluish-gray-gradient-background{background: var(--wp--preset--gradient--very-light-gray-to-cyan-bluish-gray) !important;}.has-cool-to-warm-spectrum-gradient-background{background: var(--wp--preset--gradient--cool-to-warm-spectrum) !important;}.has-blush-light-purple-gradient-background{background: var(--wp--preset--gradient--blush-light-purple) !important;}.has-blush-bordeaux-gradient-background{background: var(--wp--preset--gradient--blush-bordeaux) !important;}.has-luminous-dusk-gradient-background{background: var(--wp--preset--gradient--luminous-dusk) !important;}.has-pale-ocean-gradient-background{background: var(--wp--preset--gradient--pale-ocean) !important;}.has-electric-grass-gradient-background{background: var(--wp--preset--gradient--electric-grass) !important;}.has-midnight-gradient-background{background: var(--wp--preset--gradient--midnight) !important;}.has-small-font-size{font-size: var(--wp--preset--font-size--small) !important;}.has-medium-font-size{font-size: var(--wp--preset--font-size--medium) !important;}.has-large-font-size{font-size: var(--wp--preset--font-size--large) !important;}.has-x-large-font-size{font-size: var(--wp--preset--font-size--x-large) !important;}.has-normal-font-size{font-size: var(--wp--preset--font-size--normal) !important;}.has-huge-font-size{font-size: var(--wp--preset--font-size--huge) !important;} | |
</style> | |
<link rel='stylesheet' id='print-css-3-1' href='https://s0.wp.com/wp-content/themes/pub/varia/print.css?m=1571655471h&cssminify=yes' type='text/css' media='print' /> | |
<link rel='stylesheet' id='all-css-4-1' href='https://s0.wp.com/_static/??-eJx9jUsOwjAMBS+EcfmoZYM4S5q6JSixI8dtxe0pYsNP3b2RZvRwzuCFjdjQrpSoYB5bTKIdMRa7R9r6Ujb435ucBoeB/UuFOXtJP0EaIcdxCFxwIIEo3lkQ/gDoowu6lrLY8uq6FBhapzDt12ylNsqwzAEX6w3XIpMCSlnUoBdN3/xML+m8q49V1ZyaQ317ABFzdpY=?cssminify=yes' type='text/css' media='all' /> | |
<link crossorigin="anonymous" rel='stylesheet' id='morden-fonts-css' href='https://fonts.googleapis.com/css?family=Noto+Sans%3A400%2C400i%2C700%2C700i&subset=latin%2Clatin-ext' media='all' /> | |
<link rel='stylesheet' id='all-css-6-1' href='https://s0.wp.com/_static/??/wp-content/themes/pub/morden/style.css,/wp-content/mu-plugins/admin-bar/masterbar-overrides/masterbar.css?m=1640078736j&cssminify=yes' type='text/css' media='all' /> | |
<style id='jetpack-global-styles-frontend-style-inline-css'> | |
@import url('https://fonts.googleapis.com/css?family=Fira Sans:thin,extralight,light,regular,medium,semibold,bold,italic,bolditalic,extrabold,black|Playfair Display:thin,extralight,light,regular,medium,semibold,bold,italic,bolditalic,extrabold,black|');:root { --font-headings: Playfair Display; --font-base: Fira Sans; --font-headings-default: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif; --font-base-default: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;} | |
</style> | |
<link rel='stylesheet' id='all-css-8-1' href='https://s0.wp.com/wp-content/themes/h4/global.css?m=1420737423h&cssminify=yes' type='text/css' media='all' /> | |
<script data-ampdevmode> | |
( () => { | |
if ( 'amp-wizard-completion-preview' !== window.name ) { | |
return; | |
} | |
/** @type {HTMLStyleElement} */ | |
const style = document.createElement( 'style' ); | |
style.setAttribute( 'type', 'text/css' ); | |
style.appendChild( document.createTextNode( 'html { margin-top: 0 !important; } #wpadminbar { display: none !important; }' ) ); | |
document.head.appendChild( style ); | |
document.addEventListener( 'DOMContentLoaded', function() { | |
const adminBar = document.getElementById( 'wpadminbar' ); | |
if ( adminBar ) { | |
document.body.classList.remove( 'admin-bar' ); | |
adminBar.remove(); | |
} | |
}); | |
} )(); | |
</script> | |
<script id='wpcom-actionbar-placeholder-js-extra'> | |
var actionbardata = {"siteID":"190652711","siteURL":"https:\/\/web-dev-hub.com","xhrURL":"https:\/\/web-dev-hub.com\/wp-admin\/admin-ajax.php","nonce":"b0188b5d7f","isLoggedIn":"1","statusMessage":"","subsEmailDefault":"instantly","proxyScriptUrl":"https:\/\/s0.wp.com\/wp-content\/js\/wpcom-proxy-request.js?ver=20211021","i18n":{"followedText":"New posts from this site will now appear in your <a href=\"https:\/\/wordpress.com\/read\">Reader<\/a>","foldBar":"Collapse this bar","unfoldBar":"Expand this bar"}}; | |
</script> | |
<script crossorigin='anonymous' type='text/javascript' src='https://s0.wp.com/_static/??-eJyNzsEKwjAMBuAXsq3isHgQn2WrXUlJm9o0zL29PewgMkQIhISP5DdLUZAdysOzib2e4uu6NZ0g68gH8wupBKGOzX9iR7n53EwSVVACZDYsE7sKpQH1aSZEWr55P51oAvRK2Ncx9F3/O9OOq9hUqfRa9/Jx+SO33tQ93U6Xs7XHYbja+AbfjWT8'></script> | |
<script type='text/javascript'> | |
window.addEventListener( 'DOMContentLoaded', function() { | |
rltInitialize( {"token":"rlt-MnxGeFpOU1JjWUxZbklyYVlkb3UzUUVwMklFelBYOHNET1didTVxV3MwaVMxVVNJekhIaERFM082WDRPM3NCd25KQzR0M3QzSjVTUmdCV0N1b242VHpOaTdBaFZhRDhlNDVyeEMyME5VUDB4SHYvY0djb0FTb05hS3RuakNYMzdMMnFJUjlkNWp3RWE4QzRtbDgxUmhKRVkwNVovbWYrRUcrWjNNaVE2am5uMzdncGF6TG1uYy9McnV2L0YxM3RVWXBocnd3K3VWTEYxenVKak11ZWZZZ0VsT211bTlRc2tvMFhabHJaQXZGVVRlN210WWlOS1JNUGszR01kazl3dHI2ZElIajZiV2pSWlZjMUdCbXpsWU1MWVQzWkJoZkNud2oxMStIU1ZQV3hXQWxmYW9NZFVpWEUxRT18MmQyYzlkMTY1MWZjYTFjNTE1ZmMzMjUyZWE0NTU3ZDZjODkyOTg2NzdlMDgwNGQwfGQyNDQ2ZDM3YjY5ZGE2Nzk1M2ZhMmZmNzAyMDg0Njk0N2IyYTFiYThkNDA2NzMwZTcxMjYyYzU1ZjAxYTZmYTE4NjQyMjU0NjMyYjZlZWU5MjdhMDExMGVhODRiZTU0MGVlZTZiMWZlMWQzNDliZmQ5YjZlODE0Y2UyY2Y3MTA0","iframeOrigins":["https:\/\/widgets.wp.com"]} ); | |
} ); | |
</script> | |
<link rel='stylesheet' id='all-css-0-2' href='https://s0.wp.com/wp-content/mu-plugins/highlander-comments/style.css?m=1638269982h&cssminify=yes' type='text/css' media='all' /> | |
<link rel="EditURI" type="application/rsd+xml" title="RSD" href="https://webdevhubcom.wordpress.com/xmlrpc.php?rsd" /> | |
<link rel="wlwmanifest" type="application/wlwmanifest+xml" href="https://s0.wp.com/wp-includes/wlwmanifest.xml" /> | |
<meta name="generator" content="WordPress.com" /> | |
<link rel='shortlink' href='https://wp.me/cTXtJ' /> | |
<!-- Custom Logo: hide header text --> | |
<style id="custom-logo-css" type="text/css"> | |
.site-title, .site-description { | |
position: absolute; | |
clip: rect(1px, 1px, 1px, 1px); | |
} | |
</style> | |
<!-- Jetpack Open Graph Tags --> | |
<meta property="og:type" content="website" /> | |
<meta property="og:title" content="Web Development Resources Site" /> | |
<meta property="og:description" content="webdevhub" /> | |
<meta property="og:url" content="https://web-dev-hub.com/" /> | |
<meta property="og:site_name" content="Web Development Resources Site" /> | |
<meta property="og:image" content="https://webdevhubcom.files.wordpress.com/2021/03/image.jpg?w=200" /> | |
<meta property="og:image:width" content="200" /> | |
<meta property="og:image:height" content="200" /> | |
<meta property="og:image:alt" content="" /> | |
<meta property="og:locale" content="en_US" /> | |
<!-- End Jetpack Open Graph Tags --> | |
<link rel="search" type="application/opensearchdescription+xml" href="https://web-dev-hub.com/osd.xml" title="Web Development Resources Site" /> | |
<link rel="search" type="application/opensearchdescription+xml" href="https://s1.wp.com/opensearch.xml" title="WordPress.com" /> | |
<meta name="application-name" content="Web Development Resources Site" /><meta name="msapplication-window" content="width=device-width;height=device-height" /><meta name="msapplication-tooltip" content="webdevhub" /><meta name="msapplication-task" content="name=Write a post;action-uri=https://wordpress.com/post/web-dev-hub.com;icon-uri=https://s0.wp.com/i/icons/post.ico" /><meta name="msapplication-task" content="name=Moderate comments;action-uri=https://webdevhubcom.wordpress.com/wp-admin/edit-comments.php?comment_status=moderated;icon-uri=https://s0.wp.com/i/icons/comment.ico" /><meta name="msapplication-task" content="name=Upload new media;action-uri=https://webdevhubcom.wordpress.com/wp-admin/media-new.php;icon-uri=https://s0.wp.com/i/icons/media.ico" /><meta name="msapplication-task" content="name=Blog stats;action-uri=https://webdevhubcom.wordpress.com/wp-admin/index.php?page=stats;icon-uri=https://s0.wp.com/i/icons/stats.ico" /><meta name="description" content="webdevhub" /> | |
<!-- There is no amphtml version available for this URL. --><style type="text/css" media="print">#wpadminbar { display:none; }</style> | |
<style type="text/css" media="screen"> | |
html { margin-top: 32px !important; } | |
* html body { margin-top: 32px !important; } | |
@media screen and ( max-width: 782px ) { | |
html { margin-top: 46px !important; } | |
* html body { margin-top: 46px !important; } | |
} | |
</style> | |
<link rel="icon" href="https://webdevhubcom.files.wordpress.com/2021/03/image.jpg?w=32" sizes="32x32" /> | |
<link rel="icon" href="https://webdevhubcom.files.wordpress.com/2021/03/image.jpg?w=192" sizes="192x192" /> | |
<link rel="apple-touch-icon" href="https://webdevhubcom.files.wordpress.com/2021/03/image.jpg?w=180" /> | |
<meta name="msapplication-TileImage" content="https://webdevhubcom.files.wordpress.com/2021/03/image.jpg?w=270" /> | |
</head> | |
<body class="home blog logged-in admin-bar no-customize-support wp-custom-logo wp-embed-responsive customizer-styles-applied hfeed image-filters-enabled hide-homepage-title mobile-nav-side highlander-enabled highlander-light"> | |
<div id="wpadminbar" class="nojq nojs ltr nav-unification"> | |
<a class="screen-reader-shortcut" href="#wp-toolbar" tabindex="1">Skip to toolbar</a> | |
<div class="quicklinks" id="wp-toolbar" role="navigation" aria-label="Toolbar" tabindex="0"> | |
<ul id="wp-admin-bar-root-default" class="ab-top-menu"> | |
<li id="wp-admin-bar-blog" class="my-sites mb-trackable"><a class="ab-item" href="https://wordpress.com/sites/web-dev-hub.com">My Sites</a> </li> | |
<li id="wp-admin-bar-jumptotop-button-menu"><a class="ab-item" href="#"><div id="jumptotop"><span class="noticon noticon-top"></span></div></a> </li> | |
<li id="wp-admin-bar-newdash" class="mb-trackable"><a class="ab-item" href="https://wordpress.com/read">Reader</a> </li> </ul> | |
<ul id="wp-admin-bar-top-secondary" class="ab-top-secondary ab-top-menu"> | |
<li id="wp-admin-bar-notes" class="menupop"> <div class="ab-item ab-empty-item" ><span id="wpnt-notes-unread-count" class="wpnt-loading wpn-read"></span><span class="noticon noticon-bell"></span><span class="ab-text">Notifications</span></div><div id="wpnt-notes-panel2" style="display:none" lang="en" dir="ltr"><div class="wpnt-notes-panel-header"><span class="wpnt-notes-header"></span><span class="wpnt-notes-panel-link"></span></div></div> </li> | |
<li id="wp-admin-bar-my-account" class="with-avatar mb-trackable"><a class="ab-item" href="https://wordpress.com/me/"><img alt='' src='https://1.gravatar.com/avatar/4c4ec05acd63612984efbe17dec9dd88?s=32&d=mm&r=G' class='avatar avatar-32' height='32' width='32' /><span class="ab-text">Me</span></a> </li> | |
<li id="wp-admin-bar-ab-new-post" class="mb-trackable"><a class="ab-item" href="https://wordpress.com/post/web-dev-hub.com"><span>Write</span></a> </li> </ul> | |
</div> | |
<a class="screen-reader-shortcut" href="https://webdevhubcom.wordpress.com/wp-login.php?action=logout&_wpnonce=27b7eb61b3">Log Out</a> | |
</div> | |
<script type="text/javascript"> | |
/* <![CDATA[ */ | |
var clickDebugLink; | |
jQuery(document).ready( function($) { | |
var single = false, w = 1000, | |
supe = false; | |
$(document.body).load(function(){ $('#wpadminbar img.grav-hashed').removeClass('grav-hashed'); }); // hack to hide the gravatar hovercard | |
if ( single && supe ) | |
w = 1385; | |
else if ( supe ) | |
w = 1200; | |
// debug bar extra | |
clickDebugLink = function( parent_id, obj ) { | |
$('#'+parent_id).children('div').hide(); | |
document.getElementById( obj.href.substr( obj.href.indexOf( '#' ) + 1 ) ).style.display = 'block'; | |
$( obj.href.substr( obj.href.indexOf( '#' ) ) ).show() | |
$(obj).parent().addClass('current').siblings('li').removeClass('current'); | |
return false; | |
}; | |
$( '#wpadminbar #wp-admin-bar-shortlink' ).click( function() { | |
$( '#adminbar-shortlink-input' ).select(); | |
}); | |
// skip tap-to-hover on site switcher for mobile | |
if ( 'ontouchstart' in window ) { | |
$('#wp-admin-bar-switch-site').on( 'touchstart', function( event ) { | |
if ( $( window ).width() > 782 ) { | |
return; | |
} | |
event.stopPropagation(); | |
$( event.target ).first( 'a' ).click(); | |
}); | |
} | |
}); | |
/* ]]> */ | |
</script> | |
<div class="wpcom-bubble action-bubble"> | |
<div class="bubble-txt"></div> | |
</div> | |
<script type="text/javascript">function hideBubble() { jQuery('body').append( jQuery( 'div.wpcom-bubble' ).removeClass( 'fadein' ) ).off( 'click.bubble touchstart.bubble' ); jQuery(document).off( 'scroll.bubble' ); };</script> | |
<script type="text/javascript"> | |
jQuery( '#wp-admin-bar-jumptotop-button-menu a' ).click( function( e ) { | |
e.preventDefault(); | |
jQuery( 'html, body' ).animate( { scrollTop: 0 }, 'fast' ); | |
} ); | |
function hideShowTbJumpToTop() { | |
var total_width = 0; | |
// Calculate total width taken by items minus our button to see if it'll | |
// overlap with other toolbar menus. | |
jQuery( '#wp-admin-bar-root-default > li' ).each( function() { | |
var self = jQuery( this ); | |
if ( 'wp-admin-bar-jumptotop-button-menu' != self.attr( 'id' ) ) | |
total_width += self.width(); | |
}); | |
if ( jQuery( '#wp-admin-bar-jumptotop-button-menu' ).position()['left'] - total_width < 10 ) { | |
jQuery( '#jumptotop' ).animate( { 'top': '-50px' }, 'fast' ); | |
} else if ( jQuery( window ).scrollTop() >= 350 && parseInt( jQuery( '#jumptotop' ).css( 'top' ) ) < 0 ) { | |
if ( jQuery( '#wp-admin-bar-jumptotop-button-menu' ).position()['left'] - total_width < 10 ) | |
return; | |
jQuery( '#jumptotop' ).animate( { 'top': 0 }, 'fast' ); | |
} else if ( jQuery( window ).scrollTop() < 1 && parseInt( jQuery( '#jumptotop' ).css( 'top' ) ) >= 0 ) { | |
jQuery( '#jumptotop' ).animate( { 'top': '-50px' }, 'fast' ); | |
} | |
} | |
// handle on page load if auto scrolling to a position | |
hideShowTbJumpToTop(); | |
// bind to scrolll event | |
var jumpToTopTimer = null; | |
jQuery( window ).scroll( function() { | |
clearTimeout( jumpToTopTimer ); | |
jumpToTopTimer = setTimeout( jumpToTopRefresh, 150 ); | |
} ); | |
var jumpToTopRefresh = function() { | |
hideShowTbJumpToTop(); | |
}; | |
</script> | |
<div id="page" class="site"> | |
<a class="skip-link screen-reader-text" href="#content">Skip to content</a> | |
<header id="masthead" class="site-header" role="banner"> | |
<div class="site-header-wrap responsive-max-width has-logo has-menu"> | |
<div class="site-logo"><a href="https://web-dev-hub.com/" class="custom-logo-link" rel="home" aria-current="page"><img width="697" height="419" src="https://webdevhubcom.files.wordpress.com/2021/04/3e56c-0kwm2zier68qbjwls.gif" class="custom-logo" alt="Web Development Resources Site" data-attachment-id="646" data-permalink="https://web-dev-hub.com/2021/04/12/vscode-extension-readme-compilation/0kwm2zier68qbjwls/" data-orig-file="https://webdevhubcom.files.wordpress.com/2021/04/3e56c-0kwm2zier68qbjwls.gif" data-orig-size="697,419" data-comments-opened="0" data-image-meta="{"aperture":"0","credit":"","camera":"","caption":"","created_timestamp":"0","copyright":"","focal_length":"0","iso":"0","shutter_speed":"0","title":"","orientation":"0"}" data-image-title="0*KWm2zIER68qBJWls" data-image-description="" data-image-caption="" data-medium-file="https://webdevhubcom.files.wordpress.com/2021/04/3e56c-0kwm2zier68qbjwls.gif?w=300" data-large-file="https://webdevhubcom.files.wordpress.com/2021/04/3e56c-0kwm2zier68qbjwls.gif?w=697" /></a></div> | |
<h1 class="site-title"><a href="https://web-dev-hub.com/" rel="home">Web Development Resources Site</a></h1> | |
<p class="site-description"> | |
webdevhub </p> | |
<nav id="site-navigation" class="main-navigation" aria-label="Main Navigation"> | |
<input type="checkbox" role="button" aria-haspopup="true" id="toggle" class="hide-visually"> | |
<label for="toggle" id="toggle-menu" class="button"> | |
Menu <span class="dropdown-icon open">+</span> | |
<span class="dropdown-icon close">×</span> | |
<span class="hide-visually expanded-text">expanded</span> | |
<span class="hide-visually collapsed-text">collapsed</span> | |
</label> | |
<div class="main-menu-container"><ul id="menu-primary-1" class="main-menu" aria-label="submenu"><li class="menu-item menu-item-type-post_type menu-item-object-page menu-item-home menu-item-19"><a href="https://web-dev-hub.com/?page_id=108">Projects</a></li> | |
<li class="menu-item menu-item-type-post_type menu-item-object-page menu-item-21"><a href="https://web-dev-hub.com/contact/about/">Cover Letter</a></li> | |
<li class="menu-item menu-item-type-post_type menu-item-object-page menu-item-22"><a href="https://web-dev-hub.com/contact/">Contact</a></li> | |
</ul></div> </nav><!-- #site-navigation --> | |
</div><!-- .site-header-wrap --> | |
</header><!-- #masthead --> | |
<div id="content" class="site-content"> | |
<section id="primary" class="content-area"> | |
<main id="main" class="site-main"> | |
<article id="post-373" class="post-373 post type-post status-publish format-standard sticky hentry category-uncategorized entry"> | |
<header class="entry-header responsive-max-width"> | |
<span class="sticky-post">Featured</span><h2 class="entry-title"><a href="https://web-dev-hub.com/2021/03/23/hi-%f0%9f%91%8b-im-bryan/" rel="bookmark">Hi 👋, I’m Bryan</a></h2> </header><!-- .entry-header --> | |
<div class="entry-content"> | |
<h4>Passionate Web Developer, Electrical Engineer, Audio Engineer and Musician / Teacher!</h4> | |
<hr class="wp-block-separator" /> | |
<div data-carousel-extra='{"blog_id":190652711,"permalink":"https:\/\/web-dev-hub.com\/2021\/03\/23\/hi-%f0%9f%91%8b-im-bryan\/"}' class="wp-container-61c6b342c676d wp-block-buttons alignfull is-content-justification-center"> | |
<div data-carousel-extra='{"blog_id":190652711,"permalink":"https:\/\/web-dev-hub.com\/2021\/03\/23\/hi-%f0%9f%91%8b-im-bryan\/"}' class="wp-block-button is-style-outline"><a class="wp-block-button__link has-foreground-color has-text-color" href="https://modest-booth-4e17df.netlify.app/" style="border-radius:47px;"><strong><em><span style="color:#303030;" class="has-inline-color">blog</span></em></strong></a></div> | |
<div data-carousel-extra='{"blog_id":190652711,"permalink":"https:\/\/web-dev-hub.com\/2021\/03\/23\/hi-%f0%9f%91%8b-im-bryan\/"}' class="wp-block-button is-style-outline"><a class="wp-block-button__link has-foreground-color has-text-color" href="https://github.com/bgoonz" style="border-radius:50px;"><strong><em><span style="color:#303030;" class="has-inline-color">GitHub</span></em></strong></a></div> | |
<div data-carousel-extra='{"blog_id":190652711,"permalink":"https:\/\/web-dev-hub.com\/2021\/03\/23\/hi-%f0%9f%91%8b-im-bryan\/"}' class="wp-block-button is-style-outline"><a class="wp-block-button__link has-foreground-color has-text-color" href="https://github.com/bgoonz/resume-cv-portfolio-samples/blob/master/2021-resume/bryan-guner-resume-2021.pdf" style="border-radius:50px;"><strong><em><span style="color:#303030;" class="has-inline-color">Resume</span></em></strong></a></div> | |
<div data-carousel-extra='{"blog_id":190652711,"permalink":"https:\/\/web-dev-hub.com\/2021\/03\/23\/hi-%f0%9f%91%8b-im-bryan\/"}' class="wp-block-button is-style-outline"><a class="wp-block-button__link has-foreground-color has-text-color" href="https://www.linkedin.com/in/bryan-guner-046199128/" style="border-radius:50px;"><strong><em><span style="color:#303030;" class="has-inline-color">Linkedin</span></em></strong></a></div> | |
<div data-carousel-extra='{"blog_id":190652711,"permalink":"https:\/\/web-dev-hub.com\/2021\/03\/23\/hi-%f0%9f%91%8b-im-bryan\/"}' class="wp-block-button is-style-outline"><a class="wp-block-button__link has-foreground-color has-text-color" href="https://gist.github.com/bgoonz/659a9b81ac45453bedc0a1a36275b580" style="border-radius:50px;"><strong><em><span style="color:#303030;" class="has-inline-color">Deploys</span></em></strong></a></div> | |
<div data-carousel-extra='{"blog_id":190652711,"permalink":"https:\/\/web-dev-hub.com\/2021\/03\/23\/hi-%f0%9f%91%8b-im-bryan\/"}' class="wp-block-button is-style-outline"><a class="wp-block-button__link has-foreground-color has-text-color" href="https://web-dev-resource-hub.netlify.app/" style="border-radius:50px;" rel="https://web-dev-resource-hub.netlify.app/"><strong><em><span style="color:#303030;" class="has-inline-color">Site</span></em></strong></a></div> | |
</div> | |
<div data-carousel-extra='{"blog_id":190652711,"permalink":"https:\/\/web-dev-hub.com\/2021\/03\/23\/hi-%f0%9f%91%8b-im-bryan\/"}' class="wp-block-image"><figure class="aligncenter"><a href="https://camo.githubusercontent.com/41fbd874c1ba0b69222440c1527ceb24831f388dcf4b875c048dbf0ce11fce58/68747470733a2f2f76696577732e77686174696c656172656e65642e746f6461792f76696577732f6769746875622f62676f6f6e7a2f76696577732e737667" target="_blank" rel="noreferrer noopener"><img src="https://camo.githubusercontent.com/41fbd874c1ba0b69222440c1527ceb24831f388dcf4b875c048dbf0ce11fce58/68747470733a2f2f76696577732e77686174696c656172656e65642e746f6461792f76696577732f6769746875622f62676f6f6e7a2f76696577732e737667" alt="Profile views" /></a></figure></div> | |
<hr class="wp-block-separator" /> | |
<div data-carousel-extra='{"blog_id":190652711,"permalink":"https:\/\/web-dev-hub.com\/2021\/03\/23\/hi-%f0%9f%91%8b-im-bryan\/"}' class="wp-block-image"><figure class="aligncenter"><a href="https://github.com/bgoonz/bgoonz/blob/master/circle-small-sharp.png?raw=true?raw=true" target="_blank" rel="noreferrer noopener"><img src="https://github.com/bgoonz/bgoonz/raw/master/circle-small-sharp.png?raw=true?raw=true" alt="" /></a></figure></div> | |
<h3><a href="https://github.com/bgoonz#a-passionate-web-developer-electrical-engineer-musician--producer"></a>A passionate Web Developer, Electrical Engineer, Musician & Producer</h3> | |
<ul><li>🔭 Contract Web Development <strong>Relational Concepts</strong></li><li>🌱 I’m currently learning <strong>React/Redux, Python, Java, Express, jQuery</strong></li><li>👯 I’m looking to collaborate on <a href="https://goofy-euclid-1cd736.netlify.app/core-site/index.html">Any web audio or open source educational tools.</a></li><li>🤝 I’m looking for help with <a href="https://github.com/bgoonz/React-Practice">Learning React</a></li><li>👨💻 All of my projects are available at <a href="https://bgoonz.github.io/">https://bgoonz.github.io/</a></li><li>📝 I regularly write articles on <a href="https://bryanguner.medium.com/">medium</a> && <a href="https://web-dev-resource-hub.netlify.app/">Web-Dev-Resource-Hub</a></li><li>💬 Ask me about <strong>Anything:</strong></li><li>📫 How to reach me <strong><a href="mailto:bryan.guner@gmail.com">bryan.guner@gmail.com</a></strong></li><li>⚡ Fun fact <strong>I played Bamboozle Music Festival at the Meadowlands Stadium Complex when I was 14.</strong></li></ul> | |
<hr class="wp-block-separator" /> | |
<div data-carousel-extra='{"blog_id":190652711,"permalink":"https:\/\/web-dev-hub.com\/2021\/03\/23\/hi-%f0%9f%91%8b-im-bryan\/"}' class="wp-block-image"><figure class="aligncenter is-resized"><a href="https://camo.githubusercontent.com/727b46e1d3fa1dc9460d1f7a8c4f4fb8a5523029a3389abf818bc1f95430b4ac/68747470733a2f2f726561646d652d6a6f6b65732e76657263656c2e6170702f617069" target="_blank" rel="noreferrer noopener"><img src="https://camo.githubusercontent.com/727b46e1d3fa1dc9460d1f7a8c4f4fb8a5523029a3389abf818bc1f95430b4ac/68747470733a2f2f726561646d652d6a6f6b65732e76657263656c2e6170702f617069" alt="" width="529" height="158" /></a></figure></div> | |
<hr class="wp-block-separator" /> | |
<figure class="wp-block-image"><a href="https://github.com/bgoonz#_email_"><img src="https://raw.githubusercontent.com/andreasbm/readme/master/assets/lines/colored.png" alt="-----------------------------------------------------" /></a></figure> | |
<h2><a href="https://github.com/bgoonz#-email"></a>➤ <em>Email</em></h2> | |
<p><a href="https://github.com/bgoonz#">bryan.guner.dev@gmail.com</a></p> | |
<figure class="wp-block-image"><a href="https://github.com/bgoonz#_phone_"><img src="https://raw.githubusercontent.com/andreasbm/readme/master/assets/lines/colored.png" alt="-----------------------------------------------------" /></a></figure> | |
<h2>Connect with me:</h2> | |
<div data-carousel-extra='{"blog_id":190652711,"permalink":"https:\/\/web-dev-hub.com\/2021\/03\/23\/hi-%f0%9f%91%8b-im-bryan\/"}' class="wp-block-columns"> | |
<div data-carousel-extra='{"blog_id":190652711,"permalink":"https:\/\/web-dev-hub.com\/2021\/03\/23\/hi-%f0%9f%91%8b-im-bryan\/"}' class="wp-block-column" style="flex-basis:20%;"> | |
<figure class="wp-block-image"><a href="https://stackoverflow.com/users/20645183"><img src="https://camo.githubusercontent.com/bd44ccfd9dad8d42fb19cacdac1ce3d2da666127da16876455a661988cf65f5d/68747470733a2f2f63646e2e6a7364656c6976722e6e65742f6e706d2f73696d706c652d69636f6e7340332e302e312f69636f6e732f737461636b6f766572666c6f772e737667" alt="20645183" /></a></figure> | |
</div> | |
<div data-carousel-extra='{"blog_id":190652711,"permalink":"https:\/\/web-dev-hub.com\/2021\/03\/23\/hi-%f0%9f%91%8b-im-bryan\/"}' class="wp-block-column" style="flex-basis:20%;"> | |
<figure class="wp-block-image is-resized"><a href="https://codesandbox.com/bgoonz"><img src="https://camo.githubusercontent.com/7a9df7545ac90d346949d6781841f8dddb4c01b4f882272714bfbd13b5872c2f/68747470733a2f2f63646e2e6a7364656c6976722e6e65742f6e706d2f73696d706c652d69636f6e7340332e302e312f69636f6e732f636f646573616e64626f782e737667" alt="bgoonz" width="25" height="25" /></a></figure> | |
</div> | |
<div data-carousel-extra='{"blog_id":190652711,"permalink":"https:\/\/web-dev-hub.com\/2021\/03\/23\/hi-%f0%9f%91%8b-im-bryan\/"}' class="wp-block-column" style="flex-basis:20%;"> | |
<figure class="wp-block-image"><a href="https://instagram.com/bgoonz"><img src="https://camo.githubusercontent.com/aecaf87326884e8b0466bb799265a13fee7586246ebda3e066cb7fad82a1fd23/68747470733a2f2f63646e2e6a7364656c6976722e6e65742f6e706d2f73696d706c652d69636f6e7340332e302e312f69636f6e732f696e7374616772616d2e737667" alt="bgoonz" /></a></figure> | |
</div> | |
<div data-carousel-extra='{"blog_id":190652711,"permalink":"https:\/\/web-dev-hub.com\/2021\/03\/23\/hi-%f0%9f%91%8b-im-bryan\/"}' class="wp-block-column" style="flex-basis:20%;"> | |
<figure class="wp-block-image"><a href="https://www.youtube.com/watch?v=xGZSWvFess8"><img src="https://camo.githubusercontent.com/4a20e861b6593d07cef8e8b740e64a866ba7a9916d7e00a9c50c05e93a8096b8/68747470733a2f2f63646e2e6a7364656c6976722e6e65742f6e706d2f73696d706c652d69636f6e7340332e302e312f69636f6e732f796f75747562652e737667" alt="bryan guner" /></a></figure> | |
</div> | |
<div data-carousel-extra='{"blog_id":190652711,"permalink":"https:\/\/web-dev-hub.com\/2021\/03\/23\/hi-%f0%9f%91%8b-im-bryan\/"}' class="wp-block-column" style="flex-basis:20%;"> | |
<figure class="wp-block-image"><a href="https://www.leetcode.com/bgoonz"><img src="https://camo.githubusercontent.com/031caf938447e457226d5d394c550909299fa104f70601ba8c5e82077f8b1f96/68747470733a2f2f63646e2e6a7364656c6976722e6e65742f6e706d2f73696d706c652d69636f6e7340332e302e312f69636f6e732f6c656574636f64652e737667" alt="bgoonz" /></a></figure> | |
</div> | |
</div> | |
<hr class="wp-block-separator" /> | |
<figure class="wp-block-image"><a href="https://github.com/bgoonz#social"><img src="https://raw.githubusercontent.com/andreasbm/readme/master/assets/lines/colored.png" alt="-----------------------------------------------------" /></a></figure> | |
<h2><a href="https://github.com/bgoonz#-social"></a>➤ Other Social</h2> | |
<ul><li><a href="https://github.com/bgoonz">GitHub</a></li><li><a href="https://gitlab.com/bryan.guner.dev">Gitlab</a></li><li><a href="https://bitbucket.org/bgoonz/">Bitbucket</a></li><li><a href="https://codepen.io/bgoonz">code pen</a></li><li><a href="https://glitch.com/@bgoonz">Glitch</a></li><li><a href="https://repl.it/@bgoonz/">Replit</a></li><li><a href="https://www.reddit.com/user/bgoonz1">Redit</a></li><li><a href="https://runkit.com/bgoonz">runkit</a></li><li><a href="https://meta.stackexchange.com/users/936785/bryan-guner">stack-exchange</a></li><li><a href="https://app.netlify.com/user/settings#profile">Netlify</a></li><li><a href="https://bryanguner.medium.com/">Medium</a></li><li><a href="https://webcomponents.dev/user/bgoonz">webcomponents.dev</a></li><li><a href="https://www.npmjs.com/~bgoonz11">npm</a></li><li><a href="https://www.upwork.com/freelancers/~01bb1a3627e1e9c630?viewMode=1&s=1110580755057594368">Upwork</a></li><li><a href="https://angel.co/u/bryan-guner">AngelList</a></li><li><a href="https://www.quora.com/q/webdevresourcehub?invite_code=qwZOqbpAhgQ6hjjGl8NN">Quora</a></li></ul> | |
<figure class="wp-block-image"><a href="https://github.com/bgoonz#blog"><img src="https://raw.githubusercontent.com/andreasbm/readme/master/assets/lines/colored.png" alt="-----------------------------------------------------" /></a></figure> | |
<h2 class="has-small-font-size" style="line-height:.9;"><a href="https://github.com/bgoonz#-blog"></a>➤ <a href="">Blog:</a><a href="https://bryanguner.medium.com/">https://bryanguner.medium.com/</a></h2> | |
<figure class="wp-block-image is-resized"><a href="https://github.com/bgoonz#projects"><img src="https://raw.githubusercontent.com/andreasbm/readme/master/assets/lines/colored.png" alt="-----------------------------------------------------" width="900" height="9" /></a></figure> | |
<h1><a href="https://github.com/bgoonz#-projects"></a>➤ Projects:</h1> | |
<div data-carousel-extra='{"blog_id":190652711,"permalink":"https:\/\/web-dev-hub.com\/2021\/03\/23\/hi-%f0%9f%91%8b-im-bryan\/"}' class="wp-block-columns"> | |
<div data-carousel-extra='{"blog_id":190652711,"permalink":"https:\/\/web-dev-hub.com\/2021\/03\/23\/hi-%f0%9f%91%8b-im-bryan\/"}' class="wp-block-column" style="flex-basis:100%;"> | |
<div data-carousel-extra='{"blog_id":190652711,"permalink":"https:\/\/web-dev-hub.com\/2021\/03\/23\/hi-%f0%9f%91%8b-im-bryan\/"}' class="wp-container-61c6b342c6f3c wp-block-group"><div data-carousel-extra='{"blog_id":190652711,"permalink":"https:\/\/web-dev-hub.com\/2021\/03\/23\/hi-%f0%9f%91%8b-im-bryan\/"}' class="wp-block-group__inner-container"> | |
<div data-carousel-extra='{"blog_id":190652711,"permalink":"https:\/\/web-dev-hub.com\/2021\/03\/23\/hi-%f0%9f%91%8b-im-bryan\/"}' class="wp-block-columns"> | |
<div data-carousel-extra='{"blog_id":190652711,"permalink":"https:\/\/web-dev-hub.com\/2021\/03\/23\/hi-%f0%9f%91%8b-im-bryan\/"}' class="wp-block-column" style="flex-basis:100%;"> | |
<pre class="wp-block-preformatted" style="font-size:12px;"><a href="https://project-showcase-bgoonz.netlify.app/">https://project-showcase-bgoonz.netlify.app/</a></pre> | |
</div> | |
</div> | |
</div></div> | |
</div> | |
</div> | |
<hr class="wp-block-separator" /> | |
<h2><a href="https://github.com/bgoonz#web-dev-resource-hub"></a>Web Dev Resource Hub</h2> | |
<h3><a href="https://github.com/bgoonz#my-personal-web-development-blog-and-resource-sharing-site"></a>My personal Web Development blog and resource sharing site</h3> | |
<ul><li><a href="https://web-dev-resource-hub.netlify.app/">Live Site</a></li></ul> | |
<figure class="wp-block-image"><a href="https://camo.githubusercontent.com/627c52694b92ec1f13be3a7995d46352915ad96ac13261cc37ccf987364cabd2/68747470733a2f2f636c6f75642e6e65746c69667975736572636f6e74656e742e636f6d2f6173736574732f33343464626638382d666466392d343262622d616462342d3436663031656564643632392f32336239623233362d373436652d343039632d386538362d3330623433383565336237322f6872312d7261797068616d2e676966" target="_blank" rel="noreferrer noopener"><img src="https://camo.githubusercontent.com/627c52694b92ec1f13be3a7995d46352915ad96ac13261cc37ccf987364cabd2/68747470733a2f2f636c6f75642e6e65746c69667975736572636f6e74656e742e636f6d2f6173736574732f33343464626638382d666466392d343262622d616462342d3436663031656564643632392f32336239623233362d373436652d343039632d386538362d3330623433383565336237322f6872312d7261797068616d2e676966" alt="hr-line" /></a></figure> | |
<figure class="wp-block-image"><a href="https://github.com/bgoonz#mihir_begcom"><img src="https://raw.githubusercontent.com/andreasbm/readme/master/assets/lines/colored.png" alt="-----------------------------------------------------" /></a></figure> | |
<h1><a href="https://github.com/bgoonz#-mihir_begcom"></a>➤ Mihir_Beg.com</h1> | |
<h3><a href="https://github.com/bgoonz#created-a-dynamic-web-page-for-a-local-musician-using-the-bootsrtap-framework"></a>Created a dynamic web page for a local musician using the Bootsrtap framework.</h3> | |
<p>-Talk about App Features & Design Process Here-</p> | |
<ul><li><a href="https://eloquent-sammet-ba1810.netlify.app/">Live Site</a></li></ul> | |
<figure class="wp-block-image"><a href="https://camo.githubusercontent.com/627c52694b92ec1f13be3a7995d46352915ad96ac13261cc37ccf987364cabd2/68747470733a2f2f636c6f75642e6e65746c69667975736572636f6e74656e742e636f6d2f6173736574732f33343464626638382d666466392d343262622d616462342d3436663031656564643632392f32336239623233362d373436652d343039632d386538362d3330623433383565336237322f6872312d7261797068616d2e676966" target="_blank" rel="noreferrer noopener"><img src="https://camo.githubusercontent.com/627c52694b92ec1f13be3a7995d46352915ad96ac13261cc37ccf987364cabd2/68747470733a2f2f636c6f75642e6e65746c69667975736572636f6e74656e742e636f6d2f6173736574732f33343464626638382d666466392d343262622d616462342d3436663031656564643632392f32336239623233362d373436652d343039632d386538362d3330623433383565336237322f6872312d7261797068616d2e676966" alt="hr-line" /></a></figure> | |
<hr class="wp-block-separator" /> | |
<hr class="wp-block-separator" /> | |
<h2><a href="https://github.com/bgoonz#interview-prep-static-site"></a>Interview Prep Static Site</h2> | |
<h3><a href="https://github.com/bgoonz#data-structures-repository"></a>Data Structures Repository</h3> | |
<p>-Hope this helps someone other than me!-</p> | |
<ul><li><a href="https://ds-algo-official-c3dw6uapg-bgoonz.vercel.app/">Live Site</a></li></ul> | |
<hr class="wp-block-separator" /> | |
<figure class="wp-block-image"><a href="https://camo.githubusercontent.com/627c52694b92ec1f13be3a7995d46352915ad96ac13261cc37ccf987364cabd2/68747470733a2f2f636c6f75642e6e65746c69667975736572636f6e74656e742e636f6d2f6173736574732f33343464626638382d666466392d343262622d616462342d3436663031656564643632392f32336239623233362d373436652d343039632d386538362d3330623433383565336237322f6872312d7261797068616d2e676966" target="_blank" rel="noreferrer noopener"><img src="https://camo.githubusercontent.com/627c52694b92ec1f13be3a7995d46352915ad96ac13261cc37ccf987364cabd2/68747470733a2f2f636c6f75642e6e65746c69667975736572636f6e74656e742e636f6d2f6173736574732f33343464626638382d666466392d343262622d616462342d3436663031656564643632392f32336239623233362d373436652d343039632d386538362d3330623433383565336237322f6872312d7261797068616d2e676966" alt="hr-line" /></a></figure> | |
<hr class="wp-block-separator" /> | |
<hr class="wp-block-separator" /> | |
<h2><a href="https://github.com/bgoonz#learning-react-blog"></a>Learning React Blog</h2> | |
<p><a href="https://ecstatic-jang-593fd1.netlify.app/readme" rel="nofollow">https://ecstatic-jang-593fd1.netlify.app/readme</a></p> | |
<h4><a href="https://github.com/bgoonz#react-repo"></a>React Repo:</h4> | |
<p><a href="https://github.com/bgoonz/React-Practice">React Repo</a></p> | |
<hr class="wp-block-separator" /> | |
<h2><a href="https://github.com/bgoonz#"></a><a href="https://codesandbox.io/embed/zealous-microservice-ti7em?autoresize=1&expanddevtools=1&fontsize=14&hidenavigation=1&moduleview=1&theme=dark"></a></h2> | |
<figure class="wp-block-image"><a href="https://camo.githubusercontent.com/627c52694b92ec1f13be3a7995d46352915ad96ac13261cc37ccf987364cabd2/68747470733a2f2f636c6f75642e6e65746c69667975736572636f6e74656e742e636f6d2f6173736574732f33343464626638382d666466392d343262622d616462342d3436663031656564643632392f32336239623233362d373436652d343039632d386538362d3330623433383565336237322f6872312d7261797068616d2e676966" target="_blank" rel="noreferrer noopener"><img src="https://camo.githubusercontent.com/627c52694b92ec1f13be3a7995d46352915ad96ac13261cc37ccf987364cabd2/68747470733a2f2f636c6f75642e6e65746c69667975736572636f6e74656e742e636f6d2f6173736574732f33343464626638382d666466392d343262622d616462342d3436663031656564643632392f32336239623233362d373436652d343039632d386538362d3330623433383565336237322f6872312d7261797068616d2e676966" alt="hr-line" /></a></figure> | |
<p><a href="https://documentation-site-react2-peitff669-bgoonz.vercel.app/">react-documentation-site</a></p> | |
<figure class="wp-block-image"><a href="https://codesandbox.io/s/magical-stallman-ov0d1?autoresize=1&expanddevtools=1&fontsize=12&hidenavigation=1&moduleview=1&theme=dark"><img src="https://camo.githubusercontent.com/90808661433696bc57dce8d4ad732307b5cec6270e6b846f114dcd7ee7f9458a/68747470733a2f2f636f646573616e64626f782e696f2f7374617469632f696d672f706c61792d636f646573616e64626f782e737667" alt="Edit magical-stallman-ov0d1" /></a></figure> | |
<figure class="wp-block-image"><a href="https://camo.githubusercontent.com/627c52694b92ec1f13be3a7995d46352915ad96ac13261cc37ccf987364cabd2/68747470733a2f2f636c6f75642e6e65746c69667975736572636f6e74656e742e636f6d2f6173736574732f33343464626638382d666466392d343262622d616462342d3436663031656564643632392f32336239623233362d373436652d343039632d386538362d3330623433383565336237322f6872312d7261797068616d2e676966" target="_blank" rel="noreferrer noopener"><img src="https://camo.githubusercontent.com/627c52694b92ec1f13be3a7995d46352915ad96ac13261cc37ccf987364cabd2/68747470733a2f2f636c6f75642e6e65746c69667975736572636f6e74656e742e636f6d2f6173736574732f33343464626638382d666466392d343262622d616462342d3436663031656564643632392f32336239623233362d373436652d343039632d386538362d3330623433383565336237322f6872312d7261797068616d2e676966" alt="hr-line" /></a></figure> | |
<hr class="wp-block-separator" /> | |
<h1><a href="https://github.com/bgoonz#mini-project-showcase"></a>Mini Project Showcase</h1> | |
<h4><a href="https://github.com/bgoonz#just-some-simpe-static-webpage-projects"></a>Just some simpe static webpage projects</h4> | |
<p><a href="https://jovial-agnesi-8ec8b1.netlify.app/">mini-projects</a></p> | |
<h2><a href="https://github.com/bgoonz#codepens-mostly-embeded-animations"></a>Codepens (mostly embeded animations)</h2> | |
<p><a href="https://embedable-content.netlify.app/">code-pens-embedded</a></p> | |
<hr class="wp-block-separator" /> | |
<p>Click to expand!</p> | |
<hr class="wp-block-separator" /> | |
<hr class="wp-block-separator" /> | |
<figure class="wp-block-image alignwide is-style-rounded"><a href="https://github.com/bgoonz/bgoonz/blob/master/skills.PNG" target="_blank" rel="noreferrer noopener"><img src="https://github.com/bgoonz/bgoonz/raw/master/skills.PNG" alt="skills" /></a></figure> | |
<hr class="wp-block-separator" /> | |
<hr class="wp-block-separator" /> | |
<h3><a href="https://github.com/bgoonz#languages-and-tools"></a>Languages and Tools:</h3> | |
<pre class="wp-block-preformatted"></pre> | |
<figure class="wp-block-gallery columns-8 is-cropped"><ul data-carousel-extra='{"blog_id":190652711,"permalink":"https:\/\/web-dev-hub.com\/2021\/03\/23\/hi-%f0%9f%91%8b-im-bryan\/"}' class="blocks-gallery-grid"><li class="blocks-gallery-item"><figure><img src="https://camo.githubusercontent.com/b3a1cdd20d0f308634ddd4598cdaa729c2d77047f51e66fa7206b9b4bac94c23/68747470733a2f2f63646e2e776f726c64766563746f726c6f676f2e636f6d2f6c6f676f732f61726475696e6f2d312e737667" alt="arduino" data-id="" /></figure></li><li class="blocks-gallery-item"><figure><img src="https://raw.githubusercontent.com/devicons/devicon/master/icons/amazonwebservices/amazonwebservices-original-wordmark.svg" alt="aws" data-id="" /></figure></li><li class="blocks-gallery-item"><figure><img src="https://camo.githubusercontent.com/6df31a460cb0c38f960e92812c8b6f8bce4c7f13170fb4782f0b31ab8e792ac2/68747470733a2f2f7777772e766563746f726c6f676f2e7a6f6e652f6c6f676f732f6d6963726f736f66745f617a7572652f6d6963726f736f66745f617a7572652d69636f6e2e737667" alt="azure" data-id="" /></figure></li><li class="blocks-gallery-item"><figure><img src="https://camo.githubusercontent.com/1abf71d00a4a13bfdeccdc131c65f02644fae4e746289bd7c21bf1d2af986389/68747470733a2f2f7777772e766563746f726c6f676f2e7a6f6e652f6c6f676f732f626162656c6a732f626162656c6a732d69636f6e2e737667" alt="babel" data-id="" /></figure></li><li class="blocks-gallery-item"><figure><img src="https://camo.githubusercontent.com/bbb327d6ba7708520eaafd13396fed64d73bf5df5c4cdd0ba03cf0843f7a9340/68747470733a2f2f7777772e766563746f726c6f676f2e7a6f6e652f6c6f676f732f676e755f626173682f676e755f626173682d69636f6e2e737667" alt="bash" data-id="" /></figure></li><li class="blocks-gallery-item"><figure><img src="https://raw.githubusercontent.com/devicons/devicon/master/icons/bootstrap/bootstrap-plain-wordmark.svg" alt="bootstrap" data-id="" /></figure></li><li class="blocks-gallery-item"><figure><img src="https://raw.githubusercontent.com/devicons/devicon/master/icons/cplusplus/cplusplus-original.svg" alt="cplusplus" data-id="" /></figure></li><li class="blocks-gallery-item"><figure><img src="https://raw.githubusercontent.com/devicons/devicon/master/icons/css3/css3-original-wordmark.svg" alt="css3" data-id="" /></figure></li><li class="blocks-gallery-item"><figure><img src="https://raw.githubusercontent.com/devicons/devicon/master/icons/d3js/d3js-original.svg" alt="d3js" data-id="" /></figure></li><li class="blocks-gallery-item"><figure><img src="https://raw.githubusercontent.com/devicons/devicon/master/icons/docker/docker-original-wordmark.svg" alt="docker" data-id="" /></figure></li><li class="blocks-gallery-item"><figure><img src="https://camo.githubusercontent.com/d4cbacdc000de378e0dcae3b5ee54923c0ad04f6e52b7aa886a748fba5578def/68747470733a2f2f7777772e766563746f726c6f676f2e7a6f6e652f6c6f676f732f656c61737469632f656c61737469632d69636f6e2e737667" alt="elasticsearch" data-id="" /></figure></li><li class="blocks-gallery-item"><figure><img src="https://raw.githubusercontent.com/devicons/devicon/master/icons/ember/ember-original-wordmark.svg" alt="ember" data-id="" /></figure></li><li class="blocks-gallery-item"><figure><img src="https://raw.githubusercontent.com/devicons/devicon/master/icons/express/express-original-wordmark.svg" alt="express" data-id="" /></figure></li><li class="blocks-gallery-item"><figure><img src="https://camo.githubusercontent.com/dd4b2422ed3bfc9da88c43d18550375c66f9584327dff7ecc19315ce50b96f07/68747470733a2f2f7777772e766563746f726c6f676f2e7a6f6e652f6c6f676f732f66697265626173652f66697265626173652d69636f6e2e737667" alt="firebase" data-id="" /></figure></li><li class="blocks-gallery-item"><figure><img src="https://camo.githubusercontent.com/ba9df1e4c5f7c9f6503f2668f03a934b4553c5840dd6067ee1ab013c2af86afc/68747470733a2f2f7777772e766563746f726c6f676f2e7a6f6e652f6c6f676f732f6761747362796a732f6761747362796a732d69636f6e2e737667" alt="gatsby" data-id="" /></figure></li><li class="blocks-gallery-item"><figure><img src="https://camo.githubusercontent.com/582944f6627732531ce1a2e20ad43538d1896e16a5f159ea28fd137dbb8e798a/68747470733a2f2f7777772e766563746f726c6f676f2e7a6f6e652f6c6f676f732f676f6f676c655f636c6f75642f676f6f676c655f636c6f75642d69636f6e2e737667" alt="gcp" data-id="" /></figure></li><li class="blocks-gallery-item"><figure><img src="https://camo.githubusercontent.com/fbfcb9e3dc648adc93bef37c718db16c52f617ad055a26de6dc3c21865c3321d/68747470733a2f2f7777772e766563746f726c6f676f2e7a6f6e652f6c6f676f732f6769742d73636d2f6769742d73636d2d69636f6e2e737667" alt="git" data-id="" /></figure></li><li class="blocks-gallery-item"><figure><img src="https://camo.githubusercontent.com/df12cb598044a3f38efc1f45e3580558c324cf8789b79487125044eeebcc4dee/68747470733a2f2f7777772e766563746f726c6f676f2e7a6f6e652f6c6f676f732f6865726f6b752f6865726f6b752d69636f6e2e737667" alt="heroku" data-id="" /></figure></li><li class="blocks-gallery-item"><figure><img src="https://raw.githubusercontent.com/devicons/devicon/master/icons/html5/html5-original-wordmark.svg" alt="html5" data-id="" /></figure></li><li class="blocks-gallery-item"><figure><img src="https://raw.githubusercontent.com/devicons/devicon/master/icons/javascript/javascript-original.svg" alt="javascript" data-id="" /></figure></li><li class="blocks-gallery-item"><figure><img src="https://camo.githubusercontent.com/d7a4f32c1f2f389d3db9810abfe171cd5d68f9239d2918f975845faf0cbbb70c/68747470733a2f2f7777772e766563746f726c6f676f2e7a6f6e652f6c6f676f732f6a656b796c6c72622f6a656b796c6c72622d69636f6e2e737667" alt="jekyll" data-id="" /></figure></li><li class="blocks-gallery-item"><figure><img src="https://raw.githubusercontent.com/devicons/devicon/master/icons/linux/linux-original.svg" alt="linux" data-id="" /></figure></li><li class="blocks-gallery-item"><figure><img src="https://raw.githubusercontent.com/simple-icons/simple-icons/master/icons/mathworks.svg" alt="matlab" data-id="" /></figure></li><li class="blocks-gallery-item"><figure><img src="https://camo.githubusercontent.com/4253eb6921d60a216772940978dea3a0cf2113f2f29b5545720d3b5b6960e467/68747470733a2f2f7777772e766563746f726c6f676f2e7a6f6e652f6c6f676f732f6d6f6368616a732f6d6f6368616a732d69636f6e2e737667" alt="mocha" data-id="" /></figure></li><li class="blocks-gallery-item"><figure><img src="https://raw.githubusercontent.com/devicons/devicon/master/icons/mongodb/mongodb-original-wordmark.svg" alt="mongodb" data-id="" /></figure></li><li class="blocks-gallery-item"><figure><img src="https://camo.githubusercontent.com/300c2986a53648631c34798554da7cde3779de253b02a15da6bccc59ea9f0317/68747470733a2f2f63646e2e776f726c64766563746f726c6f676f2e636f6d2f6c6f676f732f6e6578746a732d332e737667" alt="nextjs" data-id="" /></figure></li><li class="blocks-gallery-item"><figure><img src="https://raw.githubusercontent.com/devicons/devicon/master/icons/nodejs/nodejs-original-wordmark.svg" alt="nodejs" data-id="" /></figure></li><li class="blocks-gallery-item"><figure><img src="https://raw.githubusercontent.com/devicons/devicon/master/icons/photoshop/photoshop-line.svg" alt="photoshop" data-id="" /></figure></li><li class="blocks-gallery-item"><figure><img src="https://raw.githubusercontent.com/devicons/devicon/master/icons/postgresql/postgresql-original-wordmark.svg" alt="postgresql" data-id="" /></figure></li><li class="blocks-gallery-item"><figure><img src="https://camo.githubusercontent.com/93b32389bf746009ca2370de7fe06c3b5146f4c99d99df65994f9ced0ba41685/68747470733a2f2f7777772e766563746f726c6f676f2e7a6f6e652f6c6f676f732f676574706f73746d616e2f676574706f73746d616e2d69636f6e2e737667" alt="postman" data-id="" /></figure></li><li class="blocks-gallery-item"><figure><img src="https://camo.githubusercontent.com/e6f31db76aa258d4e26be8464f2dff9796d5cf59185976df02dd80ae6a60cc9e/68747470733a2f2f63646e2e776f726c64766563746f726c6f676f2e636f6d2f6c6f676f732f7075672e737667" alt="pug" data-id="" /></figure></li><li class="blocks-gallery-item"><figure><img src="https://camo.githubusercontent.com/9391ab4ec8994e921292160bd31966a5886d8599af858ee5e513f2a3d868c403/68747470733a2f2f7777772e766563746f726c6f676f2e7a6f6e652f6c6f676f732f707074726465762f707074726465762d6f6666696369616c2e737667" alt="puppeteer" data-id="" /></figure></li><li class="blocks-gallery-item"><figure><img src="https://raw.githubusercontent.com/devicons/devicon/master/icons/python/python-original.svg" alt="python" data-id="" /></figure></li><li class="blocks-gallery-item"><figure><img src="https://raw.githubusercontent.com/devicons/devicon/master/icons/react/react-original-wordmark.svg" alt="react" data-id="" /></figure></li><li class="blocks-gallery-item"><figure><img src="https://camo.githubusercontent.com/5c92eeb467fd5d2b1ef1c560e3c3c2f758a8d4e03a8136bda7b41a2d3d4a1b59/68747470733a2f2f72656163746e61746976652e6465762f696d672f6865616465725f6c6f676f2e737667" alt="reactnative" data-id="" /></figure></li><li class="blocks-gallery-item"><figure><img src="https://raw.githubusercontent.com/devicons/devicon/master/icons/typescript/typescript-original.svg" alt="typescript" data-id="" /></figure></li><li class="blocks-gallery-item"><figure><img src="https://camo.githubusercontent.com/8ce24bc85eb4a64c6ad571675cbc7dca48a49feea462d572204505907c6ca957/68747470733a2f2f7777772e766563746f726c6f676f2e7a6f6e652f6c6f676f732f76616772616e7475702f76616772616e7475702d69636f6e2e737667" alt="vagrant" data-id="" /></figure></li><li class="blocks-gallery-item"><figure><img src="https://raw.githubusercontent.com/devicons/devicon/d00d0969292a6569d45b06d3f350f463a0107b0d/icons/webpack/webpack-original-wordmark.svg" alt="webpack" data-id="" /></figure></li><li class="blocks-gallery-item"><figure><img src="https://camo.githubusercontent.com/8f391d66440860f43c55d4d8ad22733a6919059108642cfdad9be4fc5f4f1d79/68747470733a2f2f7777772e766563746f726c6f676f2e7a6f6e652f6c6f676f732f7a61706965722f7a61706965722d69636f6e2e737667" alt="zapier" data-id="" /></figure></li></ul></figure> | |
<hr class="wp-block-separator" /> | |
<hr class="wp-block-separator" /> | |
<figure class="wp-block-image"><a href="https://camo.githubusercontent.com/cf5d4a973533a4c4231a2385ee68163bc88bc95bcc047eb238ee8269943a60b6/68747470733a2f2f6769746875622d726561646d652d73746174732e76657263656c2e6170702f6170693f757365726e616d653d62676f6f6e7a2673686f775f69636f6e733d74727565266c6f63616c653d656e" target="_blank" rel="noreferrer noopener"><img src="https://camo.githubusercontent.com/cf5d4a973533a4c4231a2385ee68163bc88bc95bcc047eb238ee8269943a60b6/68747470733a2f2f6769746875622d726561646d652d73746174732e76657263656c2e6170702f6170693f757365726e616d653d62676f6f6e7a2673686f775f69636f6e733d74727565266c6f63616c653d656e" alt="bgoonz" /></a></figure> | |
<figure class="wp-block-image"><a href="https://camo.githubusercontent.com/3a0b40daebc9fe1d25f51ff4923c0d02451e3f986c04d95692e919412afc3f95/68747470733a2f2f6769746875622d726561646d652d73747265616b2d73746174732e6865726f6b756170702e636f6d2f3f757365723d62676f6f6e7a26" target="_blank" rel="noreferrer noopener"><img src="https://camo.githubusercontent.com/3a0b40daebc9fe1d25f51ff4923c0d02451e3f986c04d95692e919412afc3f95/68747470733a2f2f6769746875622d726561646d652d73747265616b2d73746174732e6865726f6b756170702e636f6d2f3f757365723d62676f6f6e7a26" alt="bgoonz" /></a></figure> | |
<figure class="wp-block-image"><a href="https://github.com/bgoonz/github-profile-trophy"><img src="https://camo.githubusercontent.com/ec5908a2b7b26de2d103e5281abfb6ca1d1a31b3b9b6e54c1e72c01c123e995f/68747470733a2f2f6769746875622d70726f66696c652d74726f7068792e76657263656c2e6170702f3f757365726e616d653d62676f6f6e7a26726f773d31" alt="trophy" /></a></figure> | |
<p class="has-text-align-center">Medium Articles Self Hosted:</p> | |
<p><a href="https://modest-booth-4e17df.netlify.app/" rel="nofollow">https://modest-booth-4e17df.netlify.app/</a></p> | |
</div><!-- .entry-content --> | |
<footer class="entry-footer responsive-max-width"> | |
<span class="byline"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><span class="screen-reader-text">Posted by</span><span class="author vcard"><a class="url fn n" href="https://web-dev-hub.com/author/gunerb1/">bgoonz</a></span></span><span class="posted-on"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><defs><path id="a" d="M0 0h24v24H0V0z"></path></defs><clipPath id="b"><use xlink:href="#a" overflow="visible"></use></clipPath><path clip-path="url(#b)" d="M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10 10-4.5 10-10S17.5 2 12 2zm4.2 14.2L11 13V7h1.5v5.2l4.5 2.7-.8 1.3z"></path></svg><a href="https://web-dev-hub.com/2021/03/23/hi-%f0%9f%91%8b-im-bryan/" rel="bookmark"><time class="entry-date published" datetime="2021-03-23T15:12:43-04:00">March 23, 2021</time><time class="updated" datetime="2021-03-23T23:44:50-04:00">March 23, 2021</time></a></span><span class="cat-links"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M10 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2h-8l-2-2z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><span class="screen-reader-text">Posted in</span><a href="https://web-dev-hub.com/category/uncategorized/" rel="category tag">Uncategorized</a></span><span class="comments-link"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M21.99 4c0-1.1-.89-2-1.99-2H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h14l4 4-.01-18z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><a href="https://web-dev-hub.com/2021/03/23/hi-%f0%9f%91%8b-im-bryan/#respond">Leave a comment<span class="screen-reader-text"> on Hi 👋, I’m Bryan</span></a></span><span class="edit-link"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04c.39-.39.39-1.02 0-1.41l-2.34-2.34c-.39-.39-1.02-.39-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><a class="post-edit-link" href="https://wordpress.com/post/web-dev-hub.com/373">Edit <span class="screen-reader-text">Hi 👋, I’m Bryan</span></a></span> </footer><!-- .entry-footer --> | |
</article><!-- #post-${ID} --> | |
<article id="post-11" class="post-11 post type-post status-publish format-standard sticky hentry category-uncategorized entry"> | |
<header class="entry-header responsive-max-width"> | |
<span class="sticky-post">Featured</span><h2 class="entry-title"><a href="https://web-dev-hub.com/2021/03/15/example-post/" rel="bookmark">Hi 👋, I’m Bryan</a></h2> </header><!-- .entry-header --> | |
<div class="entry-content"> | |
<h4>Passionate Web Developer, Electrical Engineer, Audio Engineer and Musician / Teacher!</h4> | |
<hr class="wp-block-separator" /> | |
<div data-carousel-extra='{"blog_id":190652711,"permalink":"https:\/\/web-dev-hub.com\/2021\/03\/15\/example-post\/"}' class="wp-container-61c6b342cb84c wp-block-buttons alignfull is-content-justification-center"> | |
<div data-carousel-extra='{"blog_id":190652711,"permalink":"https:\/\/web-dev-hub.com\/2021\/03\/15\/example-post\/"}' class="wp-block-button is-style-outline"><a class="wp-block-button__link has-foreground-color has-text-color" href="https://modest-booth-4e17df.netlify.app/" style="border-radius:47px;"><strong><em><span style="color:#303030;" class="has-inline-color">blog</span></em></strong></a></div> | |
<div data-carousel-extra='{"blog_id":190652711,"permalink":"https:\/\/web-dev-hub.com\/2021\/03\/15\/example-post\/"}' class="wp-block-button is-style-outline"><a class="wp-block-button__link has-foreground-color has-text-color" href="https://github.com/bgoonz" style="border-radius:50px;"><strong><em><span style="color:#303030;" class="has-inline-color">GitHub</span></em></strong></a></div> | |
<div data-carousel-extra='{"blog_id":190652711,"permalink":"https:\/\/web-dev-hub.com\/2021\/03\/15\/example-post\/"}' class="wp-block-button is-style-outline"><a class="wp-block-button__link has-foreground-color has-text-color" href="https://github.com/bgoonz/resume-cv-portfolio-samples/blob/master/2021-resume/bryan-guner-resume-2021.pdf" style="border-radius:50px;"><strong><em><span style="color:#303030;" class="has-inline-color">Resume</span></em></strong></a></div> | |
<div data-carousel-extra='{"blog_id":190652711,"permalink":"https:\/\/web-dev-hub.com\/2021\/03\/15\/example-post\/"}' class="wp-block-button is-style-outline"><a class="wp-block-button__link has-foreground-color has-text-color" href="https://www.linkedin.com/in/bryan-guner-046199128/" style="border-radius:50px;"><strong><em><span style="color:#303030;" class="has-inline-color">Linkedin</span></em></strong></a></div> | |
<div data-carousel-extra='{"blog_id":190652711,"permalink":"https:\/\/web-dev-hub.com\/2021\/03\/15\/example-post\/"}' class="wp-block-button is-style-outline"><a class="wp-block-button__link has-foreground-color has-text-color" href="https://gist.github.com/bgoonz/659a9b81ac45453bedc0a1a36275b580" style="border-radius:50px;"><strong><em><span style="color:#303030;" class="has-inline-color">Deploys</span></em></strong></a></div> | |
<div data-carousel-extra='{"blog_id":190652711,"permalink":"https:\/\/web-dev-hub.com\/2021\/03\/15\/example-post\/"}' class="wp-block-button is-style-outline"><a class="wp-block-button__link has-foreground-color has-text-color" href="https://web-dev-resource-hub.netlify.app/" style="border-radius:50px;" rel="https://web-dev-resource-hub.netlify.app/"><strong><em><span style="color:#303030;" class="has-inline-color">Site</span></em></strong></a></div> | |
</div> | |
<div data-carousel-extra='{"blog_id":190652711,"permalink":"https:\/\/web-dev-hub.com\/2021\/03\/15\/example-post\/"}' class="wp-block-image"><figure class="aligncenter"><a href="https://camo.githubusercontent.com/41fbd874c1ba0b69222440c1527ceb24831f388dcf4b875c048dbf0ce11fce58/68747470733a2f2f76696577732e77686174696c656172656e65642e746f6461792f76696577732f6769746875622f62676f6f6e7a2f76696577732e737667" target="_blank" rel="noreferrer noopener"><img src="https://camo.githubusercontent.com/41fbd874c1ba0b69222440c1527ceb24831f388dcf4b875c048dbf0ce11fce58/68747470733a2f2f76696577732e77686174696c656172656e65642e746f6461792f76696577732f6769746875622f62676f6f6e7a2f76696577732e737667" alt="Profile views" /></a></figure></div> | |
<hr class="wp-block-separator" /> | |
<div data-carousel-extra='{"blog_id":190652711,"permalink":"https:\/\/web-dev-hub.com\/2021\/03\/15\/example-post\/"}' class="wp-block-image"><figure class="aligncenter"><a href="https://github.com/bgoonz/bgoonz/blob/master/circle-small-sharp.png?raw=true?raw=true" target="_blank" rel="noreferrer noopener"><img src="https://github.com/bgoonz/bgoonz/raw/master/circle-small-sharp.png?raw=true?raw=true" alt="" /></a></figure></div> | |
<h3><a href="https://github.com/bgoonz#a-passionate-web-developer-electrical-engineer-musician--producer"></a>A passionate Web Developer, Electrical Engineer, Musician & Producer</h3> | |
<ul><li>🔭 Contract Web Development <strong>Relational Concepts</strong></li><li>🌱 I’m currently learning <strong>React/Redux, Python, Java, Express, jQuery</strong></li><li>👯 I’m looking to collaborate on <a href="https://goofy-euclid-1cd736.netlify.app/core-site/index.html">Any web audio or open source educational tools.</a></li><li>🤝 I’m looking for help with <a href="https://github.com/bgoonz/React-Practice">Learning React</a></li><li>👨💻 All of my projects are available at <a href="https://bgoonz.github.io/">https://bgoonz.github.io/</a></li><li>📝 I regularly write articles on <a href="https://bryanguner.medium.com/">medium</a> && <a href="https://web-dev-resource-hub.netlify.app/">Web-Dev-Resource-Hub</a></li><li>💬 Ask me about <strong>Anything:</strong></li><li>📫 How to reach me <strong><a href="mailto:bryan.guner@gmail.com">bryan.guner@gmail.com</a></strong></li><li>⚡ Fun fact <strong>I played Bamboozle Music Festival at the Meadowlands Stadium Complex when I was 14.</strong></li></ul> | |
<hr class="wp-block-separator" /> | |
<div data-carousel-extra='{"blog_id":190652711,"permalink":"https:\/\/web-dev-hub.com\/2021\/03\/15\/example-post\/"}' class="wp-block-image"><figure class="aligncenter is-resized"><a href="https://camo.githubusercontent.com/727b46e1d3fa1dc9460d1f7a8c4f4fb8a5523029a3389abf818bc1f95430b4ac/68747470733a2f2f726561646d652d6a6f6b65732e76657263656c2e6170702f617069" target="_blank" rel="noreferrer noopener"><img src="https://camo.githubusercontent.com/727b46e1d3fa1dc9460d1f7a8c4f4fb8a5523029a3389abf818bc1f95430b4ac/68747470733a2f2f726561646d652d6a6f6b65732e76657263656c2e6170702f617069" alt="" width="529" height="158" /></a></figure></div> | |
<hr class="wp-block-separator" /> | |
<figure class="wp-block-image"><a href="https://github.com/bgoonz#_email_"><img src="https://raw.githubusercontent.com/andreasbm/readme/master/assets/lines/colored.png" alt="-----------------------------------------------------" /></a></figure> | |
<h2><a href="https://github.com/bgoonz#-email"></a>➤ <em>Email</em></h2> | |
<p><a href="https://github.com/bgoonz#">bryan.guner.dev@gmail.com</a></p> | |
<figure class="wp-block-image"><a href="https://github.com/bgoonz#_phone_"><img src="https://raw.githubusercontent.com/andreasbm/readme/master/assets/lines/colored.png" alt="-----------------------------------------------------" /></a></figure> | |
<h2>Connect with me:</h2> | |
<div data-carousel-extra='{"blog_id":190652711,"permalink":"https:\/\/web-dev-hub.com\/2021\/03\/15\/example-post\/"}' class="wp-block-columns"> | |
<div data-carousel-extra='{"blog_id":190652711,"permalink":"https:\/\/web-dev-hub.com\/2021\/03\/15\/example-post\/"}' class="wp-block-column" style="flex-basis:20%;"> | |
<figure class="wp-block-image"><a href="https://stackoverflow.com/users/20645183"><img src="https://camo.githubusercontent.com/bd44ccfd9dad8d42fb19cacdac1ce3d2da666127da16876455a661988cf65f5d/68747470733a2f2f63646e2e6a7364656c6976722e6e65742f6e706d2f73696d706c652d69636f6e7340332e302e312f69636f6e732f737461636b6f766572666c6f772e737667" alt="20645183" /></a></figure> | |
</div> | |
<div data-carousel-extra='{"blog_id":190652711,"permalink":"https:\/\/web-dev-hub.com\/2021\/03\/15\/example-post\/"}' class="wp-block-column" style="flex-basis:20%;"> | |
<figure class="wp-block-image is-resized"><a href="https://codesandbox.com/bgoonz"><img src="https://camo.githubusercontent.com/7a9df7545ac90d346949d6781841f8dddb4c01b4f882272714bfbd13b5872c2f/68747470733a2f2f63646e2e6a7364656c6976722e6e65742f6e706d2f73696d706c652d69636f6e7340332e302e312f69636f6e732f636f646573616e64626f782e737667" alt="bgoonz" width="25" height="25" /></a></figure> | |
</div> | |
<div data-carousel-extra='{"blog_id":190652711,"permalink":"https:\/\/web-dev-hub.com\/2021\/03\/15\/example-post\/"}' class="wp-block-column" style="flex-basis:20%;"> | |
<figure class="wp-block-image"><a href="https://instagram.com/bgoonz"><img src="https://camo.githubusercontent.com/aecaf87326884e8b0466bb799265a13fee7586246ebda3e066cb7fad82a1fd23/68747470733a2f2f63646e2e6a7364656c6976722e6e65742f6e706d2f73696d706c652d69636f6e7340332e302e312f69636f6e732f696e7374616772616d2e737667" alt="bgoonz" /></a></figure> | |
</div> | |
<div data-carousel-extra='{"blog_id":190652711,"permalink":"https:\/\/web-dev-hub.com\/2021\/03\/15\/example-post\/"}' class="wp-block-column" style="flex-basis:20%;"> | |
<figure class="wp-block-image"><a href="https://www.youtube.com/watch?v=xGZSWvFess8"><img src="https://camo.githubusercontent.com/4a20e861b6593d07cef8e8b740e64a866ba7a9916d7e00a9c50c05e93a8096b8/68747470733a2f2f63646e2e6a7364656c6976722e6e65742f6e706d2f73696d706c652d69636f6e7340332e302e312f69636f6e732f796f75747562652e737667" alt="bryan guner" /></a></figure> | |
</div> | |
<div data-carousel-extra='{"blog_id":190652711,"permalink":"https:\/\/web-dev-hub.com\/2021\/03\/15\/example-post\/"}' class="wp-block-column" style="flex-basis:20%;"> | |
<figure class="wp-block-image"><a href="https://www.leetcode.com/bgoonz"><img src="https://camo.githubusercontent.com/031caf938447e457226d5d394c550909299fa104f70601ba8c5e82077f8b1f96/68747470733a2f2f63646e2e6a7364656c6976722e6e65742f6e706d2f73696d706c652d69636f6e7340332e302e312f69636f6e732f6c656574636f64652e737667" alt="bgoonz" /></a></figure> | |
</div> | |
</div> | |
<hr class="wp-block-separator" /> | |
<figure class="wp-block-image"><a href="https://github.com/bgoonz#social"><img src="https://raw.githubusercontent.com/andreasbm/readme/master/assets/lines/colored.png" alt="-----------------------------------------------------" /></a></figure> | |
<h2><a href="https://github.com/bgoonz#-social"></a>➤ Other Social</h2> | |
<ul><li><a href="https://github.com/bgoonz">GitHub</a></li><li><a href="https://gitlab.com/bryan.guner.dev">Gitlab</a></li><li><a href="https://bitbucket.org/bgoonz/">Bitbucket</a></li><li><a href="https://codepen.io/bgoonz">code pen</a></li><li><a href="https://glitch.com/@bgoonz">Glitch</a></li><li><a href="https://repl.it/@bgoonz/">Replit</a></li><li><a href="https://www.reddit.com/user/bgoonz1">Redit</a></li><li><a href="https://runkit.com/bgoonz">runkit</a></li><li><a href="https://meta.stackexchange.com/users/936785/bryan-guner">stack-exchange</a></li><li><a href="https://app.netlify.com/user/settings#profile">Netlify</a></li><li><a href="https://bryanguner.medium.com/">Medium</a></li><li><a href="https://webcomponents.dev/user/bgoonz">webcomponents.dev</a></li><li><a href="https://www.npmjs.com/~bgoonz11">npm</a></li><li><a href="https://www.upwork.com/freelancers/~01bb1a3627e1e9c630?viewMode=1&s=1110580755057594368">Upwork</a></li><li><a href="https://angel.co/u/bryan-guner">AngelList</a></li><li><a href="https://www.quora.com/q/webdevresourcehub?invite_code=qwZOqbpAhgQ6hjjGl8NN">Quora</a></li></ul> | |
<figure class="wp-block-image"><a href="https://github.com/bgoonz#blog"><img src="https://raw.githubusercontent.com/andreasbm/readme/master/assets/lines/colored.png" alt="-----------------------------------------------------" /></a></figure> | |
<h2 class="has-small-font-size" style="line-height:.9;"><a href="https://github.com/bgoonz#-blog"></a>➤ <a href="">Blog:</a><a href="https://bryanguner.medium.com/">https://bryanguner.medium.com/</a></h2> | |
<figure class="wp-block-image is-resized"><a href="https://github.com/bgoonz#projects"><img src="https://raw.githubusercontent.com/andreasbm/readme/master/assets/lines/colored.png" alt="-----------------------------------------------------" width="900" height="9" /></a></figure> | |
<h1><a href="https://github.com/bgoonz#-projects"></a>➤ Projects:</h1> | |
<div data-carousel-extra='{"blog_id":190652711,"permalink":"https:\/\/web-dev-hub.com\/2021\/03\/15\/example-post\/"}' class="wp-block-columns"> | |
<div data-carousel-extra='{"blog_id":190652711,"permalink":"https:\/\/web-dev-hub.com\/2021\/03\/15\/example-post\/"}' class="wp-block-column" style="flex-basis:100%;"> | |
<div data-carousel-extra='{"blog_id":190652711,"permalink":"https:\/\/web-dev-hub.com\/2021\/03\/15\/example-post\/"}' class="wp-container-61c6b342cc2c8 wp-block-group"><div data-carousel-extra='{"blog_id":190652711,"permalink":"https:\/\/web-dev-hub.com\/2021\/03\/15\/example-post\/"}' class="wp-block-group__inner-container"> | |
<div data-carousel-extra='{"blog_id":190652711,"permalink":"https:\/\/web-dev-hub.com\/2021\/03\/15\/example-post\/"}' class="wp-block-columns"> | |
<div data-carousel-extra='{"blog_id":190652711,"permalink":"https:\/\/web-dev-hub.com\/2021\/03\/15\/example-post\/"}' class="wp-block-column" style="flex-basis:100%;"> | |
<pre class="wp-block-preformatted" style="font-size:12px;"><a href="https://project-showcase-bgoonz.netlify.app/">https://project-showcase-bgoonz.netlify.app/</a></pre> | |
</div> | |
</div> | |
</div></div> | |
</div> | |
</div> | |
<hr class="wp-block-separator" /> | |
<h2><a href="https://github.com/bgoonz#web-dev-resource-hub"></a>Web Dev Resource Hub</h2> | |
<h3><a href="https://github.com/bgoonz#my-personal-web-development-blog-and-resource-sharing-site"></a>My personal Web Development blog and resource sharing site</h3> | |
<ul><li><a href="https://web-dev-resource-hub.netlify.app/">Live Site</a></li></ul> | |
<figure class="wp-block-image"><a href="https://camo.githubusercontent.com/627c52694b92ec1f13be3a7995d46352915ad96ac13261cc37ccf987364cabd2/68747470733a2f2f636c6f75642e6e65746c69667975736572636f6e74656e742e636f6d2f6173736574732f33343464626638382d666466392d343262622d616462342d3436663031656564643632392f32336239623233362d373436652d343039632d386538362d3330623433383565336237322f6872312d7261797068616d2e676966" target="_blank" rel="noreferrer noopener"><img src="https://camo.githubusercontent.com/627c52694b92ec1f13be3a7995d46352915ad96ac13261cc37ccf987364cabd2/68747470733a2f2f636c6f75642e6e65746c69667975736572636f6e74656e742e636f6d2f6173736574732f33343464626638382d666466392d343262622d616462342d3436663031656564643632392f32336239623233362d373436652d343039632d386538362d3330623433383565336237322f6872312d7261797068616d2e676966" alt="hr-line" /></a></figure> | |
<figure class="wp-block-image"><a href="https://github.com/bgoonz#mihir_begcom"><img src="https://raw.githubusercontent.com/andreasbm/readme/master/assets/lines/colored.png" alt="-----------------------------------------------------" /></a></figure> | |
<h1><a href="https://github.com/bgoonz#-mihir_begcom"></a>➤ Mihir_Beg.com</h1> | |
<h3><a href="https://github.com/bgoonz#created-a-dynamic-web-page-for-a-local-musician-using-the-bootsrtap-framework"></a>Created a dynamic web page for a local musician using the Bootsrtap framework.</h3> | |
<p>-Talk about App Features & Design Process Here-</p> | |
<ul><li><a href="https://eloquent-sammet-ba1810.netlify.app/">Live Site</a></li></ul> | |
<figure class="wp-block-image"><a href="https://camo.githubusercontent.com/627c52694b92ec1f13be3a7995d46352915ad96ac13261cc37ccf987364cabd2/68747470733a2f2f636c6f75642e6e65746c69667975736572636f6e74656e742e636f6d2f6173736574732f33343464626638382d666466392d343262622d616462342d3436663031656564643632392f32336239623233362d373436652d343039632d386538362d3330623433383565336237322f6872312d7261797068616d2e676966" target="_blank" rel="noreferrer noopener"><img src="https://camo.githubusercontent.com/627c52694b92ec1f13be3a7995d46352915ad96ac13261cc37ccf987364cabd2/68747470733a2f2f636c6f75642e6e65746c69667975736572636f6e74656e742e636f6d2f6173736574732f33343464626638382d666466392d343262622d616462342d3436663031656564643632392f32336239623233362d373436652d343039632d386538362d3330623433383565336237322f6872312d7261797068616d2e676966" alt="hr-line" /></a></figure> | |
<hr class="wp-block-separator" /> | |
<hr class="wp-block-separator" /> | |
<h2><a href="https://github.com/bgoonz#interview-prep-static-site"></a>Interview Prep Static Site</h2> | |
<h3><a href="https://github.com/bgoonz#data-structures-repository"></a>Data Structures Repository</h3> | |
<p>-Hope this helps someone other than me!-</p> | |
<ul><li><a href="https://ds-algo-official-c3dw6uapg-bgoonz.vercel.app/">Live Site</a></li></ul> | |
<hr class="wp-block-separator" /> | |
<figure class="wp-block-image"><a href="https://camo.githubusercontent.com/627c52694b92ec1f13be3a7995d46352915ad96ac13261cc37ccf987364cabd2/68747470733a2f2f636c6f75642e6e65746c69667975736572636f6e74656e742e636f6d2f6173736574732f33343464626638382d666466392d343262622d616462342d3436663031656564643632392f32336239623233362d373436652d343039632d386538362d3330623433383565336237322f6872312d7261797068616d2e676966" target="_blank" rel="noreferrer noopener"><img src="https://camo.githubusercontent.com/627c52694b92ec1f13be3a7995d46352915ad96ac13261cc37ccf987364cabd2/68747470733a2f2f636c6f75642e6e65746c69667975736572636f6e74656e742e636f6d2f6173736574732f33343464626638382d666466392d343262622d616462342d3436663031656564643632392f32336239623233362d373436652d343039632d386538362d3330623433383565336237322f6872312d7261797068616d2e676966" alt="hr-line" /></a></figure> | |
<hr class="wp-block-separator" /> | |
<hr class="wp-block-separator" /> | |
<h2><a href="https://github.com/bgoonz#learning-react-blog"></a>Learning React Blog</h2> | |
<p><a href="https://ecstatic-jang-593fd1.netlify.app/readme" rel="nofollow">https://ecstatic-jang-593fd1.netlify.app/readme</a></p> | |
<h4><a href="https://github.com/bgoonz#react-repo"></a>React Repo:</h4> | |
<p><a href="https://github.com/bgoonz/React-Practice">React Repo</a></p> | |
<hr class="wp-block-separator" /> | |
<h2><a href="https://github.com/bgoonz#"></a><a href="https://codesandbox.io/embed/zealous-microservice-ti7em?autoresize=1&expanddevtools=1&fontsize=14&hidenavigation=1&moduleview=1&theme=dark"></a></h2> | |
<figure class="wp-block-image"><a href="https://camo.githubusercontent.com/627c52694b92ec1f13be3a7995d46352915ad96ac13261cc37ccf987364cabd2/68747470733a2f2f636c6f75642e6e65746c69667975736572636f6e74656e742e636f6d2f6173736574732f33343464626638382d666466392d343262622d616462342d3436663031656564643632392f32336239623233362d373436652d343039632d386538362d3330623433383565336237322f6872312d7261797068616d2e676966" target="_blank" rel="noreferrer noopener"><img src="https://camo.githubusercontent.com/627c52694b92ec1f13be3a7995d46352915ad96ac13261cc37ccf987364cabd2/68747470733a2f2f636c6f75642e6e65746c69667975736572636f6e74656e742e636f6d2f6173736574732f33343464626638382d666466392d343262622d616462342d3436663031656564643632392f32336239623233362d373436652d343039632d386538362d3330623433383565336237322f6872312d7261797068616d2e676966" alt="hr-line" /></a></figure> | |
<p><a href="https://documentation-site-react2-peitff669-bgoonz.vercel.app/">react-documentation-site</a></p> | |
<figure class="wp-block-image"><a href="https://codesandbox.io/s/magical-stallman-ov0d1?autoresize=1&expanddevtools=1&fontsize=12&hidenavigation=1&moduleview=1&theme=dark"><img src="https://camo.githubusercontent.com/90808661433696bc57dce8d4ad732307b5cec6270e6b846f114dcd7ee7f9458a/68747470733a2f2f636f646573616e64626f782e696f2f7374617469632f696d672f706c61792d636f646573616e64626f782e737667" alt="Edit magical-stallman-ov0d1" /></a></figure> | |
<figure class="wp-block-image"><a href="https://camo.githubusercontent.com/627c52694b92ec1f13be3a7995d46352915ad96ac13261cc37ccf987364cabd2/68747470733a2f2f636c6f75642e6e65746c69667975736572636f6e74656e742e636f6d2f6173736574732f33343464626638382d666466392d343262622d616462342d3436663031656564643632392f32336239623233362d373436652d343039632d386538362d3330623433383565336237322f6872312d7261797068616d2e676966" target="_blank" rel="noreferrer noopener"><img src="https://camo.githubusercontent.com/627c52694b92ec1f13be3a7995d46352915ad96ac13261cc37ccf987364cabd2/68747470733a2f2f636c6f75642e6e65746c69667975736572636f6e74656e742e636f6d2f6173736574732f33343464626638382d666466392d343262622d616462342d3436663031656564643632392f32336239623233362d373436652d343039632d386538362d3330623433383565336237322f6872312d7261797068616d2e676966" alt="hr-line" /></a></figure> | |
<hr class="wp-block-separator" /> | |
<h1><a href="https://github.com/bgoonz#mini-project-showcase"></a>Mini Project Showcase</h1> | |
<h4><a href="https://github.com/bgoonz#just-some-simpe-static-webpage-projects"></a>Just some simpe static webpage projects</h4> | |
<p><a href="https://jovial-agnesi-8ec8b1.netlify.app/">mini-projects</a></p> | |
<h2><a href="https://github.com/bgoonz#codepens-mostly-embeded-animations"></a>Codepens (mostly embeded animations)</h2> | |
<p><a href="https://embedable-content.netlify.app/">code-pens-embedded</a></p> | |
<hr class="wp-block-separator" /> | |
<p>Click to expand!</p> | |
<hr class="wp-block-separator" /> | |
<hr class="wp-block-separator" /> | |
<figure class="wp-block-image alignwide is-style-rounded"><a href="https://github.com/bgoonz/bgoonz/blob/master/skills.PNG" target="_blank" rel="noreferrer noopener"><img src="https://github.com/bgoonz/bgoonz/raw/master/skills.PNG" alt="skills" /></a></figure> | |
<hr class="wp-block-separator" /> | |
<hr class="wp-block-separator" /> | |
<h3><a href="https://github.com/bgoonz#languages-and-tools"></a>Languages and Tools:</h3> | |
<pre class="wp-block-preformatted"></pre> | |
<figure class="wp-block-gallery columns-8 is-cropped"><ul data-carousel-extra='{"blog_id":190652711,"permalink":"https:\/\/web-dev-hub.com\/2021\/03\/15\/example-post\/"}' class="blocks-gallery-grid"><li class="blocks-gallery-item"><figure><img src="https://camo.githubusercontent.com/b3a1cdd20d0f308634ddd4598cdaa729c2d77047f51e66fa7206b9b4bac94c23/68747470733a2f2f63646e2e776f726c64766563746f726c6f676f2e636f6d2f6c6f676f732f61726475696e6f2d312e737667" alt="arduino" data-id="" /></figure></li><li class="blocks-gallery-item"><figure><img src="https://raw.githubusercontent.com/devicons/devicon/master/icons/amazonwebservices/amazonwebservices-original-wordmark.svg" alt="aws" data-id="" /></figure></li><li class="blocks-gallery-item"><figure><img src="https://camo.githubusercontent.com/6df31a460cb0c38f960e92812c8b6f8bce4c7f13170fb4782f0b31ab8e792ac2/68747470733a2f2f7777772e766563746f726c6f676f2e7a6f6e652f6c6f676f732f6d6963726f736f66745f617a7572652f6d6963726f736f66745f617a7572652d69636f6e2e737667" alt="azure" data-id="" /></figure></li><li class="blocks-gallery-item"><figure><img src="https://camo.githubusercontent.com/1abf71d00a4a13bfdeccdc131c65f02644fae4e746289bd7c21bf1d2af986389/68747470733a2f2f7777772e766563746f726c6f676f2e7a6f6e652f6c6f676f732f626162656c6a732f626162656c6a732d69636f6e2e737667" alt="babel" data-id="" /></figure></li><li class="blocks-gallery-item"><figure><img src="https://camo.githubusercontent.com/bbb327d6ba7708520eaafd13396fed64d73bf5df5c4cdd0ba03cf0843f7a9340/68747470733a2f2f7777772e766563746f726c6f676f2e7a6f6e652f6c6f676f732f676e755f626173682f676e755f626173682d69636f6e2e737667" alt="bash" data-id="" /></figure></li><li class="blocks-gallery-item"><figure><img src="https://raw.githubusercontent.com/devicons/devicon/master/icons/bootstrap/bootstrap-plain-wordmark.svg" alt="bootstrap" data-id="" /></figure></li><li class="blocks-gallery-item"><figure><img src="https://raw.githubusercontent.com/devicons/devicon/master/icons/cplusplus/cplusplus-original.svg" alt="cplusplus" data-id="" /></figure></li><li class="blocks-gallery-item"><figure><img src="https://raw.githubusercontent.com/devicons/devicon/master/icons/css3/css3-original-wordmark.svg" alt="css3" data-id="" /></figure></li><li class="blocks-gallery-item"><figure><img src="https://raw.githubusercontent.com/devicons/devicon/master/icons/d3js/d3js-original.svg" alt="d3js" data-id="" /></figure></li><li class="blocks-gallery-item"><figure><img src="https://raw.githubusercontent.com/devicons/devicon/master/icons/docker/docker-original-wordmark.svg" alt="docker" data-id="" /></figure></li><li class="blocks-gallery-item"><figure><img src="https://camo.githubusercontent.com/d4cbacdc000de378e0dcae3b5ee54923c0ad04f6e52b7aa886a748fba5578def/68747470733a2f2f7777772e766563746f726c6f676f2e7a6f6e652f6c6f676f732f656c61737469632f656c61737469632d69636f6e2e737667" alt="elasticsearch" data-id="" /></figure></li><li class="blocks-gallery-item"><figure><img src="https://raw.githubusercontent.com/devicons/devicon/master/icons/ember/ember-original-wordmark.svg" alt="ember" data-id="" /></figure></li><li class="blocks-gallery-item"><figure><img src="https://raw.githubusercontent.com/devicons/devicon/master/icons/express/express-original-wordmark.svg" alt="express" data-id="" /></figure></li><li class="blocks-gallery-item"><figure><img src="https://camo.githubusercontent.com/dd4b2422ed3bfc9da88c43d18550375c66f9584327dff7ecc19315ce50b96f07/68747470733a2f2f7777772e766563746f726c6f676f2e7a6f6e652f6c6f676f732f66697265626173652f66697265626173652d69636f6e2e737667" alt="firebase" data-id="" /></figure></li><li class="blocks-gallery-item"><figure><img src="https://camo.githubusercontent.com/ba9df1e4c5f7c9f6503f2668f03a934b4553c5840dd6067ee1ab013c2af86afc/68747470733a2f2f7777772e766563746f726c6f676f2e7a6f6e652f6c6f676f732f6761747362796a732f6761747362796a732d69636f6e2e737667" alt="gatsby" data-id="" /></figure></li><li class="blocks-gallery-item"><figure><img src="https://camo.githubusercontent.com/582944f6627732531ce1a2e20ad43538d1896e16a5f159ea28fd137dbb8e798a/68747470733a2f2f7777772e766563746f726c6f676f2e7a6f6e652f6c6f676f732f676f6f676c655f636c6f75642f676f6f676c655f636c6f75642d69636f6e2e737667" alt="gcp" data-id="" /></figure></li><li class="blocks-gallery-item"><figure><img src="https://camo.githubusercontent.com/fbfcb9e3dc648adc93bef37c718db16c52f617ad055a26de6dc3c21865c3321d/68747470733a2f2f7777772e766563746f726c6f676f2e7a6f6e652f6c6f676f732f6769742d73636d2f6769742d73636d2d69636f6e2e737667" alt="git" data-id="" /></figure></li><li class="blocks-gallery-item"><figure><img src="https://camo.githubusercontent.com/df12cb598044a3f38efc1f45e3580558c324cf8789b79487125044eeebcc4dee/68747470733a2f2f7777772e766563746f726c6f676f2e7a6f6e652f6c6f676f732f6865726f6b752f6865726f6b752d69636f6e2e737667" alt="heroku" data-id="" /></figure></li><li class="blocks-gallery-item"><figure><img src="https://raw.githubusercontent.com/devicons/devicon/master/icons/html5/html5-original-wordmark.svg" alt="html5" data-id="" /></figure></li><li class="blocks-gallery-item"><figure><img src="https://raw.githubusercontent.com/devicons/devicon/master/icons/javascript/javascript-original.svg" alt="javascript" data-id="" /></figure></li><li class="blocks-gallery-item"><figure><img src="https://camo.githubusercontent.com/d7a4f32c1f2f389d3db9810abfe171cd5d68f9239d2918f975845faf0cbbb70c/68747470733a2f2f7777772e766563746f726c6f676f2e7a6f6e652f6c6f676f732f6a656b796c6c72622f6a656b796c6c72622d69636f6e2e737667" alt="jekyll" data-id="" /></figure></li><li class="blocks-gallery-item"><figure><img src="https://raw.githubusercontent.com/devicons/devicon/master/icons/linux/linux-original.svg" alt="linux" data-id="" /></figure></li><li class="blocks-gallery-item"><figure><img src="https://raw.githubusercontent.com/simple-icons/simple-icons/master/icons/mathworks.svg" alt="matlab" data-id="" /></figure></li><li class="blocks-gallery-item"><figure><img src="https://camo.githubusercontent.com/4253eb6921d60a216772940978dea3a0cf2113f2f29b5545720d3b5b6960e467/68747470733a2f2f7777772e766563746f726c6f676f2e7a6f6e652f6c6f676f732f6d6f6368616a732f6d6f6368616a732d69636f6e2e737667" alt="mocha" data-id="" /></figure></li><li class="blocks-gallery-item"><figure><img src="https://raw.githubusercontent.com/devicons/devicon/master/icons/mongodb/mongodb-original-wordmark.svg" alt="mongodb" data-id="" /></figure></li><li class="blocks-gallery-item"><figure><img src="https://camo.githubusercontent.com/300c2986a53648631c34798554da7cde3779de253b02a15da6bccc59ea9f0317/68747470733a2f2f63646e2e776f726c64766563746f726c6f676f2e636f6d2f6c6f676f732f6e6578746a732d332e737667" alt="nextjs" data-id="" /></figure></li><li class="blocks-gallery-item"><figure><img src="https://raw.githubusercontent.com/devicons/devicon/master/icons/nodejs/nodejs-original-wordmark.svg" alt="nodejs" data-id="" /></figure></li><li class="blocks-gallery-item"><figure><img src="https://raw.githubusercontent.com/devicons/devicon/master/icons/photoshop/photoshop-line.svg" alt="photoshop" data-id="" /></figure></li><li class="blocks-gallery-item"><figure><img src="https://raw.githubusercontent.com/devicons/devicon/master/icons/postgresql/postgresql-original-wordmark.svg" alt="postgresql" data-id="" /></figure></li><li class="blocks-gallery-item"><figure><img src="https://camo.githubusercontent.com/93b32389bf746009ca2370de7fe06c3b5146f4c99d99df65994f9ced0ba41685/68747470733a2f2f7777772e766563746f726c6f676f2e7a6f6e652f6c6f676f732f676574706f73746d616e2f676574706f73746d616e2d69636f6e2e737667" alt="postman" data-id="" /></figure></li><li class="blocks-gallery-item"><figure><img src="https://camo.githubusercontent.com/e6f31db76aa258d4e26be8464f2dff9796d5cf59185976df02dd80ae6a60cc9e/68747470733a2f2f63646e2e776f726c64766563746f726c6f676f2e636f6d2f6c6f676f732f7075672e737667" alt="pug" data-id="" /></figure></li><li class="blocks-gallery-item"><figure><img src="https://camo.githubusercontent.com/9391ab4ec8994e921292160bd31966a5886d8599af858ee5e513f2a3d868c403/68747470733a2f2f7777772e766563746f726c6f676f2e7a6f6e652f6c6f676f732f707074726465762f707074726465762d6f6666696369616c2e737667" alt="puppeteer" data-id="" /></figure></li><li class="blocks-gallery-item"><figure><img src="https://raw.githubusercontent.com/devicons/devicon/master/icons/python/python-original.svg" alt="python" data-id="" /></figure></li><li class="blocks-gallery-item"><figure><img src="https://raw.githubusercontent.com/devicons/devicon/master/icons/react/react-original-wordmark.svg" alt="react" data-id="" /></figure></li><li class="blocks-gallery-item"><figure><img src="https://camo.githubusercontent.com/5c92eeb467fd5d2b1ef1c560e3c3c2f758a8d4e03a8136bda7b41a2d3d4a1b59/68747470733a2f2f72656163746e61746976652e6465762f696d672f6865616465725f6c6f676f2e737667" alt="reactnative" data-id="" /></figure></li><li class="blocks-gallery-item"><figure><img src="https://raw.githubusercontent.com/devicons/devicon/master/icons/typescript/typescript-original.svg" alt="typescript" data-id="" /></figure></li><li class="blocks-gallery-item"><figure><img src="https://camo.githubusercontent.com/8ce24bc85eb4a64c6ad571675cbc7dca48a49feea462d572204505907c6ca957/68747470733a2f2f7777772e766563746f726c6f676f2e7a6f6e652f6c6f676f732f76616772616e7475702f76616772616e7475702d69636f6e2e737667" alt="vagrant" data-id="" /></figure></li><li class="blocks-gallery-item"><figure><img src="https://raw.githubusercontent.com/devicons/devicon/d00d0969292a6569d45b06d3f350f463a0107b0d/icons/webpack/webpack-original-wordmark.svg" alt="webpack" data-id="" /></figure></li><li class="blocks-gallery-item"><figure><img src="https://camo.githubusercontent.com/8f391d66440860f43c55d4d8ad22733a6919059108642cfdad9be4fc5f4f1d79/68747470733a2f2f7777772e766563746f726c6f676f2e7a6f6e652f6c6f676f732f7a61706965722f7a61706965722d69636f6e2e737667" alt="zapier" data-id="" /></figure></li></ul></figure> | |
<hr class="wp-block-separator" /> | |
<hr class="wp-block-separator" /> | |
<figure class="wp-block-image"><a href="https://camo.githubusercontent.com/cf5d4a973533a4c4231a2385ee68163bc88bc95bcc047eb238ee8269943a60b6/68747470733a2f2f6769746875622d726561646d652d73746174732e76657263656c2e6170702f6170693f757365726e616d653d62676f6f6e7a2673686f775f69636f6e733d74727565266c6f63616c653d656e" target="_blank" rel="noreferrer noopener"><img src="https://camo.githubusercontent.com/cf5d4a973533a4c4231a2385ee68163bc88bc95bcc047eb238ee8269943a60b6/68747470733a2f2f6769746875622d726561646d652d73746174732e76657263656c2e6170702f6170693f757365726e616d653d62676f6f6e7a2673686f775f69636f6e733d74727565266c6f63616c653d656e" alt="bgoonz" /></a></figure> | |
<figure class="wp-block-image"><a href="https://camo.githubusercontent.com/3a0b40daebc9fe1d25f51ff4923c0d02451e3f986c04d95692e919412afc3f95/68747470733a2f2f6769746875622d726561646d652d73747265616b2d73746174732e6865726f6b756170702e636f6d2f3f757365723d62676f6f6e7a26" target="_blank" rel="noreferrer noopener"><img src="https://camo.githubusercontent.com/3a0b40daebc9fe1d25f51ff4923c0d02451e3f986c04d95692e919412afc3f95/68747470733a2f2f6769746875622d726561646d652d73747265616b2d73746174732e6865726f6b756170702e636f6d2f3f757365723d62676f6f6e7a26" alt="bgoonz" /></a></figure> | |
<figure class="wp-block-image"><a href="https://github.com/bgoonz/github-profile-trophy"><img src="https://camo.githubusercontent.com/ec5908a2b7b26de2d103e5281abfb6ca1d1a31b3b9b6e54c1e72c01c123e995f/68747470733a2f2f6769746875622d70726f66696c652d74726f7068792e76657263656c2e6170702f3f757365726e616d653d62676f6f6e7a26726f773d31" alt="trophy" /></a></figure> | |
<p></p> | |
</div><!-- .entry-content --> | |
<footer class="entry-footer responsive-max-width"> | |
<span class="byline"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><span class="screen-reader-text">Posted by</span><span class="author vcard"><a class="url fn n" href="https://web-dev-hub.com/author/gunerb1/">bgoonz</a></span></span><span class="posted-on"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><defs><path id="a" d="M0 0h24v24H0V0z"></path></defs><clipPath id="b"><use xlink:href="#a" overflow="visible"></use></clipPath><path clip-path="url(#b)" d="M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10 10-4.5 10-10S17.5 2 12 2zm4.2 14.2L11 13V7h1.5v5.2l4.5 2.7-.8 1.3z"></path></svg><a href="https://web-dev-hub.com/2021/03/15/example-post/" rel="bookmark"><time class="entry-date published" datetime="2021-03-15T02:54:37-04:00">March 15, 2021</time><time class="updated" datetime="2021-03-23T21:30:28-04:00">March 23, 2021</time></a></span><span class="cat-links"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M10 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2h-8l-2-2z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><span class="screen-reader-text">Posted in</span><a href="https://web-dev-hub.com/category/uncategorized/" rel="category tag">Uncategorized</a></span><span class="comments-link"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M21.99 4c0-1.1-.89-2-1.99-2H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h14l4 4-.01-18z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><a href="https://web-dev-hub.com/2021/03/15/example-post/#respond">Leave a comment<span class="screen-reader-text"> on Hi 👋, I’m Bryan</span></a></span><span class="edit-link"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04c.39-.39.39-1.02 0-1.41l-2.34-2.34c-.39-.39-1.02-.39-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><a class="post-edit-link" href="https://wordpress.com/post/web-dev-hub.com/11">Edit <span class="screen-reader-text">Hi 👋, I’m Bryan</span></a></span> </footer><!-- .entry-footer --> | |
</article><!-- #post-${ID} --> | |
<article id="post-1050" class="post-1050 post type-post status-publish format-standard hentry category-uncategorized entry"> | |
<header class="entry-header responsive-max-width"> | |
<h2 class="entry-title"><a href="https://web-dev-hub.com/2021/12/25/javascript-snippets/" rel="bookmark">JavaScript Snippets</a></h2> </header><!-- .entry-header --> | |
<div class="entry-content"> | |
<p></p> | |
<div class="wp-block-jetpack-markdown"><hr> | |
<h2>title: CSVToArray</h2> | |
<p>Converts a comma-separated values (CSV) string to a 2D array.</p> | |
<ul> | |
<li>Use <code>Array.prototype.slice()</code> and <code>Array.prototype.indexOf('\n')</code> to remove the first row (title row) if <code>omitFirstRow</code> is <code>true</code>.</li> | |
<li>Use <code>String.prototype.split('\n')</code> to create a string for each row, then <code>String.prototype.split(delimiter)</code> to separate the values in each row.</li> | |
<li>Omit the second argument, <code>delimiter</code>, to use a default delimiter of <code>','</code>.</li> | |
<li>Omit the third argument, <code>omitFirstRow</code>, to include the first row (title row) of the CSV string.</li> | |
</ul> | |
<pre><code class="language-js">const CSVToArray = (data, delimiter = ',', omitFirstRow = false) => | |
data | |
.slice(omitFirstRow ? data.indexOf('\n') + 1 : 0) | |
.split('\n') | |
.map(v => v.split(delimiter)); | |
</code></pre> | |
<pre><code class="language-js">CSVToArray('a,b\nc,d'); // [['a', 'b'], ['c', 'd']]; | |
CSVToArray('a;b\nc;d', ';'); // [['a', 'b'], ['c', 'd']]; | |
CSVToArray('col1,col2\na,b\nc,d', ',', true); // [['a', 'b'], ['c', 'd']]; | |
</code></pre> | |
<hr> | |
<h2>title: CSVToJSON</h2> | |
<p>Converts a comma-separated values (CSV) string to a 2D array of objects. | |
The first row of the string is used as the title row.</p> | |
<ul> | |
<li>Use <code>Array.prototype.slice()</code> and <code>Array.prototype.indexOf('\n')</code> and <code>String.prototype.split(delimiter)</code> to separate the first row (title row) into values.</li> | |
<li>Use <code>String.prototype.split('\n')</code> to create a string for each row, then <code>Array.prototype.map()</code> and <code>String.prototype.split(delimiter)</code> to separate the values in each row.</li> | |
<li>Use <code>Array.prototype.reduce()</code> to create an object for each row’s values, with the keys parsed from the title row.</li> | |
<li>Omit the second argument, <code>delimiter</code>, to use a default delimiter of <code>,</code>.</li> | |
</ul> | |
<pre><code class="language-js">const CSVToJSON = (data, delimiter = ',') => { | |
const titles = data.slice(0, data.indexOf('\n')).split(delimiter); | |
return data | |
.slice(data.indexOf('\n') + 1) | |
.split('\n') | |
.map(v => { | |
const values = v.split(delimiter); | |
return titles.reduce( | |
(obj, title, index) => ((obj[title] = values[index]), obj), | |
{} | |
); | |
}); | |
}; | |
</code></pre> | |
<pre><code class="language-js">CSVToJSON('col1,col2\na,b\nc,d'); | |
// [{'col1': 'a', 'col2': 'b'}, {'col1': 'c', 'col2': 'd'}]; | |
CSVToJSON('col1;col2\na;b\nc;d', ';'); | |
// [{'col1': 'a', 'col2': 'b'}, {'col1': 'c', 'col2': 'd'}]; | |
</code></pre> | |
<hr> | |
<h2>title: CSVToArray</h2> | |
<p>Converts a comma-separated values (CSV) string to a 2D array.</p> | |
<ul> | |
<li>Use <code>Array.prototype.slice()</code> and <code>Array.prototype.indexOf('\n')</code> to remove the first row (title row) if <code>omitFirstRow</code> is <code>true</code>.</li> | |
<li>Use <code>String.prototype.split('\n')</code> to create a string for each row, then <code>String.prototype.split(delimiter)</code> to separate the values in each row.</li> | |
<li>Omit the second argument, <code>delimiter</code>, to use a default delimiter of <code>','</code>.</li> | |
<li>Omit the third argument, <code>omitFirstRow</code>, to include the first row (title row) of the CSV string.</li> | |
</ul> | |
<pre><code class="language-js">const CSVToArray = (data, delimiter = ',', omitFirstRow = false) => | |
data | |
.slice(omitFirstRow ? data.indexOf('\n') + 1 : 0) | |
.split('\n') | |
.map(v => v.split(delimiter)); | |
</code></pre> | |
<pre><code class="language-js">CSVToArray('a,b\nc,d'); // [['a', 'b'], ['c', 'd']]; | |
CSVToArray('a;b\nc;d', ';'); // [['a', 'b'], ['c', 'd']]; | |
CSVToArray('col1,col2\na,b\nc,d', ',', true); // [['a', 'b'], ['c', 'd']]; | |
</code></pre> | |
<hr> | |
<h2>title: CSVToJSON</h2> | |
<p>Converts a comma-separated values (CSV) string to a 2D array of objects. | |
The first row of the string is used as the title row.</p> | |
<ul> | |
<li>Use <code>Array.prototype.slice()</code> and <code>Array.prototype.indexOf('\n')</code> and <code>String.prototype.split(delimiter)</code> to separate the first row (title row) into values.</li> | |
<li>Use <code>String.prototype.split('\n')</code> to create a string for each row, then <code>Array.prototype.map()</code> and <code>String.prototype.split(delimiter)</code> to separate the values in each row.</li> | |
<li>Use <code>Array.prototype.reduce()</code> to create an object for each row’s values, with the keys parsed from the title row.</li> | |
<li>Omit the second argument, <code>delimiter</code>, to use a default delimiter of <code>,</code>.</li> | |
</ul> | |
<pre><code class="language-js">const CSVToJSON = (data, delimiter = ',') => { | |
const titles = data.slice(0, data.indexOf('\n')).split(delimiter); | |
return data | |
.slice(data.indexOf('\n') + 1) | |
.split('\n') | |
.map(v => { | |
const values = v.split(delimiter); | |
return titles.reduce( | |
(obj, title, index) => ((obj[title] = values[index]), obj), | |
{} | |
); | |
}); | |
}; | |
</code></pre> | |
<pre><code class="language-js">CSVToJSON('col1,col2\na,b\nc,d'); | |
// [{'col1': 'a', 'col2': 'b'}, {'col1': 'c', 'col2': 'd'}]; | |
CSVToJSON('col1;col2\na;b\nc;d', ';'); | |
// [{'col1': 'a', 'col2': 'b'}, {'col1': 'c', 'col2': 'd'}]; | |
</code></pre> | |
<hr> | |
<h2>title: HSBToRGB</h2> | |
<p>Converts a HSB color tuple to RGB format.</p> | |
<ul> | |
<li>Use the <a href="https://en.wikipedia.org/wiki/HSL_and_HSV#HSV_to_RGB">HSB to RGB conversion formula</a> to convert to the appropriate format.</li> | |
<li>The range of the input parameters is H: [0, 360], S: [0, 100], B: [0, 100].</li> | |
<li>The range of all output values is [0, 255].</li> | |
</ul> | |
<pre><code class="language-js">const HSBToRGB = (h, s, b) => { | |
s /= 100; | |
b /= 100; | |
const k = (n) => (n + h / 60) % 6; | |
const f = (n) => b * (1 - s * Math.max(0, Math.min(k(n), 4 - k(n), 1))); | |
return [255 * f(5), 255 * f(3), 255 * f(1)]; | |
}; | |
</code></pre> | |
<pre><code class="language-js">HSBToRGB(18, 81, 99); // [252.45, 109.31084999999996, 47.965499999999984] | |
</code></pre> | |
<hr> | |
<h2>title: HSLToRGB</h2> | |
<p>Converts a HSL color tuple to RGB format.</p> | |
<ul> | |
<li>Use the <a href="https://en.wikipedia.org/wiki/HSL_and_HSV#HSL_to_RGB">HSL to RGB conversion formula</a> to convert to the appropriate format.</li> | |
<li>The range of the input parameters is H: [0, 360], S: [0, 100], L: [0, 100].</li> | |
<li>The range of all output values is [0, 255].</li> | |
</ul> | |
<pre><code class="language-js">const HSLToRGB = (h, s, l) => { | |
s /= 100; | |
l /= 100; | |
const k = n => (n + h / 30) % 12; | |
const a = s * Math.min(l, 1 - l); | |
const f = n => | |
l - a * Math.max(-1, Math.min(k(n) - 3, Math.min(9 - k(n), 1))); | |
return [255 * f(0), 255 * f(8), 255 * f(4)]; | |
}; | |
</code></pre> | |
<pre><code class="language-js">HSLToRGB(13, 100, 11); // [56.1, 12.155, 0] | |
</code></pre> | |
<hr> | |
<h2>title: JSONToFile</h2> | |
<p>Writes a JSON object to a file.</p> | |
<ul> | |
<li>Use <code>fs.writeFileSync()</code>, template literals and <code>JSON.stringify()</code> to write a <code>json</code> object to a <code>.json</code> file.</li> | |
</ul> | |
<pre><code class="language-js">const fs = require('fs'); | |
const JSONToFile = (obj, filename) => | |
fs.writeFileSync(`${filename}.json`, JSON.stringify(obj, null, 2)); | |
</code></pre> | |
<pre><code class="language-js">JSONToFile({ test: 'is passed' }, 'testJsonFile'); | |
// writes the object to 'testJsonFile.json' | |
</code></pre> | |
<hr> | |
<h2>title: JSONtoCSV</h2> | |
<p>Converts an array of objects to a comma-separated values (CSV) string that contains only the <code>columns</code> specified.</p> | |
<ul> | |
<li>Use <code>Array.prototype.join(delimiter)</code> to combine all the names in <code>columns</code> to create the first row.</li> | |
<li>Use <code>Array.prototype.map()</code> and <code>Array.prototype.reduce()</code> to create a row for each object. Substitute non-existent values with empty strings and only mapping values in <code>columns</code>.</li> | |
<li>Use <code>Array.prototype.join('\n')</code> to combine all rows into a string.</li> | |
<li>Omit the third argument, <code>delimiter</code>, to use a default delimiter of <code>','</code>.</li> | |
</ul> | |
<pre><code class="language-js">const JSONtoCSV = (arr, columns, delimiter = ',') => | |
[ | |
columns.join(delimiter), | |
...arr.map(obj => | |
columns.reduce( | |
(acc, key) => | |
`${acc}${!acc.length ? '' : delimiter}"${!obj[key] ? '' : obj[key]}"`, | |
'' | |
) | |
), | |
].join('\n'); | |
</code></pre> | |
<pre><code class="language-js">JSONtoCSV( | |
[{ a: 1, b: 2 }, { a: 3, b: 4, c: 5 }, { a: 6 }, { b: 7 }], | |
['a', 'b'] | |
); // 'a,b\n"1","2"\n"3","4"\n"6",""\n"","7"' | |
JSONtoCSV( | |
[{ a: 1, b: 2 }, { a: 3, b: 4, c: 5 }, { a: 6 }, { b: 7 }], | |
['a', 'b'], | |
';' | |
); // 'a;b\n"1";"2"\n"3";"4"\n"6";""\n"";"7"' | |
</code></pre> | |
<hr> | |
<h2>title: RGBToHSB</h2> | |
<p>Converts a RGB color tuple to HSB format.</p> | |
<ul> | |
<li>Use the <a href="https://en.wikipedia.org/wiki/HSL_and_HSV#From_RGB">RGB to HSB conversion formula</a> to convert to the appropriate format.</li> | |
<li>The range of all input parameters is [0, 255].</li> | |
<li>The range of the resulting values is H: [0, 360], S: [0, 100], B: [0, 100].</li> | |
</ul> | |
<pre><code class="language-js">const RGBToHSB = (r, g, b) => { | |
r /= 255; | |
g /= 255; | |
b /= 255; | |
const v = Math.max(r, g, b), | |
n = v - Math.min(r, g, b); | |
const h = | |
n === 0 ? 0 : n && v === r ? (g - b) / n : v === g ? 2 + (b - r) / n : 4 + (r - g) / n; | |
return [60 * (h < 0 ? h + 6 : h), v && (n / v) * 100, v * 100]; | |
}; | |
</code></pre> | |
<pre><code class="language-js">RGBToHSB(252, 111, 48); | |
// [18.529411764705856, 80.95238095238095, 98.82352941176471] | |
</code></pre> | |
<hr> | |
<h2>title: RGBToHSL</h2> | |
<p>Converts a RGB color tuple to HSL format.</p> | |
<ul> | |
<li>Use the <a href="https://www.niwa.nu/2013/05/math-behind-colorspace-conversions-rgb-hsl/">RGB to HSL conversion formula</a> to convert to the appropriate format.</li> | |
<li>The range of all input parameters is [0, 255].</li> | |
<li>The range of the resulting values is H: [0, 360], S: [0, 100], L: [0, 100].</li> | |
</ul> | |
<pre><code class="language-js">const RGBToHSL = (r, g, b) => { | |
r /= 255; | |
g /= 255; | |
b /= 255; | |
const l = Math.max(r, g, b); | |
const s = l - Math.min(r, g, b); | |
const h = s | |
? l === r | |
? (g - b) / s | |
: l === g | |
? 2 + (b - r) / s | |
: 4 + (r - g) / s | |
: 0; | |
return [ | |
60 * h < 0 ? 60 * h + 360 : 60 * h, | |
100 * (s ? (l <= 0.5 ? s / (2 * l - s) : s / (2 - (2 * l - s))) : 0), | |
(100 * (2 * l - s)) / 2, | |
]; | |
}; | |
</code></pre> | |
<pre><code class="language-js">RGBToHSL(45, 23, 11); // [21.17647, 60.71428, 10.98039] | |
</code></pre> | |
<hr> | |
<h2>title: RGBToHex</h2> | |
<p>Converts the values of RGB components to a hexadecimal color code.</p> | |
<ul> | |
<li>Convert given RGB parameters to hexadecimal string using bitwise left-shift operator (<code><<</code>) and <code>Number.prototype.toString(16)</code>.</li> | |
<li>Use <code>String.prototype.padStart(6, '0')</code> to get a 6-digit hexadecimal value.</li> | |
</ul> | |
<pre><code class="language-js">const RGBToHex = (r, g, b) => | |
((r << 16) + (g << 8) + b).toString(16).padStart(6, '0'); | |
</code></pre> | |
<pre><code class="language-js">RGBToHex(255, 165, 1); // 'ffa501' | |
</code></pre> | |
<hr> | |
<h2>title: URLJoin</h2> | |
<p>Joins all given URL segments together, then normalizes the resulting URL.</p> | |
<ul> | |
<li>Use <code>String.prototype.join('/')</code> to combine URL segments.</li> | |
<li>Use a series of <code>String.prototype.replace()</code> calls with various regexps to normalize the resulting URL (remove double slashes, add proper slashes for protocol, remove slashes before parameters, combine parameters with <code>'&'</code> and normalize first parameter delimiter).</li> | |
</ul> | |
<pre><code class="language-js">const URLJoin = (...args) => | |
args | |
.join('/') | |
.replace(/[\/]+/g, '/') | |
.replace(/^(.+):\//, '$1://') | |
.replace(/^file:/, 'file:/') | |
.replace(/\/(\?|&|#[^!])/g, '$1') | |
.replace(/\?/g, '&') | |
.replace('&', '?'); | |
</code></pre> | |
<pre><code class="language-js">URLJoin('http://www.google.com', 'a', '/b/cd', '?foo=123', '?bar=foo'); | |
// 'http://www.google.com/a/b/cd?foo=123&bar=foo' | |
</code></pre> | |
<hr> | |
<h2>title: UUIDGeneratorBrowser</h2> | |
<p>Generates a UUID in a browser.</p> | |
<ul> | |
<li>Use <code>Crypto.getRandomValues()</code> to generate a UUID, compliant with <a href="https://www.ietf.org/rfc/rfc4122.txt">RFC4122</a> version 4.</li> | |
<li>Use <code>Number.prototype.toString(16)</code> to convert it to a proper UUID.</li> | |
</ul> | |
<pre><code class="language-js">const UUIDGeneratorBrowser = () => | |
([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, c => | |
( | |
c ^ | |
(crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (c / 4))) | |
).toString(16) | |
); | |
</code></pre> | |
<pre><code class="language-js">UUIDGeneratorBrowser(); // '7982fcfe-5721-4632-bede-6000885be57d' | |
</code></pre> | |
<hr> | |
<h2>title: UUIDGeneratorNode</h2> | |
<p>Generates a UUID in Node.JS.</p> | |
<ul> | |
<li>Use <code>crypto.randomBytes()</code> to generate a UUID, compliant with <a href="https://www.ietf.org/rfc/rfc4122.txt">RFC4122</a> version 4.</li> | |
<li>Use <code>Number.prototype.toString(16)</code> to convert it to a proper UUID.</li> | |
</ul> | |
<pre><code class="language-js">const crypto = require('crypto'); | |
const UUIDGeneratorNode = () => | |
([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, c => | |
(c ^ (crypto.randomBytes(1)[0] & (15 >> (c / 4)))).toString(16) | |
); | |
</code></pre> | |
<pre><code class="language-js">UUIDGeneratorNode(); // '79c7c136-60ee-40a2-beb2-856f1feabefc' | |
</code></pre> | |
<hr> | |
<h2>title: accumulate</h2> | |
<p>Creates an array of partial sums.</p> | |
<ul> | |
<li>Use <code>Array.prototype.reduce()</code>, initialized with an empty array accumulator to iterate over <code>nums</code>.</li> | |
<li>Use <code>Array.prototype.slice(-1)</code>, the spread operator (<code>...</code>) and the unary <code>+</code> operator to add each value to the accumulator array containing the previous sums.</li> | |
</ul> | |
<pre><code class="language-js">const accumulate = (...nums) => | |
nums.reduce((acc, n) => [...acc, n + +acc.slice(-1)], []); | |
</code></pre> | |
<pre><code class="language-js">accumulate(1, 2, 3, 4); // [1, 3, 6, 10] | |
accumulate(...[1, 2, 3, 4]); // [1, 3, 6, 10] | |
</code></pre> | |
<hr> | |
<h2>title: addClass</h2> | |
<p>Adds a class to an HTML element.</p> | |
<ul> | |
<li>Use <code>Element.classList</code> and <code>DOMTokenList.add()</code> to add the specified class to the element.</li> | |
</ul> | |
<pre><code class="language-js">const addClass = (el, className) => el.classList.add(className); | |
</code></pre> | |
<pre><code class="language-js">addClass(document.querySelector('p'), 'special'); | |
// The paragraph will now have the 'special' class | |
</code></pre> | |
<hr> | |
<h2>title: addDaysToDate</h2> | |
<p>Calculates the date of <code>n</code> days from the given date, returning its string representation.</p> | |
<ul> | |
<li>Use <code>new Date()</code> to create a date object from the first argument.</li> | |
<li>Use <code>Date.prototype.getDate()</code> and <code>Date.prototype.setDate()</code> to add <code>n</code> days to the given date.</li> | |
<li>Use <code>Date.prototype.toISOString()</code> to return a string in <code>yyyy-mm-dd</code> format.</li> | |
</ul> | |
<pre><code class="language-js">const addDaysToDate = (date, n) => { | |
const d = new Date(date); | |
d.setDate(d.getDate() + n); | |
return d.toISOString().split('T')[0]; | |
}; | |
</code></pre> | |
<pre><code class="language-js">addDaysToDate('2020-10-15', 10); // '2020-10-25' | |
addDaysToDate('2020-10-15', -10); // '2020-10-05' | |
</code></pre> | |
<hr> | |
<h2>title: addEventListenerAll</h2> | |
<p>Attaches an event listener to all the provided targets.</p> | |
<ul> | |
<li>Use <code>Array.prototype.forEach()</code> and <code>EventTarget.addEventListener()</code> to attach the provided <code>listener</code> for the given event <code>type</code> to all <code>targets</code>.</li> | |
</ul> | |
<pre><code class="language-js">const addEventListenerAll = (targets, type, listener, options, useCapture) => { | |
targets.forEach(target => | |
target.addEventListener(type, listener, options, useCapture) | |
); | |
}; | |
</code></pre> | |
<pre><code class="language-js">addEventListenerAll(document.querySelectorAll('a'), 'click', () => | |
console.log('Clicked a link') | |
); | |
// Logs 'Clicked a link' whenever any anchor element is clicked | |
</code></pre> | |
<hr> | |
<h2>title: addMinutesToDate</h2> | |
<p>Calculates the date of <code>n</code> minutes from the given date, returning its string representation.</p> | |
<ul> | |
<li>Use <code>new Date()</code> to create a date object from the first argument.</li> | |
<li>Use <code>Date.prototype.getTime()</code> and <code>Date.prototype.setTime()</code> to add <code>n</code> minutes to the given date.</li> | |
<li>Use <code>Date.prototype.toISOString()</code>, <code>String.prototype.split()</code> and <code>String.prototype.replace()</code> to return a string in <code>yyyy-mm-dd HH:MM:SS</code> format.</li> | |
</ul> | |
<pre><code class="language-js">const addMinutesToDate = (date, n) => { | |
const d = new Date(date); | |
d.setTime(d.getTime() + n * 60000); | |
return d.toISOString().split('.')[0].replace('T',' '); | |
}; | |
</code></pre> | |
<pre><code class="language-js">addMinutesToDate('2020-10-19 12:00:00', 10); // '2020-10-19 12:10:00' | |
addMinutesToDate('2020-10-19', -10); // '2020-10-18 23:50:00' | |
</code></pre> | |
<hr> | |
<h2>title: addMultipleListeners</h2> | |
<p>Adds multiple event listeners with the same handler to an element.</p> | |
<ul> | |
<li>Use <code>Array.prototype.forEach()</code> and <code>EventTarget.addEventListener()</code> to add multiple event listeners with an assigned callback function to an element.</li> | |
</ul> | |
<pre><code class="language-js">const addMultipleListeners = (el, types, listener, options, useCapture) => { | |
types.forEach(type => | |
el.addEventListener(type, listener, options, useCapture) | |
); | |
}; | |
</code></pre> | |
<pre><code class="language-js">addMultipleListeners( | |
document.querySelector('.my-element'), | |
['click', 'mousedown'], | |
() => { console.log('hello!') } | |
); | |
</code></pre> | |
<hr> | |
<h2>title: addStyles</h2> | |
<p>Adds the provided styles to the given element.</p> | |
<ul> | |
<li>Use <code>Object.assign()</code> and <code>ElementCSSInlineStyle.style</code> to merge the provided <code>styles</code> object into the style of the given element.</li> | |
</ul> | |
<pre><code class="language-js">const addStyles = (el, styles) => Object.assign(el.style, styles); | |
</code></pre> | |
<pre><code class="language-js">addStyles(document.getElementById('my-element'), { | |
background: 'red', | |
color: '#ffff00', | |
fontSize: '3rem' | |
}); | |
</code></pre> | |
<hr> | |
<h2>title: addWeekDays</h2> | |
<p>Calculates the date after adding the given number of business days.</p> | |
<ul> | |
<li>Use <code>Array.from()</code> to construct an array with <code>length</code> equal to the <code>count</code> of business days to be added.</li> | |
<li>Use <code>Array.prototype.reduce()</code> to iterate over the array, starting from <code>startDate</code> and incrementing, using <code>Date.prototype.getDate()</code> and <code>Date.prototype.setDate()</code>.</li> | |
<li>If the current <code>date</code> is on a weekend, update it again by adding either one day or two days to make it a weekday.</li> | |
<li><strong>NOTE:</strong> Does not take official holidays into account.</li> | |
</ul> | |
<pre><code class="language-js">const addWeekDays = (startDate, count) => | |
Array.from({ length: count }).reduce(date => { | |
date = new Date(date.setDate(date.getDate() + 1)); | |
if (date.getDay() % 6 === 0) | |
date = new Date(date.setDate(date.getDate() + (date.getDay() / 6 + 1))); | |
return date; | |
}, startDate); | |
</code></pre> | |
<pre><code class="language-js">addWeekDays(new Date('Oct 09, 2020'), 5); // 'Oct 16, 2020' | |
addWeekDays(new Date('Oct 12, 2020'), 5); // 'Oct 19, 2020' | |
</code></pre> | |
<hr> | |
<h2>title: all</h2> | |
<p>Checks if the provided predicate function returns <code>true</code> for all elements in a collection.</p> | |
<ul> | |
<li>Use <code>Array.prototype.every()</code> to test if all elements in the collection return <code>true</code> based on <code>fn</code>.</li> | |
<li>Omit the second argument, <code>fn</code>, to use <code>Boolean</code> as a default.</li> | |
</ul> | |
<pre><code class="language-js">const all = (arr, fn = Boolean) => arr.every(fn); | |
</code></pre> | |
<pre><code class="language-js">all([4, 2, 3], x => x > 1); // true | |
all([1, 2, 3]); // true | |
</code></pre> | |
<hr> | |
<h2>title: allEqual</h2> | |
<p>Checks if all elements in an array are equal.</p> | |
<ul> | |
<li>Use <code>Array.prototype.every()</code> to check if all the elements of the array are the same as the first one.</li> | |
<li>Elements in the array are compared using the strict comparison operator, which does not account for <code>NaN</code> self-inequality.</li> | |
</ul> | |
<pre><code class="language-js">const allEqual = arr => arr.every(val => val === arr[0]); | |
</code></pre> | |
<pre><code class="language-js">allEqual([1, 2, 3, 4, 5, 6]); // false | |
allEqual([1, 1, 1, 1]); // true | |
</code></pre> | |
<hr> | |
<h2>title: allEqualBy</h2> | |
<p>Checks if all elements in an array are equal, based on the provided mapping function.</p> | |
<ul> | |
<li>Apply <code>fn</code> to the first element of <code>arr</code>.</li> | |
<li>Use <code>Array.prototype.every()</code> to check if <code>fn</code> returns the same value for all elements in the array as it did for the first one.</li> | |
<li>Elements in the array are compared using the strict comparison operator, which does not account for <code>NaN</code> self-inequality.</li> | |
</ul> | |
<pre><code class="language-js">const allEqualBy = (arr, fn) => { | |
const eql = fn(arr[0]); | |
return arr.every(val => fn(val) === eql); | |
}; | |
</code></pre> | |
<pre><code class="language-js">allEqualBy([1.1, 1.2, 1.3], Math.round); // true | |
allEqualBy([1.1, 1.3, 1.6], Math.round); // false | |
</code></pre> | |
<hr> | |
<h2>title: allUnique</h2> | |
<p>Checks if all elements in an array are unique.</p> | |
<ul> | |
<li>Create a new <code>Set</code> from the mapped values to keep only unique occurrences.</li> | |
<li>Use <code>Array.prototype.length</code> and <code>Set.prototype.size</code> to compare the length of the unique values to the original array.</li> | |
</ul> | |
<pre><code class="language-js">const allUnique = arr => arr.length === new Set(arr).size; | |
</code></pre> | |
<pre><code class="language-js">allUnique([1, 2, 3, 4]); // true | |
allUnique([1, 1, 2, 3]); // false | |
</code></pre> | |
<hr> | |
<h2>title: allUniqueBy</h2> | |
<p>Checks if all elements in an array are unique, based on the provided mapping function.</p> | |
<ul> | |
<li>Use <code>Array.prototype.map()</code> to apply <code>fn</code> to all elements in <code>arr</code>.</li> | |
<li>Create a new <code>Set</code> from the mapped values to keep only unique occurrences.</li> | |
<li>Use <code>Array.prototype.length</code> and <code>Set.prototype.size</code> to compare the length of the unique mapped values to the original array.</li> | |
</ul> | |
<pre><code class="language-js">const allUniqueBy = (arr, fn) => arr.length === new Set(arr.map(fn)).size; | |
</code></pre> | |
<pre><code class="language-js">allUniqueBy([1.2, 2.4, 2.9], Math.round); // true | |
allUniqueBy([1.2, 2.3, 2.4], Math.round); // false | |
</code></pre> | |
<hr> | |
<h2>title: and | |
unlisted: true</h2> | |
<p>Checks if both arguments are <code>true</code>.</p> | |
<ul> | |
<li>Use the logical and (<code>&&</code>) operator on the two given values.</li> | |
</ul> | |
<pre><code class="language-js">const and = (a, b) => a && b; | |
</code></pre> | |
<pre><code class="language-js">and(true, true); // true | |
and(true, false); // false | |
and(false, false); // false | |
</code></pre> | |
<hr> | |
<h2>title: any</h2> | |
<p>Checks if the provided predicate function returns <code>true</code> for at least one element in a collection.</p> | |
<ul> | |
<li>Use <code>Array.prototype.some()</code> to test if any elements in the collection return <code>true</code> based on <code>fn</code>.</li> | |
<li>Omit the second argument, <code>fn</code>, to use <code>Boolean</code> as a default.</li> | |
</ul> | |
<pre><code class="language-js">const any = (arr, fn = Boolean) => arr.some(fn); | |
</code></pre> | |
<pre><code class="language-js">any([0, 1, 2, 0], x => x >= 2); // true | |
any([0, 0, 1, 0]); // true | |
</code></pre> | |
<hr> | |
<h2>title: aperture</h2> | |
<p>Creates an array of <code>n</code>-tuples of consecutive elements.</p> | |
<ul> | |
<li>Use <code>Array.prototype.slice()</code> and <code>Array.prototype.map()</code> to create an array of appropriate length.</li> | |
<li>Populate the array with <code>n</code>-tuples of consecutive elements from <code>arr</code>.</li> | |
<li>If <code>n</code> is greater than the length of <code>arr</code>, return an empty array.</li> | |
</ul> | |
<pre><code class="language-js">const aperture = (n, arr) => | |
n > arr.length | |
? [] | |
: arr.slice(n - 1).map((v, i) => arr.slice(i, i + n)); | |
</code></pre> | |
<pre><code class="language-js">aperture(2, [1, 2, 3, 4]); // [[1, 2], [2, 3], [3, 4]] | |
aperture(3, [1, 2, 3, 4]); // [[1, 2, 3], [2, 3, 4]] | |
aperture(5, [1, 2, 3, 4]); // [] | |
</code></pre> | |
<hr> | |
<h2>title: approximatelyEqual</h2> | |
<p>Checks if two numbers are approximately equal to each other.</p> | |
<ul> | |
<li>Use <code>Math.abs()</code> to compare the absolute difference of the two values to <code>epsilon</code>.</li> | |
<li>Omit the third argument, <code>epsilon</code>, to use a default value of <code>0.001</code>.</li> | |
</ul> | |
<pre><code class="language-js">const approximatelyEqual = (v1, v2, epsilon = 0.001) => | |
Math.abs(v1 - v2) < epsilon; | |
</code></pre> | |
<pre><code class="language-js">approximatelyEqual(Math.PI / 2.0, 1.5708); // true | |
</code></pre> | |
<hr> | |
<h2>title: arithmeticProgression</h2> | |
<p>Creates an array of numbers in the arithmetic progression, starting with the given positive integer and up to the specified limit.</p> | |
<ul> | |
<li>Use <code>Array.from()</code> to create an array of the desired length, <code>lim/n</code>. Use a map function to fill it with the desired values in the given range.</li> | |
</ul> | |
<pre><code class="language-js">const arithmeticProgression = (n, lim) => | |
Array.from({ length: Math.ceil(lim / n) }, (_, i) => (i + 1) * n ); | |
</code></pre> | |
<pre><code class="language-js">arithmeticProgression(5, 25); // [5, 10, 15, 20, 25] | |
</code></pre> | |
<hr> | |
<h2>title: arrayToCSV</h2> | |
<p>Converts a 2D array to a comma-separated values (CSV) string.</p> | |
<ul> | |
<li>Use <code>Array.prototype.map()</code> and <code>Array.prototype.join(delimiter)</code> to combine individual 1D arrays (rows) into strings.</li> | |
<li>Use <code>Array.prototype.join('\n')</code> to combine all rows into a CSV string, separating each row with a newline.</li> | |
<li>Omit the second argument, <code>delimiter</code>, to use a default delimiter of <code>,</code>.</li> | |
</ul> | |
<pre><code class="language-js">const arrayToCSV = (arr, delimiter = ',') => | |
arr | |
.map(v => | |
v.map(x => (isNaN(x) ? `"${x.replace(/"/g, '""')}"` : x)).join(delimiter) | |
) | |
.join('\n'); | |
</code></pre> | |
<pre><code class="language-js">arrayToCSV([['a', 'b'], ['c', 'd']]); // '"a","b"\n"c","d"' | |
arrayToCSV([['a', 'b'], ['c', 'd']], ';'); // '"a";"b"\n"c";"d"' | |
arrayToCSV([['a', '"b" great'], ['c', 3.1415]]); | |
// '"a","""b"" great"\n"c",3.1415' | |
</code></pre> | |
<hr> | |
<h2>title: arrayToHTMLList</h2> | |
<p>Converts the given array elements into <code><li></code> tags and appends them to the list of the given id.</p> | |
<ul> | |
<li>Use <code>Array.prototype.map()</code> and <code>Document.querySelector()</code> to create a list of html tags.</li> | |
</ul> | |
<pre><code class="language-js">const arrayToHTMLList = (arr, listID) => | |
document.querySelector(`#${listID}`).innerHTML += arr | |
.map(item => `<li>${item}</li>`) | |
.join(''); | |
</code></pre> | |
<pre><code class="language-js">arrayToHTMLList(['item 1', 'item 2'], 'myListID'); | |
</code></pre> | |
<hr> | |
<h2>title: ary</h2> | |
<p>Creates a function that accepts up to <code>n</code> arguments, ignoring any additional arguments.</p> | |
<ul> | |
<li>Call the provided function, <code>fn</code>, with up to <code>n</code> arguments, using <code>Array.prototype.slice(0, n)</code> and the spread operator (<code>...</code>).</li> | |
</ul> | |
<pre><code class="language-js">const ary = (fn, n) => (...args) => fn(...args.slice(0, n)); | |
</code></pre> | |
<pre><code class="language-js">const firstTwoMax = ary(Math.max, 2); | |
[[2, 6, 'a'], [6, 4, 8], [10]].map(x => firstTwoMax(...x)); // [6, 6, 10] | |
</code></pre> | |
<hr> | |
<h2>title: assertValidKeys</h2> | |
<p>Validates all keys in an object match the given <code>keys</code>.</p> | |
<ul> | |
<li>Use <code>Object.keys()</code> to get the keys of the given object, <code>obj</code>.</li> | |
<li>Use <code>Array.prototype.every()</code> and <code>Array.prototype.includes()</code> to validate that each key in the object is specified in the <code>keys</code> array.</li> | |
</ul> | |
<pre><code class="language-js">const assertValidKeys = (obj, keys) => | |
Object.keys(obj).every(key => keys.includes(key)); | |
</code></pre> | |
<pre><code class="language-js">assertValidKeys({ id: 10, name: 'apple' }, ['id', 'name']); // true | |
assertValidKeys({ id: 10, name: 'apple' }, ['id', 'type']); // false | |
</code></pre> | |
<hr> | |
<h2>title: atob</h2> | |
<p>Decodes a string of data which has been encoded using base-64 encoding.</p> | |
<ul> | |
<li>Create a <code>Buffer</code> for the given string with base-64 encoding and use <code>Buffer.toString('binary')</code> to return the decoded string.</li> | |
</ul> | |
<pre><code class="language-js">const atob = str => Buffer.from(str, 'base64').toString('binary'); | |
</code></pre> | |
<pre><code class="language-js">atob('Zm9vYmFy'); // 'foobar' | |
</code></pre> | |
<hr> | |
<h2>title: attempt</h2> | |
<p>Attempts to invoke a function with the provided arguments, returning either the result or the caught error object.</p> | |
<ul> | |
<li>Use a <code>try... catch</code> block to return either the result of the function or an appropriate error.</li> | |
<li>If the caught object is not an <code>Error</code>, use it to create a new <code>Error</code>.</li> | |
</ul> | |
<pre><code class="language-js">const attempt = (fn, ...args) => { | |
try { | |
return fn(...args); | |
} catch (e) { | |
return e instanceof Error ? e : new Error(e); | |
} | |
}; | |
</code></pre> | |
<pre><code class="language-js">let elements = attempt(function(selector) { | |
return document.querySelectorAll(selector); | |
}, '>_>'); | |
if (elements instanceof Error) elements = []; // elements = [] | |
</code></pre> | |
<hr> | |
<h2>title: average</h2> | |
<p>Calculates the average of two or more numbers.</p> | |
<ul> | |
<li>Use <code>Array.prototype.reduce()</code> to add each value to an accumulator, initialized with a value of <code>0</code>.</li> | |
<li>Divide the resulting array by its length.</li> | |
</ul> | |
<pre><code class="language-js">const average = (...nums) => | |
nums.reduce((acc, val) => acc + val, 0) / nums.length; | |
</code></pre> | |
<pre><code class="language-js">average(...[1, 2, 3]); // 2 | |
average(1, 2, 3); // 2 | |
</code></pre> | |
<hr> | |
<h2>title: averageBy</h2> | |
<p>Calculates the average of an array, after mapping each element to a value using the provided function.</p> | |
<ul> | |
<li>Use <code>Array.prototype.map()</code> to map each element to the value returned by <code>fn</code>.</li> | |
<li>Use <code>Array.prototype.reduce()</code> to add each value to an accumulator, initialized with a value of <code>0</code>.</li> | |
<li>Divide the resulting array by its length.</li> | |
</ul> | |
<pre><code class="language-js">const averageBy = (arr, fn) => | |
arr | |
.map(typeof fn === 'function' ? fn : val => val[fn]) | |
.reduce((acc, val) => acc + val, 0) / arr.length; | |
</code></pre> | |
<pre><code class="language-js">averageBy([{ n: 4 }, { n: 2 }, { n: 8 }, { n: 6 }], o => o.n); // 5 | |
averageBy([{ n: 4 }, { n: 2 }, { n: 8 }, { n: 6 }], 'n'); // 5 | |
</code></pre> | |
<hr> | |
<h2>title: bifurcate</h2> | |
<p>Splits values into two groups, based on the result of the given <code>filter</code> array.</p> | |
<ul> | |
<li>Use <code>Array.prototype.reduce()</code> and <code>Array.prototype.push()</code> to add elements to groups, based on <code>filter</code>.</li> | |
<li>If <code>filter</code> has a truthy value for any element, add it to the first group, otherwise add it to the second group.</li> | |
</ul> | |
<pre><code class="language-js">const bifurcate = (arr, filter) => | |
arr.reduce((acc, val, i) => (acc[filter[i] ? 0 : 1].push(val), acc), [ | |
[], | |
[], | |
]); | |
</code></pre> | |
<pre><code class="language-js">bifurcate(['beep', 'boop', 'foo', 'bar'], [true, true, false, true]); | |
// [ ['beep', 'boop', 'bar'], ['foo'] ] | |
</code></pre> | |
<hr> | |
<h2>title: bifurcateBy</h2> | |
<p>Splits values into two groups, based on the result of the given filtering function.</p> | |
<ul> | |
<li>Use <code>Array.prototype.reduce()</code> and <code>Array.prototype.push()</code> to add elements to groups, based on the value returned by <code>fn</code> for each element.</li> | |
<li>If <code>fn</code> returns a truthy value for any element, add it to the first group, otherwise add it to the second group.</li> | |
</ul> | |
<pre><code class="language-js">const bifurcateBy = (arr, fn) => | |
arr.reduce((acc, val, i) => (acc[fn(val, i) ? 0 : 1].push(val), acc), [ | |
[], | |
[], | |
]); | |
</code></pre> | |
<pre><code class="language-js">bifurcateBy(['beep', 'boop', 'foo', 'bar'], x => x[0] === 'b'); | |
// [ ['beep', 'boop', 'bar'], ['foo'] ] | |
</code></pre> | |
<hr> | |
<h2>title: binary</h2> | |
<p>Creates a function that accepts up to two arguments, ignoring any additional arguments.</p> | |
<ul> | |
<li>Call the provided function, <code>fn</code>, with the first two arguments given.</li> | |
</ul> | |
<pre><code class="language-js">const binary = fn => (a, b) => fn(a, b); | |
</code></pre> | |
<pre><code class="language-js">['2', '1', '0'].map(binary(Math.max)); // [2, 1, 2] | |
</code></pre> | |
<hr> | |
<h2>title: binarySearch</h2> | |
<p>Finds the index of a given element in a sorted array using the binary search algorithm.</p> | |
<ul> | |
<li>Declare the left and right search boundaries, <code>l</code> and <code>r</code>, initialized to <code>0</code> and the <code>length</code> of the array respectively.</li> | |
<li>Use a <code>while</code> loop to repeatedly narrow down the search subarray, using <code>Math.floor()</code> to cut it in half.</li> | |
<li>Return the index of the element if found, otherwise return <code>-1</code>.</li> | |
<li><strong>Note:</strong> Does not account for duplicate values in the array.</li> | |
</ul> | |
<pre><code class="language-js">const binarySearch = (arr, item) => { | |
let l = 0, | |
r = arr.length - 1; | |
while (l <= r) { | |
const mid = Math.floor((l + r) / 2); | |
const guess = arr[mid]; | |
if (guess === item) return mid; | |
if (guess > item) r = mid - 1; | |
else l = mid + 1; | |
} | |
return -1; | |
}; | |
</code></pre> | |
<pre><code class="language-js">binarySearch([1, 2, 3, 4, 5], 1); // 0 | |
binarySearch([1, 2, 3, 4, 5], 5); // 4 | |
binarySearch([1, 2, 3, 4, 5], 6); // -1 | |
</code></pre> | |
<hr> | |
<h2>title: bind</h2> | |
<p>Creates a function that invokes <code>fn</code> with a given context, optionally prepending any additional supplied parameters to the arguments.</p> | |
<ul> | |
<li>Return a <code>function</code> that uses <code>Function.prototype.apply()</code> to apply the given <code>context</code> to <code>fn</code>.</li> | |
<li>Use the spread operator (<code>...</code>) to prepend any additional supplied parameters to the arguments.</li> | |
</ul> | |
<pre><code class="language-js">const bind = (fn, context, ...boundArgs) => (...args) => | |
fn.apply(context, [...boundArgs, ...args]); | |
</code></pre> | |
<pre><code class="language-js">function greet(greeting, punctuation) { | |
return greeting + ' ' + this.user + punctuation; | |
} | |
const freddy = { user: 'fred' }; | |
const freddyBound = bind(greet, freddy); | |
console.log(freddyBound('hi', '!')); // 'hi fred!' | |
</code></pre> | |
<hr> | |
<h2>title: bindAll</h2> | |
<p>Binds methods of an object to the object itself, overwriting the existing method.</p> | |
<ul> | |
<li>Use <code>Array.prototype.forEach()</code> to iterate over the given <code>fns</code>.</li> | |
<li>Return a function for each one, using <code>Function.prototype.apply()</code> to apply the given context (<code>obj</code>) to <code>fn</code>.</li> | |
</ul> | |
<pre><code class="language-js">const bindAll = (obj, ...fns) => | |
fns.forEach( | |
fn => ( | |
(f = obj[fn]), | |
(obj[fn] = function() { | |
return f.apply(obj); | |
}) | |
) | |
); | |
</code></pre> | |
<pre><code class="language-js">let view = { | |
label: 'docs', | |
click: function() { | |
console.log('clicked ' + this.label); | |
} | |
}; | |
bindAll(view, 'click'); | |
document.body.addEventListener('click', view.click); | |
// Log 'clicked docs' when clicked. | |
</code></pre> | |
<hr> | |
<h2>title: bindKey</h2> | |
<p>Creates a function that invokes the method at a given key of an object, optionally prepending any additional supplied parameters to the arguments.</p> | |
<ul> | |
<li>Return a <code>function</code> that uses <code>Function.prototype.apply()</code> to bind <code>context[fn]</code> to <code>context</code>.</li> | |
<li>Use the spread operator (<code>...</code>) to prepend any additional supplied parameters to the arguments.</li> | |
</ul> | |
<pre><code class="language-js">const bindKey = (context, fn, ...boundArgs) => (...args) => | |
context[fn].apply(context, [...boundArgs, ...args]); | |
</code></pre> | |
<pre><code class="language-js">const freddy = { | |
user: 'fred', | |
greet: function(greeting, punctuation) { | |
return greeting + ' ' + this.user + punctuation; | |
} | |
}; | |
const freddyBound = bindKey(freddy, 'greet'); | |
console.log(freddyBound('hi', '!')); // 'hi fred!' | |
</code></pre> | |
<hr> | |
<h2>title: binomialCoefficient</h2> | |
<p>Calculates the number of ways to choose <code>k</code> items from <code>n</code> items without repetition and without order.</p> | |
<ul> | |
<li>Use <code>Number.isNaN()</code> to check if any of the two values is <code>NaN</code>.</li> | |
<li>Check if <code>k</code> is less than <code>0</code>, greater than or equal to <code>n</code>, equal to <code>1</code> or <code>n - 1</code> and return the appropriate result.</li> | |
<li>Check if <code>n - k</code> is less than <code>k</code> and switch their values accordingly.</li> | |
<li>Loop from <code>2</code> through <code>k</code> and calculate the binomial coefficient.</li> | |
<li>Use <code>Math.round()</code> to account for rounding errors in the calculation.</li> | |
</ul> | |
<pre><code class="language-js">const binomialCoefficient = (n, k) => { | |
if (Number.isNaN(n) || Number.isNaN(k)) return NaN; | |
if (k < 0 || k > n) return 0; | |
if (k === 0 || k === n) return 1; | |
if (k === 1 || k === n - 1) return n; | |
if (n - k < k) k = n - k; | |
let res = n; | |
for (let j = 2; j <= k; j++) res *= (n - j + 1) / j; | |
return Math.round(res); | |
}; | |
</code></pre> | |
<pre><code class="language-js">binomialCoefficient(8, 2); // 28 | |
</code></pre> | |
<hr> | |
<h2>title: both | |
unlisted: true</h2> | |
<p>Checks if both of the given functions return <code>true</code> for a given set of arguments.</p> | |
<ul> | |
<li>Use the logical and (<code>&&</code>) operator on the result of calling the two functions with the supplied <code>args</code>.</li> | |
</ul> | |
<pre><code class="language-js">const both = (f, g) => (...args) => f(...args) && g(...args); | |
</code></pre> | |
<pre><code class="language-js">const isEven = num => num % 2 === 0; | |
const isPositive = num => num > 0; | |
const isPositiveEven = both(isEven, isPositive); | |
isPositiveEven(4); // true | |
isPositiveEven(-2); // false | |
</code></pre> | |
<hr> | |
<h2>title: HSBToRGB</h2> | |
<p>Converts a HSB color tuple to RGB format.</p> | |
<ul> | |
<li>Use the <a href="https://en.wikipedia.org/wiki/HSL_and_HSV#HSV_to_RGB">HSB to RGB conversion formula</a> to convert to the appropriate format.</li> | |
<li>The range of the input parameters is H: [0, 360], S: [0, 100], B: [0, 100].</li> | |
<li>The range of all output values is [0, 255].</li> | |
</ul> | |
<pre><code class="language-js">const HSBToRGB = (h, s, b) => { | |
s /= 100; | |
b /= 100; | |
const k = (n) => (n + h / 60) % 6; | |
const f = (n) => b * (1 - s * Math.max(0, Math.min(k(n), 4 - k(n), 1))); | |
return [255 * f(5), 255 * f(3), 255 * f(1)]; | |
}; | |
</code></pre> | |
<pre><code class="language-js">HSBToRGB(18, 81, 99); // [252.45, 109.31084999999996, 47.965499999999984] | |
</code></pre> | |
<hr> | |
<h2>title: HSLToRGB</h2> | |
<p>Converts a HSL color tuple to RGB format.</p> | |
<ul> | |
<li>Use the <a href="https://en.wikipedia.org/wiki/HSL_and_HSV#HSL_to_RGB">HSL to RGB conversion formula</a> to convert to the appropriate format.</li> | |
<li>The range of the input parameters is H: [0, 360], S: [0, 100], L: [0, 100].</li> | |
<li>The range of all output values is [0, 255].</li> | |
</ul> | |
<pre><code class="language-js">const HSLToRGB = (h, s, l) => { | |
s /= 100; | |
l /= 100; | |
const k = n => (n + h / 30) % 12; | |
const a = s * Math.min(l, 1 - l); | |
const f = n => | |
l - a * Math.max(-1, Math.min(k(n) - 3, Math.min(9 - k(n), 1))); | |
return [255 * f(0), 255 * f(8), 255 * f(4)]; | |
}; | |
</code></pre> | |
<pre><code class="language-js">HSLToRGB(13, 100, 11); // [56.1, 12.155, 0] | |
</code></pre> | |
<hr> | |
<h2>title: JSONToFile</h2> | |
<p>Writes a JSON object to a file.</p> | |
<ul> | |
<li>Use <code>fs.writeFileSync()</code>, template literals and <code>JSON.stringify()</code> to write a <code>json</code> object to a <code>.json</code> file.</li> | |
</ul> | |
<pre><code class="language-js">const fs = require('fs'); | |
const JSONToFile = (obj, filename) => | |
fs.writeFileSync(`${filename}.json`, JSON.stringify(obj, null, 2)); | |
</code></pre> | |
<pre><code class="language-js">JSONToFile({ test: 'is passed' }, 'testJsonFile'); | |
// writes the object to 'testJsonFile.json' | |
</code></pre> | |
<hr> | |
<h2>title: JSONtoCSV</h2> | |
<p>Converts an array of objects to a comma-separated values (CSV) string that contains only the <code>columns</code> specified.</p> | |
<ul> | |
<li>Use <code>Array.prototype.join(delimiter)</code> to combine all the names in <code>columns</code> to create the first row.</li> | |
<li>Use <code>Array.prototype.map()</code> and <code>Array.prototype.reduce()</code> to create a row for each object. Substitute non-existent values with empty strings and only mapping values in <code>columns</code>.</li> | |
<li>Use <code>Array.prototype.join('\n')</code> to combine all rows into a string.</li> | |
<li>Omit the third argument, <code>delimiter</code>, to use a default delimiter of <code>','</code>.</li> | |
</ul> | |
<pre><code class="language-js">const JSONtoCSV = (arr, columns, delimiter = ',') => | |
[ | |
columns.join(delimiter), | |
...arr.map(obj => | |
columns.reduce( | |
(acc, key) => | |
`${acc}${!acc.length ? '' : delimiter}"${!obj[key] ? '' : obj[key]}"`, | |
'' | |
) | |
), | |
].join('\n'); | |
</code></pre> | |
<pre><code class="language-js">JSONtoCSV( | |
[{ a: 1, b: 2 }, { a: 3, b: 4, c: 5 }, { a: 6 }, { b: 7 }], | |
['a', 'b'] | |
); // 'a,b\n"1","2"\n"3","4"\n"6",""\n"","7"' | |
JSONtoCSV( | |
[{ a: 1, b: 2 }, { a: 3, b: 4, c: 5 }, { a: 6 }, { b: 7 }], | |
['a', 'b'], | |
';' | |
); // 'a;b\n"1";"2"\n"3";"4"\n"6";""\n"";"7"' | |
</code></pre> | |
<hr> | |
<h2>title: RGBToHSB</h2> | |
<p>Converts a RGB color tuple to HSB format.</p> | |
<ul> | |
<li>Use the <a href="https://en.wikipedia.org/wiki/HSL_and_HSV#From_RGB">RGB to HSB conversion formula</a> to convert to the appropriate format.</li> | |
<li>The range of all input parameters is [0, 255].</li> | |
<li>The range of the resulting values is H: [0, 360], S: [0, 100], B: [0, 100].</li> | |
</ul> | |
<pre><code class="language-js">const RGBToHSB = (r, g, b) => { | |
r /= 255; | |
g /= 255; | |
b /= 255; | |
const v = Math.max(r, g, b), | |
n = v - Math.min(r, g, b); | |
const h = | |
n === 0 ? 0 : n && v === r ? (g - b) / n : v === g ? 2 + (b - r) / n : 4 + (r - g) / n; | |
return [60 * (h < 0 ? h + 6 : h), v && (n / v) * 100, v * 100]; | |
}; | |
</code></pre> | |
<pre><code class="language-js">RGBToHSB(252, 111, 48); | |
// [18.529411764705856, 80.95238095238095, 98.82352941176471] | |
</code></pre> | |
<hr> | |
<h2>title: RGBToHSL</h2> | |
<p>Converts a RGB color tuple to HSL format.</p> | |
<ul> | |
<li>Use the <a href="https://www.niwa.nu/2013/05/math-behind-colorspace-conversions-rgb-hsl/">RGB to HSL conversion formula</a> to convert to the appropriate format.</li> | |
<li>The range of all input parameters is [0, 255].</li> | |
<li>The range of the resulting values is H: [0, 360], S: [0, 100], L: [0, 100].</li> | |
</ul> | |
<pre><code class="language-js">const RGBToHSL = (r, g, b) => { | |
r /= 255; | |
g /= 255; | |
b /= 255; | |
const l = Math.max(r, g, b); | |
const s = l - Math.min(r, g, b); | |
const h = s | |
? l === r | |
? (g - b) / s | |
: l === g | |
? 2 + (b - r) / s | |
: 4 + (r - g) / s | |
: 0; | |
return [ | |
60 * h < 0 ? 60 * h + 360 : 60 * h, | |
100 * (s ? (l <= 0.5 ? s / (2 * l - s) : s / (2 - (2 * l - s))) : 0), | |
(100 * (2 * l - s)) / 2, | |
]; | |
}; | |
</code></pre> | |
<pre><code class="language-js">RGBToHSL(45, 23, 11); // [21.17647, 60.71428, 10.98039] | |
</code></pre> | |
<hr> | |
<h2>title: RGBToHex</h2> | |
<p>Converts the values of RGB components to a hexadecimal color code.</p> | |
<ul> | |
<li>Convert given RGB parameters to hexadecimal string using bitwise left-shift operator (<code><<</code>) and <code>Number.prototype.toString(16)</code>.</li> | |
<li>Use <code>String.prototype.padStart(6, '0')</code> to get a 6-digit hexadecimal value.</li> | |
</ul> | |
<pre><code class="language-js">const RGBToHex = (r, g, b) => | |
((r << 16) + (g << 8) + b).toString(16).padStart(6, '0'); | |
</code></pre> | |
<pre><code class="language-js">RGBToHex(255, 165, 1); // 'ffa501' | |
</code></pre> | |
<hr> | |
<h2>title: URLJoin</h2> | |
<p>Joins all given URL segments together, then normalizes the resulting URL.</p> | |
<ul> | |
<li>Use <code>String.prototype.join('/')</code> to combine URL segments.</li> | |
<li>Use a series of <code>String.prototype.replace()</code> calls with various regexps to normalize the resulting URL (remove double slashes, add proper slashes for protocol, remove slashes before parameters, combine parameters with <code>'&'</code> and normalize first parameter delimiter).</li> | |
</ul> | |
<pre><code class="language-js">const URLJoin = (...args) => | |
args | |
.join('/') | |
.replace(/[\/]+/g, '/') | |
.replace(/^(.+):\//, '$1://') | |
.replace(/^file:/, 'file:/') | |
.replace(/\/(\?|&|#[^!])/g, '$1') | |
.replace(/\?/g, '&') | |
.replace('&', '?'); | |
</code></pre> | |
<pre><code class="language-js">URLJoin('http://www.google.com', 'a', '/b/cd', '?foo=123', '?bar=foo'); | |
// 'http://www.google.com/a/b/cd?foo=123&bar=foo' | |
</code></pre> | |
<hr> | |
<h2>title: UUIDGeneratorBrowser</h2> | |
<p>Generates a UUID in a browser.</p> | |
<ul> | |
<li>Use <code>Crypto.getRandomValues()</code> to generate a UUID, compliant with <a href="https://www.ietf.org/rfc/rfc4122.txt">RFC4122</a> version 4.</li> | |
<li>Use <code>Number.prototype.toString(16)</code> to convert it to a proper UUID.</li> | |
</ul> | |
<pre><code class="language-js">const UUIDGeneratorBrowser = () => | |
([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, c => | |
( | |
c ^ | |
(crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (c / 4))) | |
).toString(16) | |
); | |
</code></pre> | |
<pre><code class="language-js">UUIDGeneratorBrowser(); // '7982fcfe-5721-4632-bede-6000885be57d' | |
</code></pre> | |
<hr> | |
<h2>title: UUIDGeneratorNode</h2> | |
<p>Generates a UUID in Node.JS.</p> | |
<ul> | |
<li>Use <code>crypto.randomBytes()</code> to generate a UUID, compliant with <a href="https://www.ietf.org/rfc/rfc4122.txt">RFC4122</a> version 4.</li> | |
<li>Use <code>Number.prototype.toString(16)</code> to convert it to a proper UUID.</li> | |
</ul> | |
<pre><code class="language-js">const crypto = require('crypto'); | |
const UUIDGeneratorNode = () => | |
([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, c => | |
(c ^ (crypto.randomBytes(1)[0] & (15 >> (c / 4)))).toString(16) | |
); | |
</code></pre> | |
<pre><code class="language-js">UUIDGeneratorNode(); // '79c7c136-60ee-40a2-beb2-856f1feabefc' | |
</code></pre> | |
<hr> | |
<h2>title: accumulate</h2> | |
<p>Creates an array of partial sums.</p> | |
<ul> | |
<li>Use <code>Array.prototype.reduce()</code>, initialized with an empty array accumulator to iterate over <code>nums</code>.</li> | |
<li>Use <code>Array.prototype.slice(-1)</code>, the spread operator (<code>...</code>) and the unary <code>+</code> operator to add each value to the accumulator array containing the previous sums.</li> | |
</ul> | |
<pre><code class="language-js">const accumulate = (...nums) => | |
nums.reduce((acc, n) => [...acc, n + +acc.slice(-1)], []); | |
</code></pre> | |
<pre><code class="language-js">accumulate(1, 2, 3, 4); // [1, 3, 6, 10] | |
accumulate(...[1, 2, 3, 4]); // [1, 3, 6, 10] | |
</code></pre> | |
<hr> | |
<h2>title: addClass</h2> | |
<p>Adds a class to an HTML element.</p> | |
<ul> | |
<li>Use <code>Element.classList</code> and <code>DOMTokenList.add()</code> to add the specified class to the element.</li> | |
</ul> | |
<pre><code class="language-js">const addClass = (el, className) => el.classList.add(className); | |
</code></pre> | |
<pre><code class="language-js">addClass(document.querySelector('p'), 'special'); | |
// The paragraph will now have the 'special' class | |
</code></pre> | |
<hr> | |
<h2>title: addDaysToDate</h2> | |
<p>Calculates the date of <code>n</code> days from the given date, returning its string representation.</p> | |
<ul> | |
<li>Use <code>new Date()</code> to create a date object from the first argument.</li> | |
<li>Use <code>Date.prototype.getDate()</code> and <code>Date.prototype.setDate()</code> to add <code>n</code> days to the given date.</li> | |
<li>Use <code>Date.prototype.toISOString()</code> to return a string in <code>yyyy-mm-dd</code> format.</li> | |
</ul> | |
<pre><code class="language-js">const addDaysToDate = (date, n) => { | |
const d = new Date(date); | |
d.setDate(d.getDate() + n); | |
return d.toISOString().split('T')[0]; | |
}; | |
</code></pre> | |
<pre><code class="language-js">addDaysToDate('2020-10-15', 10); // '2020-10-25' | |
addDaysToDate('2020-10-15', -10); // '2020-10-05' | |
</code></pre> | |
<hr> | |
<h2>title: addEventListenerAll</h2> | |
<p>Attaches an event listener to all the provided targets.</p> | |
<ul> | |
<li>Use <code>Array.prototype.forEach()</code> and <code>EventTarget.addEventListener()</code> to attach the provided <code>listener</code> for the given event <code>type</code> to all <code>targets</code>.</li> | |
</ul> | |
<pre><code class="language-js">const addEventListenerAll = (targets, type, listener, options, useCapture) => { | |
targets.forEach(target => | |
target.addEventListener(type, listener, options, useCapture) | |
); | |
}; | |
</code></pre> | |
<pre><code class="language-js">addEventListenerAll(document.querySelectorAll('a'), 'click', () => | |
console.log('Clicked a link') | |
); | |
// Logs 'Clicked a link' whenever any anchor element is clicked | |
</code></pre> | |
<hr> | |
<h2>title: addMinutesToDate</h2> | |
<p>Calculates the date of <code>n</code> minutes from the given date, returning its string representation.</p> | |
<ul> | |
<li>Use <code>new Date()</code> to create a date object from the first argument.</li> | |
<li>Use <code>Date.prototype.getTime()</code> and <code>Date.prototype.setTime()</code> to add <code>n</code> minutes to the given date.</li> | |
<li>Use <code>Date.prototype.toISOString()</code>, <code>String.prototype.split()</code> and <code>String.prototype.replace()</code> to return a string in <code>yyyy-mm-dd HH:MM:SS</code> format.</li> | |
</ul> | |
<pre><code class="language-js">const addMinutesToDate = (date, n) => { | |
const d = new Date(date); | |
d.setTime(d.getTime() + n * 60000); | |
return d.toISOString().split('.')[0].replace('T',' '); | |
}; | |
</code></pre> | |
<pre><code class="language-js">addMinutesToDate('2020-10-19 12:00:00', 10); // '2020-10-19 12:10:00' | |
addMinutesToDate('2020-10-19', -10); // '2020-10-18 23:50:00' | |
</code></pre> | |
<hr> | |
<h2>title: addMultipleListeners</h2> | |
<p>Adds multiple event listeners with the same handler to an element.</p> | |
<ul> | |
<li>Use <code>Array.prototype.forEach()</code> and <code>EventTarget.addEventListener()</code> to add multiple event listeners with an assigned callback function to an element.</li> | |
</ul> | |
<pre><code class="language-js">const addMultipleListeners = (el, types, listener, options, useCapture) => { | |
types.forEach(type => | |
el.addEventListener(type, listener, options, useCapture) | |
); | |
}; | |
</code></pre> | |
<pre><code class="language-js">addMultipleListeners( | |
document.querySelector('.my-element'), | |
['click', 'mousedown'], | |
() => { console.log('hello!') } | |
); | |
</code></pre> | |
<hr> | |
<h2>title: addStyles</h2> | |
<p>Adds the provided styles to the given element.</p> | |
<ul> | |
<li>Use <code>Object.assign()</code> and <code>ElementCSSInlineStyle.style</code> to merge the provided <code>styles</code> object into the style of the given element.</li> | |
</ul> | |
<pre><code class="language-js">const addStyles = (el, styles) => Object.assign(el.style, styles); | |
</code></pre> | |
<pre><code class="language-js">addStyles(document.getElementById('my-element'), { | |
background: 'red', | |
color: '#ffff00', | |
fontSize: '3rem' | |
}); | |
</code></pre> | |
<hr> | |
<h2>title: addWeekDays</h2> | |
<p>Calculates the date after adding the given number of business days.</p> | |
<ul> | |
<li>Use <code>Array.from()</code> to construct an array with <code>length</code> equal to the <code>count</code> of business days to be added.</li> | |
<li>Use <code>Array.prototype.reduce()</code> to iterate over the array, starting from <code>startDate</code> and incrementing, using <code>Date.prototype.getDate()</code> and <code>Date.prototype.setDate()</code>.</li> | |
<li>If the current <code>date</code> is on a weekend, update it again by adding either one day or two days to make it a weekday.</li> | |
<li><strong>NOTE:</strong> Does not take official holidays into account.</li> | |
</ul> | |
<pre><code class="language-js">const addWeekDays = (startDate, count) => | |
Array.from({ length: count }).reduce(date => { | |
date = new Date(date.setDate(date.getDate() + 1)); | |
if (date.getDay() % 6 === 0) | |
date = new Date(date.setDate(date.getDate() + (date.getDay() / 6 + 1))); | |
return date; | |
}, startDate); | |
</code></pre> | |
<pre><code class="language-js">addWeekDays(new Date('Oct 09, 2020'), 5); // 'Oct 16, 2020' | |
addWeekDays(new Date('Oct 12, 2020'), 5); // 'Oct 19, 2020' | |
</code></pre> | |
<hr> | |
<h2>title: all</h2> | |
<p>Checks if the provided predicate function returns <code>true</code> for all elements in a collection.</p> | |
<ul> | |
<li>Use <code>Array.prototype.every()</code> to test if all elements in the collection return <code>true</code> based on <code>fn</code>.</li> | |
<li>Omit the second argument, <code>fn</code>, to use <code>Boolean</code> as a default.</li> | |
</ul> | |
<pre><code class="language-js">const all = (arr, fn = Boolean) => arr.every(fn); | |
</code></pre> | |
<pre><code class="language-js">all([4, 2, 3], x => x > 1); // true | |
all([1, 2, 3]); // true | |
</code></pre> | |
<hr> | |
<h2>title: allEqual</h2> | |
<p>Checks if all elements in an array are equal.</p> | |
<ul> | |
<li>Use <code>Array.prototype.every()</code> to check if all the elements of the array are the same as the first one.</li> | |
<li>Elements in the array are compared using the strict comparison operator, which does not account for <code>NaN</code> self-inequality.</li> | |
</ul> | |
<pre><code class="language-js">const allEqual = arr => arr.every(val => val === arr[0]); | |
</code></pre> | |
<pre><code class="language-js">allEqual([1, 2, 3, 4, 5, 6]); // false | |
allEqual([1, 1, 1, 1]); // true | |
</code></pre> | |
<hr> | |
<h2>title: allEqualBy</h2> | |
<p>Checks if all elements in an array are equal, based on the provided mapping function.</p> | |
<ul> | |
<li>Apply <code>fn</code> to the first element of <code>arr</code>.</li> | |
<li>Use <code>Array.prototype.every()</code> to check if <code>fn</code> returns the same value for all elements in the array as it did for the first one.</li> | |
<li>Elements in the array are compared using the strict comparison operator, which does not account for <code>NaN</code> self-inequality.</li> | |
</ul> | |
<pre><code class="language-js">const allEqualBy = (arr, fn) => { | |
const eql = fn(arr[0]); | |
return arr.every(val => fn(val) === eql); | |
}; | |
</code></pre> | |
<pre><code class="language-js">allEqualBy([1.1, 1.2, 1.3], Math.round); // true | |
allEqualBy([1.1, 1.3, 1.6], Math.round); // false | |
</code></pre> | |
<hr> | |
<h2>title: allUnique</h2> | |
<p>Checks if all elements in an array are unique.</p> | |
<ul> | |
<li>Create a new <code>Set</code> from the mapped values to keep only unique occurrences.</li> | |
<li>Use <code>Array.prototype.length</code> and <code>Set.prototype.size</code> to compare the length of the unique values to the original array.</li> | |
</ul> | |
<pre><code class="language-js">const allUnique = arr => arr.length === new Set(arr).size; | |
</code></pre> | |
<pre><code class="language-js">allUnique([1, 2, 3, 4]); // true | |
allUnique([1, 1, 2, 3]); // false | |
</code></pre> | |
<hr> | |
<h2>title: allUniqueBy</h2> | |
<p>Checks if all elements in an array are unique, based on the provided mapping function.</p> | |
<ul> | |
<li>Use <code>Array.prototype.map()</code> to apply <code>fn</code> to all elements in <code>arr</code>.</li> | |
<li>Create a new <code>Set</code> from the mapped values to keep only unique occurrences.</li> | |
<li>Use <code>Array.prototype.length</code> and <code>Set.prototype.size</code> to compare the length of the unique mapped values to the original array.</li> | |
</ul> | |
<pre><code class="language-js">const allUniqueBy = (arr, fn) => arr.length === new Set(arr.map(fn)).size; | |
</code></pre> | |
<pre><code class="language-js">allUniqueBy([1.2, 2.4, 2.9], Math.round); // true | |
allUniqueBy([1.2, 2.3, 2.4], Math.round); // false | |
</code></pre> | |
<hr> | |
<h2>title: and | |
unlisted: true</h2> | |
<p>Checks if both arguments are <code>true</code>.</p> | |
<ul> | |
<li>Use the logical and (<code>&&</code>) operator on the two given values.</li> | |
</ul> | |
<pre><code class="language-js">const and = (a, b) => a && b; | |
</code></pre> | |
<pre><code class="language-js">and(true, true); // true | |
and(true, false); // false | |
and(false, false); // false | |
</code></pre> | |
<hr> | |
<h2>title: any</h2> | |
<p>Checks if the provided predicate function returns <code>true</code> for at least one element in a collection.</p> | |
<ul> | |
<li>Use <code>Array.prototype.some()</code> to test if any elements in the collection return <code>true</code> based on <code>fn</code>.</li> | |
<li>Omit the second argument, <code>fn</code>, to use <code>Boolean</code> as a default.</li> | |
</ul> | |
<pre><code class="language-js">const any = (arr, fn = Boolean) => arr.some(fn); | |
</code></pre> | |
<pre><code class="language-js">any([0, 1, 2, 0], x => x >= 2); // true | |
any([0, 0, 1, 0]); // true | |
</code></pre> | |
<hr> | |
<h2>title: aperture</h2> | |
<p>Creates an array of <code>n</code>-tuples of consecutive elements.</p> | |
<ul> | |
<li>Use <code>Array.prototype.slice()</code> and <code>Array.prototype.map()</code> to create an array of appropriate length.</li> | |
<li>Populate the array with <code>n</code>-tuples of consecutive elements from <code>arr</code>.</li> | |
<li>If <code>n</code> is greater than the length of <code>arr</code>, return an empty array.</li> | |
</ul> | |
<pre><code class="language-js">const aperture = (n, arr) => | |
n > arr.length | |
? [] | |
: arr.slice(n - 1).map((v, i) => arr.slice(i, i + n)); | |
</code></pre> | |
<pre><code class="language-js">aperture(2, [1, 2, 3, 4]); // [[1, 2], [2, 3], [3, 4]] | |
aperture(3, [1, 2, 3, 4]); // [[1, 2, 3], [2, 3, 4]] | |
aperture(5, [1, 2, 3, 4]); // [] | |
</code></pre> | |
<hr> | |
<h2>title: approximatelyEqual</h2> | |
<p>Checks if two numbers are approximately equal to each other.</p> | |
<ul> | |
<li>Use <code>Math.abs()</code> to compare the absolute difference of the two values to <code>epsilon</code>.</li> | |
<li>Omit the third argument, <code>epsilon</code>, to use a default value of <code>0.001</code>.</li> | |
</ul> | |
<pre><code class="language-js">const approximatelyEqual = (v1, v2, epsilon = 0.001) => | |
Math.abs(v1 - v2) < epsilon; | |
</code></pre> | |
<pre><code class="language-js">approximatelyEqual(Math.PI / 2.0, 1.5708); // true | |
</code></pre> | |
<hr> | |
<h2>title: arithmeticProgression</h2> | |
<p>Creates an array of numbers in the arithmetic progression, starting with the given positive integer and up to the specified limit.</p> | |
<ul> | |
<li>Use <code>Array.from()</code> to create an array of the desired length, <code>lim/n</code>. Use a map function to fill it with the desired values in the given range.</li> | |
</ul> | |
<pre><code class="language-js">const arithmeticProgression = (n, lim) => | |
Array.from({ length: Math.ceil(lim / n) }, (_, i) => (i + 1) * n ); | |
</code></pre> | |
<pre><code class="language-js">arithmeticProgression(5, 25); // [5, 10, 15, 20, 25] | |
</code></pre> | |
<hr> | |
<h2>title: arrayToCSV</h2> | |
<p>Converts a 2D array to a comma-separated values (CSV) string.</p> | |
<ul> | |
<li>Use <code>Array.prototype.map()</code> and <code>Array.prototype.join(delimiter)</code> to combine individual 1D arrays (rows) into strings.</li> | |
<li>Use <code>Array.prototype.join('\n')</code> to combine all rows into a CSV string, separating each row with a newline.</li> | |
<li>Omit the second argument, <code>delimiter</code>, to use a default delimiter of <code>,</code>.</li> | |
</ul> | |
<pre><code class="language-js">const arrayToCSV = (arr, delimiter = ',') => | |
arr | |
.map(v => | |
v.map(x => (isNaN(x) ? `"${x.replace(/"/g, '""')}"` : x)).join(delimiter) | |
) | |
.join('\n'); | |
</code></pre> | |
<pre><code class="language-js">arrayToCSV([['a', 'b'], ['c', 'd']]); // '"a","b"\n"c","d"' | |
arrayToCSV([['a', 'b'], ['c', 'd']], ';'); // '"a";"b"\n"c";"d"' | |
arrayToCSV([['a', '"b" great'], ['c', 3.1415]]); | |
// '"a","""b"" great"\n"c",3.1415' | |
</code></pre> | |
<hr> | |
<h2>title: arrayToHTMLList</h2> | |
<p>Converts the given array elements into <code><li></code> tags and appends them to the list of the given id.</p> | |
<ul> | |
<li>Use <code>Array.prototype.map()</code> and <code>Document.querySelector()</code> to create a list of html tags.</li> | |
</ul> | |
<pre><code class="language-js">const arrayToHTMLList = (arr, listID) => | |
document.querySelector(`#${listID}`).innerHTML += arr | |
.map(item => `<li>${item}</li>`) | |
.join(''); | |
</code></pre> | |
<pre><code class="language-js">arrayToHTMLList(['item 1', 'item 2'], 'myListID'); | |
</code></pre> | |
<hr> | |
<h2>title: ary</h2> | |
<p>Creates a function that accepts up to <code>n</code> arguments, ignoring any additional arguments.</p> | |
<ul> | |
<li>Call the provided function, <code>fn</code>, with up to <code>n</code> arguments, using <code>Array.prototype.slice(0, n)</code> and the spread operator (<code>...</code>).</li> | |
</ul> | |
<pre><code class="language-js">const ary = (fn, n) => (...args) => fn(...args.slice(0, n)); | |
</code></pre> | |
<pre><code class="language-js">const firstTwoMax = ary(Math.max, 2); | |
[[2, 6, 'a'], [6, 4, 8], [10]].map(x => firstTwoMax(...x)); // [6, 6, 10] | |
</code></pre> | |
<hr> | |
<h2>title: assertValidKeys</h2> | |
<p>Validates all keys in an object match the given <code>keys</code>.</p> | |
<ul> | |
<li>Use <code>Object.keys()</code> to get the keys of the given object, <code>obj</code>.</li> | |
<li>Use <code>Array.prototype.every()</code> and <code>Array.prototype.includes()</code> to validate that each key in the object is specified in the <code>keys</code> array.</li> | |
</ul> | |
<pre><code class="language-js">const assertValidKeys = (obj, keys) => | |
Object.keys(obj).every(key => keys.includes(key)); | |
</code></pre> | |
<pre><code class="language-js">assertValidKeys({ id: 10, name: 'apple' }, ['id', 'name']); // true | |
assertValidKeys({ id: 10, name: 'apple' }, ['id', 'type']); // false | |
</code></pre> | |
<hr> | |
<h2>title: atob</h2> | |
<p>Decodes a string of data which has been encoded using base-64 encoding.</p> | |
<ul> | |
<li>Create a <code>Buffer</code> for the given string with base-64 encoding and use <code>Buffer.toString('binary')</code> to return the decoded string.</li> | |
</ul> | |
<pre><code class="language-js">const atob = str => Buffer.from(str, 'base64').toString('binary'); | |
</code></pre> | |
<pre><code class="language-js">atob('Zm9vYmFy'); // 'foobar' | |
</code></pre> | |
<hr> | |
<h2>title: attempt</h2> | |
<p>Attempts to invoke a function with the provided arguments, returning either the result or the caught error object.</p> | |
<ul> | |
<li>Use a <code>try... catch</code> block to return either the result of the function or an appropriate error.</li> | |
<li>If the caught object is not an <code>Error</code>, use it to create a new <code>Error</code>.</li> | |
</ul> | |
<pre><code class="language-js">const attempt = (fn, ...args) => { | |
try { | |
return fn(...args); | |
} catch (e) { | |
return e instanceof Error ? e : new Error(e); | |
} | |
}; | |
</code></pre> | |
<pre><code class="language-js">let elements = attempt(function(selector) { | |
return document.querySelectorAll(selector); | |
}, '>_>'); | |
if (elements instanceof Error) elements = []; // elements = [] | |
</code></pre> | |
<hr> | |
<h2>title: average</h2> | |
<p>Calculates the average of two or more numbers.</p> | |
<ul> | |
<li>Use <code>Array.prototype.reduce()</code> to add each value to an accumulator, initialized with a value of <code>0</code>.</li> | |
<li>Divide the resulting array by its length.</li> | |
</ul> | |
<pre><code class="language-js">const average = (...nums) => | |
nums.reduce((acc, val) => acc + val, 0) / nums.length; | |
</code></pre> | |
<pre><code class="language-js">average(...[1, 2, 3]); // 2 | |
average(1, 2, 3); // 2 | |
</code></pre> | |
<hr> | |
<h2>title: averageBy</h2> | |
<p>Calculates the average of an array, after mapping each element to a value using the provided function.</p> | |
<ul> | |
<li>Use <code>Array.prototype.map()</code> to map each element to the value returned by <code>fn</code>.</li> | |
<li>Use <code>Array.prototype.reduce()</code> to add each value to an accumulator, initialized with a value of <code>0</code>.</li> | |
<li>Divide the resulting array by its length.</li> | |
</ul> | |
<pre><code class="language-js">const averageBy = (arr, fn) => | |
arr | |
.map(typeof fn === 'function' ? fn : val => val[fn]) | |
.reduce((acc, val) => acc + val, 0) / arr.length; | |
</code></pre> | |
<pre><code class="language-js">averageBy([{ n: 4 }, { n: 2 }, { n: 8 }, { n: 6 }], o => o.n); // 5 | |
averageBy([{ n: 4 }, { n: 2 }, { n: 8 }, { n: 6 }], 'n'); // 5 | |
</code></pre> | |
<hr> | |
<h2>title: bifurcate</h2> | |
<p>Splits values into two groups, based on the result of the given <code>filter</code> array.</p> | |
<ul> | |
<li>Use <code>Array.prototype.reduce()</code> and <code>Array.prototype.push()</code> to add elements to groups, based on <code>filter</code>.</li> | |
<li>If <code>filter</code> has a truthy value for any element, add it to the first group, otherwise add it to the second group.</li> | |
</ul> | |
<pre><code class="language-js">const bifurcate = (arr, filter) => | |
arr.reduce((acc, val, i) => (acc[filter[i] ? 0 : 1].push(val), acc), [ | |
[], | |
[], | |
]); | |
</code></pre> | |
<pre><code class="language-js">bifurcate(['beep', 'boop', 'foo', 'bar'], [true, true, false, true]); | |
// [ ['beep', 'boop', 'bar'], ['foo'] ] | |
</code></pre> | |
<hr> | |
<h2>title: bifurcateBy</h2> | |
<p>Splits values into two groups, based on the result of the given filtering function.</p> | |
<ul> | |
<li>Use <code>Array.prototype.reduce()</code> and <code>Array.prototype.push()</code> to add elements to groups, based on the value returned by <code>fn</code> for each element.</li> | |
<li>If <code>fn</code> returns a truthy value for any element, add it to the first group, otherwise add it to the second group.</li> | |
</ul> | |
<pre><code class="language-js">const bifurcateBy = (arr, fn) => | |
arr.reduce((acc, val, i) => (acc[fn(val, i) ? 0 : 1].push(val), acc), [ | |
[], | |
[], | |
]); | |
</code></pre> | |
<pre><code class="language-js">bifurcateBy(['beep', 'boop', 'foo', 'bar'], x => x[0] === 'b'); | |
// [ ['beep', 'boop', 'bar'], ['foo'] ] | |
</code></pre> | |
<hr> | |
<h2>title: binary</h2> | |
<p>Creates a function that accepts up to two arguments, ignoring any additional arguments.</p> | |
<ul> | |
<li>Call the provided function, <code>fn</code>, with the first two arguments given.</li> | |
</ul> | |
<pre><code class="language-js">const binary = fn => (a, b) => fn(a, b); | |
</code></pre> | |
<pre><code class="language-js">['2', '1', '0'].map(binary(Math.max)); // [2, 1, 2] | |
</code></pre> | |
<hr> | |
<h2>title: binarySearch</h2> | |
<p>Finds the index of a given element in a sorted array using the binary search algorithm.</p> | |
<ul> | |
<li>Declare the left and right search boundaries, <code>l</code> and <code>r</code>, initialized to <code>0</code> and the <code>length</code> of the array respectively.</li> | |
<li>Use a <code>while</code> loop to repeatedly narrow down the search subarray, using <code>Math.floor()</code> to cut it in half.</li> | |
<li>Return the index of the element if found, otherwise return <code>-1</code>.</li> | |
<li><strong>Note:</strong> Does not account for duplicate values in the array.</li> | |
</ul> | |
<pre><code class="language-js">const binarySearch = (arr, item) => { | |
let l = 0, | |
r = arr.length - 1; | |
while (l <= r) { | |
const mid = Math.floor((l + r) / 2); | |
const guess = arr[mid]; | |
if (guess === item) return mid; | |
if (guess > item) r = mid - 1; | |
else l = mid + 1; | |
} | |
return -1; | |
}; | |
</code></pre> | |
<pre><code class="language-js">binarySearch([1, 2, 3, 4, 5], 1); // 0 | |
binarySearch([1, 2, 3, 4, 5], 5); // 4 | |
binarySearch([1, 2, 3, 4, 5], 6); // -1 | |
</code></pre> | |
<hr> | |
<h2>title: bind</h2> | |
<p>Creates a function that invokes <code>fn</code> with a given context, optionally prepending any additional supplied parameters to the arguments.</p> | |
<ul> | |
<li>Return a <code>function</code> that uses <code>Function.prototype.apply()</code> to apply the given <code>context</code> to <code>fn</code>.</li> | |
<li>Use the spread operator (<code>...</code>) to prepend any additional supplied parameters to the arguments.</li> | |
</ul> | |
<pre><code class="language-js">const bind = (fn, context, ...boundArgs) => (...args) => | |
fn.apply(context, [...boundArgs, ...args]); | |
</code></pre> | |
<pre><code class="language-js">function greet(greeting, punctuation) { | |
return greeting + ' ' + this.user + punctuation; | |
} | |
const freddy = { user: 'fred' }; | |
const freddyBound = bind(greet, freddy); | |
console.log(freddyBound('hi', '!')); // 'hi fred!' | |
</code></pre> | |
<hr> | |
<h2>title: bindAll</h2> | |
<p>Binds methods of an object to the object itself, overwriting the existing method.</p> | |
<ul> | |
<li>Use <code>Array.prototype.forEach()</code> to iterate over the given <code>fns</code>.</li> | |
<li>Return a function for each one, using <code>Function.prototype.apply()</code> to apply the given context (<code>obj</code>) to <code>fn</code>.</li> | |
</ul> | |
<pre><code class="language-js">const bindAll = (obj, ...fns) => | |
fns.forEach( | |
fn => ( | |
(f = obj[fn]), | |
(obj[fn] = function() { | |
return f.apply(obj); | |
}) | |
) | |
); | |
</code></pre> | |
<pre><code class="language-js">let view = { | |
label: 'docs', | |
click: function() { | |
console.log('clicked ' + this.label); | |
} | |
}; | |
bindAll(view, 'click'); | |
document.body.addEventListener('click', view.click); | |
// Log 'clicked docs' when clicked. | |
</code></pre> | |
<hr> | |
<h2>title: bindKey</h2> | |
<p>Creates a function that invokes the method at a given key of an object, optionally prepending any additional supplied parameters to the arguments.</p> | |
<ul> | |
<li>Return a <code>function</code> that uses <code>Function.prototype.apply()</code> to bind <code>context[fn]</code> to <code>context</code>.</li> | |
<li>Use the spread operator (<code>...</code>) to prepend any additional supplied parameters to the arguments.</li> | |
</ul> | |
<pre><code class="language-js">const bindKey = (context, fn, ...boundArgs) => (...args) => | |
context[fn].apply(context, [...boundArgs, ...args]); | |
</code></pre> | |
<pre><code class="language-js">const freddy = { | |
user: 'fred', | |
greet: function(greeting, punctuation) { | |
return greeting + ' ' + this.user + punctuation; | |
} | |
}; | |
const freddyBound = bindKey(freddy, 'greet'); | |
console.log(freddyBound('hi', '!')); // 'hi fred!' | |
</code></pre> | |
<hr> | |
<h2>title: binomialCoefficient</h2> | |
<p>Calculates the number of ways to choose <code>k</code> items from <code>n</code> items without repetition and without order.</p> | |
<ul> | |
<li>Use <code>Number.isNaN()</code> to check if any of the two values is <code>NaN</code>.</li> | |
<li>Check if <code>k</code> is less than <code>0</code>, greater than or equal to <code>n</code>, equal to <code>1</code> or <code>n - 1</code> and return the appropriate result.</li> | |
<li>Check if <code>n - k</code> is less than <code>k</code> and switch their values accordingly.</li> | |
<li>Loop from <code>2</code> through <code>k</code> and calculate the binomial coefficient.</li> | |
<li>Use <code>Math.round()</code> to account for rounding errors in the calculation.</li> | |
</ul> | |
<pre><code class="language-js">const binomialCoefficient = (n, k) => { | |
if (Number.isNaN(n) || Number.isNaN(k)) return NaN; | |
if (k < 0 || k > n) return 0; | |
if (k === 0 || k === n) return 1; | |
if (k === 1 || k === n - 1) return n; | |
if (n - k < k) k = n - k; | |
let res = n; | |
for (let j = 2; j <= k; j++) res *= (n - j + 1) / j; | |
return Math.round(res); | |
}; | |
</code></pre> | |
<pre><code class="language-js">binomialCoefficient(8, 2); // 28 | |
</code></pre> | |
<hr> | |
<h2>title: both | |
unlisted: true</h2> | |
<p>Checks if both of the given functions return <code>true</code> for a given set of arguments.</p> | |
<ul> | |
<li>Use the logical and (<code>&&</code>) operator on the result of calling the two functions with the supplied <code>args</code>.</li> | |
</ul> | |
<pre><code class="language-js">const both = (f, g) => (...args) => f(...args) && g(...args); | |
</code></pre> | |
<pre><code class="language-js">const isEven = num => num % 2 === 0; | |
const isPositive = num => num > 0; | |
const isPositiveEven = both(isEven, isPositive); | |
isPositiveEven(4); // true | |
isPositiveEven(-2); // false | |
</code></pre> | |
<p><a href="https://www.wappalyzer.com/technologies/widgets/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer">Widgets</a> | |
chrome-extension://gppongmhjkpfnbhagpmjfkannfbllamg/images/icons/Moat.svg | |
chrome-extension://gppongmhjkpfnbhagpmjfkannfbllamg/images/icons/Facebook.svg | |
<img src="//gppongmhjkpfnbhagpmjfkannfbllamg/images/icons/Facebook.svg" alt=""></p> | |
<p>Facebook](<a href="https://www.wappalyzer.com/technologies/widgets/facebook/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer" rel="nofollow">https://www.wappalyzer.com/technologies/widgets/facebook/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer</a>)</p> | |
<p>[<img src="//gppongmhjkpfnbhagpmjfkannfbllamg/images/icons/AddThis.svg" alt=""></p> | |
<p>AddThis](<a href="https://www.wappalyzer.com/technologies/widgets/addthis/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer" rel="nofollow">https://www.wappalyzer.com/technologies/widgets/addthis/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer</a>)</p> | |
<p><a href="https://www.wappalyzer.com/technologies/analytics/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer">Analytics</a></p> | |
<p>[<img src="//gppongmhjkpfnbhagpmjfkannfbllamg/images/icons/Moat.svg" alt=""></p> | |
<p>Moat](<a href="https://www.wappalyzer.com/technologies/analytics/moat/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer" rel="nofollow">https://www.wappalyzer.com/technologies/analytics/moat/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer</a>)</p> | |
<p>[<img src="//gppongmhjkpfnbhagpmjfkannfbllamg/images/icons/Google%20Analytics.svg" alt=""></p> | |
<p>Google Analytics](<a href="https://www.wappalyzer.com/technologies/analytics/google-analytics/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer" rel="nofollow">https://www.wappalyzer.com/technologies/analytics/google-analytics/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer</a>)</p> | |
<p>[<img src="//gppongmhjkpfnbhagpmjfkannfbllamg/images/icons/Google.svg" alt=""></p> | |
<p>Google Ads Conversion Tracking](<a href="https://www.wappalyzer.com/technologies/analytics/google-ads-conversion-tracking/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer" rel="nofollow">https://www.wappalyzer.com/technologies/analytics/google-ads-conversion-tracking/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer</a>)</p> | |
<p><a href="https://www.wappalyzer.com/technologies/javascript-frameworks/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer">JavaScript frameworks</a></p> | |
<p>[<img src="//gppongmhjkpfnbhagpmjfkannfbllamg/images/icons/React.png" alt=""></p> | |
<p>React](<a href="https://www.wappalyzer.com/technologies/javascript-frameworks/react/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer" rel="nofollow">https://www.wappalyzer.com/technologies/javascript-frameworks/react/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer</a>)</p> | |
<p>[<img src="//gppongmhjkpfnbhagpmjfkannfbllamg/images/icons/Gatsby.svg" alt=""></p> | |
<p>Gatsby2.25.4](<a href="https://www.wappalyzer.com/technologies/javascript-frameworks/gatsby/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer" rel="nofollow">https://www.wappalyzer.com/technologies/javascript-frameworks/gatsby/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer</a>)</p> | |
<p><a href="https://www.wappalyzer.com/technologies/font-scripts/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer">Font scripts</a></p> | |
<p>[<img src="//gppongmhjkpfnbhagpmjfkannfbllamg/images/icons/Google%20Font%20API.png" alt=""></p> | |
<p>Google Font API](<a href="https://www.wappalyzer.com/technologies/font-scripts/google-font-api/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer" rel="nofollow">https://www.wappalyzer.com/technologies/font-scripts/google-font-api/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer</a>)</p> | |
<p><a href="https://www.wappalyzer.com/technologies/miscellaneous/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer">Miscellaneous</a></p> | |
<p>[<img src="//gppongmhjkpfnbhagpmjfkannfbllamg/images/icons/webpack.svg" alt=""></p> | |
<p>webpack](<a href="https://www.wappalyzer.com/technologies/miscellaneous/webpack/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer" rel="nofollow">https://www.wappalyzer.com/technologies/miscellaneous/webpack/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer</a>)</p> | |
<p>[<img src="//gppongmhjkpfnbhagpmjfkannfbllamg/images/icons/Prism.svg" alt=""></p> | |
<p>Prism](<a href="https://www.wappalyzer.com/technologies/miscellaneous/prism/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer" rel="nofollow">https://www.wappalyzer.com/technologies/miscellaneous/prism/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer</a>)</p> | |
<p><a href="https://www.wappalyzer.com/technologies/cdn/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer">CDN</a></p> | |
<p>[<img src="//gppongmhjkpfnbhagpmjfkannfbllamg/images/icons/Unpkg.png" alt=""></p> | |
<p>Unpkg](<a href="https://www.wappalyzer.com/technologies/cdn/unpkg/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer" rel="nofollow">https://www.wappalyzer.com/technologies/cdn/unpkg/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer</a>)</p> | |
<p>[<img src="//gppongmhjkpfnbhagpmjfkannfbllamg/images/icons/jsdelivr-icon.svg" alt=""></p> | |
<p>jsDelivr](<a href="https://www.wappalyzer.com/technologies/cdn/jsdelivr/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer" rel="nofollow">https://www.wappalyzer.com/technologies/cdn/jsdelivr/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer</a>)</p> | |
<p>[<img src="//gppongmhjkpfnbhagpmjfkannfbllamg/images/icons/jQuery.svg" alt=""></p> | |
<p>jQuery CDN](<a href="https://www.wappalyzer.com/technologies/cdn/jquery-cdn/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer" rel="nofollow">https://www.wappalyzer.com/technologies/cdn/jquery-cdn/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer</a>)</p> | |
<p>[<img src="//gppongmhjkpfnbhagpmjfkannfbllamg/images/icons/Netlify.svg" alt=""></p> | |
<p>Netlify](<a href="https://www.wappalyzer.com/technologies/cdn/netlify/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer" rel="nofollow">https://www.wappalyzer.com/technologies/cdn/netlify/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer</a>)</p> | |
<p><a href="https://www.wappalyzer.com/technologies/marketing-automation/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer">Marketing automation</a></p> | |
<p>[<img src="//gppongmhjkpfnbhagpmjfkannfbllamg/images/icons/mailchimp.svg" alt=""></p> | |
<p>MailChimp](<a href="https://www.wappalyzer.com/technologies/marketing-automation/mailchimp/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer" rel="nofollow">https://www.wappalyzer.com/technologies/marketing-automation/mailchimp/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer</a>)</p> | |
<p><a href="https://www.wappalyzer.com/technologies/advertising/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer">Advertising</a></p> | |
<p>[<img src="//gppongmhjkpfnbhagpmjfkannfbllamg/images/icons/Google%20AdSense.svg" alt=""></p> | |
<p>Google AdSense](<a href="https://www.wappalyzer.com/technologies/advertising/google-adsense/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer" rel="nofollow">https://www.wappalyzer.com/technologies/advertising/google-adsense/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer</a>)</p> | |
<p><a href="https://www.wappalyzer.com/technologies/tag-managers/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer">Tag managers</a></p> | |
<p>[<img src="//gppongmhjkpfnbhagpmjfkannfbllamg/images/icons/Google%20Tag%20Manager.svg" alt=""></p> | |
<p>Google Tag Manager](<a href="https://www.wappalyzer.com/technologies/tag-managers/google-tag-manager/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer" rel="nofollow">https://www.wappalyzer.com/technologies/tag-managers/google-tag-manager/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer</a>)</p> | |
<p><a href="https://www.wappalyzer.com/technologies/live-chat/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer">Live chat</a></p> | |
<p>[<img src="//gppongmhjkpfnbhagpmjfkannfbllamg/images/icons/Smartsupp.svg" alt=""></p> | |
<p>Smartsupp1](<a href="https://www.wappalyzer.com/technologies/live-chat/smartsupp/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer" rel="nofollow">https://www.wappalyzer.com/technologies/live-chat/smartsupp/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer</a>)</p> | |
<p>[<img src="//gppongmhjkpfnbhagpmjfkannfbllamg/images/icons/LiveChat.png" alt=""></p> | |
<p>LiveChat](<a href="https://www.wappalyzer.com/technologies/live-chat/livechat/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer" rel="nofollow">https://www.wappalyzer.com/technologies/live-chat/livechat/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer</a>)</p> | |
<p><a href="https://www.wappalyzer.com/technologies/static-site-generator/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer">Static site generators</a></p> | |
<p>[<img src="//gppongmhjkpfnbhagpmjfkannfbllamg/images/icons/Gatsby.svg" alt=""></p> | |
<p>Gatsby2.25.4](<a href="https://www.wappalyzer.com/technologies/static-site-generator/gatsby/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer" rel="nofollow">https://www.wappalyzer.com/technologies/static-site-generator/gatsby/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer</a>)</p> | |
<p><a href="https://www.wappalyzer.com/technologies/javascript-libraries/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer">JavaScript libraries</a></p> | |
<p>[<img src="//gppongmhjkpfnbhagpmjfkannfbllamg/images/icons/Lo-dash.png" alt=""></p> | |
<p>Lodash4.17.11](<a href="https://www.wappalyzer.com/technologies/javascript-libraries/lodash/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer" rel="nofollow">https://www.wappalyzer.com/technologies/javascript-libraries/lodash/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer</a>)</p> | |
<p>[<img src="//gppongmhjkpfnbhagpmjfkannfbllamg/images/icons/Dojo.png" alt=""></p> | |
<p>Dojo1](<a href="https://www.wappalyzer.com/technologies/javascript-libraries/dojo/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer" rel="nofollow">https://www.wappalyzer.com/technologies/javascript-libraries/dojo/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer</a>)</p> | |
<p>[<img src="//gppongmhjkpfnbhagpmjfkannfbllamg/images/icons/core-js.png" alt=""></p> | |
<p>core-js3.10.2](<a href="https://www.wappalyzer.com/technologies/javascript-libraries/core-js/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer" rel="nofollow">https://www.wappalyzer.com/technologies/javascript-libraries/core-js/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer</a>)</p> | |
<p>[<img src="//gppongmhjkpfnbhagpmjfkannfbllamg/images/icons/jQuery.svg" alt=""></p> | |
<p>jQuery3.1.1](<a href="https://www.wappalyzer.com/technologies/javascript-libraries/jquery/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer" rel="nofollow">https://www.wappalyzer.com/technologies/javascript-libraries/jquery/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer</a>)</p> | |
<p><a href="https://www.wappalyzer.com/technologies/paas/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer">PaaS</a></p> | |
<p>[<img src="//gppongmhjkpfnbhagpmjfkannfbllamg/images/icons/Netlify.svg" alt=""></p> | |
<p>Netlify](<a href="https://www.wappalyzer.com/technologies/paas/netlify/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer" rel="nofollow">https://www.wappalyzer.com/technologies/paas/netlify/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer</a>)</p> | |
<p><a href="https://www.wappalyzer.com/technologies/ui-frameworks/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer">UI frameworks</a></p> | |
<p>[<img src="//gppongmhjkpfnbhagpmjfkannfbllamg/images/icons/Bootstrap.svg" alt=""></p> | |
<p>Bootstrap5.1.1](<a href="https://www.wappalyzer.com/technologies/ui-frameworks/bootstrap/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer" rel="nofollow">https://www.wappalyzer.com/technologies/ui-frameworks/bootstrap/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer</a>)</p> | |
<p><a href="https://www.wappalyzer.com/technologies/authentication/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer">Authentication</a></p> | |
<p>[<img src="//gppongmhjkpfnbhagpmjfkannfbllamg/images/icons/Facebook.svg" alt=""></p> | |
<p>Facebook Login](<a href="https://www.wappalyzer.com/technologies/authentication/facebook-login/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer" rel="nofollow">https://www.wappalyzer.com/technologies/authentication/facebook-login/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer</a>)</p> | |
<p><a href="https://www.wappalyzer.com/technologies/email/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer">Email</a></p> | |
<p>[<img src="//gppongmhjkpfnbhagpmjfkannfbllamg/images/icons/mailchimp.svg" alt=""></p> | |
<p>MailChimp](<a href="https://www.wappalyzer.com/technologies/email/mailchimp/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer" rel="nofollow">https://www.wappalyzer.com/technologies/email/mailchimp/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer</a>)</p> | |
<p><a href="https://www.wappalyzer.com/technologies/retargeting/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer">Retargeting</a></p> | |
<p>[<img src="//gppongmhjkpfnbhagpmjfkannfbllamg/images/icons/Google%20Tag%20Manager.svg" alt=""></p> | |
<p>Google Remarketing Tag](<a href="https://www.wappalyzer.com/technologies/retargeting/google-remarketing-tag/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer" rel="nofollow">https://www.wappalyzer.com/technologies/retargeting/google-remarketing-tag/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer</a>)</p> | |
<hr> | |
<h2>title: btoa</h2> | |
<p>Creates a base-64 encoded ASCII string from a String object in which each character in the string is treated as a byte of binary data.</p> | |
<ul> | |
<li>Create a <code>Buffer</code> for the given string with binary encoding and use <code>Buffer.toString('base64')</code> to return the encoded string.</li> | |
</ul> | |
<pre><code class="language-js">const btoa = str => Buffer.from(str, 'binary').toString('base64'); | |
</code></pre> | |
<pre><code class="language-js">btoa('foobar'); // 'Zm9vYmFy' | |
</code></pre> | |
<hr> | |
<h2>title: bubbleSort</h2> | |
<p>Sorts an array of numbers, using the bubble sort algorithm.</p> | |
<ul> | |
<li>Declare a variable, <code>swapped</code>, that indicates if any values were swapped during the current iteration.</li> | |
<li>Use the spread operator (<code>...</code>) to clone the original array, <code>arr</code>.</li> | |
<li>Use a <code>for</code> loop to iterate over the elements of the cloned array, terminating before the last element.</li> | |
<li>Use a nested <code>for</code> loop to iterate over the segment of the array between <code>0</code> and <code>i</code>, swapping any adjacent out of order elements and setting <code>swapped</code> to <code>true</code>.</li> | |
<li>If <code>swapped</code> is <code>false</code> after an iteration, no more changes are needed, so the cloned array is returned.</li> | |
</ul> | |
<pre><code class="language-js">const bubbleSort = arr => { | |
let swapped = false; | |
const a = [...arr]; | |
for (let i = 1; i < a.length; i++) { | |
swapped = false; | |
for (let j = 0; j < a.length - i; j++) { | |
if (a[j + 1] < a[j]) { | |
[a[j], a[j + 1]] = [a[j + 1], a[j]]; | |
swapped = true; | |
} | |
} | |
if (!swapped) return a; | |
} | |
return a; | |
}; | |
</code></pre> | |
<pre><code class="language-js">bubbleSort([2, 1, 4, 3]); // [1, 2, 3, 4] | |
</code></pre> | |
<hr> | |
<h2>title: bucketSort</h2> | |
<p>Sorts an array of numbers, using the bucket sort algorithm.</p> | |
<ul> | |
<li>Use <code>Math.min(),</code> <code>Math.max()</code> and the spread operator (<code>...</code>) to find the minimum and maximum values of the given array.</li> | |
<li>Use <code>Array.from()</code> and <code>Math.floor()</code> to create the appropriate number of <code>buckets</code> (empty arrays).</li> | |
<li>Use <code>Array.prototype.forEach()</code> to populate each bucket with the appropriate elements from the array.</li> | |
<li>Use <code>Array.prototype.reduce()</code>, the spread operator (<code>...</code>) and <code>Array.prototype.sort()</code> to sort each bucket and append it to the result.</li> | |
</ul> | |
<pre><code class="language-js">const bucketSort = (arr, size = 5) => { | |
const min = Math.min(...arr); | |
const max = Math.max(...arr); | |
const buckets = Array.from( | |
{ length: Math.floor((max - min) / size) + 1 }, | |
() => [] | |
); | |
arr.forEach(val => { | |
buckets[Math.floor((val - min) / size)].push(val); | |
}); | |
return buckets.reduce((acc, b) => [...acc, ...b.sort((a, b) => a - b)], []); | |
}; | |
</code></pre> | |
<pre><code class="language-js">bucketSort([6, 3, 4, 1]); // [1, 3, 4, 6] | |
</code></pre> | |
<hr> | |
<h2>title: byteSize</h2> | |
<p>Returns the length of a string in bytes.</p> | |
<ul> | |
<li>Convert a given string to a <a href="https://developer.mozilla.org/en-US/docs/Web/API/Blob"><code>Blob</code> Object</a>.</li> | |
<li>Use <code>Blob.size</code> to get the length of the string in bytes.</li> | |
</ul> | |
<pre><code class="language-js">const byteSize = str => new Blob([str]).size; | |
</code></pre> | |
<pre><code class="language-js">byteSize('😀'); // 4 | |
byteSize('Hello World'); // 11 | |
</code></pre> | |
<hr> | |
<h2>title: caesarCipher</h2> | |
<p>Encrypts or decrypts a given string using the Caesar cipher.</p> | |
<ul> | |
<li>Use the modulo (<code>%</code>) operator and the ternary operator (<code>?</code>) to calculate the correct encryption/decryption key.</li> | |
<li>Use the spread operator (<code>...</code>) and <code>Array.prototype.map()</code> to iterate over the letters of the given string.</li> | |
<li>Use <code>String.prototype.charCodeAt()</code> and <code>String.fromCharCode()</code> to convert each letter appropriately, ignoring special characters, spaces etc.</li> | |
<li>Use <code>Array.prototype.join()</code> to combine all the letters into a string.</li> | |
<li>Pass <code>true</code> to the last parameter, <code>decrypt</code>, to decrypt an encrypted string.</li> | |
</ul> | |
<pre><code class="language-js">const caesarCipher = (str, shift, decrypt = false) => { | |
const s = decrypt ? (26 - shift) % 26 : shift; | |
const n = s > 0 ? s : 26 + (s % 26); | |
return [...str] | |
.map((l, i) => { | |
const c = str.charCodeAt(i); | |
if (c >= 65 && c <= 90) | |
return String.fromCharCode(((c - 65 + n) % 26) + 65); | |
if (c >= 97 && c <= 122) | |
return String.fromCharCode(((c - 97 + n) % 26) + 97); | |
return l; | |
}) | |
.join(''); | |
}; | |
</code></pre> | |
<pre><code class="language-js">caesarCipher('Hello World!', -3); // 'Ebiil Tloia!' | |
caesarCipher('Ebiil Tloia!', 23, true); // 'Hello World!' | |
</code></pre> | |
<hr> | |
<h2>title: call</h2> | |
<p>Given a key and a set of arguments, call them when given a context.</p> | |
<ul> | |
<li>Use a closure to call <code>key</code> with <code>args</code> for the given <code>context</code>.</li> | |
</ul> | |
<pre><code class="language-js">const call = (key, ...args) => context => context[key](...args); | |
</code></pre> | |
<pre><code class="language-js">Promise.resolve([1, 2, 3]) | |
.then(call('map', x => 2 * x)) | |
.then(console.log); // [ 2, 4, 6 ] | |
const map = call.bind(null, 'map'); | |
Promise.resolve([1, 2, 3]) | |
.then(map(x => 2 * x)) | |
.then(console.log); // [ 2, 4, 6 ] | |
</code></pre> | |
<hr> | |
<h2>title: capitalize</h2> | |
<p>Capitalizes the first letter of a string.</p> | |
<ul> | |
<li>Use array destructuring and <code>String.prototype.toUpperCase()</code> to capitalize the first letter of the string.</li> | |
<li>Use <code>Array.prototype.join('')</code> to combine the capitalized <code>first</code> with the <code>...rest</code> of the characters.</li> | |
<li>Omit the <code>lowerRest</code> argument to keep the rest of the string intact, or set it to <code>true</code> to convert to lowercase.</li> | |
</ul> | |
<pre><code class="language-js">const capitalize = ([first, ...rest], lowerRest = false) => | |
first.toUpperCase() + | |
(lowerRest ? rest.join('').toLowerCase() : rest.join('')); | |
</code></pre> | |
<pre><code class="language-js">capitalize('fooBar'); // 'FooBar' | |
capitalize('fooBar', true); // 'Foobar' | |
</code></pre> | |
<hr> | |
<h2>title: capitalizeEveryWord</h2> | |
<p>Capitalizes the first letter of every word in a string.</p> | |
<ul> | |
<li>Use <code>String.prototype.replace()</code> to match the first character of each word and <code>String.prototype.toUpperCase()</code> to capitalize it.</li> | |
</ul> | |
<pre><code class="language-js">const capitalizeEveryWord = str => | |
str.replace(/\b[a-z]/g, char => char.toUpperCase()); | |
</code></pre> | |
<pre><code class="language-js">capitalizeEveryWord('hello world!'); // 'Hello World!' | |
</code></pre> | |
<hr> | |
<h2>title: cartesianProduct</h2> | |
<p>Calculates the cartesian product of two arrays.</p> | |
<ul> | |
<li>Use <code>Array.prototype.reduce()</code>, <code>Array.prototype.map()</code> and the spread operator (<code>...</code>) to generate all possible element pairs from the two arrays.</li> | |
</ul> | |
<pre><code class="language-js">const cartesianProduct = (a, b) => | |
a.reduce((p, x) => [...p, ...b.map(y => [x, y])], []); | |
</code></pre> | |
<pre><code class="language-js">cartesianProduct(['x', 'y'], [1, 2]); | |
// [['x', 1], ['x', 2], ['y', 1], ['y', 2]] | |
</code></pre> | |
<hr> | |
<h2>title: castArray</h2> | |
<p>Casts the provided value as an array if it’s not one.</p> | |
<ul> | |
<li>Use <code>Array.prototype.isArray()</code> to determine if <code>val</code> is an array and return it as-is or encapsulated in an array accordingly.</li> | |
</ul> | |
<pre><code class="language-js">const castArray = val => (Array.isArray(val) ? val : [val]); | |
</code></pre> | |
<pre><code class="language-js">castArray('foo'); // ['foo'] | |
castArray([1]); // [1] | |
</code></pre> | |
<hr> | |
<h2>title: celsiusToFahrenheit | |
unlisted: true</h2> | |
<p>Converts Celsius to Fahrenheit.</p> | |
<ul> | |
<li>Follow the conversion formula <code>F = 1.8 * C + 32</code>.</li> | |
</ul> | |
<pre><code class="language-js">const celsiusToFahrenheit = degrees => 1.8 * degrees + 32; | |
</code></pre> | |
<pre><code class="language-js">celsiusToFahrenheit(33); // 91.4 | |
</code></pre> | |
<hr> | |
<h2>title: chainAsync</h2> | |
<p>Chains asynchronous functions.</p> | |
<ul> | |
<li>Loop through an array of functions containing asynchronous events, calling <code>next</code> when each asynchronous event has completed.</li> | |
</ul> | |
<pre><code class="language-js">const chainAsync = fns => { | |
let curr = 0; | |
const last = fns[fns.length - 1]; | |
const next = () => { | |
const fn = fns[curr++]; | |
fn === last ? fn() : fn(next); | |
}; | |
next(); | |
}; | |
</code></pre> | |
<pre><code class="language-js">chainAsync([ | |
next => { | |
console.log('0 seconds'); | |
setTimeout(next, 1000); | |
}, | |
next => { | |
console.log('1 second'); | |
setTimeout(next, 1000); | |
}, | |
() => { | |
console.log('2 second'); | |
} | |
]); | |
</code></pre> | |
<hr> | |
<h2>title: changeLightness</h2> | |
<p>Changes the lightness value of an <code>hsl()</code> color string.</p> | |
<ul> | |
<li>Use <code>String.prototype.match()</code> to get an array of 3 strings with the numeric values.</li> | |
<li>Use <code>Array.prototype.map()</code> in combination with <code>Number</code> to convert them into an array of numeric values.</li> | |
<li>Make sure the lightness is within the valid range (between <code>0</code> and <code>100</code>), using <code>Math.max()</code> and <code>Math.min()</code>.</li> | |
<li>Use a template literal to create a new <code>hsl()</code> string with the updated value.</li> | |
</ul> | |
<pre><code class="language-js">const changeLightness = (delta, hslStr) => { | |
const [hue, saturation, lightness] = hslStr.match(/\d+/g).map(Number); | |
const newLightness = Math.max( | |
0, | |
Math.min(100, lightness + parseFloat(delta)) | |
); | |
return `hsl(${hue}, ${saturation}%, ${newLightness}%)`; | |
}; | |
</code></pre> | |
<pre><code class="language-js">changeLightness(10, 'hsl(330, 50%, 50%)'); // 'hsl(330, 50%, 60%)' | |
changeLightness(-10, 'hsl(330, 50%, 50%)'); // 'hsl(330, 50%, 40%)' | |
</code></pre> | |
<hr> | |
<h2>title: checkProp</h2> | |
<p>Creates a function that will invoke a predicate function for the specified property on a given object.</p> | |
<ul> | |
<li>Return a curried function, that will invoke <code>predicate</code> for the specified <code>prop</code> on <code>obj</code> and return a boolean.</li> | |
</ul> | |
<pre><code class="language-js">const checkProp = (predicate, prop) => obj => !!predicate(obj[prop]); | |
</code></pre> | |
<pre><code class="language-js">const lengthIs4 = checkProp(l => l === 4, 'length'); | |
lengthIs4([]); // false | |
lengthIs4([1, 2, 3, 4]); // true | |
lengthIs4(new Set([1, 2, 3, 4])); // false (Set uses Size, not length) | |
const session = { user: {} }; | |
const validUserSession = checkProp(u => u.active && !u.disabled, 'user'); | |
validUserSession(session); // false | |
session.user.active = true; | |
validUserSession(session); // true | |
const noLength = checkProp(l => l === undefined, 'length'); | |
noLength([]); // false | |
noLength({}); // true | |
noLength(new Set()); // true | |
</code></pre> | |
<hr> | |
<h2>title: chunk</h2> | |
<p>Chunks an array into smaller arrays of a specified size.</p> | |
<ul> | |
<li>Use <code>Array.from()</code> to create a new array, that fits the number of chunks that will be produced.</li> | |
<li>Use <code>Array.prototype.slice()</code> to map each element of the new array to a chunk the length of <code>size</code>.</li> | |
<li>If the original array can’t be split evenly, the final chunk will contain the remaining elements.</li> | |
</ul> | |
<pre><code class="language-js">const chunk = (arr, size) => | |
Array.from({ length: Math.ceil(arr.length / size) }, (v, i) => | |
arr.slice(i * size, i * size + size) | |
); | |
</code></pre> | |
<pre><code class="language-js">chunk([1, 2, 3, 4, 5], 2); // [[1, 2], [3, 4], [5]] | |
</code></pre> | |
<hr> | |
<h2>title: chunkIntoN</h2> | |
<p>Chunks an array into <code>n</code> smaller arrays.</p> | |
<ul> | |
<li>Use <code>Math.ceil()</code> and <code>Array.prototype.length</code> to get the size of each chunk.</li> | |
<li>Use <code>Array.from()</code> to create a new array of size <code>n</code>.</li> | |
<li>Use <code>Array.prototype.slice()</code> to map each element of the new array to a chunk the length of <code>size</code>.</li> | |
<li>If the original array can’t be split evenly, the final chunk will contain the remaining elements.</li> | |
</ul> | |
<pre><code class="language-js">const chunkIntoN = (arr, n) => { | |
const size = Math.ceil(arr.length / n); | |
return Array.from({ length: n }, (v, i) => | |
arr.slice(i * size, i * size + size) | |
); | |
} | |
</code></pre> | |
<pre><code class="language-js">chunkIntoN([1, 2, 3, 4, 5, 6, 7], 4); // [[1, 2], [3, 4], [5, 6], [7]] | |
</code></pre> | |
<hr> | |
<h2>title: chunkify</h2> | |
<p>Chunks an iterable into smaller arrays of a specified size.</p> | |
<ul> | |
<li>Use a <code>for...of</code> loop over the given iterable, using <code>Array.prototype.push()</code> to add each new value to the current <code>chunk</code>.</li> | |
<li>Use <code>Array.prototype.length</code> to check if the current <code>chunk</code> is of the desired <code>size</code> and <code>yield</code> the value if it is.</li> | |
<li>Finally, use <code>Array.prototype.length</code> to check the final <code>chunk</code> and <code>yield</code> it if it’s non-empty.</li> | |
</ul> | |
<pre><code class="language-js">const chunkify = function* (itr, size) { | |
let chunk = []; | |
for (const v of itr) { | |
chunk.push(v); | |
if (chunk.length === size) { | |
yield chunk; | |
chunk = []; | |
} | |
} | |
if (chunk.length) yield chunk; | |
}; | |
</code></pre> | |
<pre><code class="language-js">const x = new Set([1, 2, 1, 3, 4, 1, 2, 5]); | |
[...chunkify(x, 2)]; // [[1, 2], [3, 4], [5]] | |
</code></pre> | |
<hr> | |
<h2>title: clampNumber</h2> | |
<p>Clamps <code>num</code> within the inclusive range specified by the boundary values <code>a</code> and <code>b</code>.</p> | |
<ul> | |
<li>If <code>num</code> falls within the range, return <code>num</code>.</li> | |
<li>Otherwise, return the nearest number in the range.</li> | |
</ul> | |
<pre><code class="language-js">const clampNumber = (num, a, b) => | |
Math.max(Math.min(num, Math.max(a, b)), Math.min(a, b)); | |
</code></pre> | |
<pre><code class="language-js">clampNumber(2, 3, 5); // 3 | |
clampNumber(1, -1, -5); // -1 | |
</code></pre> | |
<hr> | |
<h2>title: cloneRegExp</h2> | |
<p>Clones a regular expression.</p> | |
<ul> | |
<li>Use <code>new RegExp()</code>, <code>RegExp.prototype.source</code> and <code>RegExp.prototype.flags</code> to clone the given regular expression.</li> | |
</ul> | |
<pre><code class="language-js">const cloneRegExp = regExp => new RegExp(regExp.source, regExp.flags); | |
</code></pre> | |
<pre><code class="language-js">const regExp = /lorem ipsum/gi; | |
const regExp2 = cloneRegExp(regExp); // regExp !== regExp2 | |
</code></pre> | |
<hr> | |
<h2>title: coalesce</h2> | |
<p>Returns the first defined, non-null argument.</p> | |
<ul> | |
<li>Use <code>Array.prototype.find()</code> and <code>Array.prototype.includes()</code> to find the first value that is not equal to <code>undefined</code> or <code>null</code>.</li> | |
</ul> | |
<pre><code class="language-js">const coalesce = (...args) => args.find(v => ![undefined, null].includes(v)); | |
</code></pre> | |
<pre><code class="language-js">coalesce(null, undefined, '', NaN, 'Waldo'); // '' | |
</code></pre> | |
<hr> | |
<h2>title: coalesceFactory</h2> | |
<p>Customizes a coalesce function that returns the first argument which is true based on the given validator.</p> | |
<ul> | |
<li>Use <code>Array.prototype.find()</code> to return the first argument that returns <code>true</code> from the provided argument validation function, <code>valid</code>.</li> | |
</ul> | |
<pre><code class="language-js">const coalesceFactory = valid => (...args) => args.find(valid); | |
</code></pre> | |
<pre><code class="language-js">const customCoalesce = coalesceFactory( | |
v => ![null, undefined, '', NaN].includes(v) | |
); | |
customCoalesce(undefined, null, NaN, '', 'Waldo'); // 'Waldo' | |
</code></pre> | |
<hr> | |
<h2>title: collectInto</h2> | |
<p>Changes a function that accepts an array into a variadic function.</p> | |
<ul> | |
<li>Given a function, return a closure that collects all inputs into an array-accepting function.</li> | |
</ul> | |
<pre><code class="language-js">const collectInto = fn => (...args) => fn(args); | |
</code></pre> | |
<pre><code class="language-js">const Pall = collectInto(Promise.all.bind(Promise)); | |
let p1 = Promise.resolve(1); | |
let p2 = Promise.resolve(2); | |
let p3 = new Promise(resolve => setTimeout(resolve, 2000, 3)); | |
Pall(p1, p2, p3).then(console.log); // [1, 2, 3] (after about 2 seconds) | |
</code></pre> | |
<hr> | |
<h2>title: colorize</h2> | |
<p>Adds special characters to text to print in color in the console (combined with <code>console.log()</code>).</p> | |
<ul> | |
<li>Use template literals and special characters to add the appropriate color code to the string output.</li> | |
<li>For background colors, add a special character that resets the background color at the end of the string.</li> | |
</ul> | |
<pre><code class="language-js">const colorize = (...args) => ({ | |
black: `\x1b[30m${args.join(' ')}`, | |
red: `\x1b[31m${args.join(' ')}`, | |
green: `\x1b[32m${args.join(' ')}`, | |
yellow: `\x1b[33m${args.join(' ')}`, | |
blue: `\x1b[34m${args.join(' ')}`, | |
magenta: `\x1b[35m${args.join(' ')}`, | |
cyan: `\x1b[36m${args.join(' ')}`, | |
white: `\x1b[37m${args.join(' ')}`, | |
bgBlack: `\x1b[40m${args.join(' ')}\x1b[0m`, | |
bgRed: `\x1b[41m${args.join(' ')}\x1b[0m`, | |
bgGreen: `\x1b[42m${args.join(' ')}\x1b[0m`, | |
bgYellow: `\x1b[43m${args.join(' ')}\x1b[0m`, | |
bgBlue: `\x1b[44m${args.join(' ')}\x1b[0m`, | |
bgMagenta: `\x1b[45m${args.join(' ')}\x1b[0m`, | |
bgCyan: `\x1b[46m${args.join(' ')}\x1b[0m`, | |
bgWhite: `\x1b[47m${args.join(' ')}\x1b[0m` | |
}); | |
</code></pre> | |
<pre><code class="language-js">console.log(colorize('foo').red); // 'foo' (red letters) | |
console.log(colorize('foo', 'bar').bgBlue); // 'foo bar' (blue background) | |
console.log(colorize(colorize('foo').yellow, colorize('foo').green).bgWhite); | |
// 'foo bar' (first word in yellow letters, second word in green letters, white background for both) | |
</code></pre> | |
<hr> | |
<h2>title: combine</h2> | |
<p>Combines two arrays of objects, using the specified key to match objects.</p> | |
<ul> | |
<li>Use <code>Array.prototype.reduce()</code> with an object accumulator to combine all objects in both arrays based on the given <code>prop</code>.</li> | |
<li>Use <code>Object.values()</code> to convert the resulting object to an array and return it.</li> | |
</ul> | |
<pre><code class="language-js">const combine = (a, b, prop) => | |
Object.values( | |
[...a, ...b].reduce((acc, v) => { | |
if (v[prop]) | |
acc[v[prop]] = acc[v[prop]] | |
? { ...acc[v[prop]], ...v } | |
: { ...v }; | |
return acc; | |
}, {}) | |
); | |
</code></pre> | |
<pre><code class="language-js">const x = [ | |
{ id: 1, name: 'John' }, | |
{ id: 2, name: 'Maria' } | |
]; | |
const y = [ | |
{ id: 1, age: 28 }, | |
{ id: 3, age: 26 }, | |
{ age: 3} | |
]; | |
combine(x, y, 'id'); | |
// [ | |
// { id: 1, name: 'John', age: 28 }, | |
// { id: 2, name: 'Maria' }, | |
// { id: 3, age: 26 } | |
// ] | |
</code></pre> | |
<hr> | |
<h2>title: compact</h2> | |
<p>Removes falsy values from an array.</p> | |
<ul> | |
<li>Use <code>Array.prototype.filter()</code> to filter out falsy values (<code>false</code>, <code>null</code>, <code>0</code>, <code>""</code>, <code>undefined</code>, and <code>NaN</code>).</li> | |
</ul> | |
<pre><code class="language-js">const compact = arr => arr.filter(Boolean); | |
</code></pre> | |
<pre><code class="language-js">compact([0, 1, false, 2, '', 3, 'a', 'e' * 23, NaN, 's', 34]); | |
// [ 1, 2, 3, 'a', 's', 34 ] | |
</code></pre> | |
<hr> | |
<h2>title: compactObject</h2> | |
<p>Deeply removes all falsy values from an object or array.</p> | |
<ul> | |
<li>Use recursion.</li> | |
<li>Initialize the iterable data, using <code>Array.isArray()</code>, <code>Array.prototype.filter()</code> and <code>Boolean</code> for arrays in order to avoid sparse arrays.</li> | |
<li>Use <code>Object.keys()</code> and <code>Array.prototype.reduce()</code> to iterate over each key with an appropriate initial value.</li> | |
<li>Use <code>Boolean</code> to determine the truthiness of each key’s value and add it to the accumulator if it’s truthy.</li> | |
<li>Use <code>typeof</code> to determine if a given value is an <code>object</code> and call the function again to deeply compact it.</li> | |
</ul> | |
<pre><code class="language-js">const compactObject = val => { | |
const data = Array.isArray(val) ? val.filter(Boolean) : val; | |
return Object.keys(data).reduce( | |
(acc, key) => { | |
const value = data[key]; | |
if (Boolean(value)) | |
acc[key] = typeof value === 'object' ? compactObject(value) : value; | |
return acc; | |
}, | |
Array.isArray(val) ? [] : {} | |
); | |
}; | |
</code></pre> | |
<pre><code class="language-js">const obj = { | |
a: null, | |
b: false, | |
c: true, | |
d: 0, | |
e: 1, | |
f: '', | |
g: 'a', | |
h: [null, false, '', true, 1, 'a'], | |
i: { j: 0, k: false, l: 'a' } | |
}; | |
compactObject(obj); | |
// { c: true, e: 1, g: 'a', h: [ true, 1, 'a' ], i: { l: 'a' } } | |
</code></pre> | |
<hr> | |
<h2>title: compactWhitespace</h2> | |
<p>Compacts whitespaces in a string.</p> | |
<ul> | |
<li>Use <code>String.prototype.replace()</code> with a regular expression to replace all occurrences of 2 or more whitespace characters with a single space.</li> | |
</ul> | |
<pre><code class="language-js">const compactWhitespace = str => str.replace(/\s{2,}/g, ' '); | |
</code></pre> | |
<pre><code class="language-js">compactWhitespace('Lorem Ipsum'); // 'Lorem Ipsum' | |
compactWhitespace('Lorem \n Ipsum'); // 'Lorem Ipsum' | |
</code></pre> | |
<hr> | |
<h2>title: complement</h2> | |
<p>Returns a function that is the logical complement of the given function, <code>fn</code>.</p> | |
<ul> | |
<li>Use the logical not (<code>!</code>) operator on the result of calling <code>fn</code> with any supplied <code>args</code>.</li> | |
</ul> | |
<pre><code class="language-js">const complement = fn => (...args) => !fn(...args); | |
</code></pre> | |
<pre><code class="language-js">const isEven = num => num % 2 === 0; | |
const isOdd = complement(isEven); | |
isOdd(2); // false | |
isOdd(3); // true | |
</code></pre> | |
<hr> | |
<h2>title: compose</h2> | |
<p>Performs right-to-left function composition.</p> | |
<ul> | |
<li>Use <code>Array.prototype.reduce()</code> to perform right-to-left function composition.</li> | |
<li>The last (rightmost) function can accept one or more arguments; the remaining functions must be unary.</li> | |
</ul> | |
<pre><code class="language-js">const compose = (...fns) => | |
fns.reduce((f, g) => (...args) => f(g(...args))); | |
</code></pre> | |
<pre><code class="language-js">const add5 = x => x + 5; | |
const multiply = (x, y) => x * y; | |
const multiplyAndAdd5 = compose( | |
add5, | |
multiply | |
); | |
multiplyAndAdd5(5, 2); // 15 | |
</code></pre> | |
<hr> | |
<h2>title: composeRight</h2> | |
<p>Performs left-to-right function composition.</p> | |
<ul> | |
<li>Use <code>Array.prototype.reduce()</code> to perform left-to-right function composition.</li> | |
<li>The first (leftmost) function can accept one or more arguments; the remaining functions must be unary.</li> | |
</ul> | |
<pre><code class="language-js">const composeRight = (...fns) => | |
fns.reduce((f, g) => (...args) => g(f(...args))); | |
</code></pre> | |
<pre><code class="language-js">const add = (x, y) => x + y; | |
const square = x => x * x; | |
const addAndSquare = composeRight(add, square); | |
addAndSquare(1, 2); // 9 | |
</code></pre> | |
<hr> | |
<h2>title: containsWhitespace</h2> | |
<p>Checks if the given string contains any whitespace characters.</p> | |
<ul> | |
<li>Use <code>RegExp.prototype.test()</code> with an appropriate regular expression to check if the given string contains any whitespace characters.</li> | |
</ul> | |
<pre><code class="language-js">const containsWhitespace = str => /\s/.test(str); | |
</code></pre> | |
<pre><code class="language-js">containsWhitespace('lorem'); // false | |
containsWhitespace('lorem ipsum'); // true | |
</code></pre> | |
<hr> | |
<h2>title: converge</h2> | |
<p>Accepts a converging function and a list of branching functions and returns a function that applies each branching function to the arguments and the results of the branching functions are passed as arguments to the converging function.</p> | |
<ul> | |
<li>Use <code>Array.prototype.map()</code> and <code>Function.prototype.apply()</code> to apply each function to the given arguments.</li> | |
<li>Use the spread operator (<code>...</code>) to call <code>converger</code> with the results of all other functions.</li> | |
</ul> | |
<pre><code class="language-js">const converge = (converger, fns) => (...args) => | |
converger(...fns.map(fn => fn.apply(null, args))); | |
</code></pre> | |
<pre><code class="language-js">const average = converge((a, b) => a / b, [ | |
arr => arr.reduce((a, v) => a + v, 0), | |
arr => arr.length | |
]); | |
average([1, 2, 3, 4, 5, 6, 7]); // 4 | |
</code></pre> | |
<hr> | |
<h2>title: copySign</h2> | |
<p>Returns the absolute value of the first number, but the sign of the second.</p> | |
<ul> | |
<li>Use <code>Math.sign()</code> to check if the two numbers have the same sign.</li> | |
<li>Return <code>x</code> if they do, <code>-x</code> otherwise.</li> | |
</ul> | |
<pre><code class="language-js">const copySign = (x, y) => Math.sign(x) === Math.sign(y) ? x : -x; | |
</code></pre> | |
<pre><code class="language-js">copySign(2, 3); // 2 | |
copySign(2, -3); // -2 | |
copySign(-2, 3); // 2 | |
copySign(-2, -3); // -2 | |
</code></pre> | |
<hr> | |
<h2>title: copyToClipboard</h2> | |
<p>Copies a string to the clipboard. | |
Only works as a result of user action (i.e. inside a <code>click</code> event listener).</p> | |
<ul> | |
<li>Create a new <code><textarea></code> element, fill it with the supplied data and add it to the HTML document.</li> | |
<li>Use <code>Selection.getRangeAt()</code>to store the selected range (if any).</li> | |
<li>Use <code>Document.execCommand('copy')</code> to copy to the clipboard.</li> | |
<li>Remove the <code><textarea></code> element from the HTML document.</li> | |
<li>Finally, use <code>Selection().addRange()</code> to recover the original selected range (if any).</li> | |
<li><strong>Note:</strong> You can use the new asynchronous Clipboard API to implement the same functionality. It’s experimental but should be used in the future instead of this snippet. Find out more about it <a href="https://github.com/w3c/clipboard-apis/blob/master/explainer.adoc#writing-to-the-clipboard">here</a>.</li> | |
</ul> | |
<pre><code class="language-js">const copyToClipboard = str => { | |
const el = document.createElement('textarea'); | |
el.value = str; | |
el.setAttribute('readonly', ''); | |
el.style.position = 'absolute'; | |
el.style.left = '-9999px'; | |
document.body.appendChild(el); | |
const selected = | |
document.getSelection().rangeCount > 0 | |
? document.getSelection().getRangeAt(0) | |
: false; | |
el.select(); | |
document.execCommand('copy'); | |
document.body.removeChild(el); | |
if (selected) { | |
document.getSelection().removeAllRanges(); | |
document.getSelection().addRange(selected); | |
} | |
}; | |
</code></pre> | |
<pre><code class="language-js">copyToClipboard('Lorem ipsum'); // 'Lorem ipsum' copied to clipboard. | |
</code></pre> | |
<hr> | |
<h2>title: countBy</h2> | |
<p>Groups the elements of an array based on the given function and returns the count of elements in each group.</p> | |
<ul> | |
<li>Use <code>Array.prototype.map()</code> to map the values of an array to a function or property name.</li> | |
<li>Use <code>Array.prototype.reduce()</code> to create an object, where the keys are produced from the mapped results.</li> | |
</ul> | |
<pre><code class="language-js">const countBy = (arr, fn) => | |
arr.map(typeof fn === 'function' ? fn : val => val[fn]).reduce((acc, val) => { | |
acc[val] = (acc[val] || 0) + 1; | |
return acc; | |
}, {}); | |
</code></pre> | |
<pre><code class="language-js">countBy([6.1, 4.2, 6.3], Math.floor); // {4: 1, 6: 2} | |
countBy(['one', 'two', 'three'], 'length'); // {3: 2, 5: 1} | |
countBy([{ count: 5 }, { count: 10 }, { count: 5 }], x => x.count) | |
// {5: 2, 10: 1} | |
</code></pre> | |
<hr> | |
<h2>title: countOccurrences</h2> | |
<p>Counts the occurrences of a value in an array.</p> | |
<ul> | |
<li>Use <code>Array.prototype.reduce()</code> to increment a counter each time the specific value is encountered inside the array.</li> | |
</ul> | |
<pre><code class="language-js">const countOccurrences = (arr, val) => | |
arr.reduce((a, v) => (v === val ? a + 1 : a), 0); | |
</code></pre> | |
<pre><code class="language-js">countOccurrences([1, 1, 2, 1, 2, 3], 1); // 3 | |
</code></pre> | |
<hr> | |
<h2>title: countSubstrings</h2> | |
<p>Counts the occurrences of a substring in a given string.</p> | |
<ul> | |
<li>Use <code>Array.prototype.indexOf()</code> to look for <code>searchValue</code> in <code>str</code>.</li> | |
<li>Increment a counter if the value is found and update the index, <code>i</code>.</li> | |
<li>Use a <code>while</code> loop that will return as soon as the value returned from <code>Array.prototype.indexOf()</code> is <code>-1</code>.</li> | |
</ul> | |
<pre><code class="language-js">const countSubstrings = (str, searchValue) => { | |
let count = 0, | |
i = 0; | |
while (true) { | |
const r = str.indexOf(searchValue, i); | |
if (r !== -1) [count, i] = [count + 1, r + 1]; | |
else return count; | |
} | |
}; | |
</code></pre> | |
<pre><code class="language-js">countSubstrings('tiktok tok tok tik tok tik', 'tik'); // 3 | |
countSubstrings('tutut tut tut', 'tut'); // 4 | |
</code></pre> | |
<hr> | |
<h2>title: countWeekDaysBetween</h2> | |
<p>Counts the weekdays between two dates.</p> | |
<ul> | |
<li>Use <code>Array.from()</code> to construct an array with <code>length</code> equal to the number of days between <code>startDate</code> and <code>endDate</code>.</li> | |
<li>Use <code>Array.prototype.reduce()</code> to iterate over the array, checking if each date is a weekday and incrementing <code>count</code>.</li> | |
<li>Update <code>startDate</code> with the next day each loop using <code>Date.prototype.getDate()</code> and <code>Date.prototype.setDate()</code> to advance it by one day.</li> | |
<li><strong>NOTE:</strong> Does not take official holidays into account.</li> | |
</ul> | |
<pre><code class="language-js">const countWeekDaysBetween = (startDate, endDate) => | |
Array | |
.from({ length: (endDate - startDate) / (1000 * 3600 * 24) }) | |
.reduce(count => { | |
if (startDate.getDay() % 6 !== 0) count++; | |
startDate = new Date(startDate.setDate(startDate.getDate() + 1)); | |
return count; | |
}, 0); | |
</code></pre> | |
<pre><code class="language-js">countWeekDaysBetween(new Date('Oct 05, 2020'), new Date('Oct 06, 2020')); // 1 | |
countWeekDaysBetween(new Date('Oct 05, 2020'), new Date('Oct 14, 2020')); // 7 | |
</code></pre> | |
<hr> | |
<h2>title: counter</h2> | |
<p>Creates a counter with the specified range, step and duration for the specified selector.</p> | |
<ul> | |
<li>Check if <code>step</code> has the proper sign and change it accordingly.</li> | |
<li>Use <code>setInterval()</code> in combination with <code>Math.abs()</code> and <code>Math.floor()</code> to calculate the time between each new text draw.</li> | |
<li>Use <code>Document.querySelector()</code>, <code>Element.innerHTML</code> to update the value of the selected element.</li> | |
<li>Omit the fourth argument, <code>step</code>, to use a default step of <code>1</code>.</li> | |
<li>Omit the fifth argument, <code>duration</code>, to use a default duration of <code>2000</code>ms.</li> | |
</ul> | |
<pre><code class="language-js">const counter = (selector, start, end, step = 1, duration = 2000) => { | |
let current = start, | |
_step = (end - start) * step < 0 ? -step : step, | |
timer = setInterval(() => { | |
current += _step; | |
document.querySelector(selector).innerHTML = current; | |
if (current >= end) document.querySelector(selector).innerHTML = end; | |
if (current >= end) clearInterval(timer); | |
}, Math.abs(Math.floor(duration / (end - start)))); | |
return timer; | |
}; | |
</code></pre> | |
<pre><code class="language-js">counter('#my-id', 1, 1000, 5, 2000); | |
// Creates a 2-second timer for the element with id="my-id" | |
</code></pre> | |
<hr> | |
<h2>title: createDirIfNotExists</h2> | |
<p>Creates a directory, if it does not exist.</p> | |
<ul> | |
<li>Use <code>fs.existsSync()</code> to check if the directory exists, <code>fs.mkdirSync()</code> to create it.</li> | |
</ul> | |
<pre><code class="language-js">const fs = require('fs'); | |
const createDirIfNotExists = dir => (!fs.existsSync(dir) ? fs.mkdirSync(dir) : undefined); | |
</code></pre> | |
<pre><code class="language-js">createDirIfNotExists('test'); | |
// creates the directory 'test', if it doesn't exist | |
</code></pre> | |
<hr> | |
<h2>title: createElement</h2> | |
<p>Creates an element from a string (without appending it to the document). | |
If the given string contains multiple elements, only the first one will be returned.</p> | |
<ul> | |
<li>Use <code>Document.createElement()</code> to create a new element.</li> | |
<li>Use <code>Element.innerHTML</code> to set its inner HTML to the string supplied as the argument.</li> | |
<li>Use <code>ParentNode.firstElementChild</code> to return the element version of the string.</li> | |
</ul> | |
<pre><code class="language-js">const createElement = str => { | |
const el = document.createElement('div'); | |
el.innerHTML = str; | |
return el.firstElementChild; | |
}; | |
</code></pre> | |
<pre><code class="language-js">const el = createElement( | |
`<div class="container"> | |
<p>Hello!</p> | |
</div>` | |
); | |
console.log(el.className); // 'container' | |
</code></pre> | |
<hr> | |
<h2>title: createEventHub</h2> | |
<p>Creates a pub/sub (<a href="https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern">publish–subscribe</a>) event hub with <code>emit</code>, <code>on</code>, and <code>off</code> methods.</p> | |
<ul> | |
<li>Use <code>Object.create(null)</code> to create an empty <code>hub</code> object that does not inherit properties from <code>Object.prototype</code>.</li> | |
<li>For <code>emit</code>, resolve the array of handlers based on the <code>event</code> argument and then run each one with <code>Array.prototype.forEach()</code> by passing in the data as an argument.</li> | |
<li>For <code>on</code>, create an array for the event if it does not yet exist, then use <code>Array.prototype.push()</code> to add the handler</li> | |
<li>to the array.</li> | |
<li>For <code>off</code>, use <code>Array.prototype.findIndex()</code> to find the index of the handler in the event array and remove it using <code>Array.prototype.splice()</code>.</li> | |
</ul> | |
<pre><code class="language-js">const createEventHub = () => ({ | |
hub: Object.create(null), | |
emit(event, data) { | |
(this.hub[event] || []).forEach(handler => handler(data)); | |
}, | |
on(event, handler) { | |
if (!this.hub[event]) this.hub[event] = []; | |
this.hub[event].push(handler); | |
}, | |
off(event, handler) { | |
const i = (this.hub[event] || []).findIndex(h => h === handler); | |
if (i > -1) this.hub[event].splice(i, 1); | |
if (this.hub[event].length === 0) delete this.hub[event]; | |
} | |
}); | |
</code></pre> | |
<pre><code class="language-js">const handler = data => console.log(data); | |
const hub = createEventHub(); | |
let increment = 0; | |
// Subscribe: listen for different types of events | |
hub.on('message', handler); | |
hub.on('message', () => console.log('Message event fired')); | |
hub.on('increment', () => increment++); | |
// Publish: emit events to invoke all handlers subscribed to them, passing the data to them as an argument | |
hub.emit('message', 'hello world'); // logs 'hello world' and 'Message event fired' | |
hub.emit('message', { hello: 'world' }); // logs the object and 'Message event fired' | |
hub.emit('increment'); // `increment` variable is now 1 | |
// Unsubscribe: stop a specific handler from listening to the 'message' event | |
hub.off('message', handler); | |
</code></pre> | |
<hr> | |
<h2>title: currentURL</h2> | |
<p>Returns the current URL.</p> | |
<ul> | |
<li>Use <code>Window.location.href</code> to get the current URL.</li> | |
</ul> | |
<pre><code class="language-js">const currentURL = () => window.location.href; | |
</code></pre> | |
<pre><code class="language-js">currentURL(); // 'https://www.google.com/' | |
</code></pre> | |
<hr> | |
<h2>title: curry</h2> | |
<p>Curries a function.</p> | |
<ul> | |
<li>Use recursion.</li> | |
<li>If the number of provided arguments (<code>args</code>) is sufficient, call the passed function <code>fn</code>.</li> | |
<li>Otherwise, use <code>Function.prototype.bind()</code> to return a curried function <code>fn</code> that expects the rest of the arguments.</li> | |
<li>If you want to curry a function that accepts a variable number of arguments (a variadic function, e.g. <code>Math.min()</code>), you can optionally pass the number of arguments to the second parameter <code>arity</code>.</li> | |
</ul> | |
<pre><code class="language-js">const curry = (fn, arity = fn.length, ...args) => | |
arity <= args.length ? fn(...args) : curry.bind(null, fn, arity, ...args); | |
</code></pre> | |
<pre><code class="language-js">curry(Math.pow)(2)(10); // 1024 | |
curry(Math.min, 3)(10)(50)(2); // 2 | |
</code></pre> | |
<hr> | |
<h2>title: cycleGenerator</h2> | |
<p>Creates a generator, looping over the given array indefinitely.</p> | |
<ul> | |
<li>Use a non-terminating <code>while</code> loop, that will <code>yield</code> a value every time <code>Generator.prototype.next()</code> is called.</li> | |
<li>Use the module operator (<code>%</code>) with <code>Array.prototype.length</code> to get the next value’s index and increment the counter after each <code>yield</code> statement.</li> | |
</ul> | |
<pre><code class="language-js">const cycleGenerator = function* (arr) { | |
let i = 0; | |
while (true) { | |
yield arr[i % arr.length]; | |
i++; | |
} | |
}; | |
</code></pre> | |
<pre><code class="language-js">const binaryCycle = cycleGenerator([0, 1]); | |
binaryCycle.next(); // { value: 0, done: false } | |
binaryCycle.next(); // { value: 1, done: false } | |
binaryCycle.next(); // { value: 0, done: false } | |
binaryCycle.next(); // { value: 1, done: false } | |
</code></pre> | |
<hr> | |
<h2>title: dateRangeGenerator</h2> | |
<p>Creates a generator, that generates all dates in the given range using the given step.</p> | |
<ul> | |
<li>Use a <code>while</code> loop to iterate from <code>start</code> to <code>end</code>, using <code>yield</code> to return each date in the range, using the <code>Date</code> constructor.</li> | |
<li>Use <code>Date.prototype.getDate()</code> and <code>Date.prototype.setDate()</code> to increment by <code>step</code> days after returning each subsequent value.</li> | |
<li>Omit the third argument, <code>step</code>, to use a default value of <code>1</code>.</li> | |
</ul> | |
<pre><code class="language-js">const dateRangeGenerator = function* (start, end, step = 1) { | |
let d = start; | |
while (d < end) { | |
yield new Date(d); | |
d.setDate(d.getDate() + step); | |
} | |
}; | |
</code></pre> | |
<pre><code class="language-js">[...dateRangeGenerator(new Date('2021-06-01'), new Date('2021-06-04'))]; | |
// [ 2021-06-01, 2021-06-02, 2021-06-03 ] | |
</code></pre> | |
<hr> | |
<h2>title: dayName</h2> | |
<p>Gets the name of the weekday from a <code>Date</code> object.</p> | |
<ul> | |
<li>Use <code>Date.prototype.toLocaleDateString()</code> with the <code>{ weekday: 'long' }</code> option to retrieve the weekday.</li> | |
<li>Use the optional second argument to get a language-specific name or omit it to use the default locale.</li> | |
</ul> | |
<pre><code class="language-js">const dayName = (date, locale) => | |
date.toLocaleDateString(locale, { weekday: 'long' }); | |
</code></pre> | |
<pre><code class="language-js">dayName(new Date()); // 'Saturday' | |
dayName(new Date('09/23/2020'), 'de-DE'); // 'Samstag' | |
</code></pre> | |
<hr> | |
<h2>title: dayOfYear</h2> | |
<p>Gets the day of the year (number in the range 1-366) from a <code>Date</code> object.</p> | |
<ul> | |
<li>Use <code>new Date()</code> and <code>Date.prototype.getFullYear()</code> to get the first day of the year as a <code>Date</code> object.</li> | |
<li>Subtract the first day of the year from <code>date</code> and divide with the milliseconds in each day to get the result.</li> | |
<li>Use <code>Math.floor()</code> to appropriately round the resulting day count to an integer.</li> | |
</ul> | |
<pre><code class="language-js">const dayOfYear = date => | |
Math.floor((date - new Date(date.getFullYear(), 0, 0)) / 1000 / 60 / 60 / 24); | |
</code></pre> | |
<pre><code class="language-js">dayOfYear(new Date()); // 272 | |
</code></pre> | |
<hr> | |
<h2>title: daysAgo</h2> | |
<p>Calculates the date of <code>n</code> days ago from today as a string representation.</p> | |
<ul> | |
<li>Use <code>new Date()</code> to get the current date, <code>Math.abs()</code> and <code>Date.prototype.getDate()</code> to update the date accordingly and set to the result using <code>Date.prototype.setDate()</code>.</li> | |
<li>Use <code>Date.prototype.toISOString()</code> to return a string in <code>yyyy-mm-dd</code> format.</li> | |
</ul> | |
<pre><code class="language-js">const daysAgo = n => { | |
let d = new Date(); | |
d.setDate(d.getDate() - Math.abs(n)); | |
return d.toISOString().split('T')[0]; | |
}; | |
</code></pre> | |
<pre><code class="language-js">daysAgo(20); // 2020-09-16 (if current date is 2020-10-06) | |
</code></pre> | |
<hr> | |
<h2>title: daysFromNow</h2> | |
<p>Calculates the date of <code>n</code> days from today as a string representation.</p> | |
<ul> | |
<li>Use <code>new Date()</code> to get the current date, <code>Math.abs()</code> and <code>Date.prototype.getDate()</code> to update the date accordingly and set to the result using <code>Date.prototype.setDate()</code>.</li> | |
<li>Use <code>Date.prototype.toISOString()</code> to return a string in <code>yyyy-mm-dd</code> format.</li> | |
</ul> | |
<pre><code class="language-js">const daysFromNow = n => { | |
let d = new Date(); | |
d.setDate(d.getDate() + Math.abs(n)); | |
return d.toISOString().split('T')[0]; | |
}; | |
</code></pre> | |
<pre><code class="language-js">daysFromNow(5); // 2020-10-13 (if current date is 2020-10-08) | |
</code></pre> | |
<hr> | |
<h2>title: daysInMonth</h2> | |
<p>Gets the number of days in the given <code>month</code> of the specified <code>year</code>.</p> | |
<ul> | |
<li>Use the <code>new Date()</code> constructor to create a date from the given <code>year</code> and <code>month</code>.</li> | |
<li>Set the days parameter to <code>0</code> to get the last day of the previous month, as months are zero-indexed.</li> | |
<li>Use <code>Date.prototype.getDate()</code> to return the number of days in the given <code>month</code>.</li> | |
</ul> | |
<pre><code class="language-js">const daysInMonth = (year, month) => new Date(year, month, 0).getDate(); | |
</code></pre> | |
<pre><code class="language-js">daysInMonth(2020, 12)); // 31 | |
daysInMonth(2024, 2)); // 29 | |
</code></pre> | |
<hr> | |
<h2>title: debounce</h2> | |
<p>Creates a debounced function that delays invoking the provided function until at least <code>ms</code> milliseconds have elapsed since its last invocation.</p> | |
<ul> | |
<li>Each time the debounced function is invoked, clear the current pending timeout with <code>clearTimeout()</code>. Use <code>setTimeout()</code> to create a new timeout that delays invoking the function until at least <code>ms</code> milliseconds have elapsed.</li> | |
<li>Use <code>Function.prototype.apply()</code> to apply the <code>this</code> context to the function and provide the necessary arguments.</li> | |
<li>Omit the second argument, <code>ms</code>, to set the timeout at a default of <code>0</code> ms.</li> | |
</ul> | |
<pre><code class="language-js">const debounce = (fn, ms = 0) => { | |
let timeoutId; | |
return function(...args) { | |
clearTimeout(timeoutId); | |
timeoutId = setTimeout(() => fn.apply(this, args), ms); | |
}; | |
}; | |
</code></pre> | |
<pre><code class="language-js">window.addEventListener( | |
'resize', | |
debounce(() => { | |
console.log(window.innerWidth); | |
console.log(window.innerHeight); | |
}, 250) | |
); // Will log the window dimensions at most every 250ms | |
</code></pre> | |
<hr> | |
<h2>title: debouncePromise</h2> | |
<p>Creates a debounced function that returns a promise, but delays invoking the provided function until at least <code>ms</code> milliseconds have elapsed since the last time it was invoked. | |
All promises returned during this time will return the same data.</p> | |
<ul> | |
<li>Each time the debounced function is invoked, clear the current pending timeout with <code>clearTimeout()</code> and use <code>setTimeout()</code> to create a new timeout that delays invoking the function until at least <code>ms</code> milliseconds has elapsed.</li> | |
<li>Use <code>Function.prototype.apply()</code> to apply the <code>this</code> context to the function and provide the necessary arguments.</li> | |
<li>Create a new <code>Promise</code> and add its <code>resolve</code> and <code>reject</code> callbacks to the <code>pending</code> promises stack.</li> | |
<li>When <code>setTimeout</code> is called, copy the current stack (as it can change between the provided function call and its resolution), clear it and call the provided function.</li> | |
<li>When the provided function resolves/rejects, resolve/reject all promises in the stack (copied when the function was called) with the returned data.</li> | |
<li>Omit the second argument, <code>ms</code>, to set the timeout at a default of <code>0</code> ms.</li> | |
</ul> | |
<pre><code class="language-js">const debouncePromise = (fn, ms = 0) => { | |
let timeoutId; | |
const pending = []; | |
return (...args) => | |
new Promise((res, rej) => { | |
clearTimeout(timeoutId); | |
timeoutId = setTimeout(() => { | |
const currentPending = [...pending]; | |
pending.length = 0; | |
Promise.resolve(fn.apply(this, args)).then( | |
data => { | |
currentPending.forEach(({ resolve }) => resolve(data)); | |
}, | |
error => { | |
currentPending.forEach(({ reject }) => reject(error)); | |
} | |
); | |
}, ms); | |
pending.push({ resolve: res, reject: rej }); | |
}); | |
}; | |
</code></pre> | |
<pre><code class="language-js">const fn = arg => new Promise(resolve => { | |
setTimeout(resolve, 1000, ['resolved', arg]); | |
}); | |
const debounced = debouncePromise(fn, 200); | |
debounced('foo').then(console.log); | |
debounced('bar').then(console.log); | |
// Will log ['resolved', 'bar'] both times | |
</code></pre> | |
<hr> | |
<h2>title: decapitalize</h2> | |
<p>Decapitalizes the first letter of a string.</p> | |
<ul> | |
<li>Use array destructuring and <code>String.prototype.toLowerCase()</code> to decapitalize first letter, <code>...rest</code> to get array of characters after first letter and then <code>Array.prototype.join('')</code> to make it a string again.</li> | |
<li>Omit the <code>upperRest</code> argument to keep the rest of the string intact, or set it to <code>true</code> to convert to uppercase.</li> | |
</ul> | |
<pre><code class="language-js">const decapitalize = ([first, ...rest], upperRest = false) => | |
first.toLowerCase() + | |
(upperRest ? rest.join('').toUpperCase() : rest.join('')); | |
</code></pre> | |
<pre><code class="language-js">decapitalize('FooBar'); // 'fooBar' | |
decapitalize('FooBar', true); // 'fOOBAR' | |
</code></pre> | |
<hr> | |
<h2>title: deepClone</h2> | |
<p>Creates a deep clone of an object. | |
Clones primitives, arrays and objects, excluding class instances.</p> | |
<ul> | |
<li>Use recursion.</li> | |
<li>Check if the passed object is <code>null</code> and, if so, return <code>null</code>.</li> | |
<li>Use <code>Object.assign()</code> and an empty object (<code>{}</code>) to create a shallow clone of the original.</li> | |
<li>Use <code>Object.keys()</code> and <code>Array.prototype.forEach()</code> to determine which key-value pairs need to be deep cloned.</li> | |
<li>If the object is an <code>Array</code>, set the <code>clone</code>‘s <code>length</code> to that of the original and use <code>Array.from(clone)</code> to create a clone.</li> | |
</ul> | |
<pre><code class="language-js">const deepClone = obj => { | |
if (obj === null) return null; | |
let clone = Object.assign({}, obj); | |
Object.keys(clone).forEach( | |
key => | |
(clone[key] = | |
typeof obj[key] === 'object' ? deepClone(obj[key]) : obj[key]) | |
); | |
if (Array.isArray(obj)) { | |
clone.length = obj.length; | |
return Array.from(clone); | |
} | |
return clone; | |
}; | |
</code></pre> | |
<pre><code class="language-js">const a = { foo: 'bar', obj: { a: 1, b: 2 } }; | |
const b = deepClone(a); // a !== b, a.obj !== b.obj | |
</code></pre> | |
<hr> | |
<h2>title: deepFlatten</h2> | |
<p>Deep flattens an array.</p> | |
<ul> | |
<li>Use recursion.</li> | |
<li>Use <code>Array.prototype.concat()</code> with an empty array (<code>[]</code>) and the spread operator (<code>...</code>) to flatten an array.</li> | |
<li>Recursively flatten each element that is an array.</li> | |
</ul> | |
<pre><code class="language-js">const deepFlatten = arr => | |
[].concat(...arr.map(v => (Array.isArray(v) ? deepFlatten(v) : v))); | |
</code></pre> | |
<pre><code class="language-js">deepFlatten([1, [2], [[3], 4], 5]); // [1, 2, 3, 4, 5] | |
</code></pre> | |
<hr> | |
<h2>title: deepFreeze</h2> | |
<p>Deep freezes an object.</p> | |
<ul> | |
<li>Use <code>Object.keys()</code> to get all the properties of the passed object, <code>Array.prototype.forEach()</code> to iterate over them.</li> | |
<li>Call <code>Object.freeze(obj)</code> recursively on all properties, applying <code>deepFreeze()</code> as necessary.</li> | |
<li>Finally, use <code>Object.freeze()</code> to freeze the given object.</li> | |
</ul> | |
<pre><code class="language-js">const deepFreeze = obj => { | |
Object.keys(obj).forEach(prop => { | |
if (typeof obj[prop] === 'object') deepFreeze(obj[prop]); | |
}); | |
return Object.freeze(obj); | |
}; | |
</code></pre> | |
<pre><code class="language-js">'use strict'; | |
const val = deepFreeze([1, [2, 3]]); | |
val[0] = 3; // not allowed | |
val[1][0] = 4; // not allowed as well | |
</code></pre> | |
<hr> | |
<h2>title: deepGet</h2> | |
<p>Gets the target value in a nested JSON object, based on the <code>keys</code> array.</p> | |
<ul> | |
<li>Compare the keys you want in the nested JSON object as an <code>Array</code>.</li> | |
<li>Use <code>Array.prototype.reduce()</code> to get the values in the nested JSON object one by one.</li> | |
<li>If the key exists in the object, return the target value, otherwise return <code>null</code>.</li> | |
</ul> | |
<pre><code class="language-js">const deepGet = (obj, keys) => | |
keys.reduce( | |
(xs, x) => (xs && xs[x] !== null && xs[x] !== undefined ? xs[x] : null), | |
obj | |
); | |
</code></pre> | |
<pre><code class="language-js">let index = 2; | |
const data = { | |
foo: { | |
foz: [1, 2, 3], | |
bar: { | |
baz: ['a', 'b', 'c'] | |
} | |
} | |
}; | |
deepGet(data, ['foo', 'foz', index]); // get 3 | |
deepGet(data, ['foo', 'bar', 'baz', 8, 'foz']); // null | |
</code></pre> | |
<hr> | |
<h2>title: deepMapKeys</h2> | |
<p>Deep maps an object’s keys.</p> | |
<ul> | |
<li>Creates an object with the same values as the provided object and keys generated by running the provided function for each key.</li> | |
<li>Use <code>Object.keys(obj)</code> to iterate over the object’s keys.</li> | |
<li>Use <code>Array.prototype.reduce()</code> to create a new object with the same values and mapped keys using <code>fn</code>.</li> | |
</ul> | |
<pre><code class="language-js">const deepMapKeys = (obj, fn) => | |
Array.isArray(obj) | |
? obj.map(val => deepMapKeys(val, fn)) | |
: typeof obj === 'object' | |
? Object.keys(obj).reduce((acc, current) => { | |
const key = fn(current); | |
const val = obj[current]; | |
acc[key] = | |
val !== null && typeof val === 'object' ? deepMapKeys(val, fn) : val; | |
return acc; | |
}, {}) | |
: obj; | |
</code></pre> | |
<pre><code class="language-js">const obj = { | |
foo: '1', | |
nested: { | |
child: { | |
withArray: [ | |
{ | |
grandChild: ['hello'] | |
} | |
] | |
} | |
} | |
}; | |
const upperKeysObj = deepMapKeys(obj, key => key.toUpperCase()); | |
/* | |
{ | |
"FOO":"1", | |
"NESTED":{ | |
"CHILD":{ | |
"WITHARRAY":[ | |
{ | |
"GRANDCHILD":[ 'hello' ] | |
} | |
] | |
} | |
} | |
} | |
*/ | |
</code></pre> | |
<hr> | |
<h2>title: deepMerge</h2> | |
<p>Deeply merges two objects, using a function to handle keys present in both.</p> | |
<ul> | |
<li>Use <code>Object.keys()</code> to get the keys of both objects, create a <code>Set</code> from them and use the spread operator (<code>...</code>) to create an array of all the unique keys.</li> | |
<li>Use <code>Array.prototype.reduce()</code> to add each unique key to the object, using <code>fn</code> to combine the values of the two given objects.</li> | |
</ul> | |
<pre><code class="language-js">const deepMerge = (a, b, fn) => | |
[...new Set([...Object.keys(a), ...Object.keys(b)])].reduce( | |
(acc, key) => ({ ...acc, [key]: fn(key, a[key], b[key]) }), | |
{} | |
); | |
</code></pre> | |
<pre><code class="language-js">deepMerge( | |
{ a: true, b: { c: [1, 2, 3] } }, | |
{ a: false, b: { d: [1, 2, 3] } }, | |
(key, a, b) => (key === 'a' ? a && b : Object.assign({}, a, b)) | |
); | |
// { a: false, b: { c: [ 1, 2, 3 ], d: [ 1, 2, 3 ] } } | |
</code></pre> | |
<hr> | |
<h2>title: defaults</h2> | |
<p>Assigns default values for all properties in an object that are <code>undefined</code>.</p> | |
<ul> | |
<li>Use <code>Object.assign()</code> to create a new empty object and copy the original one to maintain key order.</li> | |
<li>Use <code>Array.prototype.reverse()</code> and the spread operator (<code>...</code>) to combine the default values from left to right.</li> | |
<li>Finally, use <code>obj</code> again to overwrite properties that originally had a value.</li> | |
</ul> | |
<pre><code class="language-js">const defaults = (obj, ...defs) => | |
Object.assign({}, obj, ...defs.reverse(), obj); | |
</code></pre> | |
<pre><code class="language-js">defaults({ a: 1 }, { b: 2 }, { b: 6 }, { a: 3 }); // { a: 1, b: 2 } | |
</code></pre> | |
<hr> | |
<h2>title: defer</h2> | |
<p>Defers invoking a function until the current call stack has cleared.</p> | |
<ul> | |
<li>Use <code>setTimeout()</code> with a timeout of <code>1</code> ms to add a new event to the event queue and allow the rendering engine to complete its work.</li> | |
<li>Use the spread (<code>...</code>) operator to supply the function with an arbitrary number of arguments.</li> | |
</ul> | |
<pre><code class="language-js">const defer = (fn, ...args) => setTimeout(fn, 1, ...args); | |
</code></pre> | |
<pre><code class="language-js">// Example A: | |
defer(console.log, 'a'), console.log('b'); // logs 'b' then 'a' | |
// Example B: | |
document.querySelector('#someElement').innerHTML = 'Hello'; | |
longRunningFunction(); | |
// Browser will not update the HTML until this has finished | |
defer(longRunningFunction); | |
// Browser will update the HTML then run the function | |
</code></pre> | |
<hr> | |
<h2>title: degreesToRads</h2> | |
<p>Converts an angle from degrees to radians.</p> | |
<ul> | |
<li>Use <code>Math.PI</code> and the degree to radian formula to convert the angle from degrees to radians.</li> | |
</ul> | |
<pre><code class="language-js">const degreesToRads = deg => (deg * Math.PI) / 180.0; | |
</code></pre> | |
<pre><code class="language-js">degreesToRads(90.0); // ~1.5708 | |
</code></pre> | |
<hr> | |
<h2>title: delay</h2> | |
<p>Invokes the provided function after <code>ms</code> milliseconds.</p> | |
<ul> | |
<li>Use <code>setTimeout()</code> to delay execution of <code>fn</code>.</li> | |
<li>Use the spread (<code>...</code>) operator to supply the function with an arbitrary number of arguments.</li> | |
</ul> | |
<pre><code class="language-js">const delay = (fn, ms, ...args) => setTimeout(fn, ms, ...args); | |
</code></pre> | |
<pre><code class="language-js">delay( | |
function(text) { | |
console.log(text); | |
}, | |
1000, | |
'later' | |
); // Logs 'later' after one second. | |
</code></pre> | |
<hr> | |
<h2>title: detectDeviceType</h2> | |
<p>Detects whether the page is being viewed on a mobile device or a desktop.</p> | |
<ul> | |
<li>Use a regular expression to test the <code>navigator.userAgent</code> property to figure out if the device is a mobile device or a desktop.</li> | |
</ul> | |
<pre><code class="language-js">const detectDeviceType = () => | |
/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test( | |
navigator.userAgent | |
) | |
? 'Mobile' | |
: 'Desktop'; | |
</code></pre> | |
<pre><code class="language-js">detectDeviceType(); // 'Mobile' or 'Desktop' | |
</code></pre> | |
<hr> | |
<h2>title: detectLanguage</h2> | |
<p>Detects the preferred language of the current user.</p> | |
<ul> | |
<li>Use <code>NavigationLanguage.language</code> or the first <code>NavigationLanguage.languages</code> if available, otherwise return <code>defaultLang</code>.</li> | |
<li>Omit the second argument, <code>defaultLang</code>, to use <code>'en-US'</code> as the default language code.</li> | |
</ul> | |
<pre><code class="language-js">const detectLanguage = (defaultLang = 'en-US') => | |
navigator.language || | |
(Array.isArray(navigator.languages) && navigator.languages[0]) || | |
defaultLang; | |
</code></pre> | |
<pre><code class="language-js">detectLanguage(); // 'nl-NL' | |
</code></pre> | |
<hr> | |
<h2>title: difference</h2> | |
<p>Calculates the difference between two arrays, without filtering duplicate values.</p> | |
<ul> | |
<li>Create a <code>Set</code> from <code>b</code> to get the unique values in <code>b</code>.</li> | |
<li>Use <code>Array.prototype.filter()</code> on <code>a</code> to only keep values not contained in <code>b</code>, using <code>Set.prototype.has()</code>.</li> | |
</ul> | |
<pre><code class="language-js">const difference = (a, b) => { | |
const s = new Set(b); | |
return a.filter(x => !s.has(x)); | |
}; | |
</code></pre> | |
<pre><code class="language-js">difference([1, 2, 3, 3], [1, 2, 4]); // [3, 3] | |
</code></pre> | |
<hr> | |
<h2>title: differenceBy</h2> | |
<p>Returns the difference between two arrays, after applying the provided function to each array element of both.</p> | |
<ul> | |
<li>Create a <code>Set</code> by applying <code>fn</code> to each element in <code>b</code>.</li> | |
<li>Use <code>Array.prototype.map()</code> to apply <code>fn</code> to each element in <code>a</code>.</li> | |
<li>Use <code>Array.prototype.filter()</code> in combination with <code>fn</code> on <code>a</code> to only keep values not contained in <code>b</code>, using <code>Set.prototype.has()</code>.</li> | |
</ul> | |
<pre><code class="language-js">const differenceBy = (a, b, fn) => { | |
const s = new Set(b.map(fn)); | |
return a.map(fn).filter(el => !s.has(el)); | |
}; | |
</code></pre> | |
<pre><code class="language-js">differenceBy([2.1, 1.2], [2.3, 3.4], Math.floor); // [1] | |
differenceBy([{ x: 2 }, { x: 1 }], [{ x: 1 }], v => v.x); // [2] | |
</code></pre> | |
<hr> | |
<h2>title: differenceWith</h2> | |
<p>Filters out all values from an array for which the comparator function does not return <code>true</code>.</p> | |
<ul> | |
<li>Use <code>Array.prototype.filter()</code> and <code>Array.prototype.findIndex()</code> to find the appropriate values.</li> | |
<li>Omit the last argument, <code>comp</code>, to use a default strict equality comparator.</li> | |
</ul> | |
<pre><code class="language-js">const differenceWith = (arr, val, comp = (a, b) => a === b) => | |
arr.filter(a => val.findIndex(b => comp(a, b)) === -1); | |
</code></pre> | |
<pre><code class="language-js">differenceWith( | |
[1, 1.2, 1.5, 3, 0], | |
[1.9, 3, 0], | |
(a, b) => Math.round(a) === Math.round(b) | |
); // [1, 1.2] | |
differenceWith([1, 1.2, 1.3], [1, 1.3, 1.5]); // [1.2] | |
</code></pre> | |
<hr> | |
<h2>title: dig</h2> | |
<p>Gets the target value in a nested JSON object, based on the given key.</p> | |
<ul> | |
<li>Use the <code>in</code> operator to check if <code>target</code> exists in <code>obj</code>.</li> | |
<li>If found, return the value of <code>obj[target]</code>.</li> | |
<li>Otherwise use <code>Object.values(obj)</code> and <code>Array.prototype.reduce()</code> to recursively call <code>dig</code> on each nested object until the first matching key/value pair is found.</li> | |
</ul> | |
<pre><code class="language-js">const dig = (obj, target) => | |
target in obj | |
? obj[target] | |
: Object.values(obj).reduce((acc, val) => { | |
if (acc !== undefined) return acc; | |
if (typeof val === 'object') return dig(val, target); | |
}, undefined); | |
</code></pre> | |
<pre><code class="language-js">const data = { | |
level1: { | |
level2: { | |
level3: 'some data' | |
} | |
} | |
}; | |
dig(data, 'level3'); // 'some data' | |
dig(data, 'level4'); // undefined | |
</code></pre> | |
<hr> | |
<h2>title: digitize</h2> | |
<p>Converts a number to an array of digits, removing its sign if necessary.</p> | |
<ul> | |
<li>Use <code>Math.abs()</code> to strip the number’s sign.</li> | |
<li>Convert the number to a string, using the spread operator (<code>...</code>) to build an array.</li> | |
<li>Use <code>Array.prototype.map()</code> and <code>parseInt()</code> to transform each value to an integer.</li> | |
</ul> | |
<pre><code class="language-js">const digitize = n => [...`${Math.abs(n)}`].map(i => parseInt(i)); | |
</code></pre> | |
<pre><code class="language-js">digitize(123); // [1, 2, 3] | |
digitize(-123); // [1, 2, 3] | |
</code></pre> | |
<hr> | |
<h2>title: distance</h2> | |
<p>Calculates the distance between two points.</p> | |
<ul> | |
<li>Use <code>Math.hypot()</code> to calculate the Euclidean distance between two points.</li> | |
</ul> | |
<pre><code class="language-js">const distance = (x0, y0, x1, y1) => Math.hypot(x1 - x0, y1 - y0); | |
</code></pre> | |
<pre><code class="language-js">distance(1, 1, 2, 3); // ~2.2361 | |
</code></pre> | |
<hr> | |
<h2>title: divmod</h2> | |
<p>Returns an array consisting of the quotient and remainder of the given numbers.</p> | |
<ul> | |
<li>Use <code>Math.floor()</code> to get the quotient of the division <code>x / y</code>.</li> | |
<li>Use the modulo operator (<code>%</code>) to get the remainder of the division <code>x / y</code>.</li> | |
</ul> | |
<pre><code class="language-js">const divmod = (x, y) => [Math.floor(x / y), x % y]; | |
</code></pre> | |
<pre><code class="language-js">divmod(8, 3); // [2, 2] | |
divmod(3, 8); // [0, 3] | |
divmod(5, 5); // [1, 0] | |
</code></pre> | |
<hr> | |
<h2>title: drop</h2> | |
<p>Creates a new array with <code>n</code> elements removed from the left.</p> | |
<ul> | |
<li>Use <code>Array.prototype.slice()</code> to remove the specified number of elements from the left.</li> | |
<li>Omit the last argument, <code>n</code>, to use a default value of <code>1</code>.</li> | |
</ul> | |
<pre><code class="language-js">const drop = (arr, n = 1) => arr.slice(n); | |
</code></pre> | |
<pre><code class="language-js">drop([1, 2, 3]); // [2, 3] | |
drop([1, 2, 3], 2); // [3] | |
drop([1, 2, 3], 42); // [] | |
</code></pre> | |
<hr> | |
<h2>title: dropRight</h2> | |
<p>Creates a new array with <code>n</code> elements removed from the right.</p> | |
<ul> | |
<li>Use <code>Array.prototype.slice()</code> to remove the specified number of elements from the right.</li> | |
<li>Omit the last argument, <code>n</code>, to use a default value of <code>1</code>.</li> | |
</ul> | |
<pre><code class="language-js">const dropRight = (arr, n = 1) => arr.slice(0, -n); | |
</code></pre> | |
<pre><code class="language-js">dropRight([1, 2, 3]); // [1, 2] | |
dropRight([1, 2, 3], 2); // [1] | |
dropRight([1, 2, 3], 42); // [] | |
</code></pre> | |
<hr> | |
<h2>title: dropRightWhile</h2> | |
<p>Removes elements from the end of an array until the passed function returns <code>true</code>. | |
Returns the remaining elements in the array.</p> | |
<ul> | |
<li>Loop through the array, using <code>Array.prototype.slice()</code> to drop the last element of the array until the value returned from <code>func</code> is <code>true</code>.</li> | |
<li>Return the remaining elements.</li> | |
</ul> | |
<pre><code class="language-js">const dropRightWhile = (arr, func) => { | |
let rightIndex = arr.length; | |
while (rightIndex-- && !func(arr[rightIndex])); | |
return arr.slice(0, rightIndex + 1); | |
}; | |
</code></pre> | |
<pre><code class="language-js">dropRightWhile([1, 2, 3, 4], n => n < 3); // [1, 2] | |
</code></pre> | |
<hr> | |
<h2>title: dropWhile</h2> | |
<p>Removes elements in an array until the passed function returns <code>true</code>. | |
Returns the remaining elements in the array.</p> | |
<ul> | |
<li>Loop through the array, using <code>Array.prototype.slice()</code> to drop the first element of the array until the value returned from <code>func</code> is <code>true</code>.</li> | |
<li>Return the remaining elements.</li> | |
</ul> | |
<pre><code class="language-js">const dropWhile = (arr, func) => { | |
while (arr.length > 0 && !func(arr[0])) arr = arr.slice(1); | |
return arr; | |
}; | |
</code></pre> | |
<pre><code class="language-js">dropWhile([1, 2, 3, 4], n => n >= 3); // [3, 4] | |
</code></pre> | |
<hr> | |
<h2>title: either</h2> | |
<p>Checks if at least one function returns <code>true</code> for a given set of arguments.</p> | |
<ul> | |
<li>Use the logical or (<code>||</code>) operator on the result of calling the two functions with the supplied <code>args</code>.</li> | |
</ul> | |
<pre><code class="language-js">const either = (f, g) => (...args) => f(...args) || g(...args); | |
</code></pre> | |
<pre><code class="language-js">const isEven = num => num % 2 === 0; | |
const isPositive = num => num > 0; | |
const isPositiveOrEven = either(isPositive, isEven); | |
isPositiveOrEven(4); // true | |
isPositiveOrEven(3); // true | |
</code></pre> | |
<hr> | |
<h2>title: elementContains</h2> | |
<p>Checks if the <code>parent</code> element contains the <code>child</code> element.</p> | |
<ul> | |
<li>Check that <code>parent</code> is not the same element as <code>child</code>.</li> | |
<li>Use <code>Node.contains()</code> to check if the <code>parent</code> element contains the <code>child</code> element.</li> | |
</ul> | |
<pre><code class="language-js">const elementContains = (parent, child) => | |
parent !== child && parent.contains(child); | |
</code></pre> | |
<pre><code class="language-js">elementContains( | |
document.querySelector('head'), | |
document.querySelector('title') | |
); | |
// true | |
elementContains(document.querySelector('body'), document.querySelector('body')); | |
// false | |
</code></pre> | |
<hr> | |
<h2>title: elementIsFocused</h2> | |
<p>Checks if the given element is focused.</p> | |
<ul> | |
<li>Use <code>Document.activeElement</code> to determine if the given element is focused.</li> | |
</ul> | |
<pre><code class="language-js">const elementIsFocused = el => (el === document.activeElement); | |
</code></pre> | |
<pre><code class="language-js">elementIsFocused(el); // true if the element is focused | |
</code></pre> | |
<hr> | |
<h2>title: elementIsVisibleInViewport</h2> | |
<p>Checks if the element specified is visible in the viewport.</p> | |
<ul> | |
<li>Use <code>Element.getBoundingClientRect()</code> and the <code>Window.inner(Width|Height)</code> values to determine if a given element is visible in the viewport.</li> | |
<li>Omit the second argument to determine if the element is entirely visible, or specify <code>true</code> to determine if it is partially visible.</li> | |
</ul> | |
<pre><code class="language-js">const elementIsVisibleInViewport = (el, partiallyVisible = false) => { | |
const { top, left, bottom, right } = el.getBoundingClientRect(); | |
const { innerHeight, innerWidth } = window; | |
return partiallyVisible | |
? ((top > 0 && top < innerHeight) || | |
(bottom > 0 && bottom < innerHeight)) && | |
((left > 0 && left < innerWidth) || (right > 0 && right < innerWidth)) | |
: top >= 0 && left >= 0 && bottom <= innerHeight && right <= innerWidth; | |
}; | |
</code></pre> | |
<pre><code class="language-js">// e.g. 100x100 viewport and a 10x10px element at position {top: -1, left: 0, bottom: 9, right: 10} | |
elementIsVisibleInViewport(el); // false - (not fully visible) | |
elementIsVisibleInViewport(el, true); // true - (partially visible) | |
</code></pre> | |
<hr> | |
<h2>title: equals</h2> | |
<p>Performs a deep comparison between two values to determine if they are equivalent.</p> | |
<ul> | |
<li>Check if the two values are identical.</li> | |
<li>Check if both values are <code>Date</code> objects with the same time, using <code>Date.prototype.getTime()</code>.</li> | |
<li>Check if both values are non-object values with an equivalent value (strict comparison).</li> | |
<li>Check if only one value is <code>null</code> or <code>undefined</code> or if their prototypes differ.</li> | |
<li>If none of the above conditions are met, use <code>Object.keys()</code> to check if both values have the same number of keys.</li> | |
<li>Use <code>Array.prototype.every()</code> to check if every key in <code>a</code> exists in <code>b</code> and if they are equivalent by calling <code>equals()</code> recursively.</li> | |
</ul> | |
<pre><code class="language-js">const equals = (a, b) => { | |
if (a === b) return true; | |
if (a instanceof Date && b instanceof Date) | |
return a.getTime() === b.getTime(); | |
if (!a || !b || (typeof a !== 'object' && typeof b !== 'object')) | |
return a === b; | |
if (a.prototype !== b.prototype) return false; | |
const keys = Object.keys(a); | |
if (keys.length !== Object.keys(b).length) return false; | |
return keys.every(k => equals(a[k], b[k])); | |
}; | |
</code></pre> | |
<pre><code class="language-js">equals( | |
{ a: [2, { e: 3 }], b: [4], c: 'foo' }, | |
{ a: [2, { e: 3 }], b: [4], c: 'foo' } | |
); // true | |
equals([1, 2, 3], { 0: 1, 1: 2, 2: 3 }); // true | |
</code></pre> | |
<hr> | |
<h2>title: escapeHTML</h2> | |
<p>Escapes a string for use in HTML.</p> | |
<ul> | |
<li>Use <code>String.prototype.replace()</code> with a regexp that matches the characters that need to be escaped.</li> | |
<li>Use the callback function to replace each character instance with its associated escaped character using a dictionary object.</li> | |
</ul> | |
<pre><code class="language-js">const escapeHTML = str => | |
str.replace( | |
/[&<>'"]/g, | |
tag => | |
({ | |
'&': '&amp;', | |
'<': '&lt;', | |
'>': '&gt;', | |
"'": ''', | |
'"': '&quot;' | |
}[tag] || tag) | |
); | |
</code></pre> | |
<pre><code class="language-js">escapeHTML('<a href="#">Me & you</a>'); | |
// '&lt;a href=&quot;#&quot;&gt;Me &amp; you&lt;/a&gt;' | |
</code></pre> | |
<hr> | |
<h2>title: escapeRegExp</h2> | |
<p>Escapes a string to use in a regular expression.</p> | |
<ul> | |
<li>Use <code>String.prototype.replace()</code> to escape special characters.</li> | |
</ul> | |
<pre><code class="language-js">const escapeRegExp = str => str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); | |
</code></pre> | |
<pre><code class="language-js">escapeRegExp('(test)'); // \\(test\\) | |
</code></pre> | |
<hr> | |
<h2>title: euclideanDistance</h2> | |
<p>Calculates the distance between two points in any number of dimensions.</p> | |
<ul> | |
<li>Use <code>Object.keys()</code> and <code>Array.prototype.map()</code> to map each coordinate to its difference between the two points.</li> | |
<li>Use <code>Math.hypot()</code> to calculate the Euclidean distance between the two points.</li> | |
</ul> | |
<pre><code class="language-js">const euclideanDistance = (a, b) => | |
Math.hypot(...Object.keys(a).map(k => b[k] - a[k])); | |
</code></pre> | |
<pre><code class="language-js">euclideanDistance([1, 1], [2, 3]); // ~2.2361 | |
euclideanDistance([1, 1, 1], [2, 3, 2]); // ~2.4495 | |
</code></pre> | |
<hr> | |
<h2>title: everyNth</h2> | |
<p>Returns every <code>nth</code> element in an array.</p> | |
<ul> | |
<li>Use <code>Array.prototype.filter()</code> to create a new array that contains every <code>nth</code> element of a given array.</li> | |
</ul> | |
<pre><code class="language-js">const everyNth = (arr, nth) => arr.filter((e, i) => i % nth === nth - 1); | |
</code></pre> | |
<pre><code class="language-js">everyNth([1, 2, 3, 4, 5, 6], 2); // [ 2, 4, 6 ] | |
</code></pre> | |
<hr> | |
<h2>title: expandTabs</h2> | |
<p>Convert tabs to spaces, where each tab corresponds to <code>count</code> spaces.</p> | |
<ul> | |
<li>Use <code>String.prototype.replace()</code> with a regular expression and <code>String.prototype.repeat()</code> to replace each tab character with <code>count</code> spaces.</li> | |
</ul> | |
<pre><code class="language-js">const expandTabs = (str, count) => str.replace(/\t/g, ' '.repeat(count)); | |
</code></pre> | |
<pre><code class="language-js">expandTabs('\t\tlorem', 3); // ' lorem' | |
</code></pre> | |
<hr> | |
<h2>title: extendHex</h2> | |
<p>Extends a 3-digit color code to a 6-digit color code.</p> | |
<ul> | |
<li>Use <code>Array.prototype.map()</code>, <code>String.prototype.split()</code> and <code>Array.prototype.join()</code> to join the mapped array for converting a 3-digit RGB notated hexadecimal color-code to the 6-digit form.</li> | |
<li><code>Array.prototype.slice()</code> is used to remove <code>#</code> from string start since it’s added once.</li> | |
</ul> | |
<pre><code class="language-js">const extendHex = shortHex => | |
'#' + | |
shortHex | |
.slice(shortHex.startsWith('#') ? 1 : 0) | |
.split('') | |
.map(x => x + x) | |
.join(''); | |
</code></pre> | |
<pre><code class="language-js">extendHex('#03f'); // '#0033ff' | |
extendHex('05a'); // '#0055aa' | |
</code></pre> | |
<hr> | |
<h2>title: factorial</h2> | |
<p>Calculates the factorial of a number.</p> | |
<ul> | |
<li>Use recursion.</li> | |
<li>If <code>n</code> is less than or equal to <code>1</code>, return <code>1</code>.</li> | |
<li>Otherwise, return the product of <code>n</code> and the factorial of <code>n - 1</code>.</li> | |
<li>Throw a <code>TypeError</code> if <code>n</code> is a negative number.</li> | |
</ul> | |
<pre><code class="language-js">const factorial = n => | |
n < 0 | |
? (() => { | |
throw new TypeError('Negative numbers are not allowed!'); | |
})() | |
: n <= 1 | |
? 1 | |
: n * factorial(n - 1); | |
</code></pre> | |
<pre><code class="language-js">factorial(6); // 720 | |
</code></pre> | |
<hr> | |
<h2>title: fahrenheitToCelsius | |
unlisted: true</h2> | |
<p>Converts Fahrenheit to Celsius.</p> | |
<ul> | |
<li>Follow the conversion formula <code>C = (F - 32) * 5/9</code>.</li> | |
</ul> | |
<pre><code class="language-js">const fahrenheitToCelsius = degrees => (degrees - 32) * 5 / 9; | |
</code></pre> | |
<pre><code class="language-js">fahrenheitToCelsius(32); // 0 | |
</code></pre> | |
<hr> | |
<h2>title: fibonacci</h2> | |
<p>Generates an array, containing the Fibonacci sequence, up until the nth term.</p> | |
<ul> | |
<li>Use <code>Array.from()</code> to create an empty array of the specific length, initializing the first two values (<code>0</code> and <code>1</code>).</li> | |
<li>Use <code>Array.prototype.reduce()</code> and <code>Array.prototype.concat()</code> to add values into the array, using the sum of the last two values, except for the first two.</li> | |
</ul> | |
<pre><code class="language-js">const fibonacci = n => | |
Array.from({ length: n }).reduce( | |
(acc, val, i) => acc.concat(i > 1 ? acc[i - 1] + acc[i - 2] : i), | |
[] | |
); | |
</code></pre> | |
<pre><code class="language-js">fibonacci(6); // [0, 1, 1, 2, 3, 5] | |
</code></pre> | |
<hr> | |
<h2>title: filterNonUnique</h2> | |
<p>Creates an array with the non-unique values filtered out.</p> | |
<ul> | |
<li>Use <code>new Set()</code> and the spread operator (<code>...</code>) to create an array of the unique values in <code>arr</code>.</li> | |
<li>Use <code>Array.prototype.filter()</code> to create an array containing only the unique values.</li> | |
</ul> | |
<pre><code class="language-js">const filterNonUnique = arr => | |
[...new Set(arr)].filter(i => arr.indexOf(i) === arr.lastIndexOf(i)); | |
</code></pre> | |
<pre><code class="language-js">filterNonUnique([1, 2, 2, 3, 4, 4, 5]); // [1, 3, 5] | |
</code></pre> | |
<hr> | |
<h2>title: filterNonUniqueBy</h2> | |
<p>Creates an array with the non-unique values filtered out, based on a provided comparator function.</p> | |
<ul> | |
<li>Use <code>Array.prototype.filter()</code> and <code>Array.prototype.every()</code> to create an array containing only the unique values, based on the comparator function, <code>fn</code>.</li> | |
<li>The comparator function takes four arguments: the values of the two elements being compared and their indexes.</li> | |
</ul> | |
<pre><code class="language-js">const filterNonUniqueBy = (arr, fn) => | |
arr.filter((v, i) => arr.every((x, j) => (i === j) === fn(v, x, i, j))); | |
</code></pre> | |
<pre><code class="language-js">filterNonUniqueBy( | |
[ | |
{ id: 0, value: 'a' }, | |
{ id: 1, value: 'b' }, | |
{ id: 2, value: 'c' }, | |
{ id: 1, value: 'd' }, | |
{ id: 0, value: 'e' } | |
], | |
(a, b) => a.id === b.id | |
); // [ { id: 2, value: 'c' } ] | |
</code></pre> | |
<hr> | |
<h2>title: filterUnique</h2> | |
<p>Creates an array with the unique values filtered out.</p> | |
<ul> | |
<li>Use <code>new Set()</code> and the spread operator (<code>...</code>) to create an array of the unique values in <code>arr</code>.</li> | |
<li>Use <code>Array.prototype.filter()</code> to create an array containing only the non-unique values.</li> | |
</ul> | |
<pre><code class="language-js">const filterUnique = arr => | |
[...new Set(arr)].filter(i => arr.indexOf(i) !== arr.lastIndexOf(i)); | |
</code></pre> | |
<pre><code class="language-js">filterUnique([1, 2, 2, 3, 4, 4, 5]); // [2, 4] | |
</code></pre> | |
<hr> | |
<h2>title: filterUniqueBy</h2> | |
<p>Creates an array with the unique values filtered out, based on a provided comparator function.</p> | |
<ul> | |
<li>Use <code>Array.prototype.filter()</code> and <code>Array.prototype.every()</code> to create an array containing only the non-unique values, based on the comparator function, <code>fn</code>.</li> | |
<li>The comparator function takes four arguments: the values of the two elements being compared and their indexes.</li> | |
</ul> | |
<pre><code class="language-js">const filterUniqueBy = (arr, fn) => | |
arr.filter((v, i) => arr.some((x, j) => (i !== j) === fn(v, x, i, j))); | |
</code></pre> | |
<pre><code class="language-js">filterUniqueBy( | |
[ | |
{ id: 0, value: 'a' }, | |
{ id: 1, value: 'b' }, | |
{ id: 2, value: 'c' }, | |
{ id: 3, value: 'd' }, | |
{ id: 0, value: 'e' } | |
], | |
(a, b) => a.id == b.id | |
); // [ { id: 0, value: 'a' }, { id: 0, value: 'e' } ] | |
</code></pre> | |
<hr> | |
<h2>title: findClosestAnchor</h2> | |
<p>Finds the anchor node closest to the given <code>node</code>, if any.</p> | |
<ul> | |
<li>Use a <code>for</code> loop and <code>Node.parentNode</code> to traverse the node tree upwards from the given <code>node</code>.</li> | |
<li>Use <code>Node.nodeName</code> and <code>String.prototype.toLowerCase()</code> to check if any given node is an anchor (<code>'a'</code>).</li> | |
<li>If no matching node is found, return <code>null</code>.</li> | |
</ul> | |
<pre><code class="language-js">const findClosestAnchor = node => { | |
for (let n = node; n.parentNode; n = n.parentNode) | |
if (n.nodeName.toLowerCase() === 'a') return n; | |
return null; | |
}; | |
</code></pre> | |
<pre><code class="language-js">findClosestAnchor(document.querySelector('a > span')); // a | |
</code></pre> | |
<hr> | |
<h2>title: findClosestMatchingNode</h2> | |
<p>Finds the closest matching node starting at the given <code>node</code>.</p> | |
<ul> | |
<li>Use a <code>for</code> loop and <code>Node.parentNode</code> to traverse the node tree upwards from the given <code>node</code>.</li> | |
<li>Use <code>Element.matches()</code> to check if any given element node matches the provided <code>selector</code>.</li> | |
<li>If no matching node is found, return <code>null</code>.</li> | |
</ul> | |
<pre><code class="language-js">const findClosestMatchingNode = (node, selector) => { | |
for (let n = node; n.parentNode; n = n.parentNode) | |
if (n.matches && n.matches(selector)) return n; | |
return null; | |
}; | |
</code></pre> | |
<pre><code class="language-js">findClosestMatchingNode(document.querySelector('span'), 'body'); // body | |
</code></pre> | |
<hr> | |
<h2>title: findFirstN</h2> | |
<p>Finds the first <code>n</code> elements for which the provided function returns a truthy value.</p> | |
<ul> | |
<li>Use a <code>for..in</code> loop to execute the provided <code>matcher</code> for each element of <code>arr</code>.</li> | |
<li>Use <code>Array.prototype.push()</code> to append elements to the results array and return them if its <code>length</code> is equal to <code>n</code>.</li> | |
</ul> | |
<pre><code class="language-js">const findFirstN = (arr, matcher, n = 1) => { | |
let res = []; | |
for (let i in arr) { | |
const el = arr[i]; | |
const match = matcher(el, i, arr); | |
if (match) res.push(el); | |
if (res.length === n) return res; | |
} | |
return res; | |
}; | |
</code></pre> | |
<pre><code class="language-js">findFirstN([1, 2, 4, 6], n => n % 2 === 0, 2); // [2, 4] | |
findFirstN([1, 2, 4, 6], n => n % 2 === 0, 5); // [2, 4, 6] | |
</code></pre> | |
<hr> | |
<h2>title: findKey</h2> | |
<p>Finds the first key that satisfies the provided testing function. | |
Otherwise <code>undefined</code> is returned.</p> | |
<ul> | |
<li>Use <code>Object.keys(obj)</code> to get all the properties of the object, <code>Array.prototype.find()</code> to test each key-value pair using <code>fn</code>.</li> | |
<li>The callback receives three arguments – the value, the key and the object.</li> | |
</ul> | |
<pre><code class="language-js">const findKey = (obj, fn) => | |
Object.keys(obj).find(key => fn(obj[key], key, obj)); | |
</code></pre> | |
<pre><code class="language-js">findKey( | |
{ | |
barney: { age: 36, active: true }, | |
fred: { age: 40, active: false }, | |
pebbles: { age: 1, active: true } | |
}, | |
x => x['active'] | |
); // 'barney' | |
</code></pre> | |
<hr> | |
<h2>title: findKeys</h2> | |
<p>Finds all the keys in the provided object that match the given value.</p> | |
<ul> | |
<li>Use <code>Object.keys(obj)</code> to get all the properties of the object.</li> | |
<li>Use <code>Array.prototype.filter()</code> to test each key-value pair and return all keys that are equal to the given value.</li> | |
</ul> | |
<pre><code class="language-js">const findKeys = (obj, val) => | |
Object.keys(obj).filter(key => obj[key] === val); | |
</code></pre> | |
<pre><code class="language-js">const ages = { | |
Leo: 20, | |
Zoey: 21, | |
Jane: 20, | |
}; | |
findKeys(ages, 20); // [ 'Leo', 'Jane' ] | |
</code></pre> | |
<hr> | |
<h2>title: findLast</h2> | |
<p>Finds the last element for which the provided function returns a truthy value.</p> | |
<ul> | |
<li>Use <code>Array.prototype.filter()</code> to remove elements for which <code>fn</code> returns falsy values.</li> | |
<li>Use <code>Array.prototype.pop()</code> to get the last element in the filtered array.</li> | |
</ul> | |
<pre><code class="language-js">const findLast = (arr, fn) => arr.filter(fn).pop(); | |
</code></pre> | |
<pre><code class="language-js">findLast([1, 2, 3, 4], n => n % 2 === 1); // 3 | |
</code></pre> | |
<hr> | |
<h2>title: findLastIndex</h2> | |
<p>Finds the index of the last element for which the provided function returns a truthy value.</p> | |
<ul> | |
<li>Use <code>Array.prototype.map()</code> to map each element to an array with its index and value.</li> | |
<li>Use <code>Array.prototype.filter()</code> to remove elements for which <code>fn</code> returns falsy values</li> | |
<li>Use <code>Array.prototype.pop()</code> to get the last element in the filtered array.</li> | |
<li>Return <code>-1</code> if there are no matching elements.</li> | |
</ul> | |
<pre><code class="language-js">const findLastIndex = (arr, fn) => | |
(arr | |
.map((val, i) => [i, val]) | |
.filter(([i, val]) => fn(val, i, arr)) | |
.pop() || [-1])[0]; | |
</code></pre> | |
<pre><code class="language-js">findLastIndex([1, 2, 3, 4], n => n % 2 === 1); // 2 (index of the value 3) | |
findLastIndex([1, 2, 3, 4], n => n === 5); // -1 (default value when not found) | |
</code></pre> | |
<hr> | |
<h2>title: findLastKey</h2> | |
<p>Finds the last key that satisfies the provided testing function. | |
Otherwise <code>undefined</code> is returned.</p> | |
<ul> | |
<li>Use <code>Object.keys(obj)</code> to get all the properties of the object.</li> | |
<li>Use <code>Array.prototype.reverse()</code> to reverse the order and <code>Array.prototype.find()</code> to test the provided function for each key-value pair.</li> | |
<li>The callback receives three arguments – the value, the key and the object.</li> | |
</ul> | |
<pre><code class="language-js">const findLastKey = (obj, fn) => | |
Object.keys(obj) | |
.reverse() | |
.find(key => fn(obj[key], key, obj)); | |
</code></pre> | |
<pre><code class="language-js">findLastKey( | |
{ | |
barney: { age: 36, active: true }, | |
fred: { age: 40, active: false }, | |
pebbles: { age: 1, active: true } | |
}, | |
x => x['active'] | |
); // 'pebbles' | |
</code></pre> | |
<hr> | |
<h2>title: findLastN</h2> | |
<p>Finds the last <code>n</code> elements for which the provided function returns a truthy value.</p> | |
<ul> | |
<li>Use a <code>for</code> loop to execute the provided <code>matcher</code> for each element of <code>arr</code>.</li> | |
<li>Use <code>Array.prototype.unshift()</code> to prepend elements to the results array and return them if its <code>length</code> is equal to <code>n</code>.</li> | |
</ul> | |
<pre><code class="language-js">const findLastN = (arr, matcher, n = 1) => { | |
let res = []; | |
for (let i = arr.length - 1; i >= 0; i--) { | |
const el = arr[i]; | |
const match = matcher(el, i, arr); | |
if (match) res.unshift(el); | |
if (res.length === n) return res; | |
} | |
return res; | |
}; | |
</code></pre> | |
<pre><code class="language-js">findLastN([1, 2, 4, 6], n => n % 2 === 0, 2); // [4, 6] | |
findLastN([1, 2, 4, 6], n => n % 2 === 0, 5); // [2, 4, 6] | |
</code></pre> | |
<hr> | |
<h2>title: flatten</h2> | |
<p>Flattens an array up to the specified depth.</p> | |
<ul> | |
<li>Use recursion, decrementing <code>depth</code> by <code>1</code> for each level of depth.</li> | |
<li>Use <code>Array.prototype.reduce()</code> and <code>Array.prototype.concat()</code> to merge elements or arrays.</li> | |
<li>Base case, for <code>depth</code> equal to <code>1</code> stops recursion.</li> | |
<li>Omit the second argument, <code>depth</code>, to flatten only to a depth of <code>1</code> (single flatten).</li> | |
</ul> | |
<pre><code class="language-js">const flatten = (arr, depth = 1) => | |
arr.reduce( | |
(a, v) => | |
a.concat(depth > 1 && Array.isArray(v) ? flatten(v, depth - 1) : v), | |
[] | |
); | |
</code></pre> | |
<pre><code class="language-js">flatten([1, [2], 3, 4]); // [1, 2, 3, 4] | |
flatten([1, [2, [3, [4, 5], 6], 7], 8], 2); // [1, 2, 3, [4, 5], 6, 7, 8] | |
</code></pre> | |
<hr> | |
<h2>title: flattenObject</h2> | |
<p>Flattens an object with the paths for keys.</p> | |
<ul> | |
<li>Use recursion.</li> | |
<li>Use <code>Object.keys(obj)</code> combined with <code>Array.prototype.reduce()</code> to convert every leaf node to a flattened path node.</li> | |
<li>If the value of a key is an object, the function calls itself with the appropriate <code>prefix</code> to create the path using <code>Object.assign()</code>.</li> | |
<li>Otherwise, it adds the appropriate prefixed key-value pair to the accumulator object.</li> | |
<li>You should always omit the second argument, <code>prefix</code>, unless you want every key to have a prefix.</li> | |
</ul> | |
<pre><code class="language-js">const flattenObject = (obj, prefix = '') => | |
Object.keys(obj).reduce((acc, k) => { | |
const pre = prefix.length ? `${prefix}.` : ''; | |
if ( | |
typeof obj[k] === 'object' && | |
obj[k] !== null && | |
Object.keys(obj[k]).length > 0 | |
) | |
Object.assign(acc, flattenObject(obj[k], pre + k)); | |
else acc[pre + k] = obj[k]; | |
return acc; | |
}, {}); | |
</code></pre> | |
<pre><code class="language-js">flattenObject({ a: { b: { c: 1 } }, d: 1 }); // { 'a.b.c': 1, d: 1 } | |
</code></pre> | |
<hr> | |
<h2>title: flip</h2> | |
<p>Takes a function as an argument, then makes the first argument the last.</p> | |
<ul> | |
<li>Use argument destructuring and a closure with variadic arguments.</li> | |
<li>Splice the first argument, using the spread operator (<code>...</code>), to make it the last before applying the rest.</li> | |
</ul> | |
<pre><code class="language-js">const flip = fn => (first, ...rest) => fn(...rest, first); | |
</code></pre> | |
<pre><code class="language-js">let a = { name: 'John Smith' }; | |
let b = {}; | |
const mergeFrom = flip(Object.assign); | |
let mergePerson = mergeFrom.bind(null, a); | |
mergePerson(b); // == b | |
b = {}; | |
Object.assign(b, a); // == b | |
</code></pre> | |
<hr> | |
<h2>title: forEachRight</h2> | |
<p>Executes a provided function once for each array element, starting from the array’s last element.</p> | |
<ul> | |
<li>Use <code>Array.prototype.slice()</code> to clone the given array and <code>Array.prototype.reverse()</code> to reverse it.</li> | |
<li>Use <code>Array.prototype.forEach()</code> to iterate over the reversed array.</li> | |
</ul> | |
<pre><code class="language-js">const forEachRight = (arr, callback) => | |
arr | |
.slice() | |
.reverse() | |
.forEach(callback); | |
</code></pre> | |
<pre><code class="language-js">forEachRight([1, 2, 3, 4], val => console.log(val)); // '4', '3', '2', '1' | |
</code></pre> | |
<hr> | |
<h2>title: forOwn</h2> | |
<p>Iterates over all own properties of an object, running a callback for each one.</p> | |
<ul> | |
<li>Use <code>Object.keys(obj)</code> to get all the properties of the object.</li> | |
<li>Use <code>Array.prototype.forEach()</code> to run the provided function for each key-value pair.</li> | |
<li>The callback receives three arguments – the value, the key and the object.</li> | |
</ul> | |
<pre><code class="language-js">const forOwn = (obj, fn) => | |
Object.keys(obj).forEach(key => fn(obj[key], key, obj)); | |
</code></pre> | |
<pre><code class="language-js">forOwn({ foo: 'bar', a: 1 }, v => console.log(v)); // 'bar', 1 | |
</code></pre> | |
<hr> | |
<h2>title: forOwnRight</h2> | |
<p>Iterates over all own properties of an object in reverse, running a callback for each one.</p> | |
<ul> | |
<li>Use <code>Object.keys(obj)</code> to get all the properties of the object, <code>Array.prototype.reverse()</code> to reverse their order.</li> | |
<li>Use <code>Array.prototype.forEach()</code> to run the provided function for each key-value pair.</li> | |
<li>The callback receives three arguments – the value, the key and the object.</li> | |
</ul> | |
<pre><code class="language-js">const forOwnRight = (obj, fn) => | |
Object.keys(obj) | |
.reverse() | |
.forEach(key => fn(obj[key], key, obj)); | |
</code></pre> | |
<pre><code class="language-js">forOwnRight({ foo: 'bar', a: 1 }, v => console.log(v)); // 1, 'bar' | |
</code></pre> | |
<hr> | |
<h2>title: formToObject</h2> | |
<p>Encodes a set of form elements as an <code>object</code>.</p> | |
<ul> | |
<li>Use the <code>FormData</code> constructor to convert the HTML <code>form</code> to <code>FormData</code> and <code>Array.from()</code> to convert to an array.</li> | |
<li>Collect the object from the array using <code>Array.prototype.reduce()</code>.</li> | |
</ul> | |
<pre><code class="language-js">const formToObject = form => | |
Array.from(new FormData(form)).reduce( | |
(acc, [key, value]) => ({ | |
...acc, | |
[key]: value | |
}), | |
{} | |
); | |
</code></pre> | |
<pre><code class="language-js">formToObject(document.querySelector('#form')); | |
// { email: 'test@email.com', name: 'Test Name' } | |
</code></pre> | |
<hr> | |
<h2>title: formatDuration</h2> | |
<p>Returns the human-readable format of the given number of milliseconds.</p> | |
<ul> | |
<li>Divide <code>ms</code> with the appropriate values to obtain the appropriate values for <code>day</code>, <code>hour</code>, <code>minute</code>, <code>second</code> and <code>millisecond</code>.</li> | |
<li>Use <code>Object.entries()</code> with <code>Array.prototype.filter()</code> to keep only non-zero values.</li> | |
<li>Use <code>Array.prototype.map()</code> to create the string for each value, pluralizing appropriately.</li> | |
<li>Use <code>String.prototype.join(', ')</code> to combine the values into a string.</li> | |
</ul> | |
<pre><code class="language-js">const formatDuration = ms => { | |
if (ms < 0) ms = -ms; | |
const time = { | |
day: Math.floor(ms / 86400000), | |
hour: Math.floor(ms / 3600000) % 24, | |
minute: Math.floor(ms / 60000) % 60, | |
second: Math.floor(ms / 1000) % 60, | |
millisecond: Math.floor(ms) % 1000 | |
}; | |
return Object.entries(time) | |
.filter(val => val[1] !== 0) | |
.map(([key, val]) => `${val} ${key}${val !== 1 ? 's' : ''}`) | |
.join(', '); | |
}; | |
</code></pre> | |
<pre><code class="language-js">formatDuration(1001); // '1 second, 1 millisecond' | |
formatDuration(34325055574); | |
// '397 days, 6 hours, 44 minutes, 15 seconds, 574 milliseconds' | |
</code></pre> | |
<hr> | |
<h2>title: formatNumber</h2> | |
<p>Formats a number using the local number format order.</p> | |
<ul> | |
<li>Use <code>Number.prototype.toLocaleString()</code> to convert a number to using the local number format separators.</li> | |
</ul> | |
<pre><code class="language-js">const formatNumber = num => num.toLocaleString(); | |
</code></pre> | |
<pre><code class="language-js">formatNumber(123456); // '123,456' in `en-US` | |
formatNumber(15675436903); // '15.675.436.903' in `de-DE` | |
</code></pre> | |
<hr> | |
<h2>title: formatSeconds</h2> | |
<p>Returns the ISO format of the given number of seconds.</p> | |
<ul> | |
<li>Divide <code>s</code> with the appropriate values to obtain the appropriate values for <code>hour</code>, <code>minute</code> and <code>second</code>.</li> | |
<li>Store the <code>sign</code> in a variable to prepend it to the result.</li> | |
<li>Use <code>Array.prototype.map()</code> in combination with <code>Math.floor()</code> and <code>String.prototype.padStart()</code> to stringify and format each segment.</li> | |
<li>Use <code>String.prototype.join(':')</code> to combine the values into a string.</li> | |
</ul> | |
<pre><code class="language-js">const formatSeconds = s => { | |
const [hour, minute, second, sign] = | |
s > 0 | |
? [s / 3600, (s / 60) % 60, s % 60, ''] | |
: [-s / 3600, (-s / 60) % 60, -s % 60, '-']; | |
return ( | |
sign + | |
[hour, minute, second] | |
.map(v => `${Math.floor(v)}`.padStart(2, '0')) | |
.join(':') | |
); | |
}; | |
</code></pre> | |
<pre><code class="language-js">formatSeconds(200); // '00:03:20' | |
formatSeconds(-200); // '-00:03:20' | |
formatSeconds(99999); // '27:46:39' | |
</code></pre> | |
<hr> | |
<h2>title: frequencies</h2> | |
<p>Creates an object with the unique values of an array as keys and their frequencies as the values.</p> | |
<ul> | |
<li>Use <code>Array.prototype.reduce()</code> to map unique values to an object’s keys, adding to existing keys every time the same value is encountered.</li> | |
</ul> | |
<pre><code class="language-js">const frequencies = arr => | |
arr.reduce((a, v) => { | |
a[v] = a[v] ? a[v] + 1 : 1; | |
return a; | |
}, {}); | |
</code></pre> | |
<pre><code class="language-js">frequencies(['a', 'b', 'a', 'c', 'a', 'a', 'b']); // { a: 4, b: 2, c: 1 } | |
frequencies([...'ball']); // { b: 1, a: 1, l: 2 } | |
</code></pre> | |
<hr> | |
<h2>title: fromCamelCase</h2> | |
<p>Converts a string from camelcase.</p> | |
<ul> | |
<li>Use <code>String.prototype.replace()</code> to break the string into words and add a <code>separator</code> between them.</li> | |
<li>Omit the second argument to use a default <code>separator</code> of <code>_</code>.</li> | |
</ul> | |
<pre><code class="language-js">const fromCamelCase = (str, separator = '_') => | |
str | |
.replace(/([a-z\d])([A-Z])/g, '$1' + separator + '$2') | |
.replace(/([A-Z]+)([A-Z][a-z\d]+)/g, '$1' + separator + '$2') | |
.toLowerCase(); | |
</code></pre> | |
<pre><code class="language-js">fromCamelCase('someDatabaseFieldName', ' '); // 'some database field name' | |
fromCamelCase('someLabelThatNeedsToBeDecamelized', '-'); | |
// 'some-label-that-needs-to-be-decamelized' | |
fromCamelCase('someJavascriptProperty', '_'); // 'some_javascript_property' | |
fromCamelCase('JSONToCSV', '.'); // 'json.to.csv' | |
</code></pre> | |
<hr> | |
<h2>title: fromTimestamp</h2> | |
<p>Creates a <code>Date</code> object from a Unix timestamp.</p> | |
<ul> | |
<li>Convert the timestamp to milliseconds by multiplying with <code>1000</code>.</li> | |
<li>Use <code>new Date()</code> to create a new <code>Date</code> object.</li> | |
</ul> | |
<pre><code class="language-js">const fromTimestamp = timestamp => new Date(timestamp * 1000); | |
</code></pre> | |
<pre><code class="language-js">fromTimestamp(1602162242); // 2020-10-08T13:04:02.000Z | |
</code></pre> | |
<hr> | |
<h2>title: frozenSet</h2> | |
<p>Creates a frozen <code>Set</code> object.</p> | |
<ul> | |
<li>Use the <code>new Set()</code> constructor to create a new <code>Set</code> object from <code>iterable</code>.</li> | |
<li>Set the <code>add</code>, <code>delete</code> and <code>clear</code> methods of the newly created object to <code>undefined</code>, so that they cannot be used, practically freezing the object.</li> | |
</ul> | |
<pre><code class="language-js">const frozenSet = iterable => { | |
const s = new Set(iterable); | |
s.add = undefined; | |
s.delete = undefined; | |
s.clear = undefined; | |
return s; | |
}; | |
</code></pre> | |
<pre><code class="language-js">frozenSet([1, 2, 3, 1, 2]); | |
// Set { 1, 2, 3, add: undefined, delete: undefined, clear: undefined } | |
</code></pre> | |
<hr> | |
<h2>title: fullscreen</h2> | |
<p>Opens or closes an element in fullscreen mode.</p> | |
<ul> | |
<li>Use <code>Document.querySelector()</code> and <code>Element.requestFullscreen()</code> to open the given element in fullscreen.</li> | |
<li>Use <code>Document.exitFullscreen()</code> to exit fullscreen mode.</li> | |
<li>Omit the second argument, <code>el</code>, to use <code>body</code> as the default element.</li> | |
<li>Omit the first element, <code>mode</code>, to open the element in fullscreen mode by default.</li> | |
</ul> | |
<pre><code class="language-js">const fullscreen = (mode = true, el = 'body') => | |
mode | |
? document.querySelector(el).requestFullscreen() | |
: document.exitFullscreen(); | |
</code></pre> | |
<pre><code class="language-js">fullscreen(); // Opens `body` in fullscreen mode | |
fullscreen(false); // Exits fullscreen mode | |
</code></pre> | |
<hr> | |
<h2>title: functionName</h2> | |
<p>Logs the name of a function.</p> | |
<ul> | |
<li>Use <code>console.debug()</code> and the <code>name</code> property of the passed function to log the function’s name to the <code>debug</code> channel of the console.</li> | |
<li>Return the given function <code>fn</code>.</li> | |
</ul> | |
<pre><code class="language-js">const functionName = fn => (console.debug(fn.name), fn); | |
</code></pre> | |
<pre><code class="language-js">let m = functionName(Math.max)(5, 6); | |
// max (logged in debug channel of console) | |
// m = 6 | |
</code></pre> | |
<hr> | |
<h2>title: functions</h2> | |
<p>Gets an array of function property names from own (and optionally inherited) enumerable properties of an object.</p> | |
<ul> | |
<li>Use <code>Object.keys(obj)</code> to iterate over the object’s own properties.</li> | |
<li>If <code>inherited</code> is <code>true</code>, use <code>Object.getPrototypeOf(obj)</code> to also get the object’s inherited properties.</li> | |
<li>Use <code>Array.prototype.filter()</code> to keep only those properties that are functions.</li> | |
<li>Omit the second argument, <code>inherited</code>, to not include inherited properties by default.</li> | |
</ul> | |
<pre><code class="language-js">const functions = (obj, inherited = false) => | |
(inherited | |
? [...Object.keys(obj), ...Object.keys(Object.getPrototypeOf(obj))] | |
: Object.keys(obj) | |
).filter(key => typeof obj[key] === 'function'); | |
</code></pre> | |
<pre><code class="language-js">function Foo() { | |
this.a = () => 1; | |
this.b = () => 2; | |
} | |
Foo.prototype.c = () => 3; | |
functions(new Foo()); // ['a', 'b'] | |
functions(new Foo(), true); // ['a', 'b', 'c'] | |
</code></pre> | |
<hr> | |
<h2>title: gcd</h2> | |
<p>Calculates the greatest common divisor between two or more numbers/arrays.</p> | |
<ul> | |
<li>The inner <code>_gcd</code> function uses recursion.</li> | |
<li>Base case is when <code>y</code> equals <code>0</code>. In this case, return <code>x</code>.</li> | |
<li>Otherwise, return the GCD of <code>y</code> and the remainder of the division <code>x/y</code>.</li> | |
</ul> | |
<pre><code class="language-js">const gcd = (...arr) => { | |
const _gcd = (x, y) => (!y ? x : gcd(y, x % y)); | |
return [...arr].reduce((a, b) => _gcd(a, b)); | |
}; | |
</code></pre> | |
<pre><code class="language-js">gcd(8, 36); // 4 | |
gcd(...[12, 8, 32]); // 4 | |
</code></pre> | |
<hr> | |
<h2>title: generateItems</h2> | |
<p>Generates an array with the given amount of items, using the given function.</p> | |
<ul> | |
<li>Use <code>Array.from()</code> to create an empty array of the specific length, calling <code>fn</code> with the index of each newly created element.</li> | |
<li>The callback takes one argument – the index of each element.</li> | |
</ul> | |
<pre><code class="language-js">const generateItems = (n, fn) => Array.from({ length: n }, (_, i) => fn(i)); | |
</code></pre> | |
<pre><code class="language-js">generateItems(10, Math.random); | |
// [0.21, 0.08, 0.40, 0.96, 0.96, 0.24, 0.19, 0.96, 0.42, 0.70] | |
</code></pre> | |
<hr> | |
<h2>title: generatorToArray</h2> | |
<p>Converts the output of a generator function to an array.</p> | |
<ul> | |
<li>Use the spread operator (<code>...</code>) to convert the output of the generator function to an array.</li> | |
</ul> | |
<pre><code class="language-js">const generatorToArray = gen => [...gen]; | |
</code></pre> | |
<pre><code class="language-js">const s = new Set([1, 2, 1, 3, 1, 4]); | |
generatorToArray(s.entries()); // [[ 1, 1 ], [ 2, 2 ], [ 3, 3 ], [ 4, 4 ]] | |
</code></pre> | |
<hr> | |
<h2>title: geometricProgression</h2> | |
<p>Initializes an array containing the numbers in the specified range where <code>start</code> and <code>end</code> are inclusive and the ratio between two terms is <code>step</code>. | |
Returns an error if <code>step</code> equals <code>1</code>.</p> | |
<ul> | |
<li>Use <code>Array.from()</code>, <code>Math.log()</code> and <code>Math.floor()</code> to create an array of the desired length, <code>Array.prototype.map()</code> to fill with the desired values in a range.</li> | |
<li>Omit the second argument, <code>start</code>, to use a default value of <code>1</code>.</li> | |
<li>Omit the third argument, <code>step</code>, to use a default value of <code>2</code>.</li> | |
</ul> | |
<pre><code class="language-js">const geometricProgression = (end, start = 1, step = 2) => | |
Array.from({ | |
length: Math.floor(Math.log(end / start) / Math.log(step)) + 1, | |
}).map((_, i) => start * step ** i); | |
</code></pre> | |
<pre><code class="language-js">geometricProgression(256); // [1, 2, 4, 8, 16, 32, 64, 128, 256] | |
geometricProgression(256, 3); // [3, 6, 12, 24, 48, 96, 192] | |
geometricProgression(256, 1, 4); // [1, 4, 16, 64, 256] | |
</code></pre> | |
<hr> | |
<h2>title: get</h2> | |
<p>Retrieves a set of properties indicated by the given selectors from an object.</p> | |
<ul> | |
<li>Use <code>Array.prototype.map()</code> for each selector, <code>String.prototype.replace()</code> to replace square brackets with dots.</li> | |
<li>Use <code>String.prototype.split('.')</code> to split each selector.</li> | |
<li>Use <code>Array.prototype.filter()</code> to remove empty values and <code>Array.prototype.reduce()</code> to get the value indicated by each selector.</li> | |
</ul> | |
<pre><code class="language-js">const get = (from, ...selectors) => | |
[...selectors].map(s => | |
s | |
.replace(/\[([^\[\]]*)\]/g, '.$1.') | |
.split('.') | |
.filter(t => t !== '') | |
.reduce((prev, cur) => prev && prev[cur], from) | |
); | |
</code></pre> | |
<pre><code class="language-js">const obj = { | |
selector: { to: { val: 'val to select' } }, | |
target: [1, 2, { a: 'test' }], | |
}; | |
get(obj, 'selector.to.val', 'target[0]', 'target[2].a'); | |
// ['val to select', 1, 'test'] | |
</code></pre> | |
<hr> | |
<h2>title: getAncestors</h2> | |
<p>Returns all the ancestors of an element from the document root to the given element.</p> | |
<ul> | |
<li>Use <code>Node.parentNode</code> and a <code>while</code> loop to move up the ancestor tree of the element.</li> | |
<li>Use <code>Array.prototype.unshift()</code> to add each new ancestor to the start of the array.</li> | |
</ul> | |
<pre><code class="language-js">const getAncestors = el => { | |
let ancestors = []; | |
while (el) { | |
ancestors.unshift(el); | |
el = el.parentNode; | |
} | |
return ancestors; | |
}; | |
</code></pre> | |
<pre><code class="language-js">getAncestors(document.querySelector('nav')); | |
// [document, html, body, header, nav] | |
</code></pre> | |
<hr> | |
<h2>title: getBaseURL</h2> | |
<p>Gets the current URL without any parameters or fragment identifiers.</p> | |
<ul> | |
<li>Use <code>String.prototype.replace()</code> with an appropriate regular expression to remove everything after either <code>'?'</code> or <code>'#'</code>, if found.</li> | |
</ul> | |
<pre><code class="language-js">const getBaseURL = url => url.replace(/[?#].*$/, ''); | |
</code></pre> | |
<pre><code class="language-js">getBaseURL('http://url.com/page?name=Adam&surname=Smith'); | |
// 'http://url.com/page' | |
</code></pre> | |
<hr> | |
<h2>title: getColonTimeFromDate</h2> | |
<p>Returns a string of the form <code>HH:MM:SS</code> from a <code>Date</code> object.</p> | |
<ul> | |
<li>Use <code>Date.prototype.toTimeString()</code> and <code>String.prototype.slice()</code> to get the <code>HH:MM:SS</code> part of a given <code>Date</code> object.</li> | |
</ul> | |
<pre><code class="language-js">const getColonTimeFromDate = date => date.toTimeString().slice(0, 8); | |
</code></pre> | |
<pre><code class="language-js">getColonTimeFromDate(new Date()); // '08:38:00' | |
</code></pre> | |
<hr> | |
<h2>title: getDaysDiffBetweenDates</h2> | |
<p>Calculates the difference (in days) between two dates.</p> | |
<ul> | |
<li>Subtract the two <code>Date</code> objects and divide by the number of milliseconds in a day to get the difference (in days) between them.</li> | |
</ul> | |
<pre><code class="language-js">const getDaysDiffBetweenDates = (dateInitial, dateFinal) => | |
(dateFinal - dateInitial) / (1000 * 3600 * 24); | |
</code></pre> | |
<pre><code class="language-js">getDaysDiffBetweenDates(new Date('2017-12-13'), new Date('2017-12-22')); // 9 | |
</code></pre> | |
<hr> | |
<h2>title: getElementsBiggerThanViewport</h2> | |
<p>Returns an array of HTML elements whose width is larger than that of the viewport’s.</p> | |
<ul> | |
<li>Use <code>HTMLElement.offsetWidth</code> to get the width of the <code>document</code>.</li> | |
<li>Use <code>Array.prototype.filter()</code> on the result of <code>Document.querySelectorAll()</code> to check the width of all elements in the document.</li> | |
</ul> | |
<pre><code class="language-js">const getElementsBiggerThanViewport = () => { | |
const docWidth = document.documentElement.offsetWidth; | |
return [...document.querySelectorAll('*')].filter( | |
el => el.offsetWidth > docWidth | |
); | |
}; | |
</code></pre> | |
<pre><code class="language-js">getElementsBiggerThanViewport(); // <div id="ultra-wide-item" /> | |
</code></pre> | |
<hr> | |
<h2>title: getHoursDiffBetweenDates</h2> | |
<p>Calculates the difference (in hours) between two dates.</p> | |
<ul> | |
<li>Subtract the two <code>Date</code> objects and divide by the number of milliseconds in an hour to get the difference (in hours) between them.</li> | |
</ul> | |
<pre><code class="language-js">const getHoursDiffBetweenDates = (dateInitial, dateFinal) => | |
(dateFinal - dateInitial) / (1000 * 3600); | |
</code></pre> | |
<pre><code class="language-js">getHoursDiffBetweenDates( | |
new Date('2021-04-24 10:25:00'), | |
new Date('2021-04-25 10:25:00') | |
); // 24 | |
</code></pre> | |
<hr> | |
<h2>title: getImages</h2> | |
<p>Fetches all images from within an element and puts them into an array.</p> | |
<ul> | |
<li>Use <code>Element.getElementsByTagName()</code> to get all <code><img></code> elements inside the provided element.</li> | |
<li>Use <code>Array.prototype.map()</code> to map every <code>src</code> attribute of each <code><img></code> element.</li> | |
<li>If <code>includeDuplicates</code> is <code>false</code>, create a new <code>Set</code> to eliminate duplicates and return it after spreading into an array.</li> | |
<li>Omit the second argument, <code>includeDuplicates</code>, to discard duplicates by default.</li> | |
</ul> | |
<pre><code class="language-js">const getImages = (el, includeDuplicates = false) => { | |
const images = [...el.getElementsByTagName('img')].map(img => | |
img.getAttribute('src') | |
); | |
return includeDuplicates ? images : [...new Set(images)]; | |
}; | |
</code></pre> | |
<pre><code class="language-js">getImages(document, true); // ['image1.jpg', 'image2.png', 'image1.png', '...'] | |
getImages(document, false); // ['image1.jpg', 'image2.png', '...'] | |
</code></pre> | |
<hr> | |
<h2>title: getMeridiemSuffixOfInteger</h2> | |
<p>Converts an integer to a suffixed string, adding <code>am</code> or <code>pm</code> based on its value.</p> | |
<ul> | |
<li>Use the modulo operator (<code>%</code>) and conditional checks to transform an integer to a stringified 12-hour format with meridiem suffix.</li> | |
</ul> | |
<pre><code class="language-js">const getMeridiemSuffixOfInteger = num => | |
num === 0 || num === 24 | |
? 12 + 'am' | |
: num === 12 | |
? 12 + 'pm' | |
: num < 12 | |
? (num % 12) + 'am' | |
: (num % 12) + 'pm'; | |
</code></pre> | |
<pre><code class="language-js">getMeridiemSuffixOfInteger(0); // '12am' | |
getMeridiemSuffixOfInteger(11); // '11am' | |
getMeridiemSuffixOfInteger(13); // '1pm' | |
getMeridiemSuffixOfInteger(25); // '1pm' | |
</code></pre> | |
<hr> | |
<h2>title: getMinutesDiffBetweenDates</h2> | |
<p>Calculates the difference (in minutes) between two dates.</p> | |
<ul> | |
<li>Subtract the two <code>Date</code> objects and divide by the number of milliseconds in a minute to get the difference (in minutes) between them.</li> | |
</ul> | |
<pre><code class="language-js">const getMinutesDiffBetweenDates = (dateInitial, dateFinal) => | |
(dateFinal - dateInitial) / (1000 * 60); | |
</code></pre> | |
<pre><code class="language-js">getMinutesDiffBetweenDates( | |
new Date('2021-04-24 01:00:15'), | |
new Date('2021-04-24 02:00:15') | |
); // 60 | |
</code></pre> | |
<hr> | |
<h2>title: getMonthsDiffBetweenDates</h2> | |
<p>Calculates the difference (in months) between two dates.</p> | |
<ul> | |
<li>Use <code>Date.prototype.getFullYear()</code> and <code>Date.prototype.getMonth()</code> to calculate the difference (in months) between two <code>Date</code> objects.</li> | |
</ul> | |
<pre><code class="language-js">const getMonthsDiffBetweenDates = (dateInitial, dateFinal) => | |
Math.max( | |
(dateFinal.getFullYear() - dateInitial.getFullYear()) * 12 + | |
dateFinal.getMonth() - | |
dateInitial.getMonth(), | |
0 | |
); | |
</code></pre> | |
<pre><code class="language-js">getMonthsDiffBetweenDates(new Date('2017-12-13'), new Date('2018-04-29')); // 4 | |
</code></pre> | |
<hr> | |
<h2>title: getParentsUntil</h2> | |
<p>Finds all the ancestors of an element up until the element matched by the specified selector.</p> | |
<ul> | |
<li>Use <code>Node.parentNode</code> and a <code>while</code> loop to move up the ancestor tree of the element.</li> | |
<li>Use <code>Array.prototype.unshift()</code> to add each new ancestor to the start of the array.</li> | |
<li>Use <code>Element.matches()</code> to check if the current element matches the specified <code>selector</code>.</li> | |
</ul> | |
<pre><code class="language-js">const getParentsUntil = (el, selector) => { | |
let parents = [], | |
_el = el.parentNode; | |
while (_el && typeof _el.matches === 'function') { | |
parents.unshift(_el); | |
if (_el.matches(selector)) return parents; | |
else _el = _el.parentNode; | |
} | |
return []; | |
}; | |
</code></pre> | |
<pre><code class="language-js">getParentsUntil(document.querySelector('#home-link'), 'header'); | |
// [header, nav, ul, li] | |
</code></pre> | |
<hr> | |
<h2>title: getProtocol</h2> | |
<p>Gets the protocol being used on the current page.</p> | |
<ul> | |
<li>Use <code>Window.location.protocol</code> to get the protocol (<code>http:</code> or <code>https:</code>) of the current page.</li> | |
</ul> | |
<pre><code class="language-js">const getProtocol = () => window.location.protocol; | |
</code></pre> | |
<pre><code class="language-js">getProtocol(); // 'https:' | |
</code></pre> | |
<hr> | |
<h2>title: getScrollPosition</h2> | |
<p>Returns the scroll position of the current page.</p> | |
<ul> | |
<li>Use <code>Window.pageXOffset</code> and <code>Window.pageYOffset</code> if they are defined, otherwise <code>Element.scrollLeft</code> and <code>Element.scrollTop</code>.</li> | |
<li>Omit the single argument, <code>el</code>, to use a default value of <code>window</code>.</li> | |
</ul> | |
<pre><code class="language-js">const getScrollPosition = (el = window) => ({ | |
x: el.pageXOffset !== undefined ? el.pageXOffset : el.scrollLeft, | |
y: el.pageYOffset !== undefined ? el.pageYOffset : el.scrollTop | |
}); | |
</code></pre> | |
<pre><code class="language-js">getScrollPosition(); // {x: 0, y: 200} | |
</code></pre> | |
<hr> | |
<h2>title: getSecondsDiffBetweenDates</h2> | |
<p>Calculates the difference (in seconds) between two dates.</p> | |
<ul> | |
<li>Subtract the two <code>Date</code> objects and divide by the number of milliseconds in a second to get the difference (in seconds) between them.</li> | |
</ul> | |
<pre><code class="language-js">const getSecondsDiffBetweenDates = (dateInitial, dateFinal) => | |
(dateFinal - dateInitial) / 1000; | |
</code></pre> | |
<pre><code class="language-js">getSecondsDiffBetweenDates( | |
new Date('2020-12-24 00:00:15'), | |
new Date('2020-12-24 00:00:17') | |
); // 2 | |
</code></pre> | |
<hr> | |
<h2>title: getSelectedText</h2> | |
<p>Gets the currently selected text.</p> | |
<ul> | |
<li>Use <code>Window.getSelection()</code> and <code>Selection.toString()</code> to get the currently selected text.</li> | |
</ul> | |
<pre><code class="language-js">const getSelectedText = () => window.getSelection().toString(); | |
</code></pre> | |
<pre><code class="language-js">getSelectedText(); // 'Lorem ipsum' | |
</code></pre> | |
<hr> | |
<h2>title: getSiblings</h2> | |
<p>Returns an array containing all the siblings of the given element.</p> | |
<ul> | |
<li>Use <code>Node.parentNode</code> and <code>Node.childNodes</code> to get a <code>NodeList</code> of all the elements contained in the element’s parent.</li> | |
<li>Use the spread operator (<code>...</code>) and <code>Array.prototype.filter()</code> to convert to an array and remove the given element from it.</li> | |
</ul> | |
<pre><code class="language-js">const getSiblings = el => | |
[...el.parentNode.childNodes].filter(node => node !== el); | |
</code></pre> | |
<pre><code class="language-js">getSiblings(document.querySelector('head')); // ['body'] | |
</code></pre> | |
<hr> | |
<h2>title: getStyle</h2> | |
<p>Retrieves the value of a CSS rule for the specified element.</p> | |
<ul> | |
<li>Use <code>Window.getComputedStyle()</code> to get the value of the CSS rule for the specified element.</li> | |
</ul> | |
<pre><code class="language-js">const getStyle = (el, ruleName) => getComputedStyle(el)[ruleName]; | |
</code></pre> | |
<pre><code class="language-js">getStyle(document.querySelector('p'), 'font-size'); // '16px' | |
</code></pre> | |
<hr> | |
<h2>title: getTimestamp</h2> | |
<p>Gets the Unix timestamp from a <code>Date</code> object.</p> | |
<ul> | |
<li>Use <code>Date.prototype.getTime()</code> to get the timestamp in milliseconds and divide by <code>1000</code> to get the timestamp in seconds.</li> | |
<li>Use <code>Math.floor()</code> to appropriately round the resulting timestamp to an integer.</li> | |
<li>Omit the argument, <code>date</code>, to use the current date.</li> | |
</ul> | |
<pre><code class="language-js">const getTimestamp = (date = new Date()) => Math.floor(date.getTime() / 1000); | |
</code></pre> | |
<pre><code class="language-js">getTimestamp(); // 1602162242 | |
</code></pre> | |
<hr> | |
<h2>title: getType</h2> | |
<p>Returns the native type of a value.</p> | |
<ul> | |
<li>Return <code>'undefined'</code> or <code>'null'</code> if the value is <code>undefined</code> or <code>null</code>.</li> | |
<li>Otherwise, use <code>Object.prototype.constructor.name</code> to get the name of the constructor.</li> | |
</ul> | |
<pre><code class="language-js">const getType = v => | |
(v === undefined ? 'undefined' : v === null ? 'null' : v.constructor.name); | |
</code></pre> | |
<pre><code class="language-js">getType(new Set([1, 2, 3])); // 'Set' | |
</code></pre> | |
<hr> | |
<h2>title: getURLParameters</h2> | |
<p>Creates an object containing the parameters of the current URL.</p> | |
<ul> | |
<li>Use <code>String.prototype.match()</code> with an appropriate regular expression to get all key-value pairs.</li> | |
<li>Use <code>Array.prototype.reduce()</code> to map and combine them into a single object.</li> | |
<li>Pass <code>location.search</code> as the argument to apply to the current <code>url</code>.</li> | |
</ul> | |
<pre><code class="language-js">const getURLParameters = url => | |
(url.match(/([^?=&]+)(=([^&]*))/g) || []).reduce( | |
(a, v) => ( | |
(a[v.slice(0, v.indexOf('='))] = v.slice(v.indexOf('=') + 1)), a | |
), | |
{} | |
); | |
</code></pre> | |
<pre><code class="language-js">getURLParameters('google.com'); // {} | |
getURLParameters('http://url.com/page?name=Adam&surname=Smith'); | |
// {name: 'Adam', surname: 'Smith'} | |
</code></pre> | |
<hr> | |
<h2>title: getVerticalOffset</h2> | |
<p>Finds the distance from a given element to the top of the document.</p> | |
<ul> | |
<li>Use a <code>while</code> loop and <code>HTMLElement.offsetParent</code> to move up the offset parents of the given element.</li> | |
<li>Add <code>HTMLElement.offsetTop</code> for each element and return the result.</li> | |
</ul> | |
<pre><code class="language-js">const getVerticalOffset = el => { | |
let offset = el.offsetTop, | |
_el = el; | |
while (_el.offsetParent) { | |
_el = _el.offsetParent; | |
offset += _el.offsetTop; | |
} | |
return offset; | |
}; | |
</code></pre> | |
<pre><code class="language-js">getVerticalOffset('.my-element'); // 120 | |
</code></pre> | |
<hr> | |
<h2>title: groupBy</h2> | |
<p>Groups the elements of an array based on the given function.</p> | |
<ul> | |
<li>Use <code>Array.prototype.map()</code> to map the values of the array to a function or property name.</li> | |
<li>Use <code>Array.prototype.reduce()</code> to create an object, where the keys are produced from the mapped results.</li> | |
</ul> | |
<pre><code class="language-js">const groupBy = (arr, fn) => | |
arr | |
.map(typeof fn === 'function' ? fn : val => val[fn]) | |
.reduce((acc, val, i) => { | |
acc[val] = (acc[val] || []).concat(arr[i]); | |
return acc; | |
}, {}); | |
</code></pre> | |
<pre><code class="language-js">groupBy([6.1, 4.2, 6.3], Math.floor); // {4: [4.2], 6: [6.1, 6.3]} | |
groupBy(['one', 'two', 'three'], 'length'); // {3: ['one', 'two'], 5: ['three']} | |
</code></pre> | |
<hr> | |
<h2>title: hammingDistance</h2> | |
<p>Calculates the Hamming distance between two values.</p> | |
<ul> | |
<li>Use the XOR operator (<code>^</code>) to find the bit difference between the two numbers.</li> | |
<li>Convert to a binary string using <code>Number.prototype.toString(2)</code>.</li> | |
<li>Count and return the number of <code>1</code>s in the string, using <code>String.prototype.match(/1/g)</code>.</li> | |
</ul> | |
<pre><code class="language-js">const hammingDistance = (num1, num2) => | |
((num1 ^ num2).toString(2).match(/1/g) || '').length; | |
</code></pre> | |
<pre><code class="language-js">hammingDistance(2, 3); // 1 | |
</code></pre> | |
<hr> | |
<h2>title: hasClass</h2> | |
<p>Checks if the given element has the specified class.</p> | |
<ul> | |
<li>Use <code>Element.classList</code> and <code>DOMTokenList.contains()</code> to check if the element has the specified class.</li> | |
</ul> | |
<pre><code class="language-js">const hasClass = (el, className) => el.classList.contains(className); | |
</code></pre> | |
<pre><code class="language-js">hasClass(document.querySelector('p.special'), 'special'); // true | |
</code></pre> | |
<hr> | |
<h2>title: hasDuplicates</h2> | |
<p>Checks if there are duplicate values in a flat array.</p> | |
<ul> | |
<li>Use <code>Set()</code> to get the unique values in the array.</li> | |
<li>Use <code>Set.prototype.size</code> and <code>Array.prototype.length</code> to check if the count of the unique values is the same as elements in the original array.</li> | |
</ul> | |
<pre><code class="language-js">const hasDuplicates = arr => new Set(arr).size !== arr.length; | |
</code></pre> | |
<pre><code class="language-js">hasDuplicates([0, 1, 1, 2]); // true | |
hasDuplicates([0, 1, 2, 3]); // false | |
</code></pre> | |
<hr> | |
<h2>title: hasFlags</h2> | |
<p>Checks if the current process’s arguments contain the specified flags.</p> | |
<ul> | |
<li>Use <code>Array.prototype.every()</code> and <code>Array.prototype.includes()</code> to check if <code>process.argv</code> contains all the specified flags.</li> | |
<li>Use a regular expression to test if the specified flags are prefixed with <code>-</code> or <code>--</code> and prefix them accordingly.</li> | |
</ul> | |
<pre><code class="language-js">const hasFlags = (...flags) => | |
flags.every(flag => | |
process.argv.includes(/^-{1,2}/.test(flag) ? flag : '--' + flag) | |
); | |
</code></pre> | |
<pre><code class="language-js">// node myScript.js -s --test --cool=true | |
hasFlags('-s'); // true | |
hasFlags('--test', 'cool=true', '-s'); // true | |
hasFlags('special'); // false | |
</code></pre> | |
<hr> | |
<h2>title: hasKey</h2> | |
<p>Checks if the target value exists in a JSON object.</p> | |
<ul> | |
<li>Check if <code>keys</code> is non-empty and use <code>Array.prototype.every()</code> to sequentially check its keys to internal depth of the object, <code>obj</code>.</li> | |
<li>Use <code>Object.prototype.hasOwnProperty()</code> to check if <code>obj</code> does not have the current key or is not an object, stop propagation and return <code>false</code>.</li> | |
<li>Otherwise assign the key’s value to <code>obj</code> to use on the next iteration.</li> | |
<li>Return <code>false</code> beforehand if given key list is empty.</li> | |
</ul> | |
<pre><code class="language-js">const hasKey = (obj, keys) => { | |
return ( | |
keys.length > 0 && | |
keys.every(key => { | |
if (typeof obj !== 'object' || !obj.hasOwnProperty(key)) return false; | |
obj = obj[key]; | |
return true; | |
}) | |
); | |
}; | |
</code></pre> | |
<pre><code class="language-js">let obj = { | |
a: 1, | |
b: { c: 4 }, | |
'b.d': 5 | |
}; | |
hasKey(obj, ['a']); // true | |
hasKey(obj, ['b']); // true | |
hasKey(obj, ['b', 'c']); // true | |
hasKey(obj, ['b.d']); // true | |
hasKey(obj, ['d']); // false | |
hasKey(obj, ['c']); // false | |
hasKey(obj, ['b', 'f']); // false | |
</code></pre> | |
<hr> | |
<h2>title: hasMany</h2> | |
<p>Checks if an array has more than one value matching the given function.</p> | |
<ul> | |
<li>Use <code>Array.prototype.filter()</code> in combination with <code>fn</code> to find all matching array elements.</li> | |
<li>Use <code>Array.prototype.length</code> to check if more than one element match <code>fn</code>.</li> | |
</ul> | |
<pre><code class="language-js">const hasMany = (arr, fn) => arr.filter(fn).length > 1; | |
</code></pre> | |
<pre><code class="language-js">hasMany([1, 3], x => x % 2); // true | |
hasMany([1, 2], x => x % 2); // false | |
</code></pre> | |
<hr> | |
<h2>title: hasOne</h2> | |
<p>Checks if an array has only one value matching the given function.</p> | |
<ul> | |
<li>Use <code>Array.prototype.filter()</code> in combination with <code>fn</code> to find all matching array elements.</li> | |
<li>Use <code>Array.prototype.length</code> to check if only one element matches <code>fn</code>.</li> | |
</ul> | |
<pre><code class="language-js">const hasOne = (arr, fn) => arr.filter(fn).length === 1; | |
</code></pre> | |
<pre><code class="language-js">hasOne([1, 2], x => x % 2); // true | |
hasOne([1, 3], x => x % 2); // false | |
</code></pre> | |
<hr> | |
<h2>title: hashBrowser</h2> | |
<p>Creates a hash for a value using the <a href="https://en.wikipedia.org/wiki/SHA-2">SHA-256</a> algorithm. | |
Returns a promise.</p> | |
<ul> | |
<li>Use the <a href="https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto">SubtleCrypto</a> API to create a hash for the given value.</li> | |
<li>Create a new <code>TextEncoder</code> and use it to encode <code>val</code>. Pass its value to <code>SubtleCrypto.digest()</code> to generate a digest of the given data.</li> | |
<li>Use <code>DataView.prototype.getUint32()</code> to read data from the resolved <code>ArrayBuffer</code>.</li> | |
<li>Convert the data to it hexadecimal representation using <code>Number.prototype.toString(16)</code>. Add the data to an array using <code>Array.prototype.push()</code>.</li> | |
<li>Finally, use <code>Array.prototype.join()</code> to combine values in the array of <code>hexes</code> into a string.</li> | |
</ul> | |
<pre><code class="language-js">const hashBrowser = val => | |
crypto.subtle | |
.digest('SHA-256', new TextEncoder('utf-8').encode(val)) | |
.then(h => { | |
let hexes = [], | |
view = new DataView(h); | |
for (let i = 0; i < view.byteLength; i += 4) | |
hexes.push(('00000000' + view.getUint32(i).toString(16)).slice(-8)); | |
return hexes.join(''); | |
}); | |
</code></pre> | |
<pre><code class="language-js">hashBrowser( | |
JSON.stringify({ a: 'a', b: [1, 2, 3, 4], foo: { c: 'bar' } }) | |
).then(console.log); | |
// '04aa106279f5977f59f9067fa9712afc4aedc6f5862a8defc34552d8c7206393' | |
</code></pre> | |
<hr> | |
<h2>title: hashNode</h2> | |
<p>Creates a hash for a value using the <a href="https://en.wikipedia.org/wiki/SHA-2">SHA-256</a> algorithm. | |
Returns a promise.</p> | |
<ul> | |
<li>Use <code>crypto.createHash()</code> to create a <code>Hash</code> object with the appropriate algorithm.</li> | |
<li>Use <code>hash.update()</code> to add the data from <code>val</code> to the <code>Hash</code>, <code>hash.digest()</code> to calculate the digest of the data.</li> | |
<li>Use <code>setTimeout()</code> to prevent blocking on a long operation. Return a <code>Promise</code> to give it a familiar interface.</li> | |
</ul> | |
<pre><code class="language-js">const crypto = require('crypto'); | |
const hashNode = val => | |
new Promise(resolve => | |
setTimeout( | |
() => resolve(crypto.createHash('sha256').update(val).digest('hex')), | |
0 | |
) | |
); | |
</code></pre> | |
<pre><code class="language-js">hashNode(JSON.stringify({ a: 'a', b: [1, 2, 3, 4], foo: { c: 'bar' } })).then( | |
console.log | |
); | |
// '04aa106279f5977f59f9067fa9712afc4aedc6f5862a8defc34552d8c7206393' | |
</code></pre> | |
<hr> | |
<h2>title: haveSameContents</h2> | |
<p>Checks if two arrays contain the same elements regardless of order.</p> | |
<ul> | |
<li>Use a <code>for...of</code> loop over a <code>Set</code> created from the values of both arrays.</li> | |
<li>Use <code>Array.prototype.filter()</code> to compare the amount of occurrences of each distinct value in both arrays.</li> | |
<li>Return <code>false</code> if the counts do not match for any element, <code>true</code> otherwise.</li> | |
</ul> | |
<pre><code class="language-js">const haveSameContents = (a, b) => { | |
for (const v of new Set([...a, ...b])) | |
if (a.filter(e => e === v).length !== b.filter(e => e === v).length) | |
return false; | |
return true; | |
}; | |
</code></pre> | |
<pre><code class="language-js">haveSameContents([1, 2, 4], [2, 4, 1]); // true | |
</code></pre> | |
<hr> | |
<h2>title: head</h2> | |
<p>Returns the head of an array.</p> | |
<ul> | |
<li>Check if <code>arr</code> is truthy and has a <code>length</code> property.</li> | |
<li>Use <code>arr[0]</code> if possible to return the first element, otherwise return <code>undefined</code>.</li> | |
</ul> | |
<pre><code class="language-js">const head = arr => (arr && arr.length ? arr[0] : undefined); | |
</code></pre> | |
<pre><code class="language-js">head([1, 2, 3]); // 1 | |
head([]); // undefined | |
head(null); // undefined | |
head(undefined); // undefined | |
</code></pre> | |
<hr> | |
<h2>title: heapsort</h2> | |
<p>Sorts an array of numbers, using the heapsort algorithm.</p> | |
<ul> | |
<li>Use recursion.</li> | |
<li>Use the spread operator (<code>...</code>) to clone the original array, <code>arr</code>.</li> | |
<li>Use closures to declare a variable, <code>l</code>, and a function <code>heapify</code>.</li> | |
<li>Use a <code>for</code> loop and <code>Math.floor()</code> in combination with <code>heapify</code> to create a max heap from the array.</li> | |
<li>Use a <code>for</code> loop to repeatedly narrow down the considered range, using <code>heapify</code> and swapping values as necessary in order to sort the cloned array.</li> | |
</ul> | |
<pre><code class="language-js">const heapsort = arr => { | |
const a = [...arr]; | |
let l = a.length; | |
const heapify = (a, i) => { | |
const left = 2 * i + 1; | |
const right = 2 * i + 2; | |
let max = i; | |
if (left < l && a[left] > a[max]) max = left; | |
if (right < l && a[right] > a[max]) max = right; | |
if (max !== i) { | |
[a[max], a[i]] = [a[i], a[max]]; | |
heapify(a, max); | |
} | |
}; | |
for (let i = Math.floor(l / 2); i >= 0; i -= 1) heapify(a, i); | |
for (i = a.length - 1; i > 0; i--) { | |
[a[0], a[i]] = [a[i], a[0]]; | |
l--; | |
heapify(a, 0); | |
} | |
return a; | |
}; | |
</code></pre> | |
<pre><code class="language-js">heapsort([6, 3, 4, 1]); // [1, 3, 4, 6] | |
</code></pre> | |
<hr> | |
<h2>title: hexToRGB</h2> | |
<p>Converts a color code to an <code>rgb()</code> or <code>rgba()</code> string if alpha value is provided.</p> | |
<ul> | |
<li>Use bitwise right-shift operator and mask bits with <code>&</code> (and) operator to convert a hexadecimal color code (with or without prefixed with <code>#</code>) to a string with the RGB values.</li> | |
<li>If it’s 3-digit color code, first convert to 6-digit version.</li> | |
<li>If an alpha value is provided alongside 6-digit hex, give <code>rgba()</code> string in return.</li> | |
</ul> | |
<pre><code class="language-js">const hexToRGB = hex => { | |
let alpha = false, | |
h = hex.slice(hex.startsWith('#') ? 1 : 0); | |
if (h.length === 3) h = [...h].map(x => x + x).join(''); | |
else if (h.length === 8) alpha = true; | |
h = parseInt(h, 16); | |
return ( | |
'rgb' + | |
(alpha ? 'a' : '') + | |
'(' + | |
(h >>> (alpha ? 24 : 16)) + | |
', ' + | |
((h & (alpha ? 0x00ff0000 : 0x00ff00)) >>> (alpha ? 16 : 8)) + | |
', ' + | |
((h & (alpha ? 0x0000ff00 : 0x0000ff)) >>> (alpha ? 8 : 0)) + | |
(alpha ? `, ${h & 0x000000ff}` : '') + | |
')' | |
); | |
}; | |
</code></pre> | |
<pre><code class="language-js">hexToRGB('#27ae60ff'); // 'rgba(39, 174, 96, 255)' | |
hexToRGB('27ae60'); // 'rgb(39, 174, 96)' | |
hexToRGB('#fff'); // 'rgb(255, 255, 255)' | |
</code></pre> | |
<hr> | |
<h2>title: hide</h2> | |
<p>Hides all the elements specified.</p> | |
<ul> | |
<li>Use the spread operator (<code>...</code>) and <code>Array.prototype.forEach()</code> to apply <code>display: none</code> to each element specified.</li> | |
</ul> | |
<pre><code class="language-js">const hide = (...el) => [...el].forEach(e => (e.style.display = 'none')); | |
</code></pre> | |
<pre><code class="language-js">hide(...document.querySelectorAll('img')); // Hides all <img> elements on the page | |
</code></pre> | |
<hr> | |
<h2>title: httpDelete</h2> | |
<p>Makes a <code>DELETE</code> request to the passed URL.</p> | |
<ul> | |
<li>Use the <code>XMLHttpRequest</code> web API to make a <code>DELETE</code> request to the given <code>url</code>.</li> | |
<li>Handle the <code>onload</code> event, by running the provided <code>callback</code> function.</li> | |
<li>Handle the <code>onerror</code> event, by running the provided <code>err</code> function.</li> | |
<li>Omit the third argument, <code>err</code> to log the request to the console’s error stream by default.</li> | |
</ul> | |
<pre><code class="language-js">const httpDelete = (url, callback, err = console.error) => { | |
const request = new XMLHttpRequest(); | |
request.open('DELETE', url, true); | |
request.onload = () => callback(request); | |
request.onerror = () => err(request); | |
request.send(); | |
}; | |
</code></pre> | |
<pre><code class="language-js">httpDelete('https://jsonplaceholder.typicode.com/posts/1', request => { | |
console.log(request.responseText); | |
}); // Logs: {} | |
</code></pre> | |
<hr> | |
<h2>title: httpGet</h2> | |
<p>Makes a <code>GET</code> request to the passed URL.</p> | |
<ul> | |
<li>Use the <code>XMLHttpRequest</code> web API to make a <code>GET</code> request to the given <code>url</code>.</li> | |
<li>Handle the <code>onload</code> event, by calling the given <code>callback</code> the <code>responseText</code>.</li> | |
<li>Handle the <code>onerror</code> event, by running the provided <code>err</code> function.</li> | |
<li>Omit the third argument, <code>err</code>, to log errors to the console’s <code>error</code> stream by default.</li> | |
</ul> | |
<pre><code class="language-js">const httpGet = (url, callback, err = console.error) => { | |
const request = new XMLHttpRequest(); | |
request.open('GET', url, true); | |
request.onload = () => callback(request.responseText); | |
request.onerror = () => err(request); | |
request.send(); | |
}; | |
</code></pre> | |
<pre><code class="language-js">httpGet( | |
'https://jsonplaceholder.typicode.com/posts/1', | |
console.log | |
); /* | |
Logs: { | |
"userId": 1, | |
"id": 1, | |
"title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit", | |
"body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto" | |
} | |
*/ | |
</code></pre> | |
<hr> | |
<h2>title: httpPost</h2> | |
<p>Makes a <code>POST</code> request to the passed URL.</p> | |
<ul> | |
<li>Use the <code>XMLHttpRequest</code> web API to make a <code>POST</code> request to the given <code>url</code>.</li> | |
<li>Set the value of an <code>HTTP</code> request header with <code>setRequestHeader</code> method.</li> | |
<li>Handle the <code>onload</code> event, by calling the given <code>callback</code> the <code>responseText</code>.</li> | |
<li>Handle the <code>onerror</code> event, by running the provided <code>err</code> function.</li> | |
<li>Omit the fourth argument, <code>err</code>, to log errors to the console’s <code>error</code> stream by default.</li> | |
</ul> | |
<pre><code class="language-js">const httpPost = (url, data, callback, err = console.error) => { | |
const request = new XMLHttpRequest(); | |
request.open('POST', url, true); | |
request.setRequestHeader('Content-type', 'application/json; charset=utf-8'); | |
request.onload = () => callback(request.responseText); | |
request.onerror = () => err(request); | |
request.send(data); | |
}; | |
</code></pre> | |
<pre><code class="language-js">const newPost = { | |
userId: 1, | |
id: 1337, | |
title: 'Foo', | |
body: 'bar bar bar' | |
}; | |
const data = JSON.stringify(newPost); | |
httpPost( | |
'https://jsonplaceholder.typicode.com/posts', | |
data, | |
console.log | |
); /* | |
Logs: { | |
"userId": 1, | |
"id": 1337, | |
"title": "Foo", | |
"body": "bar bar bar" | |
} | |
*/ | |
httpPost( | |
'https://jsonplaceholder.typicode.com/posts', | |
null, // does not send a body | |
console.log | |
); /* | |
Logs: { | |
"id": 101 | |
} | |
*/ | |
</code></pre> | |
<hr> | |
<h2>title: httpPut</h2> | |
<p>Makes a <code>PUT</code> request to the passed URL.</p> | |
<ul> | |
<li>Use <code>XMLHttpRequest</code> web api to make a <code>PUT</code> request to the given <code>url</code>.</li> | |
<li>Set the value of an <code>HTTP</code> request header with <code>setRequestHeader</code> method.</li> | |
<li>Handle the <code>onload</code> event, by running the provided <code>callback</code> function.</li> | |
<li>Handle the <code>onerror</code> event, by running the provided <code>err</code> function.</li> | |
<li>Omit the last argument, <code>err</code> to log the request to the console’s error stream by default.</li> | |
</ul> | |
<pre><code class="language-js">const httpPut = (url, data, callback, err = console.error) => { | |
const request = new XMLHttpRequest(); | |
request.open('PUT', url, true); | |
request.setRequestHeader('Content-type', 'application/json; charset=utf-8'); | |
request.onload = () => callback(request); | |
request.onerror = () => err(request); | |
request.send(data); | |
}; | |
</code></pre> | |
<pre><code class="language-js">const password = 'fooBaz'; | |
const data = JSON.stringify({ | |
id: 1, | |
title: 'foo', | |
body: 'bar', | |
userId: 1 | |
}); | |
httpPut('https://jsonplaceholder.typicode.com/posts/1', data, request => { | |
console.log(request.responseText); | |
}); /* | |
Logs: { | |
id: 1, | |
title: 'foo', | |
body: 'bar', | |
userId: 1 | |
} | |
*/ | |
</code></pre> | |
<hr> | |
<h2>title: httpsRedirect</h2> | |
<p>Redirects the page to HTTPS if it’s currently in HTTP.</p> | |
<ul> | |
<li>Use <code>location.protocol</code> to get the protocol currently being used.</li> | |
<li>If it’s not HTTPS, use <code>location.replace()</code> to replace the existing page with the HTTPS version of the page.</li> | |
<li>Use <code>location.href</code> to get the full address, split it with <code>String.prototype.split()</code> and remove the protocol part of the URL.</li> | |
<li>Note that pressing the back button doesn’t take it back to the HTTP page as its replaced in the history.</li> | |
</ul> | |
<pre><code class="language-js">const httpsRedirect = () => { | |
if (location.protocol !== 'https:') | |
location.replace('https://' + location.href.split('//')[1]); | |
}; | |
</code></pre> | |
<pre><code class="language-js">httpsRedirect(); | |
// If you are on http://mydomain.com, you are redirected to https://mydomain.com | |
</code></pre> | |
<hr> | |
<h2>title: hz | |
unlisted: true</h2> | |
<p>Measures the number of times a function is executed per second (<code>hz</code>/<code>hertz</code>).</p> | |
<ul> | |
<li>Use <code>performance.now()</code> to get the difference in milliseconds before and after the iteration loop to calculate the time elapsed executing the function <code>iterations</code> times.</li> | |
<li>Return the number of cycles per second by converting milliseconds to seconds and dividing it by the time elapsed.</li> | |
<li>Omit the second argument, <code>iterations</code>, to use the default of 100 iterations.</li> | |
</ul> | |
<pre><code class="language-js">const hz = (fn, iterations = 100) => { | |
const before = performance.now(); | |
for (let i = 0; i < iterations; i++) fn(); | |
return (1000 * iterations) / (performance.now() - before); | |
}; | |
</code></pre> | |
<pre><code class="language-js">const numbers = Array(10000).fill().map((_, i) => i); | |
const sumReduce = () => numbers.reduce((acc, n) => acc + n, 0); | |
const sumForLoop = () => { | |
let sum = 0; | |
for (let i = 0; i < numbers.length; i++) sum += numbers[i]; | |
return sum; | |
}; | |
Math.round(hz(sumReduce)); // 572 | |
Math.round(hz(sumForLoop)); // 4784 | |
</code></pre> | |
<hr> | |
<h2>title: inRange</h2> | |
<p>Checks if the given number falls within the given range.</p> | |
<ul> | |
<li>Use arithmetic comparison to check if the given number is in the specified range.</li> | |
<li>If the second argument, <code>end</code>, is not specified, the range is considered to be from <code>0</code> to <code>start</code>.</li> | |
</ul> | |
<pre><code class="language-js">const inRange = (n, start, end = null) => { | |
if (end && start > end) [end, start] = [start, end]; | |
return end == null ? n >= 0 && n < start : n >= start && n < end; | |
}; | |
</code></pre> | |
<pre><code class="language-js">inRange(3, 2, 5); // true | |
inRange(3, 4); // true | |
inRange(2, 3, 5); // false | |
inRange(3, 2); // false | |
</code></pre> | |
<hr> | |
<h2>title: includesAll</h2> | |
<p>Checks if all the elements in <code>values</code> are included in <code>arr</code>.</p> | |
<ul> | |
<li>Use <code>Array.prototype.every()</code> and <code>Array.prototype.includes()</code> to check if all elements of <code>values</code> are included in <code>arr</code>.</li> | |
</ul> | |
<pre><code class="language-js">const includesAll = (arr, values) => values.every(v => arr.includes(v)); | |
</code></pre> | |
<pre><code class="language-js">includesAll([1, 2, 3, 4], [1, 4]); // true | |
includesAll([1, 2, 3, 4], [1, 5]); // false | |
</code></pre> | |
<hr> | |
<h2>title: includesAny</h2> | |
<p>Checks if at least one element of <code>values</code> is included in <code>arr</code>.</p> | |
<ul> | |
<li>Use <code>Array.prototype.some()</code> and <code>Array.prototype.includes()</code> to check if at least one element of <code>values</code> is included in <code>arr</code>.</li> | |
</ul> | |
<pre><code class="language-js">const includesAny = (arr, values) => values.some(v => arr.includes(v)); | |
</code></pre> | |
<pre><code class="language-js">includesAny([1, 2, 3, 4], [2, 9]); // true | |
includesAny([1, 2, 3, 4], [8, 9]); // false | |
</code></pre> | |
<hr> | |
<h2>title: indentString</h2> | |
<p>Indents each line in the provided string.</p> | |
<ul> | |
<li>Use <code>String.prototype.replace()</code> and a regular expression to add the character specified by <code>indent</code> <code>count</code> times at the start of each line.</li> | |
<li>Omit the third argument, <code>indent</code>, to use a default indentation character of <code>' '</code>.</li> | |
</ul> | |
<pre><code class="language-js">const indentString = (str, count, indent = ' ') => | |
str.replace(/^/gm, indent.repeat(count)); | |
</code></pre> | |
<pre><code class="language-js">indentString('Lorem\nIpsum', 2); // ' Lorem\n Ipsum' | |
indentString('Lorem\nIpsum', 2, '_'); // '__Lorem\n__Ipsum' | |
</code></pre> | |
<hr> | |
<h2>title: indexBy</h2> | |
<p>Creates an object from an array, using a function to map each value to a key.</p> | |
<ul> | |
<li>Use <code>Array.prototype.reduce()</code> to create an object from <code>arr</code>.</li> | |
<li>Apply <code>fn</code> to each value of <code>arr</code> to produce a key and add the key-value pair to the object.</li> | |
</ul> | |
<pre><code class="language-js">const indexBy = (arr, fn) => | |
arr.reduce((obj, v, i) => { | |
obj[fn(v, i, arr)] = v; | |
return obj; | |
}, {}); | |
</code></pre> | |
<pre><code class="language-js">indexBy([ | |
{ id: 10, name: 'apple' }, | |
{ id: 20, name: 'orange' } | |
], x => x.id); | |
// { '10': { id: 10, name: 'apple' }, '20': { id: 20, name: 'orange' } } | |
</code></pre> | |
</div> | |
</div><!-- .entry-content --> | |
<footer class="entry-footer responsive-max-width"> | |
<span class="byline"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><span class="screen-reader-text">Posted by</span><span class="author vcard"><a class="url fn n" href="https://web-dev-hub.com/author/gunerb1/">bgoonz</a></span></span><span class="posted-on"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><defs><path id="a" d="M0 0h24v24H0V0z"></path></defs><clipPath id="b"><use xlink:href="#a" overflow="visible"></use></clipPath><path clip-path="url(#b)" d="M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10 10-4.5 10-10S17.5 2 12 2zm4.2 14.2L11 13V7h1.5v5.2l4.5 2.7-.8 1.3z"></path></svg><a href="https://web-dev-hub.com/2021/12/25/javascript-snippets/" rel="bookmark"><time class="entry-date published updated" datetime="2021-12-25T00:35:25-05:00">December 25, 2021</time></a></span><span class="cat-links"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M10 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2h-8l-2-2z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><span class="screen-reader-text">Posted in</span><a href="https://web-dev-hub.com/category/uncategorized/" rel="category tag">Uncategorized</a></span><span class="comments-link"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M21.99 4c0-1.1-.89-2-1.99-2H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h14l4 4-.01-18z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><a href="https://web-dev-hub.com/2021/12/25/javascript-snippets/#respond">Leave a comment<span class="screen-reader-text"> on JavaScript Snippets</span></a></span><span class="edit-link"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04c.39-.39.39-1.02 0-1.41l-2.34-2.34c-.39-.39-1.02-.39-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><a class="post-edit-link" href="https://wordpress.com/post/web-dev-hub.com/1050">Edit <span class="screen-reader-text">JavaScript Snippets</span></a></span> </footer><!-- .entry-footer --> | |
</article><!-- #post-${ID} --> | |
<article id="post-1048" class="post-1048 post type-post status-publish format-standard hentry category-uncategorized entry"> | |
<header class="entry-header responsive-max-width"> | |
<h2 class="entry-title"><a href="https://web-dev-hub.com/2021/12/25/node-best-practices/" rel="bookmark">Node Best Practices</a></h2> </header><!-- .entry-header --> | |
<div class="entry-content"> | |
<p></p> | |
<h1 id="1-project-structure-practices"><code>1. Project Structure Practices</code></h1> | |
<h2 id="1-1-structure-your-solution-by-components"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-11-structure-your-solution-by-components"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 1.1 Structure your solution by components</h2> | |
<p><strong>TL;DR:</strong> The worst large applications pitfall is maintaining a huge code base with hundreds of dependencies – such a monolith slows down developers as they try to incorporate new features. Instead, partition your code into components, each gets its folder or a dedicated codebase, and ensure that each unit is kept small and simple. Visit ‘Read More’ below to see examples of correct project structure</p> | |
<p><strong>Otherwise:</strong> When developers who code new features struggle to realize the impact of their change and fear to break other dependent components – deployments become slower and riskier. It’s also considered harder to scale-out when all the business units are not separated</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/projectstructre/breakintcomponents.md"><strong>Read More: structure by components</strong></a></p> | |
<h2 id="1-2-layer-your-components-keep-the-web-layer-within-its-boundaries"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-12-layer-your-components-keep-the-web-layer-within-its-boundaries"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 1.2 Layer your components, keep the web layer within its boundaries</h2> | |
<p><strong>TL;DR:</strong> Each component should contain ‘layers’ – a dedicated object for the web, logic, and data access code. This not only draws a clean separation of concerns but also significantly eases mocking and testing the system. Though this is a very common pattern, API developers tend to mix layers by passing the web layer objects (e.g. Express req, res) to business logic and data layers – this makes your application dependent on and accessible only by specific web frameworks</p> | |
<p><strong>Otherwise:</strong> App that mixes web objects with other layers cannot be accessed by testing code, CRON jobs, triggers from message queues, etc</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/projectstructre/createlayers.md"><strong>Read More: layer your app</strong></a></p> | |
<h2 id="1-3-wrap-common-utilities-as-npm-packages"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-13-wrap-common-utilities-as-npm-packages"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 1.3 Wrap common utilities as npm packages</h2> | |
<p><strong>TL;DR:</strong> In a large app that constitutes a large codebase, cross-cutting-concern utilities like a logger, encryption and alike, should be wrapped by your code and exposed as private npm packages. This allows sharing them among multiple codebases and projects</p> | |
<p><strong>Otherwise:</strong> You’ll have to invent your deployment and the dependency wheel</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/projectstructre/wraputilities.md"><strong>Read More: Structure by feature</strong></a></p> | |
<h2 id="1-4-separate-express-app-and-server"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-14-separate-express-app-and-server"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 1.4 Separate Express ‘app’ and ‘server’</h2> | |
<p><strong>TL;DR:</strong> Avoid the nasty habit of defining the entire <a href="https://expressjs.com/">Express</a> app in a single huge file – separate your ‘Express’ definition to at least two files: the API declaration (app.js) and the networking concerns (WWW). For even better structure, locate your API declaration within components</p> | |
<p><strong>Otherwise:</strong> Your API will be accessible for testing via HTTP calls only (slower and much harder to generate coverage reports). It probably won’t be a big pleasure to maintain hundreds of lines of code in a single file</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/projectstructre/separateexpress.md"><strong>Read More: separate Express ‘app’ and ‘server’</strong></a></p> | |
<h2 id="1-5-use-environment-aware-secure-and-hierarchical-config"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-15-use-environment-aware-secure-and-hierarchical-config"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 1.5 Use environment aware, secure and hierarchical config</h2> | |
<p><strong>TL;DR:</strong> A perfect and flawless configuration setup should ensure (a) keys can be read from file AND from environment variable (b) secrets are kept outside committed code (c) config is hierarchical for easier findability. There are a few packages that can help tick most of those boxes like <a href="https://www.npmjs.com/package/rc">rc</a>, <a href="https://www.npmjs.com/package/nconf">nconf</a>, <a href="https://www.npmjs.com/package/config">config</a>, and <a href="https://www.npmjs.com/package/convict">convict</a>.</p> | |
<p><strong>Otherwise:</strong> Failing to satisfy any of the config requirements will simply bog down the development or DevOps team. Probably both</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/projectstructre/configguide.md"><strong>Read More: configuration best practices</strong></a></p> | |
<p><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#table-of-contents">⬆ Return to top</a></p> | |
<h1 id="2-error-handling-practices"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#2-error-handling-practices"></a><code>2. Error Handling Practices</code></h1> | |
<h2 id="2-1-use-async-await-or-promises-for-async-error-handling"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-21-use-async-await-or-promises-for-async-error-handling"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 2.1 Use Async-Await or promises for async error handling</h2> | |
<p><strong>TL;DR:</strong> Handling async errors in callback style is probably the fastest way to hell (a.k.a the pyramid of doom). The best gift you can give to your code is using a reputable promise library or async-await instead which enables a much more compact and familiar code syntax like try-catch</p> | |
<p><strong>Otherwise:</strong> Node.js callback style, function(err, response), is a promising way to un-maintainable code due to the mix of error handling with casual code, excessive nesting, and awkward coding patterns</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/errorhandling/asyncerrorhandling.md"><strong>Read More: avoiding callbacks</strong></a></p> | |
<h2 id="2-2-use-only-the-built-in-error-object"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-22-use-only-the-built-in-error-object"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 2.2 Use only the built-in Error object</h2> | |
<p><strong>TL;DR:</strong> Many throw errors as a string or as some custom type – this complicates the error handling logic and the interoperability between modules. Whether you reject a promise, throw an exception or emit an error – using only the built-in Error object (or an object that extends the built-in Error object) will increase uniformity and prevent loss of information. There is <code>no-throw-literal</code> ESLint rule that strictly checks that (although it have some <a href="https://eslint.org/docs/rules/no-throw-literal">limitations</a> which can be solved when using TypeScript and setting the <code>@typescript-eslint/no-throw-literal</code> rule)</p> | |
<p><strong>Otherwise:</strong> When invoking some component, being uncertain which type of errors come in return – it makes proper error handling much harder. Even worse, using custom types to describe errors might lead to loss of critical error information like the stack trace!</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/errorhandling/useonlythebuiltinerror.md"><strong>Read More: using the built-in error object</strong></a></p> | |
<h2 id="2-3-distinguish-operational-vs-programmer-errors"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-23-distinguish-operational-vs-programmer-errors"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 2.3 Distinguish operational vs programmer errors</h2> | |
<p><strong>TL;DR:</strong> Operational errors (e.g. API received an invalid input) refer to known cases where the error impact is fully understood and can be handled thoughtfully. On the other hand, programmer error (e.g. trying to read an undefined variable) refers to unknown code failures that dictate to gracefully restart the application</p> | |
<p><strong>Otherwise:</strong> You may always restart the application when an error appears, but why let ~5000 online users down because of a minor, predicted, operational error? the opposite is also not ideal – keeping the application up when an unknown issue (programmer error) occurred might lead to an unpredicted behavior. Differentiating the two allows acting tactfully and applying a balanced approach based on the given context</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/errorhandling/operationalvsprogrammererror.md"><strong>Read More: operational vs programmer error</strong></a></p> | |
<h2 id="2-4-handle-errors-centrally-not-within-a-middleware"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-24-handle-errors-centrally-not-within-a-middleware"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 2.4 Handle errors centrally, not within a middleware</h2> | |
<p><strong>TL;DR:</strong> Error handling logic such as mail to admin and logging should be encapsulated in a dedicated and centralized object that all endpoints (e.g. Express middleware, cron jobs, unit-testing) call when an error comes in</p> | |
<p><strong>Otherwise:</strong> Not handling errors within a single place will lead to code duplication and probably to improperly handled errors</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/errorhandling/centralizedhandling.md"><strong>Read More: handling errors in a centralized place</strong></a></p> | |
<h2 id="2-5-document-api-errors-using-swagger-or-graphql"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-25-document-api-errors-using-swagger-or-graphql"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 2.5 Document API errors using Swagger or GraphQL</h2> | |
<p><strong>TL;DR:</strong> Let your API callers know which errors might come in return so they can handle these thoughtfully without crashing. For RESTful APIs, this is usually done with documentation frameworks like Swagger. If you’re using GraphQL, you can utilize your schema and comments as well.</p> | |
<p><strong>Otherwise:</strong> An API client might decide to crash and restart only because it received back an error it couldn’t understand. Note: the caller of your API might be you (very typical in a microservice environment)</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/errorhandling/documentingusingswagger.md"><strong>Read More: documenting API errors in Swagger or GraphQL</strong></a></p> | |
<h2 id="2-6-exit-the-process-gracefully-when-a-stranger-comes-to-town"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-26-exit-the-process-gracefully-when-a-stranger-comes-to-town"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 2.6 Exit the process gracefully when a stranger comes to town</h2> | |
<p><strong>TL;DR:</strong> When an unknown error occurs (a developer error, see best practice 2.3) – there is uncertainty about the application healthiness. Common practice suggests restarting the process carefully using a process management tool like <a href="https://www.npmjs.com/package/forever">Forever</a> or <a href="http://pm2.keymetrics.io/">PM2</a></p> | |
<p><strong>Otherwise:</strong> When an unfamiliar exception occurs, some object might be in a faulty state (e.g. an event emitter which is used globally and not firing events anymore due to some internal failure) and all future requests might fail or behave crazily</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/errorhandling/shuttingtheprocess.md"><strong>Read More: shutting the process</strong></a></p> | |
<h2 id="2-7-use-a-mature-logger-to-increase-error-visibility"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-27-use-a-mature-logger-to-increase-error-visibility"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 2.7 Use a mature logger to increase error visibility</h2> | |
<p><strong>TL;DR:</strong> A set of mature logging tools like <a href="https://github.com/pinojs/pino">Pino</a> or <a href="https://www.npmjs.com/package/log4js">Log4js</a>, will speed-up error discovery and understanding. So forget about console.log</p> | |
<p><strong>Otherwise:</strong> Skimming through console.logs or manually through messy text file without querying tools or a decent log viewer might keep you busy at work until late</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/errorhandling/usematurelogger.md"><strong>Read More: using a mature logger</strong></a></p> | |
<h2 id="2-8-test-error-flows-using-your-favorite-test-framework"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-28-test-error-flows-using-your-favorite-test-framework"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 2.8 Test error flows using your favorite test framework</h2> | |
<p><strong>TL;DR:</strong> Whether professional automated QA or plain manual developer testing – Ensure that your code not only satisfies positive scenarios but also handles and returns the right errors. Testing frameworks like Mocha & Chai can handle this easily (see code examples within the “Gist popup”)</p> | |
<p><strong>Otherwise:</strong> Without testing, whether automatically or manually, you can’t rely on your code to return the right errors. Without meaningful errors – there’s no error handling</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/errorhandling/testingerrorflows.md"><strong>Read More: testing error flows</strong></a></p> | |
<h2 id="2-9-discover-errors-and-downtime-using-apm-products"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-29-discover-errors-and-downtime-using-apm-products"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 2.9 Discover errors and downtime using APM products</h2> | |
<p><strong>TL;DR:</strong> Monitoring and performance products (a.k.a APM) proactively gauge your codebase or API so they can automagically highlight errors, crashes, and slow parts that you were missing</p> | |
<p><strong>Otherwise:</strong> You might spend great effort on measuring API performance and downtimes, probably you’ll never be aware which are your slowest code parts under real-world scenario and how these affect the UX</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/errorhandling/apmproducts.md"><strong>Read More: using APM products</strong></a></p> | |
<h2 id="2-10-catch-unhandled-promise-rejections"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-210-catch-unhandled-promise-rejections"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 2.10 Catch unhandled promise rejections</h2> | |
<p><strong>TL;DR:</strong> Any exception thrown within a promise will get swallowed and discarded unless a developer didn’t forget to explicitly handle it. Even if your code is subscribed to <code>process.uncaughtException</code>! Overcome this by registering to the event <code>process.unhandledRejection</code></p> | |
<p><strong>Otherwise:</strong> Your errors will get swallowed and leave no trace. Nothing to worry about</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/errorhandling/catchunhandledpromiserejection.md"><strong>Read More: catching unhandled promise rejection</strong></a></p> | |
<h2 id="2-11-fail-fast-validate-arguments-using-a-dedicated-library"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-211-fail-fast-validate-arguments-using-a-dedicated-library"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 2.11 Fail fast, validate arguments using a dedicated library</h2> | |
<p><strong>TL;DR:</strong> Assert API input to avoid nasty bugs that are much harder to track later. The validation code is usually tedious unless you are using a very cool helper library like <a href="https://www.npmjs.com/package/ajv">ajv</a> and <a href="https://www.npmjs.com/package/joi">Joi</a></p> | |
<p><strong>Otherwise:</strong> Consider this – your function expects a numeric argument “Discount” which the caller forgets to pass, later on, your code checks if Discount!=0 (amount of allowed discount is greater than zero), then it will allow the user to enjoy a discount. OMG, what a nasty bug. Can you see it?</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/errorhandling/failfast.md"><strong>Read More: failing fast</strong></a></p> | |
<h2 id="2-12-always-await-promises-before-returning-to-avoid-a-partial-stacktrace"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-212-always-await-promises-before-returning-to-avoid-a-partial-stacktrace"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 2.12 Always await promises before returning to avoid a partial stacktrace</h2> | |
<p><strong>TL;DR:</strong> Always do <code>return await</code> when returning a promise to benefit full error stacktrace. If a function returns a promise, that function must be declared as <code>async</code> function and explicitly <code>await</code> the promise before returning it</p> | |
<p><strong>Otherwise:</strong> The function that returns a promise without awaiting won’t appear in the stacktrace. Such missing frames would probably complicate the understanding of the flow that leads to the error, especially if the cause of the abnormal behavior is inside of the missing function</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/errorhandling/returningpromises.md"><strong>Read More: returning promises</strong></a></p> | |
<p><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#table-of-contents">⬆ Return to top</a></p> | |
<h1 id="3-code-style-practices"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#3-code-style-practices"></a><code>3. Code Style Practices</code></h1> | |
<h2 id="3-1-use-eslint"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-31-use-eslint"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 3.1 Use ESLint</h2> | |
<p><strong>TL;DR:</strong> <a href="https://eslint.org/">ESLint</a> is the de-facto standard for checking possible code errors and fixing code style, not only to identify nitty-gritty spacing issues but also to detect serious code anti-patterns like developers throwing errors without classification. Though ESLint can automatically fix code styles, other tools like <a href="https://www.npmjs.com/package/prettier">prettier</a> and <a href="https://www.npmjs.com/package/js-beautify">beautify</a> are more powerful in formatting the fix and work in conjunction with ESLint</p> | |
<p><strong>Otherwise:</strong> Developers will focus on tedious spacing and line-width concerns and time might be wasted overthinking the project’s code style</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/codestylepractices/eslint_prettier.md"><strong>Read More: Using ESLint and Prettier</strong></a></p> | |
<h2 id="3-2-node-js-specific-plugins"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-32-nodejs-specific-plugins"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 3.2 Node.js specific plugins</h2> | |
<p><strong>TL;DR:</strong> On top of ESLint standard rules that cover vanilla JavaScript, add Node.js specific plugins like <a href="https://www.npmjs.com/package/eslint-plugin-node">eslint-plugin-node</a>, <a href="https://www.npmjs.com/package/eslint-plugin-mocha">eslint-plugin-mocha</a> and <a href="https://www.npmjs.com/package/eslint-plugin-security">eslint-plugin-node-security</a></p> | |
<p><strong>Otherwise:</strong> Many faulty Node.js code patterns might escape under the radar. For example, developers might require(variableAsPath) files with a variable given as a path which allows attackers to execute any JS script. Node.js linters can detect such patterns and complain early</p> | |
<h2 id="3-3-start-a-codeblock-s-curly-braces-on-the-same-line"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-33-start-a-codeblocks-curly-braces-on-the-same-line"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 3.3 Start a Codeblock’s Curly Braces on the Same Line</h2> | |
<p><strong>TL;DR:</strong> The opening curly braces of a code block should be on the same line as the opening statement</p> | |
<h3 id="code-example"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#code-example"></a>Code Example</h3> | |
<pre class="wp-block-preformatted">// Do | |
function someFunction() { | |
// code block | |
} | |
// Avoid | |
function someFunction() | |
{ | |
// code block | |
}</pre> | |
<p><strong>Otherwise:</strong> Deferring from this best practice might lead to unexpected results, as seen in the StackOverflow thread below:</p> | |
<p>🔗 <a href="https://stackoverflow.com/questions/3641519/why-does-a-results-vary-based-on-curly-brace-placement"><strong>Read more:</strong> “Why do results vary based on curly brace placement?” (StackOverflow)</a></p> | |
<h2 id="3-4-separate-your-statements-properly"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-34-separate-your-statements-properly"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 3.4 Separate your statements properly</h2> | |
<p>No matter if you use semicolons or not to separate your statements, knowing the common pitfalls of improper linebreaks or automatic semicolon insertion, will help you to eliminate regular syntax errors.</p> | |
<p><strong>TL;DR:</strong> Use ESLint to gain awareness about separation concerns. <a href="https://prettier.io/">Prettier</a> or <a href="https://standardjs.com/">Standardjs</a> can automatically resolve these issues.</p> | |
<p><strong>Otherwise:</strong> As seen in the previous section, JavaScript’s interpreter automatically adds a semicolon at the end of a statement if there isn’t one, or considers a statement as not ended where it should, which might lead to some undesired results. You can use assignments and avoid using immediately invoked function expressions to prevent most of the unexpected errors.</p> | |
<h3 id="code-example"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#code-example-1"></a>Code example</h3> | |
<pre class="wp-block-preformatted">// Do | |
function doThing() { | |
// ... | |
} | |
doThing() | |
// Do | |
const items = [1, 2, 3] | |
items.forEach(console.log) | |
// Avoid — throws exception | |
const m = new Map() | |
const a = [1,2,3] | |
[...m.values()].forEach(console.log) | |
> [...m.values()].forEach(console.log) | |
> ^^^ | |
> SyntaxError: Unexpected token ... | |
// Avoid — throws exception | |
const count = 2 // it tries to run 2(), but 2 is not a function | |
(function doSomething() { | |
// do something amazing | |
}()) | |
// put a semicolon before the immediate invoked function, after the const definition, save the return value of the anonymous function to a variable or avoid IIFEs altogether</pre> | |
<p>🔗 <a href="https://eslint.org/docs/rules/semi"><strong>Read more:</strong> “Semi ESLint rule”</a> 🔗 <a href="https://eslint.org/docs/rules/no-unexpected-multiline"><strong>Read more:</strong> “No unexpected multiline ESLint rule”</a></p> | |
<h2 id="3-5-name-your-functions"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-35-name-your-functions"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 3.5 Name your functions</h2> | |
<p><strong>TL;DR:</strong> Name all functions, including closures and callbacks. Avoid anonymous functions. This is especially useful when profiling a node app. Naming all functions will allow you to easily understand what you’re looking at when checking a memory snapshot</p> | |
<p><strong>Otherwise:</strong> Debugging production issues using a core dump (memory snapshot) might become challenging as you notice significant memory consumption from anonymous functions</p> | |
<h2 id="3-6-use-naming-conventions-for-variables-constants-functions-and-classes"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-36-use-naming-conventions-for-variables-constants-functions-and-classes"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 3.6 Use naming conventions for variables, constants, functions and classes</h2> | |
<p><strong>TL;DR:</strong> Use <strong><em>lowerCamelCase</em></strong> when naming constants, variables and functions, <strong><em>UpperCamelCase</em></strong> (capital first letter as well) when naming classes and <strong><em>UPPER_SNAKE_CASE</em></strong> when naming global or static variables. This will help you to easily distinguish between plain variables, functions, classes that require instantiation and variables declared at global module scope. Use descriptive names, but try to keep them short</p> | |
<p><strong>Otherwise:</strong> JavaScript is the only language in the world that allows invoking a constructor (“Class”) directly without instantiating it first. Consequently, Classes and function-constructors are differentiated by starting with UpperCamelCase</p> | |
<h3 id="3-6-code-example"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#36-code-example"></a>3.6 Code Example</h3> | |
<pre class="wp-block-preformatted">// for global variables names we use the const/let keyword and UPPER_SNAKE_CASE | |
let MUTABLE_GLOBAL = "mutable value" | |
const GLOBAL_CONSTANT = "immutable value"; | |
const CONFIG = { | |
key: "value", | |
}; | |
// examples of UPPER_SNAKE_CASE convetion in nodejs/javascript ecosystem | |
// in javascript Math.PI module | |
const PI = 3.141592653589793; | |
// https://github.com/nodejs/node/blob/b9f36062d7b5c5039498e98d2f2c180dca2a7065/lib/internal/http2/core.js#L303 | |
// in nodejs http2 module | |
const HTTP_STATUS_OK = 200; | |
const HTTP_STATUS_CREATED = 201; | |
// for class name we use UpperCamelCase | |
class SomeClassExample { | |
// for static class properties we use UPPER_SNAKE_CASE | |
static STATIC_PROPERTY = "value"; | |
} | |
// for functions names we use lowerCamelCase | |
function doSomething() { | |
// for scoped variable names we use the const/let keyword and lowerCamelCase | |
const someConstExample = "immutable value"; | |
let someMutableExample = "mutable value"; | |
}</pre> | |
<h2 id="3-7-prefer-const-over-let-ditch-the-var"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-37-prefer-const-over-let-ditch-the-var"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 3.7 Prefer const over let. Ditch the var</h2> | |
<p><strong>TL;DR:</strong> Using <code>const</code> means that once a variable is assigned, it cannot be reassigned. Preferring <code>const</code> will help you to not be tempted to use the same variable for different uses, and make your code clearer. If a variable needs to be reassigned, in a for loop, for example, use <code>let</code> to declare it. Another important aspect of <code>let</code> is that a variable declared using it is only available in the block scope in which it was defined. <code>var</code> is function scoped, not block-scoped, and <a href="https://hackernoon.com/why-you-shouldnt-use-var-anymore-f109a58b9b70">shouldn’t be used in ES6</a> now that you have <code>const</code> and <code>let</code> at your disposal</p> | |
<p><strong>Otherwise:</strong> Debugging becomes way more cumbersome when following a variable that frequently changes</p> | |
<p>🔗 <a href="https://medium.com/javascript-scene/javascript-es6-var-let-or-const-ba58b8dcde75"><strong>Read more: JavaScript ES6+: var, let, or const?</strong></a></p> | |
<h2 id="3-8-require-modules-first-not-inside-functions"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-38-require-modules-first-not-inside-functions"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 3.8 Require modules first, not inside functions</h2> | |
<p><strong>TL;DR:</strong> Require modules at the beginning of each file, before and outside of any functions. This simple best practice will not only help you easily and quickly tell the dependencies of a file right at the top but also avoids a couple of potential problems</p> | |
<p><strong>Otherwise:</strong> Requires are run synchronously by Node.js. If they are called from within a function, it may block other requests from being handled at a more critical time. Also, if a required module or any of its dependencies throw an error and crash the server, it is best to find out about it as soon as possible, which might not be the case if that module is required from within a function</p> | |
<h2 id="3-9-require-modules-by-folders-as-opposed-to-the-files-directly"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-39-require-modules-by-folders-as-opposed-to-the-files-directly"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 3.9 Require modules by folders, as opposed to the files directly</h2> | |
<p><strong>TL;DR:</strong> When developing a module/library in a folder, place an index.js file that exposes the module’s internals so every consumer will pass through it. This serves as an ‘interface’ to your module and eases future changes without breaking the contract</p> | |
<p><strong>Otherwise:</strong> Changing the internal structure of files or the signature may break the interface with clients</p> | |
<h3 id="3-9-code-example"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#39-code-example"></a>3.9 Code example</h3> | |
<pre class="wp-block-preformatted">// Do | |
module.exports.SMSProvider = require("./SMSProvider"); | |
module.exports.SMSNumberResolver = require("./SMSNumberResolver"); | |
// Avoid | |
module.exports.SMSProvider = require("./SMSProvider/SMSProvider.js"); | |
module.exports.SMSNumberResolver = require("./SMSNumberResolver/SMSNumberResolver.js");</pre> | |
<h2 id="3-10-use-the-operator"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-310-use-the--operator"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 3.10 Use the <code>===</code> operator</h2> | |
<p><strong>TL;DR:</strong> Prefer the strict equality operator <code>===</code> over the weaker abstract equality operator <code>==</code>. <code>==</code> will compare two variables after converting them to a common type. There is no type conversion in <code>===</code>, and both variables must be of the same type to be equal</p> | |
<p><strong>Otherwise:</strong> Unequal variables might return true when compared with the <code>==</code> operator</p> | |
<h3 id="3-10-code-example"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#310-code-example"></a>3.10 Code example</h3> | |
<pre class="wp-block-preformatted">"" == "0"; // false | |
0 == ""; // true | |
0 == "0"; // true | |
false == "false"; // false | |
false == "0"; // true | |
false == undefined; // false | |
false == null; // false | |
null == undefined; // true | |
" \t\r\n " == 0; // true</pre> | |
<p>All statements above will return false if used with <code>===</code></p> | |
<h2 id="3-11-use-async-await-avoid-callbacks"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-311-use-async-await-avoid-callbacks"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 3.11 Use Async Await, avoid callbacks</h2> | |
<p><strong>TL;DR:</strong> Node 8 LTS now has full support for Async-await. This is a new way of dealing with asynchronous code which supersedes callbacks and promises. Async-await is non-blocking, and it makes asynchronous code look synchronous. The best gift you can give to your code is using async-await which provides a much more compact and familiar code syntax like try-catch</p> | |
<p><strong>Otherwise:</strong> Handling async errors in callback style are probably the fastest way to hell – this style forces to check errors all over, deal with awkward code nesting, and makes it difficult to reason about the code flow</p> | |
<p>🔗<a href="https://github.com/yortus/asyncawait"><strong>Read more:</strong> Guide to async-await 1.0</a></p> | |
<h2 id="3-12-use-arrow-function-expressions"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-312-use-arrow-function-expressions-"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 3.12 Use arrow function expressions (=>)</h2> | |
<p><strong>TL;DR:</strong> Though it’s recommended to use async-await and avoid function parameters when dealing with older APIs that accept promises or callbacks – arrow functions make the code structure more compact and keep the lexical context of the root function (i.e. <code>this</code>)</p> | |
<p><strong>Otherwise:</strong> Longer code (in ES5 functions) is more prone to bugs and cumbersome to read</p> | |
<p>🔗 <a href="https://medium.com/javascript-scene/familiarity-bias-is-holding-you-back-its-time-to-embrace-arrow-functions-3d37e1a9bb75"><strong>Read more: It’s Time to Embrace Arrow Functions</strong></a></p> | |
<p><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#table-of-contents">⬆ Return to top</a></p> | |
<h1 id="4-testing-and-overall-quality-practices"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#4-testing-and-overall-quality-practices"></a><code>4. Testing And Overall Quality Practices</code></h1> | |
<h2 id="4-1-at-the-very-least-write-api-component-testing"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-41-at-the-very-least-write-api-component-testing"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 4.1 At the very least, write API (component) testing</h2> | |
<p><strong>TL;DR:</strong> Most projects just don’t have any automated testing due to short timetables or often the ‘testing project’ ran out of control and was abandoned. For that reason, prioritize and start with API testing which is the easiest way to write and provides more coverage than unit testing (you may even craft API tests without code using tools like <a href="https://www.getpostman.com/">Postman</a>). Afterward, should you have more resources and time, continue with advanced test types like unit testing, DB testing, performance testing, etc</p> | |
<p><strong>Otherwise:</strong> You may spend long days on writing unit tests to find out that you got only 20% system coverage</p> | |
<h2 id="4-2-include-3-parts-in-each-test-name"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-42-include-3-parts-in-each-test-name"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 4.2 Include 3 parts in each test name</h2> | |
<p><strong>TL;DR:</strong> Make the test speak at the requirements level so it’s self-explanatory also to QA engineers and developers who are not familiar with the code internals. State in the test name what is being tested (unit under test), under what circumstances, and what is the expected result</p> | |
<p><strong>Otherwise:</strong> A deployment just failed, a test named “Add product” failed. Does this tell you what exactly is malfunctioning?</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/testingandquality/3-parts-in-name.md"><strong>Read More: Include 3 parts in each test name</strong></a></p> | |
<h2 id="4-3-structure-tests-by-the-aaa-pattern"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-43-structure-tests-by-the-aaa-pattern"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 4.3 Structure tests by the AAA pattern</h2> | |
<p><strong>TL;DR:</strong> Structure your tests with 3 well-separated sections: Arrange, Act & Assert (AAA). The first part includes the test setup, then the execution of the unit under test, and finally the assertion phase. Following this structure guarantees that the reader spends no brain CPU on understanding the test plan</p> | |
<p><strong>Otherwise:</strong> Not only you spend long daily hours on understanding the main code, but now also what should have been the simple part of the day (testing) stretches your brain</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/testingandquality/aaa.md"><strong>Read More: Structure tests by the AAA pattern</strong></a></p> | |
<h2 id="4-4-detect-code-issues-with-a-linter"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-44-detect-code-issues-with-a-linter"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 4.4 Detect code issues with a linter</h2> | |
<p><strong>TL;DR:</strong> Use a code linter to check the basic quality and detect anti-patterns early. Run it before any test and add it as a pre-commit git-hook to minimize the time needed to review and correct any issue. Also check <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#3-code-style-practices">Section 3</a> on Code Style Practices</p> | |
<p><strong>Otherwise:</strong> You may let pass some anti-pattern and possible vulnerable code to your production environment.</p> | |
<h2 id="4-5-avoid-global-test-fixtures-and-seeds-add-data-per-test"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-45-avoid-global-test-fixtures-and-seeds-add-data-per-test"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 4.5 Avoid global test fixtures and seeds, add data per-test</h2> | |
<p><strong>TL;DR:</strong> To prevent test coupling and easily reason about the test flow, each test should add and act on its own set of DB rows. Whenever a test needs to pull or assume the existence of some DB data – it must explicitly add that data and avoid mutating any other records</p> | |
<p><strong>Otherwise:</strong> Consider a scenario where deployment is aborted due to failing tests, team is now going to spend precious investigation time that ends in a sad conclusion: the system works well, the tests however interfere with each other and break the build</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/testingandquality/avoid-global-test-fixture.md"><strong>Read More: Avoid global test fixtures</strong></a></p> | |
<h2 id="4-6-constantly-inspect-for-vulnerable-dependencies"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-46-constantly-inspect-for-vulnerable-dependencies"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 4.6 Constantly inspect for vulnerable dependencies</h2> | |
<p><strong>TL;DR:</strong> Even the most reputable dependencies such as Express have known vulnerabilities. This can get easily tamed using community and commercial tools such as 🔗 <a href="https://docs.npmjs.com/cli/audit">npm audit</a> and 🔗 <a href="https://snyk.io/">snyk.io</a> that can be invoked from your CI on every build</p> | |
<p><strong>Otherwise:</strong> Keeping your code clean from vulnerabilities without dedicated tools will require to constantly follow online publications about new threats. Quite tedious</p> | |
<h2 id="4-7-tag-your-tests"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-47-tag-your-tests"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 4.7 Tag your tests</h2> | |
<p><strong>TL;DR:</strong> Different tests must run on different scenarios: quick smoke, IO-less, tests should run when a developer saves or commits a file, full end-to-end tests usually run when a new pull request is submitted, etc. This can be achieved by tagging tests with keywords like #cold #api #sanity so you can grep with your testing harness and invoke the desired subset. For example, this is how you would invoke only the sanity test group with <a href="https://mochajs.org/">Mocha</a>: mocha –grep ‘sanity’</p> | |
<p><strong>Otherwise:</strong> Running all the tests, including tests that perform dozens of DB queries, any time a developer makes a small change can be extremely slow and keeps developers away from running tests</p> | |
<h2 id="4-8-check-your-test-coverage-it-helps-to-identify-wrong-test-patterns"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-48-check-your-test-coverage-it-helps-to-identify-wrong-test-patterns"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 4.8 Check your test coverage, it helps to identify wrong test patterns</h2> | |
<p><strong>TL;DR:</strong> Code coverage tools like <a href="https://github.com/istanbuljs/istanbuljs">Istanbul</a>/<a href="https://github.com/istanbuljs/nyc">NYC</a> are great for 3 reasons: it comes for free (no effort is required to benefit this reports), it helps to identify a decrease in testing coverage, and last but not least it highlights testing mismatches: by looking at colored code coverage reports you may notice, for example, code areas that are never tested like catch clauses (meaning that tests only invoke the happy paths and not how the app behaves on errors). Set it to fail builds if the coverage falls under a certain threshold</p> | |
<p><strong>Otherwise:</strong> There won’t be any automated metric telling you when a large portion of your code is not covered by testing</p> | |
<h2 id="4-9-inspect-for-outdated-packages"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-49-inspect-for-outdated-packages"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 4.9 Inspect for outdated packages</h2> | |
<p><strong>TL;DR:</strong> Use your preferred tool (e.g. <code>npm outdated</code> or <a href="https://www.npmjs.com/package/npm-check-updates">npm-check-updates</a>) to detect installed outdated packages, inject this check into your CI pipeline and even make a build fail in a severe scenario. For example, a severe scenario might be when an installed package is 5 patch commits behind (e.g. local version is 1.3.1 and repository version is 1.3.8) or it is tagged as deprecated by its author – kill the build and prevent deploying this version</p> | |
<p><strong>Otherwise:</strong> Your production will run packages that have been explicitly tagged by their author as risky</p> | |
<h2 id="4-10-use-production-like-environment-for-e2e-testing"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-410-use-production-like-environment-for-e2e-testing"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 4.10 Use production-like environment for e2e testing</h2> | |
<p><strong>TL;DR:</strong> End to end (e2e) testing which includes live data used to be the weakest link of the CI process as it depends on multiple heavy services like DB. Use an environment which is as close to your real production environment as possible like a-continue (Missed -continue here, needs content. Judging by the <strong>Otherwise</strong> clause, this should mention docker-compose)</p> | |
<p><strong>Otherwise:</strong> Without docker-compose, teams must maintain a testing DB for each testing environment including developers’ machines, keep all those DBs in sync so test results won’t vary across environments</p> | |
<h2 id="4-11-refactor-regularly-using-static-analysis-tools"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-411-refactor-regularly-using-static-analysis-tools"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 4.11 Refactor regularly using static analysis tools</h2> | |
<p><strong>TL;DR:</strong> Using static analysis tools helps by giving objective ways to improve code quality and keeps your code maintainable. You can add static analysis tools to your CI build to fail when it finds code smells. Its main selling points over plain linting are the ability to inspect quality in the context of multiple files (e.g. detect duplications), perform advanced analysis (e.g. code complexity), and follow the history and progress of code issues. Two examples of tools you can use are <a href="https://www.sonarqube.org/">Sonarqube</a> (2,600+ <a href="https://github.com/SonarSource/sonarqube">stars</a>) and <a href="https://codeclimate.com/">Code Climate</a> (1,500+ <a href="https://github.com/codeclimate/codeclimate">stars</a>).</p> | |
<p><strong>Otherwise:</strong> With poor code quality, bugs and performance will always be an issue that no shiny new library or state of the art features can fix</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/testingandquality/refactoring.md"><strong>Read More: Refactoring!</strong></a></p> | |
<h2 id="4-12-carefully-choose-your-ci-platform-jenkins-vs-circleci-vs-travis-vs-rest-of-the-world"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-412-carefully-choose-your-ci-platform-jenkins-vs-circleci-vs-travis-vs-rest-of-the-world"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 4.12 Carefully choose your CI platform (Jenkins vs CircleCI vs Travis vs Rest of the world)</h2> | |
<p><strong>TL;DR:</strong> Your continuous integration platform (CICD) will host all the quality tools (e.g. test, lint) so it should come with a vibrant ecosystem of plugins. <a href="https://jenkins.io/">Jenkins</a> used to be the default for many projects as it has the biggest community along with a very powerful platform at the price of a complex setup that demands a steep learning curve. Nowadays, it has become much easier to set up a CI solution using SaaS tools like <a href="https://circleci.com/">CircleCI</a> and others. These tools allow crafting a flexible CI pipeline without the burden of managing the whole infrastructure. Eventually, it’s a trade-off between robustness and speed – choose your side carefully</p> | |
<p><strong>Otherwise:</strong> Choosing some niche vendor might get you blocked once you need some advanced customization. On the other hand, going with Jenkins might burn precious time on infrastructure setup</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/testingandquality/citools.md"><strong>Read More: Choosing CI platform</strong></a></p> | |
<h2 id="4-13-test-your-middlewares-in-isolation"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-413-test-your-middlewares-in-isolation"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 4.13 Test your middlewares in isolation</h2> | |
<p><strong>TL;DR:</strong> When a middleware holds some immense logic that spans many requests, it is worth testing it in isolation without waking up the entire web framework. This can be easily achieved by stubbing and spying on the {req, res, next} objects</p> | |
<p><strong>Otherwise:</strong> A bug in Express middleware === a bug in all or most requests</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/testingandquality/test-middlewares.md"><strong>Read More: Test middlewares in isolation</strong></a></p> | |
<p><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#table-of-contents">⬆ Return to top</a></p> | |
<h1 id="5-going-to-production-practices"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#5-going-to-production-practices"></a><code>5. Going To Production Practices</code></h1> | |
<h2 id="5-1-monitoring"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-51-monitoring"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 5.1. Monitoring</h2> | |
<p><strong>TL;DR:</strong> Monitoring is a game of finding out issues before customers do – obviously this should be assigned unprecedented importance. The market is overwhelmed with offers thus consider starting with defining the basic metrics you must follow (my suggestions inside), then go over additional fancy features and choose the solution that ticks all boxes. Click ‘The Gist’ below for an overview of the solutions</p> | |
<p><strong>Otherwise:</strong> Failure === disappointed customers. Simple</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/production/monitoring.md"><strong>Read More: Monitoring!</strong></a></p> | |
<h2 id="5-2-increase-transparency-using-smart-logging"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-52-increase-transparency-using-smart-logging"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 5.2. Increase transparency using smart logging</h2> | |
<p><strong>TL;DR:</strong> Logs can be a dumb warehouse of debug statements or the enabler of a beautiful dashboard that tells the story of your app. Plan your logging platform from day 1: how logs are collected, stored and analyzed to ensure that the desired information (e.g. error rate, following an entire transaction through services and servers, etc) can really be extracted</p> | |
<p><strong>Otherwise:</strong> You end up with a black box that is hard to reason about, then you start re-writing all logging statements to add additional information</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/production/smartlogging.md"><strong>Read More: Increase transparency using smart logging</strong></a></p> | |
<h2 id="5-3-delegate-anything-possible-e-g-gzip-ssl-to-a-reverse-proxy"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-53-delegate-anything-possible-eg-gzip-ssl-to-a-reverse-proxy"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 5.3. Delegate anything possible (e.g. gzip, SSL) to a reverse proxy</h2> | |
<p><strong>TL;DR:</strong> Node is awfully bad at doing CPU intensive tasks like gzipping, SSL termination, etc. You should use ‘real’ middleware services like nginx, HAproxy or cloud vendor services instead</p> | |
<p><strong>Otherwise:</strong> Your poor single thread will stay busy doing infrastructural tasks instead of dealing with your application core and performance will degrade accordingly</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/production/delegatetoproxy.md"><strong>Read More: Delegate anything possible (e.g. gzip, SSL) to a reverse proxy</strong></a></p> | |
<h2 id="5-4-lock-dependencies"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-54-lock-dependencies"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 5.4. Lock dependencies</h2> | |
<p><strong>TL;DR:</strong> Your code must be identical across all environments, but amazingly npm lets dependencies drift across environments by default – when you install packages at various environments it tries to fetch packages’ latest patch version. Overcome this by using npm config files, .npmrc, that tell each environment to save the exact (not the latest) version of each package. Alternatively, for finer grained control use <code>npm shrinkwrap</code>. *Update: as of NPM5, dependencies are locked by default. The new package manager in town, Yarn, also got us covered by default</p> | |
<p><strong>Otherwise:</strong> QA will thoroughly test the code and approve a version that will behave differently in production. Even worse, different servers in the same production cluster might run different code</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/production/lockdependencies.md"><strong>Read More: Lock dependencies</strong></a></p> | |
<h2 id="5-5-guard-process-uptime-using-the-right-tool"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-55-guard-process-uptime-using-the-right-tool"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 5.5. Guard process uptime using the right tool</h2> | |
<p><strong>TL;DR:</strong> The process must go on and get restarted upon failures. For simple scenarios, process management tools like PM2 might be enough but in today’s ‘dockerized’ world, cluster management tools should be considered as well</p> | |
<p><strong>Otherwise:</strong> Running dozens of instances without a clear strategy and too many tools together (cluster management, docker, PM2) might lead to DevOps chaos</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/production/guardprocess.md"><strong>Read More: Guard process uptime using the right tool</strong></a></p> | |
<h2 id="5-6-utilize-all-cpu-cores"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-56-utilize-all-cpu-cores"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 5.6. Utilize all CPU cores</h2> | |
<p><strong>TL;DR:</strong> At its basic form, a Node app runs on a single CPU core while all others are left idling. It’s your duty to replicate the Node process and utilize all CPUs – For small-medium apps you may use Node Cluster or PM2. For a larger app consider replicating the process using some Docker cluster (e.g. K8S, ECS) or deployment scripts that are based on Linux init system (e.g. systemd)</p> | |
<p><strong>Otherwise:</strong> Your app will likely utilize only 25% of its available resources(!) or even less. Note that a typical server has 4 CPU cores or more, naive deployment of Node.js utilizes only 1 (even using PaaS services like AWS beanstalk!)</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/production/utilizecpu.md"><strong>Read More: Utilize all CPU cores</strong></a></p> | |
<h2 id="5-7-create-a-maintenance-endpoint"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-57-create-a-maintenance-endpoint"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 5.7. Create a ‘maintenance endpoint’</h2> | |
<p><strong>TL;DR:</strong> Expose a set of system-related information, like memory usage and REPL, etc in a secured API. Although it’s highly recommended to rely on standard and battle-tested tools, some valuable information and operations are easier done using code</p> | |
<p><strong>Otherwise:</strong> You’ll find that you’re performing many “diagnostic deploys” – shipping code to production only to extract some information for diagnostic purposes</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/production/createmaintenanceendpoint.md"><strong>Read More: Create a ‘maintenance endpoint’</strong></a></p> | |
<h2 id="5-8-discover-errors-and-downtime-using-apm-products"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-58-discover-errors-and-downtime-using-apm-products"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 5.8. Discover errors and downtime using APM products</h2> | |
<p><strong>TL;DR:</strong> Application monitoring and performance products (a.k.a. APM) proactively gauge codebase and API so they can auto-magically go beyond traditional monitoring and measure the overall user-experience across services and tiers. For example, some APM products can highlight a transaction that loads too slow on the end-user’s side while suggesting the root cause</p> | |
<p><strong>Otherwise:</strong> You might spend great effort on measuring API performance and downtimes, probably you’ll never be aware which is your slowest code parts under real-world scenario and how these affect the UX</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/production/apmproducts.md"><strong>Read More: Discover errors and downtime using APM products</strong></a></p> | |
<h2 id="5-9-make-your-code-production-ready"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-59-make-your-code-production-ready"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 5.9. Make your code production-ready</h2> | |
<p><strong>TL;DR:</strong> Code with the end in mind, plan for production from day 1. This sounds a bit vague so I’ve compiled a few development tips that are closely related to production maintenance (click Gist below)</p> | |
<p><strong>Otherwise:</strong> A world champion IT/DevOps guy won’t save a system that is badly written</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/production/productioncode.md"><strong>Read More: Make your code production-ready</strong></a></p> | |
<h2 id="5-10-measure-and-guard-the-memory-usage"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-510-measure-and-guard-the-memory-usage"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 5.10. Measure and guard the memory usage</h2> | |
<p><strong>TL;DR:</strong> Node.js has controversial relationships with memory: the v8 engine has soft limits on memory usage (1.4GB) and there are known paths to leak memory in Node’s code – thus watching Node’s process memory is a must. In small apps, you may gauge memory periodically using shell commands but in medium-large apps consider baking your memory watch into a robust monitoring system</p> | |
<p><strong>Otherwise:</strong> Your process memory might leak a hundred megabytes a day like how it happened at <a href="https://www.joyent.com/blog/walmart-node-js-memory-leak">Walmart</a></p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/production/measurememory.md"><strong>Read More: Measure and guard the memory usage</strong></a></p> | |
<h2 id="5-11-get-your-frontend-assets-out-of-node"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-511-get-your-frontend-assets-out-of-node"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 5.11. Get your frontend assets out of Node</h2> | |
<p><strong>TL;DR:</strong> Serve frontend content using dedicated middleware (nginx, S3, CDN) because Node performance really gets hurt when dealing with many static files due to its single-threaded model</p> | |
<p><strong>Otherwise:</strong> Your single Node thread will be busy streaming hundreds of html/images/angular/react files instead of allocating all its resources for the task it was born for – serving dynamic content</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/production/frontendout.md"><strong>Read More: Get your frontend assets out of Node</strong></a></p> | |
<h2 id="5-12-be-stateless-kill-your-servers-almost-every-day"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-512-be-stateless-kill-your-servers-almost-every-day"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 5.12. Be stateless, kill your servers almost every day</h2> | |
<p><strong>TL;DR:</strong> Store any type of data (e.g. user sessions, cache, uploaded files) within external data stores. Consider ‘killing’ your servers periodically or use ‘serverless’ platform (e.g. AWS Lambda) that explicitly enforces a stateless behavior</p> | |
<p><strong>Otherwise:</strong> Failure at a given server will result in application downtime instead of just killing a faulty machine. Moreover, scaling-out elasticity will get more challenging due to the reliance on a specific server</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/production/bestateless.md"><strong>Read More: Be stateless, kill your Servers almost every day</strong></a></p> | |
<h2 id="5-13-use-tools-that-automatically-detect-vulnerabilities"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-513-use-tools-that-automatically-detect-vulnerabilities"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 5.13. Use tools that automatically detect vulnerabilities</h2> | |
<p><strong>TL;DR:</strong> Even the most reputable dependencies such as Express have known vulnerabilities (from time to time) that can put a system at risk. This can be easily tamed using community and commercial tools that constantly check for vulnerabilities and warn (locally or at GitHub), some can even patch them immediately</p> | |
<p><strong>Otherwise:</strong> Keeping your code clean from vulnerabilities without dedicated tools will require you to constantly follow online publications about new threats. Quite tedious</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/production/detectvulnerabilities.md"><strong>Read More: Use tools that automatically detect vulnerabilities</strong></a></p> | |
<h2 id="5-14-assign-a-transaction-id-to-each-log-statement"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-514-assign-a-transaction-id-to-each-log-statement"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 5.14. Assign a transaction id to each log statement</h2> | |
<p>Also known as correlation id / transit id / tracing id / request id / request context / etc.</p> | |
<p><strong>TL;DR:</strong> Assign the same identifier, transaction-id: {some value}, to each log entry within a single request. Then when inspecting errors in logs, easily conclude what happened before and after. Until version 14 of Node, this was not easy to achieve due to Node’s async nature, but since AsyncLocalStorage came to town, this became possible and easy than ever. see code examples inside</p> | |
<p><strong>Otherwise:</strong> Looking at a production error log without the context – what happened before – makes it much harder and slower to reason about the issue</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/production/assigntransactionid.md"><strong>Read More: Assign ‘TransactionId’ to each log statement</strong></a></p> | |
<h2 id="5-15-set-node-env-production"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-515-set-node_envproduction"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 5.15. Set <code>NODE_ENV=production</code></h2> | |
<p><strong>TL;DR:</strong> Set the environment variable <code>NODE_ENV</code> to ‘production’ or ‘development’ to flag whether production optimizations should get activated – many npm packages determine the current environment and optimize their code for production</p> | |
<p><strong>Otherwise:</strong> Omitting this simple property might greatly degrade performance. For example, when using Express for server-side rendering omitting <code>NODE_ENV</code> makes it slower by a factor of three!</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/production/setnodeenv.md"><strong>Read More: Set NODE_ENV=production</strong></a></p> | |
<h2 id="5-16-design-automated-atomic-and-zero-downtime-deployments"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-516-design-automated-atomic-and-zero-downtime-deployments"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 5.16. Design automated, atomic and zero-downtime deployments</h2> | |
<p><strong>TL;DR:</strong> Research shows that teams who perform many deployments lower the probability of severe production issues. Fast and automated deployments that don’t require risky manual steps and service downtime significantly improve the deployment process. You should probably achieve this using Docker combined with CI tools as they became the industry standard for streamlined deployment</p> | |
<p><strong>Otherwise:</strong> Long deployments -> production downtime & human-related error -> team unconfident in making deployment -> fewer deployments and features</p> | |
<h2 id="5-17-use-an-lts-release-of-node-js"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-517-use-an-lts-release-of-nodejs"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 5.17. Use an LTS release of Node.js</h2> | |
<p><strong>TL;DR:</strong> Ensure you are using an LTS version of Node.js to receive critical bug fixes, security updates and performance improvements</p> | |
<p><strong>Otherwise:</strong> Newly discovered bugs or vulnerabilities could be used to exploit an application running in production, and your application may become unsupported by various modules and harder to maintain</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/production/LTSrelease.md"><strong>Read More: Use an LTS release of Node.js</strong></a></p> | |
<h2 id="5-18-don-t-route-logs-within-the-app"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-518-dont-route-logs-within-the-app"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 5.18. Don’t route logs within the app</h2> | |
<p><strong>TL;DR:</strong> Log destinations should not be hard-coded by developers within the application code, but instead should be defined by the execution environment the application runs in. Developers should write logs to <code>stdout</code> using a logger utility and then let the execution environment (container, server, etc.) pipe the <code>stdout</code> stream to the appropriate destination (i.e. Splunk, Graylog, ElasticSearch, etc.).</p> | |
<p><strong>Otherwise:</strong> Application handling log routing === hard to scale, loss of logs, poor separation of concerns</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/production/logrouting.md"><strong>Read More: Log Routing</strong></a></p> | |
<h2 id="5-19-install-your-packages-with-npm-ci"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-519-install-your-packages-with-npm-ci"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 5.19. Install your packages with <code>npm ci</code></h2> | |
<p><strong>TL;DR:</strong> You have to be sure that production code uses the exact version of the packages you have tested it with. Run <code>npm ci</code> to strictly do a clean install of your dependencies matching package.json and package-lock.json. Using this command is recommended in automated environments such as continuous integration pipelines.</p> | |
<p><strong>Otherwise:</strong> QA will thoroughly test the code and approve a version that will behave differently in production. Even worse, different servers in the same production cluster might run different code.</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/production/installpackageswithnpmci.md"><strong>Read More: Use npm ci</strong></a></p> | |
<p><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#table-of-contents">⬆ Return to top</a></p> | |
<h1 id="6-security-best-practices"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#6-security-best-practices"></a><code>6. Security Best Practices</code></h1> | |
<figure class="wp-block-image"><a href="https://camo.githubusercontent.com/198102daac38b83ffeb228c72c033dbefab7ab56116235be3e5c89c5c35607f6/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4f57415350253230546872656174732d546f7025323031302d677265656e2e737667" target="_blank" rel="noreferrer noopener"><img src="https://camo.githubusercontent.com/198102daac38b83ffeb228c72c033dbefab7ab56116235be3e5c89c5c35607f6/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4f57415350253230546872656174732d546f7025323031302d677265656e2e737667" alt="54 items" /></a></figure> | |
<h2 id="6-1-embrace-linter-security-rules"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-61-embrace-linter-security-rules"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 6.1. Embrace linter security rules</h2> | |
<figure class="wp-block-image"><a href="https://www.owasp.org/index.php/Top_10-2017_A1-Injection"><img src="https://camo.githubusercontent.com/4f9375c18ec47f3f6cfd85aaaf2a6ed3f741052334ef95e2c2ef747e1c1857ea/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2545322539432539342532304f57415350253230546872656174732532302d25323041313a496e6a656374696f6e2532302d677265656e2e737667" alt="" /></a></figure> | |
<figure class="wp-block-image"><a href="https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)"><img src="https://camo.githubusercontent.com/72f26d4c08d19f6ff8fb48c928e7c65365cf756397c6b82b1fd17bdb4872d3fe/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2545322539432539342532304f57415350253230546872656174732532302d2532305853532532302d677265656e2e737667" alt="" /></a></figure> | |
<p><strong>TL;DR:</strong> Make use of security-related linter plugins such as <a href="https://github.com/nodesecurity/eslint-plugin-security">eslint-plugin-security</a> to catch security vulnerabilities and issues as early as possible, preferably while they’re being coded. This can help catching security weaknesses like using eval, invoking a child process or importing a module with a string literal (e.g. user input). Click ‘Read more’ below to see code examples that will get caught by a security linter</p> | |
<p><strong>Otherwise:</strong> What could have been a straightforward security weakness during development becomes a major issue in production. Also, the project may not follow consistent code security practices, leading to vulnerabilities being introduced, or sensitive secrets committed into remote repositories</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/security/lintrules.md"><strong>Read More: Lint rules</strong></a></p> | |
<h2 id="6-2-limit-concurrent-requests-using-a-middleware"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-62-limit-concurrent-requests-using-a-middleware"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 6.2. Limit concurrent requests using a middleware</h2> | |
<figure class="wp-block-image"><a href="https://www.owasp.org/index.php/Denial_of_Service"><img src="https://camo.githubusercontent.com/521985f41b33563ae8b289fad5b75a8fe4c40207629d77bf65cad18421cd3eed/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2545322539432539342532304f57415350253230546872656174732532302d25323044444f532532302d677265656e2e737667" alt="" /></a></figure> | |
<p><strong>TL;DR:</strong> DOS attacks are very popular and relatively easy to conduct. Implement rate limiting using an external service such as cloud load balancers, cloud firewalls, nginx, <a href="https://www.npmjs.com/package/rate-limiter-flexible">rate-limiter-flexible</a> package, or (for smaller and less critical apps) a rate-limiting middleware (e.g. <a href="https://www.npmjs.com/package/express-rate-limit">express-rate-limit</a>)</p> | |
<p><strong>Otherwise:</strong> An application could be subject to an attack resulting in a denial of service where real users receive a degraded or unavailable service.</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/security/limitrequests.md"><strong>Read More: Implement rate limiting</strong></a></p> | |
<h2 id="6-3-extract-secrets-from-config-files-or-use-packages-to-encrypt-them"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-63-extract-secrets-from-config-files-or-use-packages-to-encrypt-them"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 6.3 Extract secrets from config files or use packages to encrypt them</h2> | |
<figure class="wp-block-image"><a href="https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration"><img src="https://camo.githubusercontent.com/a24ff0974ce5eaa1600a005885cab22bd510c052f80899a165912a63acdbcc9c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2545322539432539342532304f57415350253230546872656174732532302d25323041363a53656375726974792532304d6973636f6e66696775726174696f6e2532302d677265656e2e737667" alt="" /></a></figure> | |
<figure class="wp-block-image"><a href="https://www.owasp.org/index.php/Top_10-2017_A3-Sensitive_Data_Exposure"><img src="https://camo.githubusercontent.com/2ce0178f4887ca207d9e18b04939170e7e22ae0c025ebef9d83a02df84cc3c67/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2545322539432539342532304f57415350253230546872656174732532302d25323041333a53656e736974697665253230446174612532304578706f737572652532302d677265656e2e737667" alt="" /></a></figure> | |
<p><strong>TL;DR:</strong> Never store plain-text secrets in configuration files or source code. Instead, make use of secret-management systems like Vault products, Kubernetes/Docker Secrets, or using environment variables. As a last resort, secrets stored in source control must be encrypted and managed (rolling keys, expiring, auditing, etc). Make use of pre-commit/push hooks to prevent committing secrets accidentally</p> | |
<p><strong>Otherwise:</strong> Source control, even for private repositories, can mistakenly be made public, at which point all secrets are exposed. Access to source control for an external party will inadvertently provide access to related systems (databases, apis, services, etc).</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/security/secretmanagement.md"><strong>Read More: Secret management</strong></a></p> | |
<h2 id="6-4-prevent-query-injection-vulnerabilities-with-orm-odm-libraries"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-64-prevent-query-injection-vulnerabilities-with-ormodm-libraries"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 6.4. Prevent query injection vulnerabilities with ORM/ODM libraries</h2> | |
<figure class="wp-block-image"><a href="https://www.owasp.org/index.php/Top_10-2017_A1-Injection"><img src="https://camo.githubusercontent.com/4f9375c18ec47f3f6cfd85aaaf2a6ed3f741052334ef95e2c2ef747e1c1857ea/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2545322539432539342532304f57415350253230546872656174732532302d25323041313a496e6a656374696f6e2532302d677265656e2e737667" alt="" /></a></figure> | |
<p><strong>TL;DR:</strong> To prevent SQL/NoSQL injection and other malicious attacks, always make use of an ORM/ODM or a database library that escapes data or supports named or indexed parameterized queries, and takes care of validating user input for expected types. Never just use JavaScript template strings or string concatenation to inject values into queries as this opens your application to a wide spectrum of vulnerabilities. All the reputable Node.js data access libraries (e.g. <a href="https://github.com/sequelize/sequelize">Sequelize</a>, <a href="https://github.com/tgriesser/knex">Knex</a>, <a href="https://github.com/Automattic/mongoose">mongoose</a>) have built-in protection against injection attacks.</p> | |
<p><strong>Otherwise:</strong> Unvalidated or unsanitized user input could lead to operator injection when working with MongoDB for NoSQL, and not using a proper sanitization system or ORM will easily allow SQL injection attacks, creating a giant vulnerability.</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/security/ormodmusage.md"><strong>Read More: Query injection prevention using ORM/ODM libraries</strong></a></p> | |
<h2 id="6-5-collection-of-generic-security-best-practices"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-65-collection-of-generic-security-best-practices"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 6.5. Collection of generic security best practices</h2> | |
<p><strong>TL;DR:</strong> This is a collection of security advice that is not related directly to Node.js – the Node implementation is not much different than any other language. Click read more to skim through.</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/security/commonsecuritybestpractices.md"><strong>Read More: Common security best practices</strong></a></p> | |
<h2 id="6-6-adjust-the-http-response-headers-for-enhanced-security"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-66-adjust-the-http-response-headers-for-enhanced-security"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 6.6. Adjust the HTTP response headers for enhanced security</h2> | |
<figure class="wp-block-image"><a href="https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration"><img src="https://camo.githubusercontent.com/a24ff0974ce5eaa1600a005885cab22bd510c052f80899a165912a63acdbcc9c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2545322539432539342532304f57415350253230546872656174732532302d25323041363a53656375726974792532304d6973636f6e66696775726174696f6e2532302d677265656e2e737667" alt="" /></a></figure> | |
<p><strong>TL;DR:</strong> Your application should be using secure headers to prevent attackers from using common attacks like cross-site scripting (XSS), clickjacking and other malicious attacks. These can be configured easily using modules like <a href="https://www.npmjs.com/package/helmet">helmet</a>.</p> | |
<p><strong>Otherwise:</strong> Attackers could perform direct attacks on your application’s users, leading to huge security vulnerabilities</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/security/secureheaders.md"><strong>Read More: Using secure headers in your application</strong></a></p> | |
<h2 id="6-7-constantly-and-automatically-inspect-for-vulnerable-dependencies"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-67-constantly-and-automatically-inspect-for-vulnerable-dependencies"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 6.7. Constantly and automatically inspect for vulnerable dependencies</h2> | |
<figure class="wp-block-image"><a href="https://www.owasp.org/index.php/Top_10-2017_A9-Using_Components_with_Known_Vulnerabilities"><img src="https://camo.githubusercontent.com/c04b0beba1c3fa3992afe3a79250dfceabea71ad9799baab8b16c9c048a1e85c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2545322539432539342532304f57415350253230546872656174732532302d25323041393a4b6e6f776e25323056756c6e65726162696c69746965732532302d677265656e2e737667" alt="" /></a></figure> | |
<p><strong>TL;DR:</strong> With the npm ecosystem it is common to have many dependencies for a project. Dependencies should always be kept in check as new vulnerabilities are found. Use tools like <a href="https://docs.npmjs.com/cli/audit">npm audit</a> or <a href="https://snyk.io/">snyk</a> to track, monitor and patch vulnerable dependencies. Integrate these tools with your CI setup so you catch a vulnerable dependency before it makes it to production.</p> | |
<p><strong>Otherwise:</strong> An attacker could detect your web framework and attack all its known vulnerabilities.</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/security/dependencysecurity.md"><strong>Read More: Dependency security</strong></a></p> | |
<h2 id="6-8-protect-users-passwords-secrets-using-bcrypt-or-scrypt"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-68-protect-users-passwordssecrets-using-bcrypt-or-scrypt"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 6.8. Protect Users’ Passwords/Secrets using bcrypt or scrypt</h2> | |
<figure class="wp-block-image"><a href="https://www.owasp.org/index.php/Top_10-2017_A2-Broken_Authentication"><img src="https://camo.githubusercontent.com/3e5b9a07fcefa6f02d009bf412769ada0cac992c69182d5c830bf62bdab97466/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2545322539432539342532304f57415350253230546872656174732532302d25323041393a42726f6b656e25323041757468656e7469636174696f6e2532302d677265656e2e737667" alt="" /></a></figure> | |
<p><strong>TL;DR:</strong> Passwords or secrets (e.g. API keys) should be stored using a secure hash + salt function like <code>bcrypt</code>,<code>scrypt</code>, or worst case <code>pbkdf2</code>.</p> | |
<p><strong>Otherwise:</strong> Passwords and secrets that are stored without using a secure function are vulnerable to brute forcing and dictionary attacks that will lead to their disclosure eventually.</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/security/userpasswords.md"><strong>Read More: User Passwords</strong></a></p> | |
<h2 id="6-9-escape-html-js-and-css-output"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-69-escape-html-js-and-css-output"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 6.9. Escape HTML, JS and CSS output</h2> | |
<figure class="wp-block-image"><a href="https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)"><img src="https://camo.githubusercontent.com/c0c2244258a5ed16ffec25b7e60501f9ec8d21644c7cc266450405ab2ca4ac02/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2545322539432539342532304f57415350253230546872656174732532302d25323041373a5853532532302d677265656e2e737667" alt="" /></a></figure> | |
<p><strong>TL;DR:</strong> Untrusted data that is sent down to the browser might get executed instead of just being displayed, this is commonly referred as a cross-site-scripting (XSS) attack. Mitigate this by using dedicated libraries that explicitly mark the data as pure content that should never get executed (i.e. encoding, escaping)</p> | |
<p><strong>Otherwise:</strong> An attacker might store malicious JavaScript code in your DB which will then be sent as-is to the poor clients</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/security/escape-output.md"><strong>Read More: Escape output</strong></a></p> | |
<h2 id="6-10-validate-incoming-json-schemas"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-610-validate-incoming-json-schemas"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 6.10. Validate incoming JSON schemas</h2> | |
<figure class="wp-block-image"><a href="https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)"><img src="https://camo.githubusercontent.com/d5edcc50a8a747dfae057e9593fa0bb96cc1ec9ec71533b48111aa8082be5c5e/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2545322539432539342532304f57415350253230546872656174732532302d25323041373a205853532532302d677265656e2e737667" alt="" /></a></figure> | |
<figure class="wp-block-image"><a href="https://www.owasp.org/index.php/Top_10-2017_A8-Insecure_Deserialization"><img src="https://camo.githubusercontent.com/088dbb425b58e5412c0170d2639aa463b67f9013878bb460ae61cb34c4c50472/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2545322539432539342532304f57415350253230546872656174732532302d25323041383a496e73656375726564253230446573657269616c697a6174696f6e2532302d677265656e2e737667" alt="" /></a></figure> | |
<p><strong>TL;DR:</strong> Validate the incoming requests’ body payload and ensure it meets expectations, fail fast if it doesn’t. To avoid tedious validation coding within each route you may use lightweight JSON-based validation schemas such as <a href="https://www.npmjs.com/package/jsonschema">jsonschema</a> or <a href="https://www.npmjs.com/package/joi">joi</a></p> | |
<p><strong>Otherwise:</strong> Your generosity and permissive approach greatly increases the attack surface and encourages the attacker to try out many inputs until they find some combination to crash the application</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/security/validation.md"><strong>Read More: Validate incoming JSON schemas</strong></a></p> | |
<h2 id="6-11-support-blocklisting-jwts"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-611-support-blocklisting-jwts"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 6.11. Support blocklisting JWTs</h2> | |
<figure class="wp-block-image"><a href="https://www.owasp.org/index.php/Top_10-2017_A2-Broken_Authentication"><img src="https://camo.githubusercontent.com/3e5b9a07fcefa6f02d009bf412769ada0cac992c69182d5c830bf62bdab97466/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2545322539432539342532304f57415350253230546872656174732532302d25323041393a42726f6b656e25323041757468656e7469636174696f6e2532302d677265656e2e737667" alt="" /></a></figure> | |
<p><strong>TL;DR:</strong> When using JSON Web Tokens (for example, with <a href="https://github.com/jaredhanson/passport">Passport.js</a>), by default there’s no mechanism to revoke access from issued tokens. Once you discover some malicious user activity, there’s no way to stop them from accessing the system as long as they hold a valid token. Mitigate this by implementing a blocklist of untrusted tokens that are validated on each request.</p> | |
<p><strong>Otherwise:</strong> Expired, or misplaced tokens could be used maliciously by a third party to access an application and impersonate the owner of the token.</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/security/expirejwt.md"><strong>Read More: Blocklist JSON Web Tokens</strong></a></p> | |
<h2 id="6-12-prevent-brute-force-attacks-against-authorization"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-612-prevent-brute-force-attacks-against-authorization"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 6.12. Prevent brute-force attacks against authorization</h2> | |
<figure class="wp-block-image"><a href="https://www.owasp.org/index.php/Top_10-2017_A2-Broken_Authentication"><img src="https://camo.githubusercontent.com/3e5b9a07fcefa6f02d009bf412769ada0cac992c69182d5c830bf62bdab97466/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2545322539432539342532304f57415350253230546872656174732532302d25323041393a42726f6b656e25323041757468656e7469636174696f6e2532302d677265656e2e737667" alt="" /></a></figure> | |
<p><strong>TL;DR:</strong> A simple and powerful technique is to limit authorization attempts using two metrics:</p> | |
<ol><li>The first is number of consecutive failed attempts by the same user unique ID/name and IP address.</li><li>The second is number of failed attempts from an IP address over some long period of time. For example, block an IP address if it makes 100 failed attempts in one day.</li></ol> | |
<p><strong>Otherwise:</strong> An attacker can issue unlimited automated password attempts to gain access to privileged accounts on an application</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/security/login-rate-limit.md"><strong>Read More: Login rate limiting</strong></a></p> | |
<h2 id="6-13-run-node-js-as-non-root-user"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-613-run-nodejs-as-non-root-user"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 6.13. Run Node.js as non-root user</h2> | |
<figure class="wp-block-image"><a href="https://www.owasp.org/index.php/Top_10-2017_A5-Broken_Access_Control"><img src="https://camo.githubusercontent.com/dcf0c8492ca0ca49da08f45ca5ebe32cc7a884a1e9691bc20fe686fe70e297fe/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2545322539432539342532304f57415350253230546872656174732532302d25323041353a42726f6b656e253230416363657373253230416363657373253230436f6e74726f6c2d677265656e2e737667" alt="" /></a></figure> | |
<p><strong>TL;DR:</strong> There is a common scenario where Node.js runs as a root user with unlimited permissions. For example, this is the default behaviour in Docker containers. It’s recommended to create a non-root user and either bake it into the Docker image (examples given below) or run the process on this user’s behalf by invoking the container with the flag “-u username”</p> | |
<p><strong>Otherwise:</strong> An attacker who manages to run a script on the server gets unlimited power over the local machine (e.g. change iptable and re-route traffic to their server)</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/security/non-root-user.md"><strong>Read More: Run Node.js as non-root user</strong></a></p> | |
<h2 id="6-14-limit-payload-size-using-a-reverse-proxy-or-a-middleware"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-614-limit-payload-size-using-a-reverse-proxy-or-a-middleware"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 6.14. Limit payload size using a reverse-proxy or a middleware</h2> | |
<figure class="wp-block-image"><a href="https://www.owasp.org/index.php/Top_10-2017_A8-Insecure_Deserialization"><img src="https://camo.githubusercontent.com/088dbb425b58e5412c0170d2639aa463b67f9013878bb460ae61cb34c4c50472/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2545322539432539342532304f57415350253230546872656174732532302d25323041383a496e73656375726564253230446573657269616c697a6174696f6e2532302d677265656e2e737667" alt="" /></a></figure> | |
<figure class="wp-block-image"><a href="https://www.owasp.org/index.php/Top_10-2017_A1-Injection"><img src="https://camo.githubusercontent.com/521985f41b33563ae8b289fad5b75a8fe4c40207629d77bf65cad18421cd3eed/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2545322539432539342532304f57415350253230546872656174732532302d25323044444f532532302d677265656e2e737667" alt="" /></a></figure> | |
<p><strong>TL;DR:</strong> The bigger the body payload is, the harder your single thread works in processing it. This is an opportunity for attackers to bring servers to their knees without tremendous amount of requests (DOS/DDOS attacks). Mitigate this limiting the body size of incoming requests on the edge (e.g. firewall, ELB) or by configuring <a href="https://github.com/expressjs/body-parser">express body parser</a> to accept only small-size payloads</p> | |
<p><strong>Otherwise:</strong> Your application will have to deal with large requests, unable to process the other important work it has to accomplish, leading to performance implications and vulnerability towards DOS attacks</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/security/requestpayloadsizelimit.md"><strong>Read More: Limit payload size</strong></a></p> | |
<h2 id="6-15-avoid-javascript-eval-statements"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-615-avoid-javascript-eval-statements"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 6.15. Avoid JavaScript eval statements</h2> | |
<figure class="wp-block-image"><a href="https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)"><img src="https://camo.githubusercontent.com/c0c2244258a5ed16ffec25b7e60501f9ec8d21644c7cc266450405ab2ca4ac02/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2545322539432539342532304f57415350253230546872656174732532302d25323041373a5853532532302d677265656e2e737667" alt="" /></a></figure> | |
<figure class="wp-block-image"><a href="https://www.owasp.org/index.php/Top_10-2017_A1-Injection"><img src="https://camo.githubusercontent.com/4f9375c18ec47f3f6cfd85aaaf2a6ed3f741052334ef95e2c2ef747e1c1857ea/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2545322539432539342532304f57415350253230546872656174732532302d25323041313a496e6a656374696f6e2532302d677265656e2e737667" alt="" /></a></figure> | |
<figure class="wp-block-image"><a href="https://www.owasp.org/index.php/Top_10-2017_A4-XML_External_Entities_(XXE)"><img src="https://camo.githubusercontent.com/3a676493e6ff6c8f515e9862cbf1a55063d24ab384ea30542e6f88549fbdca92/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2545322539432539342532304f57415350253230546872656174732532302d25323041343a45787465726e616c253230456e7469746965732532302d677265656e2e737667" alt="" /></a></figure> | |
<p><strong>TL;DR:</strong> <code>eval</code> is evil as it allows executing custom JavaScript code during run time. This is not just a performance concern but also an important security concern due to malicious JavaScript code that may be sourced from user input. Another language feature that should be avoided is <code>new Function</code> constructor. <code>setTimeout</code> and <code>setInterval</code> should never be passed dynamic JavaScript code either.</p> | |
<p><strong>Otherwise:</strong> Malicious JavaScript code finds a way into text passed into <code>eval</code> or other real-time evaluating JavaScript language functions, and will gain complete access to JavaScript permissions on the page. This vulnerability is often manifested as an XSS attack.</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/security/avoideval.md"><strong>Read More: Avoid JavaScript eval statements</strong></a></p> | |
<h2 id="6-16-prevent-evil-regex-from-overloading-your-single-thread-execution"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-616-prevent-evil-regex-from-overloading-your-single-thread-execution"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 6.16. Prevent evil RegEx from overloading your single thread execution</h2> | |
<figure class="wp-block-image"><a href="https://www.owasp.org/index.php/Denial_of_Service"><img src="https://camo.githubusercontent.com/521985f41b33563ae8b289fad5b75a8fe4c40207629d77bf65cad18421cd3eed/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2545322539432539342532304f57415350253230546872656174732532302d25323044444f532532302d677265656e2e737667" alt="" /></a></figure> | |
<p><strong>TL;DR:</strong> Regular Expressions, while being handy, pose a real threat to JavaScript applications at large, and the Node.js platform in particular. A user input for text to match might require an outstanding amount of CPU cycles to process. RegEx processing might be inefficient to an extent that a single request that validates 10 words can block the entire event loop for 6 seconds and set the CPU on 🔥. For that reason, prefer third-party validation packages like <a href="https://github.com/chriso/validator.js">validator.js</a> instead of writing your own Regex patterns, or make use of <a href="https://github.com/substack/safe-regex">safe-regex</a> to detect vulnerable regex patterns</p> | |
<p><strong>Otherwise:</strong> Poorly written regexes could be susceptible to Regular Expression DoS attacks that will block the event loop completely. For example, the popular <code>moment</code> package was found vulnerable with malicious RegEx usage in November of 2017</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/security/regex.md"><strong>Read More: Prevent malicious RegEx</strong></a></p> | |
<h2 id="6-17-avoid-module-loading-using-a-variable"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-617-avoid-module-loading-using-a-variable"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 6.17. Avoid module loading using a variable</h2> | |
<figure class="wp-block-image"><a href="https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)"><img src="https://camo.githubusercontent.com/c0c2244258a5ed16ffec25b7e60501f9ec8d21644c7cc266450405ab2ca4ac02/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2545322539432539342532304f57415350253230546872656174732532302d25323041373a5853532532302d677265656e2e737667" alt="" /></a></figure> | |
<figure class="wp-block-image"><a href="https://www.owasp.org/index.php/Top_10-2017_A1-Injection"><img src="https://camo.githubusercontent.com/4f9375c18ec47f3f6cfd85aaaf2a6ed3f741052334ef95e2c2ef747e1c1857ea/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2545322539432539342532304f57415350253230546872656174732532302d25323041313a496e6a656374696f6e2532302d677265656e2e737667" alt="" /></a></figure> | |
<figure class="wp-block-image"><a href="https://www.owasp.org/index.php/Top_10-2017_A4-XML_External_Entities_(XXE)"><img src="https://camo.githubusercontent.com/3a676493e6ff6c8f515e9862cbf1a55063d24ab384ea30542e6f88549fbdca92/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2545322539432539342532304f57415350253230546872656174732532302d25323041343a45787465726e616c253230456e7469746965732532302d677265656e2e737667" alt="" /></a></figure> | |
<p><strong>TL;DR:</strong> Avoid requiring/importing another file with a path that was given as parameter due to the concern that it could have originated from user input. This rule can be extended for accessing files in general (i.e. <code>fs.readFile()</code>) or other sensitive resource access with dynamic variables originating from user input. <a href="https://www.npmjs.com/package/eslint-plugin-security">Eslint-plugin-security</a> linter can catch such patterns and warn early enough</p> | |
<p><strong>Otherwise:</strong> Malicious user input could find its way to a parameter that is used to require tampered files, for example, a previously uploaded file on the file system, or access already existing system files.</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/security/safemoduleloading.md"><strong>Read More: Safe module loading</strong></a></p> | |
<h2 id="6-18-run-unsafe-code-in-a-sandbox"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-618-run-unsafe-code-in-a-sandbox"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 6.18. Run unsafe code in a sandbox</h2> | |
<figure class="wp-block-image"><a href="https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)"><img src="https://camo.githubusercontent.com/c0c2244258a5ed16ffec25b7e60501f9ec8d21644c7cc266450405ab2ca4ac02/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2545322539432539342532304f57415350253230546872656174732532302d25323041373a5853532532302d677265656e2e737667" alt="" /></a></figure> | |
<figure class="wp-block-image"><a href="https://www.owasp.org/index.php/Top_10-2017_A1-Injection"><img src="https://camo.githubusercontent.com/4f9375c18ec47f3f6cfd85aaaf2a6ed3f741052334ef95e2c2ef747e1c1857ea/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2545322539432539342532304f57415350253230546872656174732532302d25323041313a496e6a656374696f6e2532302d677265656e2e737667" alt="" /></a></figure> | |
<figure class="wp-block-image"><a href="https://www.owasp.org/index.php/Top_10-2017_A4-XML_External_Entities_(XXE)"><img src="https://camo.githubusercontent.com/3a676493e6ff6c8f515e9862cbf1a55063d24ab384ea30542e6f88549fbdca92/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2545322539432539342532304f57415350253230546872656174732532302d25323041343a45787465726e616c253230456e7469746965732532302d677265656e2e737667" alt="" /></a></figure> | |
<p><strong>TL;DR:</strong> When tasked to run external code that is given at run-time (e.g. plugin), use any sort of ‘sandbox’ execution environment that isolates and guards the main code against the plugin. This can be achieved using a dedicated process (e.g. <code>cluster.fork()</code>), serverless environment or dedicated npm packages that act as a sandbox</p> | |
<p><strong>Otherwise:</strong> A plugin can attack through an endless variety of options like infinite loops, memory overloading, and access to sensitive process environment variables</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/security/sandbox.md"><strong>Read More: Run unsafe code in a sandbox</strong></a></p> | |
<h2 id="6-19-take-extra-care-when-working-with-child-processes"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-619-take-extra-care-when-working-with-child-processes"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 6.19. Take extra care when working with child processes</h2> | |
<figure class="wp-block-image"><a href="https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)"><img src="https://camo.githubusercontent.com/c0c2244258a5ed16ffec25b7e60501f9ec8d21644c7cc266450405ab2ca4ac02/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2545322539432539342532304f57415350253230546872656174732532302d25323041373a5853532532302d677265656e2e737667" alt="" /></a></figure> | |
<figure class="wp-block-image"><a href="https://www.owasp.org/index.php/Top_10-2017_A1-Injection"><img src="https://camo.githubusercontent.com/4f9375c18ec47f3f6cfd85aaaf2a6ed3f741052334ef95e2c2ef747e1c1857ea/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2545322539432539342532304f57415350253230546872656174732532302d25323041313a496e6a656374696f6e2532302d677265656e2e737667" alt="" /></a></figure> | |
<figure class="wp-block-image"><a href="https://www.owasp.org/index.php/Top_10-2017_A4-XML_External_Entities_(XXE)"><img src="https://camo.githubusercontent.com/3a676493e6ff6c8f515e9862cbf1a55063d24ab384ea30542e6f88549fbdca92/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2545322539432539342532304f57415350253230546872656174732532302d25323041343a45787465726e616c253230456e7469746965732532302d677265656e2e737667" alt="" /></a></figure> | |
<p><strong>TL;DR:</strong> Avoid using child processes when possible and validate and sanitize input to mitigate shell injection attacks if you still have to. Prefer using <code>child_process.execFile</code> which by definition will only execute a single command with a set of attributes and will not allow shell parameter expansion.</p> | |
<p><strong>Otherwise:</strong> Naive use of child processes could result in remote command execution or shell injection attacks due to malicious user input passed to an unsanitized system command.</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/security/childprocesses.md"><strong>Read More: Be cautious when working with child processes</strong></a></p> | |
<h2 id="6-20-hide-error-details-from-clients"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-620-hide-error-details-from-clients"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 6.20. Hide error details from clients</h2> | |
<figure class="wp-block-image"><a href="https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration"><img src="https://camo.githubusercontent.com/a24ff0974ce5eaa1600a005885cab22bd510c052f80899a165912a63acdbcc9c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2545322539432539342532304f57415350253230546872656174732532302d25323041363a53656375726974792532304d6973636f6e66696775726174696f6e2532302d677265656e2e737667" alt="" /></a></figure> | |
<p><strong>TL;DR:</strong> An integrated express error handler hides the error details by default. However, great are the chances that you implement your own error handling logic with custom Error objects (considered by many as a best practice). If you do so, ensure not to return the entire Error object to the client, which might contain some sensitive application details</p> | |
<p><strong>Otherwise:</strong> Sensitive application details such as server file paths, third party modules in use, and other internal workflows of the application which could be exploited by an attacker, could be leaked from information found in a stack trace</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/security/hideerrors.md"><strong>Read More: Hide error details from client</strong></a></p> | |
<h2 id="6-21-configure-2fa-for-npm-or-yarn"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-621-configure-2fa-for-npm-or-yarn"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 6.21. Configure 2FA for npm or Yarn</h2> | |
<figure class="wp-block-image"><a href="https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration"><img src="https://camo.githubusercontent.com/a24ff0974ce5eaa1600a005885cab22bd510c052f80899a165912a63acdbcc9c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2545322539432539342532304f57415350253230546872656174732532302d25323041363a53656375726974792532304d6973636f6e66696775726174696f6e2532302d677265656e2e737667" alt="" /></a></figure> | |
<p><strong>TL;DR:</strong> Any step in the development chain should be protected with MFA (multi-factor authentication), npm/Yarn are a sweet opportunity for attackers who can get their hands on some developer’s password. Using developer credentials, attackers can inject malicious code into libraries that are widely installed across projects and services. Maybe even across the web if published in public. Enabling 2-factor-authentication in npm leaves almost zero chances for attackers to alter your package code.</p> | |
<p><strong>Otherwise:</strong> <a href="https://medium.com/@oprearocks/eslint-backdoor-what-it-is-and-how-to-fix-the-issue-221f58f1a8c8">Have you heard about the eslint developer whose password was hijacked?</a></p> | |
<h2 id="6-22-modify-session-middleware-settings"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-622-modify-session-middleware-settings"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 6.22. Modify session middleware settings</h2> | |
<figure class="wp-block-image"><a href="https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration"><img src="https://camo.githubusercontent.com/a24ff0974ce5eaa1600a005885cab22bd510c052f80899a165912a63acdbcc9c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2545322539432539342532304f57415350253230546872656174732532302d25323041363a53656375726974792532304d6973636f6e66696775726174696f6e2532302d677265656e2e737667" alt="" /></a></figure> | |
<p><strong>TL;DR:</strong> Each web framework and technology has its known weaknesses - telling an attacker which web framework we use is a great help for them. Using the default settings for session middlewares can expose your app to module- and framework-specific hijacking attacks in a similar way to the <code>X-Powered-By</code> header. Try hiding anything that identifies and reveals your tech stack (E.g. Node.js, express)</p> | |
<p><strong>Otherwise:</strong> Cookies could be sent over insecure connections, and an attacker might use session identification to identify the underlying framework of the web application, as well as module-specific vulnerabilities</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/security/sessions.md"><strong>Read More: Cookie and session security</strong></a></p> | |
<h2 id="6-23-avoid-dos-attacks-by-explicitly-setting-when-a-process-should-crash"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-623-avoid-dos-attacks-by-explicitly-setting-when-a-process-should-crash"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 6.23. Avoid DOS attacks by explicitly setting when a process should crash</h2> | |
<figure class="wp-block-image"><a href="https://www.owasp.org/index.php/Denial_of_Service"><img src="https://camo.githubusercontent.com/521985f41b33563ae8b289fad5b75a8fe4c40207629d77bf65cad18421cd3eed/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2545322539432539342532304f57415350253230546872656174732532302d25323044444f532532302d677265656e2e737667" alt="" /></a></figure> | |
<p><strong>TL;DR:</strong> The Node process will crash when errors are not handled. Many best practices even recommend to exit even though an error was caught and got handled. Express, for example, will crash on any asynchronous error - unless you wrap routes with a catch clause. This opens a very sweet attack spot for attackers who recognize what input makes the process crash and repeatedly send the same request. There’s no instant remedy for this but a few techniques can mitigate the pain: Alert with critical severity anytime a process crashes due to an unhandled error, validate the input and avoid crashing the process due to invalid user input, wrap all routes with a catch and consider not to crash when an error originated within a request (as opposed to what happens globally)</p> | |
<p><strong>Otherwise:</strong> This is just an educated guess: given many Node.js applications, if we try passing an empty JSON body to all POST requests - a handful of applications will crash. At that point, we can just repeat sending the same request to take down the applications with ease</p> | |
<h2 id="6-24-prevent-unsafe-redirects"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-624-prevent-unsafe-redirects"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 6.24. Prevent unsafe redirects</h2> | |
<figure class="wp-block-image"><a href="https://www.owasp.org/index.php/Top_10-2017_A1-Injection"><img src="https://camo.githubusercontent.com/4f9375c18ec47f3f6cfd85aaaf2a6ed3f741052334ef95e2c2ef747e1c1857ea/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2545322539432539342532304f57415350253230546872656174732532302d25323041313a496e6a656374696f6e2532302d677265656e2e737667" alt="" /></a></figure> | |
<p><strong>TL;DR:</strong> Redirects that do not validate user input can enable attackers to launch phishing scams, steal user credentials, and perform other malicious actions.</p> | |
<p><strong>Otherwise:</strong> If an attacker discovers that you are not validating external, user-supplied input, they may exploit this vulnerability by posting specially-crafted links on forums, social media, and other public places to get users to click it.</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/security/saferedirects.md"><strong>Read More: Prevent unsafe redirects</strong></a></p> | |
<h2 id="6-25-avoid-publishing-secrets-to-the-npm-registry"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-625-avoid-publishing-secrets-to-the-npm-registry"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 6.25. Avoid publishing secrets to the npm registry</h2> | |
<figure class="wp-block-image"><a href="https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration"><img src="https://camo.githubusercontent.com/a24ff0974ce5eaa1600a005885cab22bd510c052f80899a165912a63acdbcc9c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2545322539432539342532304f57415350253230546872656174732532302d25323041363a53656375726974792532304d6973636f6e66696775726174696f6e2532302d677265656e2e737667" alt="" /></a></figure> | |
<p><strong>TL;DR:</strong> Precautions should be taken to avoid the risk of accidentally publishing secrets to public npm registries. An <code>.npmignore</code> file can be used to ignore specific files or folders, or the <code>files</code> array in <code>package.json</code> can act as an allow list.</p> | |
<p><strong>Otherwise:</strong> Your project’s API keys, passwords or other secrets are open to be abused by anyone who comes across them, which may result in financial loss, impersonation, and other risks.</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/security/avoid_publishing_secrets.md"><strong>Read More: Avoid publishing secrets</strong></a><br><br></p> | |
<p><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#table-of-contents">⬆ Return to top</a></p> | |
<h1 id="7-draft-performance-best-practices"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#7-draft-performance-best-practices"></a><code>7. Draft: Performance Best Practices</code></h1> | |
<h2 id="our-contributors-are-working-on-this-section-would-you-like-to-join"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#our-contributors-are-working-on-this-section-would-you-like-to-join"></a>Our contributors are working on this section. <a href="https://github.com/goldbergyoni/nodebestpractices/issues/256">Would you like to join?</a></h2> | |
<h2 id="7-1-don-t-block-the-event-loop"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-71-dont-block-the-event-loop"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 7.1. Don’t block the event loop</h2> | |
<p><strong>TL;DR:</strong> Avoid CPU intensive tasks as they will block the mostly single-threaded Event Loop and offload those to a dedicated thread, process or even a different technology based on the context.</p> | |
<p><strong>Otherwise:</strong> As the Event Loop is blocked, Node.js will be unable to handle other request thus causing delays for concurrent users. <strong>3000 users are waiting for a response, the content is ready to be served, but one single request blocks the server from dispatching the results back</strong></p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/performance/block-loop.md"><strong>Read More: Do not block the event loop</strong></a></p> | |
<h2 id="7-2-prefer-native-js-methods-over-user-land-utils-like-lodash"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-72-prefer-native-js-methods-over-user-land-utils-like-lodash"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 7.2. Prefer native JS methods over user-land utils like Lodash</h2> | |
<p><strong>TL;DR:</strong> It’s often more penalising to use utility libraries like <code>lodash</code> and <code>underscore</code> over native methods as it leads to unneeded dependencies and slower performance. Bear in mind that with the introduction of the new V8 engine alongside the new ES standards, native methods were improved in such a way that it’s now about 50% more performant than utility libraries.</p> | |
<p><strong>Otherwise:</strong> You’ll have to maintain less performant projects where you could have simply used what was <strong>already</strong> available or dealt with a few more lines in exchange of a few more files.</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/performance/nativeoverutil.md"><strong>Read More: Native over user land utils</strong></a></p> | |
<p><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#table-of-contents">⬆ Return to top</a></p> | |
<h1 id="8-docker-best-practices"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#8-docker-best-practices"></a><code>8. Docker Best Practices</code></h1> | |
<p>🏅 Many thanks to <a href="https://github.com/BretFisher">Bret Fisher</a> from whom we learned many of the following practices</p> | |
<h2 id="8-1-use-multi-stage-builds-for-leaner-and-more-secure-docker-images"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-81-use-multi-stage-builds-for-leaner-and-more-secure-docker-images"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 8.1 Use multi-stage builds for leaner and more secure Docker images</h2> | |
<p><strong>TL;DR:</strong> Use multi-stage build to copy only necessary production artifacts. A lot of build-time dependencies and files are not needed for running your application. With multi-stage builds these resources can be used during build while the runtime environment contains only what’s necessary. Multi-stage builds are an easy way to get rid of overweight and security threats.</p> | |
<p><strong>Otherwise:</strong> Larger images will take longer to build and ship, build-only tools might contain vulnerabilities and secrets only meant for the build phase might be leaked.</p> | |
<h3 id="example-dockerfile-for-multi-stage-builds"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#example-dockerfile-for-multi-stage-builds"></a>Example Dockerfile for multi-stage builds</h3> | |
<pre class="wp-block-preformatted">FROM node:14.4.0 AS build | |
COPY . . | |
RUN npm ci && npm run build | |
FROM node:slim-14.4.0 | |
USER node | |
EXPOSE 8080 | |
COPY --from=build /home/node/app/dist /home/node/app/package.json /home/node/app/package-lock.json ./ | |
RUN npm ci --production | |
CMD [ "node", "dist/app.js" ]</pre> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/docker/multi_stage_builds.md"><strong>Read More: Use multi-stage builds</strong></a></p> | |
<h2 id="8-2-bootstrap-using-node-command-avoid-npm-start"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-82-bootstrap-using-node-command-avoid-npm-start"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 8.2. Bootstrap using <code>node</code> command, avoid <code>npm start</code></h2> | |
<p><strong>TL;DR:</strong> use <code>CMD ['node','server.js']</code> to start your app, avoid using npm scripts which don’t pass OS signals to the code. This prevents problems with child-processes, signal handling, graceful shutdown and having zombie processes.</p> | |
<p><strong>Otherwise:</strong> When no signals are passed, your code will never be notified about shutdowns. Without this, it will lose its chance to close properly possibly losing current requests and/or data.</p> | |
<p><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/docker/bootstrap-using-node.md"><strong>Read More: Bootstrap container using node command, avoid npm start</strong></a></p> | |
<h2 id="8-3-let-the-docker-runtime-handle-replication-and-uptime"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-83-let-the-docker-runtime-handle-replication-and-uptime"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 8.3. Let the Docker runtime handle replication and uptime</h2> | |
<p><strong>TL;DR:</strong> When using a Docker run time orchestrator (e.g., Kubernetes), invoke the Node.js process directly without intermediate process managers or custom code that replicate the process (e.g. PM2, Cluster module). The runtime platform has the highest amount of data and visibility for making placement decision – It knows best how many processes are needed, how to spread them and what to do in case of crashes</p> | |
<p><strong>Otherwise:</strong> Container keeps crashing due to lack of resources will get restarted indefinitely by the process manager. Should Kubernetes be aware of that, it could relocate it to a different roomy instance</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/docker/restart-and-replicate-processes.md"><strong>Read More: Let the Docker orchestrator restart and replicate processes</strong></a></p> | |
<h2 id="8-4-use-dockerignore-to-prevent-leaking-secrets"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-84-use-dockerignore-to-prevent-leaking-secrets"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 8.4. Use .dockerignore to prevent leaking secrets</h2> | |
<p><strong>TL;DR</strong>: Include a <code>.dockerignore</code> file that filters out common secret files and development artifacts. By doing so, you might prevent secrets from leaking into the image. As a bonus the build time will significantly decrease. Also, ensure not to copy all files recursively rather explicitly choose what should be copied to Docker</p> | |
<p><strong>Otherwise</strong>: Common personal secret files like <code>.env</code>, <code>.aws</code> and <code>.npmrc</code> will be shared with anybody with access to the image (e.g. Docker repository)</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/docker/docker-ignore.md"><strong>Read More: Use .dockerignore</strong></a></p> | |
<h2 id="8-5-clean-up-dependencies-before-production"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-85-clean-up-dependencies-before-production"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 8.5. Clean-up dependencies before production</h2> | |
<p><strong>TL;DR:</strong> Although Dev-Dependencies are sometimes needed during the build and test life-cycle, eventually the image that is shipped to production should be minimal and clean from development dependencies. Doing so guarantees that only necessary code is shipped and the amount of potential attacks (i.e. attack surface) is minimized. When using multi-stage build (see dedicated bullet) this can be achieved by installing all dependencies first and finally running <code>npm ci --production</code></p> | |
<p><strong>Otherwise:</strong> Many of the infamous npm security breaches were found within development packages (e.g. <a href="https://eslint.org/blog/2018/07/postmortem-for-malicious-package-publishes">eslint-scope</a>)</p> | |
<p>🔗 Read More: <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/docker/install-for-production.md">Remove development dependencies</a></p> | |
<h2 id="8-6-shutdown-smartly-and-gracefully"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-86-shutdown-smartly-and-gracefully"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 8.6. Shutdown smartly and gracefully</h2> | |
<p><strong>TL;DR:</strong> Handle the process SIGTERM event and clean-up all existing connection and resources. This should be done while responding to ongoing requests. In Dockerized runtimes shutting down containers is not a rare event, rather a frequent occurrence that happen as part of routine work. Achieving this demands some thoughtful code to orchestrate several moving parts: The load balancer, keep-alive connections, the HTTP server and other resources</p> | |
<p><strong>Otherwise:</strong> Dying immediately means not responding to thousands of disappointed users</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/docker/graceful-shutdown.md"><strong>Read More: Graceful shutdown</strong></a></p> | |
<h2 id="8-7-set-memory-limits-using-both-docker-and-v8"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-87-set-memory-limits-using-both-docker-and-v8"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 8.7. Set memory limits using both Docker and v8</h2> | |
<p><strong>TL;DR:</strong> Always configure a memory limit using both Docker and the JavaScript runtime flags. The Docker limit is needed to make thoughtful container placement decision, the –v8’s flag max-old-space is needed to kick off the GC on time and prevent under utilization of memory. Practically, set the v8’s old space memory to be a just bit less than the container limit</p> | |
<p><strong>Otherwise:</strong> The docker definition is needed to perform thoughtful scaling decision and prevent starving other citizens. Without also defining the v8’s limits, it will under utilize the container resources – Without explicit instructions it crashes when utilizing ~50-60% of its host resources</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/docker/memory-limit.md"><strong>Read More: Set memory limits using Docker only</strong></a></p> | |
<h2 id="8-8-plan-for-efficient-caching"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-88-plan-for-efficient-caching"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 8.8. Plan for efficient caching</h2> | |
<p><strong>TL;DR:</strong> Rebuilding a whole docker image from cache can be nearly instantaneous if done correctly. The less updated instructions should be at the top of your Dockerfile and the ones constantly changing (like app code) should be at the bottom.</p> | |
<p><strong>Otherwise:</strong> Docker build will be very long and consume lot of resources even when making tiny changes</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/docker/use-cache-for-shorter-build-time.md"><strong>Read More: Leverage caching to reduce build times</strong></a></p> | |
<h2 id="8-9-use-explicit-image-reference-avoid-latest-tag"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-89-use-explicit-image-reference-avoid-latest-tag"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 8.9. Use explicit image reference, avoid <code>latest</code> tag</h2> | |
<p><strong>TL;DR:</strong> Specify an explicit image digest or versioned label, never refer to <code>latest</code>. Developers are often led to believe that specifying the <code>latest</code> tag will provide them with the most recent image in the repository however this is not the case. Using a digest guarantees that every instance of the service is running exactly the same code.</p> | |
<p>In addition, referring to an image tag means that the base image is subject to change, as image tags cannot be relied upon for a deterministic install. Instead, if a deterministic install is expected, a SHA256 digest can be used to reference an exact image.</p> | |
<p><strong>Otherwise:</strong> A new version of a base image could be deployed into production with breaking changes, causing unintended application behaviour.</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/docker/image-tags.md"><strong>Read More: Understand image tags and use the “latest” tag with caution</strong></a></p> | |
<h2 id="8-10-prefer-smaller-docker-base-images"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-810-prefer-smaller-docker-base-images"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 8.10. Prefer smaller Docker base images</h2> | |
<p><strong>TL;DR:</strong> Large images lead to higher exposure to vulnerabilities and increased resource consumption. Using leaner Docker images, such as Slim and Alpine Linux variants, mitigates this issue.</p> | |
<p><strong>Otherwise:</strong> Building, pushing, and pulling images will take longer, unknown attack vectors can be used by malicious actors and more resources are consumed.</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/docker/smaller_base_images.md"><strong>Read More: Prefer smaller images</strong></a></p> | |
<h2 id="8-11-clean-out-build-time-secrets-avoid-secrets-in-args"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-811-clean-out-build-time-secrets-avoid-secrets-in-args"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 8.11. Clean-out build-time secrets, avoid secrets in args</h2> | |
<p><strong>TL;DR:</strong> Avoid secrets leaking from the Docker build environment. A Docker image is typically shared in multiple environment like CI and a registry that are not as sanitized as production. A typical example is an npm token which is usually passed to a dockerfile as argument. This token stays within the image long after it is needed and allows the attacker indefinite access to a private npm registry. This can be avoided by coping a secret file like <code>.npmrc</code> and then removing it using multi-stage build (beware, build history should be deleted as well) or by using Docker build-kit secret feature which leaves zero traces</p> | |
<p><strong>Otherwise:</strong> Everyone with access to the CI and docker registry will also get access to some precious organization secrets as a bonus</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/docker/avoid-build-time-secrets.md"><strong>Read More: Clean-out build-time secrets</strong></a></p> | |
<h2 id="8-12-scan-images-for-multi-layers-of-vulnerabilities"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-812-scan-images-for-multi-layers-of-vulnerabilities"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 8.12. Scan images for multi layers of vulnerabilities</h2> | |
<p><strong>TL;DR:</strong> Besides checking code dependencies vulnerabilities also scan the final image that is shipped to production. Docker image scanners check the code dependencies but also the OS binaries. This E2E security scan covers more ground and verifies that no bad guy injected bad things during the build. Consequently, it is recommended running this as the last step before deployment. There are a handful of free and commercial scanners that also provide CI/CD plugins</p> | |
<p><strong>Otherwise:</strong> Your code might be entirely free from vulnerabilities. However it might still get hacked due to vulnerable version of OS-level binaries (e.g. OpenSSL, TarBall) that are commonly being used by applications</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/docker/scan-images.md"><strong>Read More: Scan the entire image before production</strong></a></p> | |
<h2 id="8-13-clean-node-module-cache"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-813-clean-node_module-cache"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 8.13 Clean NODE_MODULE cache</h2> | |
<p><strong>TL;DR:</strong> After installing dependencies in a container remove the local cache. It doesn’t make any sense to duplicate the dependencies for faster future installs since there won’t be any further installs – A Docker image is immutable. Using a single line of code tens of MB (typically 10-50% of the image size) are shaved off</p> | |
<p><strong>Otherwise:</strong> The image that will get shipped to production will weigh 30% more due to files that will never get used</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/docker/clean-cache.md"><strong>Read More: Clean NODE_MODULE cache</strong></a></p> | |
<h2 id="8-14-generic-docker-practices"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-814-generic-docker-practices"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 8.14. Generic Docker practices</h2> | |
<p><strong>TL;DR:</strong> This is a collection of Docker advice that is not related directly to Node.js – the Node implementation is not much different than any other language. Click read more to skim through.</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/docker/generic-tips.md"><strong>Read More: Generic Docker practices</strong></a></p> | |
<h2 id="8-15-lint-your-dockerfile"><a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/README.md#-815-lint-your-dockerfile"></a><a target="_blank" rel="noreferrer noopener" href="https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/checkbox-small-blue.png"></a> 8.15. Lint your Dockerfile</h2> | |
<p><strong>TL;DR:</strong> Linting your Dockerfile is an important step to identify issues in your Dockerfile which differ from best practices. By checking for potential flaws using a specialised Docker linter, performance and security improvements can be easily identified, saving countless hours of wasted time or security issues in production code.</p> | |
<p><strong>Otherwise:</strong> Mistakenly the Dockerfile creator left Root as the production user, and also used an image from unknown source repository. This could be avoided with with just a simple linter.</p> | |
<p>🔗 <a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/docker/lint-dockerfile.md"><strong>Read More: Lint your Dockerfile</strong></a></p> | |
</div><!-- .entry-content --> | |
<footer class="entry-footer responsive-max-width"> | |
<span class="byline"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><span class="screen-reader-text">Posted by</span><span class="author vcard"><a class="url fn n" href="https://web-dev-hub.com/author/gunerb1/">bgoonz</a></span></span><span class="posted-on"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><defs><path id="a" d="M0 0h24v24H0V0z"></path></defs><clipPath id="b"><use xlink:href="#a" overflow="visible"></use></clipPath><path clip-path="url(#b)" d="M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10 10-4.5 10-10S17.5 2 12 2zm4.2 14.2L11 13V7h1.5v5.2l4.5 2.7-.8 1.3z"></path></svg><a href="https://web-dev-hub.com/2021/12/25/node-best-practices/" rel="bookmark"><time class="entry-date published updated" datetime="2021-12-25T00:32:49-05:00">December 25, 2021</time></a></span><span class="cat-links"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M10 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2h-8l-2-2z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><span class="screen-reader-text">Posted in</span><a href="https://web-dev-hub.com/category/uncategorized/" rel="category tag">Uncategorized</a></span><span class="comments-link"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M21.99 4c0-1.1-.89-2-1.99-2H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h14l4 4-.01-18z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><a href="https://web-dev-hub.com/2021/12/25/node-best-practices/#respond">Leave a comment<span class="screen-reader-text"> on Node Best Practices</span></a></span><span class="edit-link"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04c.39-.39.39-1.02 0-1.41l-2.34-2.34c-.39-.39-1.02-.39-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><a class="post-edit-link" href="https://wordpress.com/post/web-dev-hub.com/1048">Edit <span class="screen-reader-text">Node Best Practices</span></a></span> </footer><!-- .entry-footer --> | |
</article><!-- #post-${ID} --> | |
<article id="post-1045" class="post-1045 post type-post status-publish format-standard hentry category-uncategorized entry"> | |
<header class="entry-header responsive-max-width"> | |
<h2 class="entry-title"><a href="https://web-dev-hub.com/2021/12/25/semantic-versioning/" rel="bookmark">Semantic Versioning</a></h2> </header><!-- .entry-header --> | |
<div class="entry-content"> | |
<h1 id="semantic-versioning">Semantic Versioning</h1> | |
<p>If there’s one great thing in Node.js packages, it’s that they all agreed on using Semantic Versioning for their version numbering.</p> | |
<p>The Semantic Versioning concept is simple: all versions have 3 digits:<code>x.y.z</code>.</p> | |
<ul><li>the first digit is the major version</li><li>the second digit is the minor version</li><li>the third digit is the patch version</li></ul> | |
<p>When you make a new release, you don’t just up a number as you please, but you have rules:</p> | |
<ul><li>you up the major version when you make incompatible API changes</li><li>you up the minor version when you add functionality in a backward-compatible manner</li><li>you up the patch version when you make backward-compatible bug fixes</li></ul> | |
<p>The convention is adopted all across programming languages, and it is very important that every<code>npm</code>package adheres to it, because the whole system depends on that.</p> | |
<p>Why is that so important?</p> | |
<p>Because<code>npm</code>set some rules we can use in the<code>package.json</code>file to choose which versions it can update our packages to, when we run<code>npm update</code>.</p> | |
<p>The rules use those symbols:</p> | |
<ul><li><code>^</code></li><li><code>~</code></li><li><code>></code></li><li><code>>=</code></li><li><code><</code></li><li><code><=</code></li><li><code>=</code></li><li><code>-</code></li><li><code>||</code></li></ul> | |
<p>Let’s see those rules in detail:</p> | |
<ul><li><code>^</code>: It will only do updates that do not change the leftmost non-zero number. If you write<code>^0.13.0</code>, when running<code>npm update</code>, it can update to<code>0.13.1</code>,<code>0.13.2</code>, and so on, but not to<code>0.14.0</code>or above. If you write<code>^1.13.0</code>, when running<code>npm update</code>, it can update to<code>1.13.1</code>,<code>1.14.0</code>and so on, but will not update to<code>2.0.0</code>or above.</li><li><code>~</code>: if you write<code>~0.13.0</code>, when running<code>npm update</code>it can update to patch releases:<code>0.13.1</code>is ok, but<code>0.14.0</code>is not.</li><li><code>></code>: you accept any version higher than the one you specify</li><li><code>>=</code>: you accept any version equal to or higher than the one you specify</li><li><code><=</code>: you accept any version equal or lower to the one you specify</li><li><code><</code>: you accept any version lower to the one you specify</li><li><code>=</code>: you accept that exact version</li><li><code>-</code>: you accept a range of versions. Example:<code>2.1.0 - 2.6.2</code></li><li><code>||</code>: you combine sets. Example:<code>< 2.1 || > 2.6</code></li></ul> | |
<p>You can combine some of those notations, for example use<code>1.0.0 || >=1.1.0 <1.2.0</code>to either use 1.0.0 or one release from 1.1.0 up, but lower than 1.2.0.</p> | |
<p>There are other rules, too:</p> | |
<ul><li>no symbol: you accept only that specific version you specify (<code>1.2.1</code>)</li><li><code>latest</code>: you want to use the latest version available</li></ul> | |
</div><!-- .entry-content --> | |
<footer class="entry-footer responsive-max-width"> | |
<span class="byline"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><span class="screen-reader-text">Posted by</span><span class="author vcard"><a class="url fn n" href="https://web-dev-hub.com/author/gunerb1/">bgoonz</a></span></span><span class="posted-on"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><defs><path id="a" d="M0 0h24v24H0V0z"></path></defs><clipPath id="b"><use xlink:href="#a" overflow="visible"></use></clipPath><path clip-path="url(#b)" d="M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10 10-4.5 10-10S17.5 2 12 2zm4.2 14.2L11 13V7h1.5v5.2l4.5 2.7-.8 1.3z"></path></svg><a href="https://web-dev-hub.com/2021/12/25/semantic-versioning/" rel="bookmark"><time class="entry-date published updated" datetime="2021-12-25T00:31:37-05:00">December 25, 2021</time></a></span><span class="cat-links"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M10 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2h-8l-2-2z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><span class="screen-reader-text">Posted in</span><a href="https://web-dev-hub.com/category/uncategorized/" rel="category tag">Uncategorized</a></span><span class="comments-link"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M21.99 4c0-1.1-.89-2-1.99-2H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h14l4 4-.01-18z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><a href="https://web-dev-hub.com/2021/12/25/semantic-versioning/#respond">Leave a comment<span class="screen-reader-text"> on Semantic Versioning</span></a></span><span class="edit-link"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04c.39-.39.39-1.02 0-1.41l-2.34-2.34c-.39-.39-1.02-.39-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><a class="post-edit-link" href="https://wordpress.com/post/web-dev-hub.com/1045">Edit <span class="screen-reader-text">Semantic Versioning</span></a></span> </footer><!-- .entry-footer --> | |
</article><!-- #post-${ID} --> | |
<article id="post-1027" class="post-1027 post type-post status-publish format-standard hentry category-uncategorized entry"> | |
<header class="entry-header responsive-max-width"> | |
<h2 class="entry-title"><a href="https://web-dev-hub.com/2021/10/12/how-to-write-website-content/" rel="bookmark">How to Write Website Content </a></h2> </header><!-- .entry-header --> | |
<div class="entry-content"> | |
<h2 id="what-is-web-copy">What Is Web Copy?</h2> | |
<p>Website copy usually refers to the main body of text on your website, intended to sell your product or service. It’s the words that guide your visitors through the site, explain your brand concept, and tell people about your services. Typically, these main pages include the Homepage, About Us, Service Page, and FAQ. </p> | |
<p>So what makes good website content?</p> | |
<p><strong>Your web copy should match the search intent of your potential customers. </strong>You want to help them solve their problem and take action — make a purchase, subscribe to your blog, or join your mailing list. </p> | |
<h2 id="how-to-write-website-content">How to Write Website Content </h2> | |
<p>We’ve divided our recommendations into three groups: Pre-Writing Tips, Writing Tips, and Post-Writing Tips.</p> | |
<figure class="wp-block-image"><img src="https://static.semrush.com/cdn-cgi/image/width=1010/blog/uploads/media/0d/13/0d13a4faae59b4a0c34667182e9f3bcf/2x_nfographic_Website_Copy_101_How_To_Write_Website_Content_1.png" alt="Website_Copy_101_How_To_Write_Website_Content_1.png" /></figure> | |
<h3 id="pre-writing-tips">Pre-Writing Tips</h3> | |
<p>Your content’s foundation should be laid before you start writing, and here are three key points to keep in mind.</p> | |
<h4 id="tip-#1:-define-your-purpose">Tip #1: Define Your Purpose</h4> | |
<p>The single most important thing for any writer of copy is to understand its purpose. Knowing your end goal from the outset helps you craft the perfect piece of content and an ideal call-to-action statement (I’ll talk more about CTAs in <a href="https://www.semrush.com/blog/14-tips-for-writing-awesome-website-content/#header8">Writing Tips</a>). </p> | |
<p>The objective of the copy supports the goals of the business. So, find your answers to the questions about it:</p> | |
<ul><li>Is the website intended to sell a product or a service?</li><li>Is it focused on building traffic with the intention of increasing advertising revenue or sponsorships?</li><li>Is it aimed at attracting new clients and generating leads?</li><li>Is the main objective to attract subscribers or build a community?</li></ul> | |
<h4 id="tip-#2:-understand-your-target-audience">Tip #2: Understand Your Target Audience</h4> | |
<p>Let’s say selling is your primary goal. You can determine the best methods of selling only by knowing your audience. The more you know about your prospects, the better you can convert them into paying customers. </p> | |
<p>To write copy that hooks your potential customers, you need to get into their mindset:</p> | |
<ul><li>Who are the people coming to your site? </li><li>What kinds of problems do they want to solve?</li><li>What search terms would they type into a search bar?</li></ul> | |
<p>If you can learn to write in the ways in which your visitors speak or search, you can start building up a relationship of trust. And if you answer their specific question, they may become your loyal audience and clients. </p> | |
<figure class="wp-block-image"><img src="https://static.semrush.com/cdn-cgi/image/width=1010/blog/uploads/media/e4/8a/e48afb1e1f95760e731ac8321b2e96c6/audience%20inisghts.png" alt="audience insights" /></figure> | |
<p>To create your customer’s persona, use our <a href="https://static.semrush.com/blog/uploads/files/05/1c/051cbe72166a042913c75ed81399e7ec/A4_How_to_Create_Your_Buyer_Persona_3.pdf?utm_source=blog&utm_medium=pdf&utm_campaign=en_buyer_persona">Buyer Persona Template</a>.</p> | |
<h4 id="tip-#3:-know-your-competitors">Tip #3: Know Your Competitors</h4> | |
<p>It’s also a good move to do some research on the websites of your competitors.</p> | |
<p>It’s likely that visitors to your website will also be considering the competition, so you need to make a strategic decision about whether to offer similar content or branch out and offer something different. Research can be an excellent way to spot trends among competitors and get ahead of the game. </p> | |
<p>The easiest way to do this is simply to search your main product, service, or topic in Google, discover which sites are ranking, and investigate what they are doing:</p> | |
<ul><li>What is the primary service they offer?</li><li>What type of content do they use on their main pages — success stories, videos, statistics?</li><li>What audience do they target? </li></ul> | |
<p><strong>Lily Ray,</strong> <a href="https://twitter.com/Whigsy">@lilyraynyc</a>:</p> | |
<p>“Look at the search results to determine how feasible it even is to rank, how we should structure our content, tone/sentiment analysis, what featured/rich snippets we can earn, and whether to focus on informational and/or transactional content.”</p> | |
<p><strong>Kyle Whigham,</strong> <a href="https://twitter.com/lilyraynyc">@Whigsy</a>:</p> | |
<p>“Identify which pieces of content are driving engagement, be it traffic (estimated of course), likes, shares, etc. Social signals send a clear message in terms of what your shared audience finds valuable and interesting. Use those pages and compare page titles, meta descriptions, and type of content (long/short form, video content, etc.).”</p> | |
<p>These are our experts’ opinions expressed on our Twitter chat about <a href="https://www.semrush.com/blog/semrushchat-ways-competitors-help-improve-content-strategy/">competitor content analysis</a> — read our summary to find more insights on the topic.</p> | |
<figure class="wp-block-image"><img src="https://static.semrush.com/cdn-cgi/image/width=1010/blog/uploads/media/5c/7d/5c7d7bd0988574c2c97f8f3e5e098e17/seo%20content%20recommendations.png" alt="seo content recommendations" /></figure> | |
<h3 id="writing-tips">Writing Tips</h3> | |
<p>Writing copy that resonates requires hard work, good writing skills, and anticipation of visitors’ questions. Here are nine tips to help you engage your audience and convert them to customers.</p> | |
<h4 id="tip-#4:-hook-your-readers-from-the-first-line">Tip #4: Hook Your Readers from the First Line</h4> | |
<p>As I said at the beginning, you might have just 15 seconds to capture your reader’s interest. If you manage this, your new challenge is to get the reader to stay on the site. </p> | |
<p>You can start your copy with some exciting data, a one-sentence story, or a question. Make sure people are hungry for more content after reading the introduction. </p> | |
<figure class="wp-block-image"><img src="https://static.semrush.com/cdn-cgi/image/width=1010/blog/uploads/media/8f/bb/8fbbee775bce0f92e5de70151c43df02/Screenshot%202020-11-05%20at%2019.56.18.png" alt="website content hook readers dyson" /></figure> | |
<h4 id="tip-#5:-make-your-copy-scannable">Tip #5: Make Your Copy Scannable</h4> | |
<p>The layout is important too. Most people skim read, so to ensure that the text is easily scannable, you should include headers, bulleted and numbered lists, descriptive subheadings, and white space between paragraphs. </p> | |
<figure class="wp-block-image"><img src="https://static.semrush.com/cdn-cgi/image/width=1010/blog/uploads/media/9f/2c/9f2c6b7f2f71a0d8190fe68488ccd494/Screenshot%202020-10-29%20at%2023.07.19.png" alt="website content -making copy scannable" /></figure> | |
<h4 id="tip-#6:-help-readers-navigate">Tip #6: Help Readers Navigate</h4> | |
<p>Remember that there are multiple routes through which audiences find web content. It could be from a post shared on social media, via links on other websites, via a marketing email, or through a search engine results page. </p> | |
<p>People who receive your message might not be that familiar with your brand. They will be grateful if you make it clear what your business offers and put relevant links for further details in your copy.</p> | |
<figure class="wp-block-image"><img src="https://static.semrush.com/cdn-cgi/image/width=1010/blog/uploads/media/00/b6/00b6c3ed198a394f9643a80bd4363d38/Screenshot%202020-10-30%20at%2018.54.49.png" alt="website content - making your offer clear" /></figure> | |
<p>It’s also a good idea to post links to your social media accounts prominently to create a connection between your brand and visitors. They may leave the site, but remain your social media subscriber and return to the site.</p> | |
<h4 id="tip-#7:-talk-to-readers-as-you-would-a-friend">Tip #7: Talk to Readers as You Would a Friend</h4> | |
<p>Create a bond between your brand and the client using such techniques as:</p> | |
<ul><li>Active voice: use sentence structure like “You can order our services” instead of “Our services can be ordered.” The passive voice is relevant when you want to sound more formal; in other cases, use the active voice to sound more personal.</li><li>Direct addressing: use “you” to address your reader, “we” to speak from the point of view of a company, and “I” for an individual voice. </li></ul> | |
<figure class="wp-block-image"><img src="https://static.semrush.com/cdn-cgi/image/width=1010/blog/uploads/media/9e/aa/9eaa16de9ea2faf6666157a46be0d853/Screenshot%202020-10-30%20at%2018.49.20.png" alt="website content language tips" /></figure> | |
<h4 id="tip-#8:-talk-in-layman's-terms">Tip #8: Talk in Layman’s Terms</h4> | |
<p>Continuing the idea of the conciseness of your copy, keep your copy simple. Research from The Literacy Project tells us that the average American reads at <a href="https://www.wyliecomm.com/2019/03/us-literacy-rate/#:~:text=The%20average%20American%20reads%20at%20the%207th-%20to%208th-grade,according%20to%20The%20Literacy%20Project.">7th to 8th-grade level</a>. If you use simple language, your readers might be more likely to understand and remember more.</p> | |
<p>Make sure you: </p> | |
<ul><li>Use short sentences — they help to communicate your message clearly.</li><li>Limit the use of adverbs and adjectives in order to keep sentences short and snappy.</li><li>Avoid using jargon — not all readers are experts, so replace professional terminology with simpler alternatives and provide hyperlinks to other articles with more background information.</li><li>Provide examples — readers better visualize your messages with examples rather than high-level statements. </li></ul> | |
<h4 id="tip-#9:-avoid-spelling,-grammar,-or-punctuation-errors">Tip #9: Avoid Spelling, Grammar, or Punctuation Errors</h4> | |
<p>It should go without saying, but the content on any platform should be free from spelling, grammar, or punctuation errors. Sloppy mistakes can put off a huge swathe of potential customers.</p> | |
<h4 id="tip-#10:-encourage-readers-to-act">Tip #10: Encourage Readers to Act</h4> | |
<p>Remember me saying that you should know your goal from the beginning? It’s time to apply this knowledge. </p> | |
<p>The purpose of your web copy is to encourage some kind of action. It might be that you want visitors to make a purchase, subscribe to your blog, or join your mailing list, etc. </p> | |
<p>By including a clear call to action using words like “Join,” “Sign Up,” “Get a Call,” “Subscribe,” “Watch,” and “Learn More” you can help to initiate the desired activity. </p> | |
<figure class="wp-block-image"><img src="https://static.semrush.com/cdn-cgi/image/width=1010/blog/uploads/media/38/2e/382ecc8d2a05802d2818fc1330b0714b/Screenshot%202020-11-03%20at%2015.29.02.png" alt="website content CTA example" /></figure> | |
<h4 id="tip-#11:-demonstrate-proof-that-the-cta-is-worth-it">Tip #11: Demonstrate Proof that the CTA Is Worth It</h4> | |
<p>A good strategy is to include some proof to back up statements you have made about your products or services. This might be through success stories, original research data, customer testimonials, a relevant expert’s biography, or partnerships. This will help show your expertise and dispel any doubts that may inhibit the customer’s action. </p> | |
<figure class="wp-block-image"><img src="https://static.semrush.com/cdn-cgi/image/width=1010/blog/uploads/media/3c/64/3c640a4c791aec1ab2633bbeb8de9947/Screenshot%202020-10-29%20at%2023.28.45.png" alt="website content testimonials and social proof" /></figure> | |
<h4 id="tip-#12:-add-visuals">Tip #12: Add Visuals</h4> | |
<p>People remember only 20% of what they read, but <a href="https://neomam.com/interactive/13reasons/">80% of what they see and do</a>. If you add infographics, pictures, graphs, or videos to your copy, this will help people process information and grab their attention. </p> | |
<p>Here, a colleague of mine wrote more ideas on <a href="https://www.semrush.com/blog/interactive-content/">what interactive content you can create</a> to interact with your audience — quizzes, calculators, infographics, games, maps, etc.</p> | |
<p>These are the main aspects of writing strong, impactful copy. For those who prefer to order content on our Marketplace, we have a guide on how to write your terms of reference and <a href="https://www.semrush.com/blog/seo-copywriting/">evaluate the work of a copywriter</a>.</p> | |
<h2 id="post-writing-tips">Post-Writing Tips</h2> | |
<p>You’ve written the text, but the work goes on because you need to ensure its searchability and regularly update it.</p> | |
<h4 id="tip-#13:-optimize-for-search-engines">Tip #13: Optimize for Search Engines</h4> | |
<p>While it’s essential to focus on your human audience, it’s a foolhardy move to ignore Google’s power. It’s important to optimize content for the audience and ensure that the relevant keywords are included in titles, subheadings, and meta descriptions.</p> | |
<p>It’s important to avoid <a href="https://support.google.com/webmasters/answer/66358?hl=en">keyword stuffing</a>, though, which can damage your rankings with search engines. Aiming for a 1-2% keyword density is about right. </p> | |
<p>You aim to produce copy which will be valuable to customers and help them to make decisions. Alongside this, you also need to remember the basics of SEO: </p> | |
<ul><li><strong>Include keywords in headlines and sub-headers.</strong> Add the primary <a href="https://www.semrush.com/blog/how-to-create-seo-friendly-content-with-semrush/#header8">keyword to the title</a> and H1 and 5-10 additional ones to the <a href="https://www.semrush.com/blog/how-to-create-seo-friendly-content-with-semrush/#header11">subheadings and body text</a>. </li><li><strong>Take care of the metadata</strong>. Describe the specific web page in <a href="https://www.semrush.com/blog/how-to-create-seo-friendly-content-with-semrush/#header10">1-2 sentences</a> to encourage a user to click on your link over your competitors’.</li><li><strong>Make your URLs readable.</strong> Help your readers to understand <a href="https://www.semrush.com/blog/how-to-create-seo-friendly-content-with-semrush/#header13">what’s inside</a> the page. </li><li><strong>Add relevant and helpful links. </strong>This way, you will encourage visitors to <a href="https://www.semrush.com/blog/how-to-create-seo-friendly-content-with-semrush/#header14">stay longer</a> on the website, and you will rise in Google’s estimation.</li><li><strong>Optimize your visual content. </strong><a href="https://www.semrush.com/blog/how-to-create-seo-friendly-content-with-semrush/#header12">Resize images</a> to make the site loading faster, and add alt tags for search engines.</li></ul> | |
<h4 id="tip-#14:-keep-your-website-fresh-and-up-to-date">Tip #14: Keep Your Website Fresh and Up to Date</h4> | |
<p>One of the first things people do after they hear about a company is look up its website. Your website is your business card, so be sure to make a good first impression. </p> | |
<ul><li><strong>Refresh your content from time to time.</strong> Add some new relevant information such as new stats and trends or new product details.</li><li><strong>Update your outdated banners or CTAs.</strong> Replace them with relevant offers to reactivate your content marketing funnel and improve your conversion rates.</li><li><strong>Make sure the copy performs well.</strong> Underperforming copy may need more examples, tips, and practical details.</li><li><strong>Repurpose your content.</strong> You can <a href="https://www.semrush.com/blog/guide-to-repurposing-content-in-2020/">try a different format</a> for this content, such as creating a video and incorporating it into the page.</li><li><strong>Optimize internal linking.</strong> Add links pointing to new articles in blog posts with related topics.</li></ul> | |
<p>You should also regularly review your <a href="https://www.semrush.com/blog/content-audit-for-content-marketing-strategy/">content strategy</a> to ensure that your web copy has the desired impact on visitor journeys through your website.</p> | |
</div><!-- .entry-content --> | |
<footer class="entry-footer responsive-max-width"> | |
<span class="byline"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><span class="screen-reader-text">Posted by</span><span class="author vcard"><a class="url fn n" href="https://web-dev-hub.com/author/gunerb1/">bgoonz</a></span></span><span class="posted-on"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><defs><path id="a" d="M0 0h24v24H0V0z"></path></defs><clipPath id="b"><use xlink:href="#a" overflow="visible"></use></clipPath><path clip-path="url(#b)" d="M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10 10-4.5 10-10S17.5 2 12 2zm4.2 14.2L11 13V7h1.5v5.2l4.5 2.7-.8 1.3z"></path></svg><a href="https://web-dev-hub.com/2021/10/12/how-to-write-website-content/" rel="bookmark"><time class="entry-date published updated" datetime="2021-10-12T06:02:04-04:00">October 12, 2021</time></a></span><span class="cat-links"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M10 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2h-8l-2-2z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><span class="screen-reader-text">Posted in</span><a href="https://web-dev-hub.com/category/uncategorized/" rel="category tag">Uncategorized</a></span><span class="comments-link"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M21.99 4c0-1.1-.89-2-1.99-2H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h14l4 4-.01-18z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><a href="https://web-dev-hub.com/2021/10/12/how-to-write-website-content/#respond">Leave a comment<span class="screen-reader-text"> on How to Write Website Content </span></a></span><span class="edit-link"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04c.39-.39.39-1.02 0-1.41l-2.34-2.34c-.39-.39-1.02-.39-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><a class="post-edit-link" href="https://wordpress.com/post/web-dev-hub.com/1027">Edit <span class="screen-reader-text">How to Write Website Content </span></a></span> </footer><!-- .entry-footer --> | |
</article><!-- #post-${ID} --> | |
<article id="post-1019" class="post-1019 post type-post status-publish format-standard hentry category-uncategorized entry"> | |
<header class="entry-header responsive-max-width"> | |
<h2 class="entry-title"><a href="https://web-dev-hub.com/2021/10/12/python/" rel="bookmark">Python</a></h2> </header><!-- .entry-header --> | |
<div class="entry-content"> | |
Python Problems & Solutions For Beginners | |
* { | |
font-family: Georgia, Cambria, “Times New Roman”, Times, serif; | |
} | |
html, body { | |
margin: 0; | |
padding: 0; | |
} | |
h1 { | |
font-size: 50px; | |
margin-bottom: 17px; | |
color: #333; | |
} | |
h2 { | |
font-size: 24px; | |
line-height: 1.6; | |
margin: 30px 0 0 0; | |
margin-bottom: 18px; | |
margin-top: 33px; | |
color: #333; | |
} | |
h3 { | |
font-size: 30px; | |
margin: 10px 0 20px 0; | |
color: #333; | |
} | |
header { | |
width: 640px; | |
margin: auto; | |
} | |
section { | |
width: 640px; | |
margin: auto; | |
} | |
section p { | |
margin-bottom: 27px; | |
font-size: 20px; | |
line-height: 1.6; | |
color: #333; | |
} | |
section img { | |
max-width: 640px; | |
} | |
footer { | |
padding: 0 20px; | |
margin: 50px 0; | |
text-align: center; | |
font-size: 12px; | |
} | |
.aspectRatioPlaceholder { | |
max-width: auto !important; | |
max-height: auto !important; | |
} | |
.aspectRatioPlaceholder-fill { | |
padding-bottom: 0 !important; | |
} | |
header, | |
section[data-field=subtitle], | |
section[data-field=description] { | |
display: none; | |
} | |
<article class="h-entry"> | |
<header> | |
<h1 class="p-name">Python Problems & Solutions For Beginners</h1> | |
</header> | |
<section class="p-summary"> | |
Introduction to python taught through example problems. Solutions are included in embedded repl.it at the bottom of this page for you to… | |
</section> | |
<section class="e-content"> | |
<section class="section section--body section--first"><div class="section-divider"><hr class="section-divider"></div><div class="section-content"><div class="section-inner sectionLayout--insetColumn"><h3 id="7c03" class="graf graf--h3 graf--leading graf--title">Python Problems & Solutions For Beginners</h3><h4 id="d9e0" class="graf graf--h4 graf-after--h3 graf--subtitle">Introduction to python taught through example problems. Solutions are included in embedded repl.it at the bottom of this page for you to practice and refactor.</h4><h3 id="bd54" class="graf graf--h3 graf-after--h4">Python Practice Problems</h3><figure id="804f" class="graf graf--figure graf-after--h3 graf--trailing"><img class="graf-image" data-width="1000" data-height="640" src="https://webdevhubcom.files.wordpress.com/2021/10/e3c0d-0dmdmgwojkhj-5sop.gif"></figure></div></div></section><section class="section section--body"><div class="section-divider"><hr class="section-divider"></div><div class="section-content"><div class="section-inner sectionLayout--insetColumn"><h4 id="ab6b" class="graf graf--h4 graf--leading">Here are some other articles for reference if you need them:</h4><div id="3689" class="graf graf--mixtapeEmbed graf-after--h4"><a href="https://medium.com/geekculture/beginners-guide-to-python-e5a59b5bb64d" class="markup--anchor markup--mixtapeEmbed-anchor" title="https://medium.com/geekculture/beginners-guide-to-python-e5a59b5bb64d"><strong class="markup--strong markup--mixtapeEmbed-strong">Beginners Guide To Python</strong><br><em class="markup--em markup--mixtapeEmbed-em">My favorite language for maintainability is Python. It has simple, clean syntax, object encapsulation, good library…</em>medium.com</a><a href="https://medium.com/geekculture/beginners-guide-to-python-e5a59b5bb64d" class="js-mixtapeImage mixtapeImage u-ignoreBlock" style="background-image:url('https://cdn-images-1.medium.com/fit/c/160/160/1*59V2ZNbyJfsdGR2N20PM7w.png');"></a></div><div id="3b6f" class="graf graf--mixtapeEmbed graf-after--mixtapeEmbed graf--trailing"><a href="https://levelup.gitconnected.com/python-study-guide-for-a-native-javascript-developer-5cfdf3d2bdfb" class="markup--anchor markup--mixtapeEmbed-anchor" title="https://levelup.gitconnected.com/python-study-guide-for-a-native-javascript-developer-5cfdf3d2bdfb"><strong class="markup--strong markup--mixtapeEmbed-strong">Python Study Guide for a JavaScript Programmer</strong><br><em class="markup--em markup--mixtapeEmbed-em">A guide to commands in Python from what you know in JavaScript</em>levelup.gitconnected.com</a><a href="https://levelup.gitconnected.com/python-study-guide-for-a-native-javascript-developer-5cfdf3d2bdfb" class="js-mixtapeImage mixtapeImage u-ignoreBlock" style="background-image:url('https://cdn-images-1.medium.com/fit/c/160/160/1*3V9VOfPk_hrFdbEAd3j-QQ.png');"></a></div></div></div></section><section class="section section--body"><div class="section-divider"><hr class="section-divider"></div><div class="section-content"><div class="section-inner sectionLayout--insetColumn"><h3 id="f507" class="graf graf--h3 graf--leading">Here are the problems without solutions for you to practice with:</h3></div><div class="section-inner sectionLayout--outsetColumn"><figure id="7edf" class="graf graf--figure graf--iframe graf--layoutOutsetCenter graf-after--h3 graf--trailing"></figure></div></div></section><section class="section section--body"><div class="section-divider"><hr class="section-divider"></div><div class="section-content"><div class="section-inner sectionLayout--insetColumn"><h3 id="ec77" class="graf graf--h3 graf--leading">Problem 1</h3><p id="af14" class="graf graf--p graf-after--h3">Create a program that asks the user to enter their name and their age. Print out a message addressed to them that tells them the year that they will turn <code class="markup--code markup--p-code">100</code> years old.</p><p id="6e36" class="graf graf--p graf-after--p">The <code class="markup--code markup--p-code"><a href="https://docs.python.org/3/library/datetime.html#module-datetime" class="markup--anchor markup--p-anchor" title="datetime: Basic date and time types." rel="noopener" target="_blank">datetime</a></code> module supplies classes for manipulating dates and times.</p><p id="4ef0" class="graf graf--p graf-after--p">While date and time arithmetic is supported, the focus of the implementation is on efficient attribute extraction for output formatting and manipulation.</p><figure id="0195" class="graf graf--figure graf--iframe graf-after--p"></figure><div id="8bfb" class="graf graf--mixtapeEmbed graf-after--figure"><a href="https://docs.python.org/3/library/datetime.html" class="markup--anchor markup--mixtapeEmbed-anchor" title="https://docs.python.org/3/library/datetime.html"><strong class="markup--strong markup--mixtapeEmbed-strong">datetime – Basic date and time types – Python 3.9.6 documentation</strong><br><em class="markup--em markup--mixtapeEmbed-em">Only one concrete class, the class, is supplied by the module. The class can represent simple timezones with fixed…</em>docs.python.org</a><a href="https://docs.python.org/3/library/datetime.html" class="js-mixtapeImage mixtapeImage mixtapeImage--empty u-ignoreBlock"></a></div><h3 id="8f5a" class="graf graf--h3 graf-after--mixtapeEmbed">Problem 2</h3><p id="bad6" class="graf graf--p graf-after--h3">Ask the user for a number. Depending on whether the number is <code class="markup--code markup--p-code">even</code> or <code class="markup--code markup--p-code">odd</code>, print out an appropriate message to the user.</p><h4 id="f29a" class="graf graf--h4 graf-after--p">Bonus:</h4><ol class="postList"><li id="eebc" class="graf graf--li graf-after--h4">If the number is a multiple of <code class="markup--code markup--li-code">4</code>, print out a different message.</li><li id="306e" class="graf graf--li graf-after--li">Ask the user for two numbers: one number to check (call it num) and one number to divide by (check). If check divides evenly into num, tell that to the user. If not, print a different appropriate message.</li></ol><figure id="33a1" class="graf graf--figure graf--iframe graf-after--li"></figure><h3 id="b364" class="graf graf--h3 graf-after--figure">Problem 3</h3><p id="5191" class="graf graf--p graf-after--h3">Take a list and write a program that prints out all the elements of the list that are <code class="markup--code markup--p-code">less</code> than <code class="markup--code markup--p-code">5</code>.</p><p id="7d28" class="graf graf--p graf-after--p">Extras:</p><ol class="postList"><li id="fe03" class="graf graf--li graf-after--p">Instead of printing the elements one by one, make a new list that has all the elements less than <code class="markup--code markup--li-code">5</code> from this list in it and print out this new list.</li><li id="186b" class="graf graf--li graf-after--li">Write this in one line of Python.</li><li id="9cd1" class="graf graf--li graf-after--li">Ask the user for a number and return a list that contains only elements from the original list a that are smaller than that number given by the user.</li></ol><figure id="b745" class="graf graf--figure graf--iframe graf-after--li"></figure><h3 id="525c" class="graf graf--h3 graf-after--figure">Problem 4</h3><p id="b39c" class="graf graf--p graf-after--h3">Create a program that asks the user for a number and then prints out a list of all the divisors of that number. (If you don’t know what a divisor is, it is a number that divides evenly into another number.</p><p id="7e32" class="graf graf--p graf-after--p">For example, <code class="markup--code markup--p-code">13</code> is a divisor of <code class="markup--code markup--p-code">26</code> because <code class="markup--code markup--p-code">26 / 13</code> has no remainder.)</p><figure id="f860" class="graf graf--figure graf--iframe graf-after--p"></figure><h3 id="e7ec" class="graf graf--h3 graf-after--figure">Problem 5</h3><p id="9b59" class="graf graf--p graf-after--h3">Take two lists, and write a program that returns a list that contains only the elements that are <code class="markup--code markup--p-code">common between the lists (without duplicates)</code>. Make sure your program works on two lists of different sizes.</p><div id="eab0" class="graf graf--mixtapeEmbed graf-after--p"><a href="https://docs.python.org/3/library/random.html" class="markup--anchor markup--mixtapeEmbed-anchor" title="https://docs.python.org/3/library/random.html"><strong class="markup--strong markup--mixtapeEmbed-strong">random – Generate pseudo-random numbers – Python 3.9.6 documentation</strong><br><em class="markup--em markup--mixtapeEmbed-em">Source code: Lib/random.py This module implements pseudo-random number generators for various distributions. For…</em>docs.python.org</a><a href="https://docs.python.org/3/library/random.html" class="js-mixtapeImage mixtapeImage mixtapeImage--empty u-ignoreBlock"></a></div><p id="5c2e" class="graf graf--p graf-after--mixtapeEmbed">Bonus:</p><ol class="postList"><li id="e18a" class="graf graf--li graf-after--p">Randomly generate two lists to test this.</li><li id="148a" class="graf graf--li graf-after--li">Write this in one line of Python.</li></ol><figure id="9371" class="graf graf--figure graf--iframe graf-after--li"></figure><h3 id="371b" class="graf graf--h3 graf-after--figure">Problem 6</h3><p id="c45b" class="graf graf--p graf-after--h3">Ask the user for a string and print out whether this string is a <code class="markup--code markup--p-code">palindrome</code> or not. (A palindrome is a string that reads the same forwards and backwards.)</p><blockquote id="2d3a" class="graf graf--pullquote graf-after--p">Here’s 5 ways to reverse a string (courtesy of <a href="https://www.geeksforgeeks.org/reverse-string-python-5-different-ways/" class="markup--anchor markup--pullquote-anchor" rel="noopener" target="_blank">geeksforgeeks</a>)</blockquote><figure id="6e18" class="graf graf--figure graf--iframe graf-after--pullquote graf--trailing"></figure></div></div></section><section class="section section--body"><div class="section-divider"><hr class="section-divider"></div><div class="section-content"><div class="section-inner sectionLayout--insetColumn"><figure id="939e" class="graf graf--figure graf--iframe graf--leading"></figure><h3 id="a503" class="graf graf--h3 graf-after--figure">Problem 7</h3><p id="c127" class="graf graf--p graf-after--h3">Let’s say I give you a list saved in a variable: a = <code class="markup--code markup--p-code">[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]</code>.</p><p id="ac74" class="graf graf--p graf-after--p">Write one line of Python that takes this list a and makes a new list that has only the <code class="markup--code markup--p-code">even</code> elements of this list in it.</p><figure id="bec2" class="graf graf--figure graf--iframe graf-after--p"></figure><h3 id="3568" class="graf graf--h3 graf-after--figure">Problem 8</h3><p id="1c93" class="graf graf--p graf-after--h3">Make a two-player <code class="markup--code markup--p-code">Rock-Paper-Scissors</code> game.</p><p id="ac08" class="graf graf--p graf-after--p"><strong class="markup--strong markup--p-strong">Hint:</strong><br>Ask for player plays (using input), compare them. Print out a message of congratulations to the winner, and ask if the players want to start a new game.</p><figure id="3aef" class="graf graf--figure graf-after--p"><img class="graf-image" data-width="1200" data-height="1148" src="https://webdevhubcom.files.wordpress.com/2021/10/2dc55-01_4w6u4d7edi2r4h.png"></figure><figure id="d230" class="graf graf--figure graf--iframe graf-after--figure"></figure><h3 id="8e61" class="graf graf--h3 graf-after--figure">Problem 9</h3><p id="65b2" class="graf graf--p graf-after--h3">Generate a random number between <code class="markup--code markup--p-code">1 and 100 (including 1 and 100)</code>. Ask the user to guess the number, then tell them whether they guessed <code class="markup--code markup--p-code">too low</code>, <code class="markup--code markup--p-code">too high</code>, or <code class="markup--code markup--p-code">exactly right</code>.</p><blockquote id="77cd" class="graf graf--pullquote graf-after--p"><strong class="markup--strong markup--pullquote-strong">Hint:</strong><br>Remember to use the user input from the very first exercise.</blockquote><p id="33d1" class="graf graf--p graf-after--pullquote"><strong class="markup--strong markup--p-strong">Extras:</strong><br>Keep the game going until the user types <code class="markup--code markup--p-code">“exit”</code>.<br>Keep track of how many guesses the user has taken, and when the game ends, print this out.</p><figure id="b9ab" class="graf graf--figure graf--iframe graf-after--p"></figure><h3 id="b213" class="graf graf--h3 graf-after--figure">Problem 10</h3><p id="f4cf" class="graf graf--p graf-after--h3">Write a program that asks the user how many Fibonacci numbers to generate and then generates them. Take this opportunity to think about how you can use functions. Make sure to ask the user to enter the number of numbers in the sequence to generate.</p><p id="ef7b" class="graf graf--p graf-after--p"><strong class="markup--strong markup--p-strong">Hint:</strong><br>The Fibonacci sequence is a sequence of numbers where the next number in the sequence is the sum of the previous two numbers in the sequence. The sequence looks like this: <code class="markup--code markup--p-code">1, 1, 2, 3, 5, 8, 13, …</code></p><figure id="d13b" class="graf graf--figure graf-after--p"><img class="graf-image" data-width="819" data-height="647" src="https://webdevhubcom.files.wordpress.com/2021/10/2c264-02xjsvlgikf6dg7qc.png"></figure><figure id="ed45" class="graf graf--figure graf--iframe graf-after--figure graf--trailing"></figure></div></div></section><section class="section section--body"><div class="section-divider"><hr class="section-divider"></div><div class="section-content"><div class="section-inner sectionLayout--insetColumn"><h3 id="115b" class="graf graf--h3 graf--leading">Intermediate Problems:</h3><figure id="f775" class="graf graf--figure graf-after--h3 graf--trailing"><img class="graf-image" data-width="1050" data-height="520" src="https://webdevhubcom.files.wordpress.com/2021/10/130ce-0htu58jgsgkrszi76.gif"></figure></div></div></section><section class="section section--body"><div class="section-divider"><hr class="section-divider"></div><div class="section-content"><div class="section-inner sectionLayout--insetColumn"><h3 id="3ce7" class="graf graf--h3 graf--leading">Problem 11</h3><p id="1e02" class="graf graf--p graf-after--h3">In linear algebra, <em class="markup--em markup--p-em">a Toeplitz matrix is one in which the elements on any given diagonal from top left to bottom right are identical.</em><br>Here is an example:</p><pre id="02d5" class="graf graf--pre graf-after--p"><code class="markup--code markup--pre-code">1 2 3 4 8<br>5 1 2 3 4<br>4 5 1 2 3<br>7 4 5 1 2</code></pre><p id="0841" class="graf graf--p graf-after--pre">Write a program to determine whether a given input is a <code class="markup--code markup--p-code">Toeplitz</code> matrix.</p><figure id="7eb8" class="graf graf--figure graf--iframe graf-after--p"></figure><h3 id="f18a" class="graf graf--h3 graf-after--figure">Problem 12</h3><p id="7370" class="graf graf--p graf-after--h3">Given a positive integer <code class="markup--code markup--p-code">N</code>, find the smallest number of steps it will take to reach <code class="markup--code markup--p-code">1</code>.</p><p id="27ac" class="graf graf--p graf-after--p">There are two kinds of permitted steps:<br> — -> You may decrement N to N — 1.<br> — -> If <code class="markup--code markup--p-code">a * b = N</code>, you may decrement <code class="markup--code markup--p-code">N to the larger of a and b</code>.</p><p id="eb97" class="graf graf--p graf-after--p">For example, given 100, you can reach 1 in 5 steps with the following route:<br><code class="markup--code markup--p-code">100 -> 10 -> 9 -> 3 -> 2 -> 1.</code></p><figure id="eae1" class="graf graf--figure graf--iframe graf-after--p"></figure><h3 id="1c97" class="graf graf--h3 graf-after--figure">Problem 13</h3><p id="1610" class="graf graf--p graf-after--h3">Consider the following scenario: there are <code class="markup--code markup--p-code">N</code> mice and <code class="markup--code markup--p-code">N</code> holes placed at integer points along a line. Given this, find a method that maps mice to holes such that the largest number of steps any mouse takes is minimized.</p><p id="3355" class="graf graf--p graf-after--p">Each move consists of moving one mouse <code class="markup--code markup--p-code">one</code> unit to the <code class="markup--code markup--p-code">left</code> or <code class="markup--code markup--p-code">right</code>, and only <code class="markup--code markup--p-code">one</code> mouse can fit inside each hole.</p><p id="38b2" class="graf graf--p graf-after--p">For example, suppose the mice are positioned at <code class="markup--code markup--p-code">[1, 4, 9, 15]</code>, and the holes are located at <code class="markup--code markup--p-code">[10, -5, 0, 16]</code>. In this case, the best pairing would require us to send the mouse at <code class="markup--code markup--p-code">1</code> to the hole at <code class="markup--code markup--p-code">-5</code>, so our function should return <code class="markup--code markup--p-code">6</code>.</p><figure id="4f77" class="graf graf--figure graf--iframe graf-after--p"></figure></div><div class="section-inner sectionLayout--outsetColumn"><figure id="d833" class="graf graf--figure graf--iframe graf--layoutOutsetCenter graf-after--figure"></figure></div><div class="section-inner sectionLayout--insetColumn"><h3 id="53da" class="graf graf--h3 graf-after--figure">My Blog:</h3><div id="d3ea" class="graf graf--mixtapeEmbed graf-after--h3"><a href="https://master--bgoonz-blog.netlify.app/" class="markup--anchor markup--mixtapeEmbed-anchor" title="https://master--bgoonz-blog.netlify.app/"><strong class="markup--strong markup--mixtapeEmbed-strong">Web-Dev-Hub</strong><br><em class="markup--em markup--mixtapeEmbed-em">Memoization, Tabulation, and Sorting Algorithms by Example Why is looking at runtime not a reliable method of…</em>master–bgoonz-blog.netlify.app</a><a href="https://master--bgoonz-blog.netlify.app/" class="js-mixtapeImage mixtapeImage u-ignoreBlock" style="background-image:url('https://cdn-images-1.medium.com/fit/c/160/160/0*2ShC45dbzN8LiL8s');"></a></div><div id="d107" class="graf graf--mixtapeEmbed graf-after--mixtapeEmbed graf--trailing"><a href="https://bryanguner.medium.com/a-list-of-all-of-my-articles-to-link-to-future-posts-1f6f88ebdf5b" class="markup--anchor markup--mixtapeEmbed-anchor" title="https://bryanguner.medium.com/a-list-of-all-of-my-articles-to-link-to-future-posts-1f6f88ebdf5b"><strong class="markup--strong markup--mixtapeEmbed-strong">A list of all of my articles to link to future posts</strong><br><em class="markup--em markup--mixtapeEmbed-em">You should probably skip this one… seriously it’s just for internal use!</em>bryanguner.medium.com</a><a href="https://bryanguner.medium.com/a-list-of-all-of-my-articles-to-link-to-future-posts-1f6f88ebdf5b" class="js-mixtapeImage mixtapeImage u-ignoreBlock" style="background-image:url('https://cdn-images-1.medium.com/fit/c/160/160/1*yZ41P3YdMYMiyFPAPrzyGw.gif');"></a></div></div></div></section><section class="section section--body section--last"><div class="section-divider"><hr class="section-divider"></div><div class="section-content"><div class="section-inner sectionLayout--insetColumn"><h3 id="79a0" class="graf graf--h3 graf--leading">Level Up Coding</h3><p id="8d1f" class="graf graf--p graf-after--h3">Thanks for being a part of our community! <a href="https://www.youtube.com/channel/UC3v9kBR_ab4UHXXdknz8Fbg?sub_confirmation=1" class="markup--anchor markup--p-anchor" rel="noopener" target="_blank">Subscribe to our YouTube channel</a> or join the <a href="https://skilled.dev/" class="markup--anchor markup--p-anchor" rel="noopener" target="_blank"><strong class="markup--strong markup--p-strong">Skilled.dev coding interview course</strong></a>.</p><div id="1050" class="graf graf--mixtapeEmbed graf-after--p graf--trailing"><a href="https://skilled.dev" class="markup--anchor markup--mixtapeEmbed-anchor" title="https://skilled.dev"><strong class="markup--strong markup--mixtapeEmbed-strong">Coding Interview Questions + Land Your Dev Job | Skilled.dev</strong><br><em class="markup--em markup--mixtapeEmbed-em">Coding interview course taught in Python</em>skilled.dev</a><a href="https://skilled.dev" class="js-mixtapeImage mixtapeImage u-ignoreBlock" style="background-image:url('https://cdn-images-1.medium.com/fit/c/160/160/0*kRLnghBKKYPQjmtf');"></a></div></div></div></section> | |
</section> | |
<footer><p>By <a href="https://medium.com/@bryanguner" class="p-author h-card">Bryan Guner</a> on <a href="https://medium.com/p/dd631e9c3a9f"><time class="dt-published" datetime="2021-08-21T04:24:46.097Z">August 21, 2021</time></a>.</p><p><a href="https://medium.com/@bryanguner/beginner-python-problems-solutions-dd631e9c3a9f" class="p-canonical">Canonical link</a></p><p>Exported from <a href="https://medium.com">Medium</a> on August 31, 2021.</p></footer></article> | |
</div><!-- .entry-content --> | |
<footer class="entry-footer responsive-max-width"> | |
<span class="byline"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><span class="screen-reader-text">Posted by</span><span class="author vcard"><a class="url fn n" href="https://web-dev-hub.com/author/gunerb1/">bgoonz</a></span></span><span class="posted-on"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><defs><path id="a" d="M0 0h24v24H0V0z"></path></defs><clipPath id="b"><use xlink:href="#a" overflow="visible"></use></clipPath><path clip-path="url(#b)" d="M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10 10-4.5 10-10S17.5 2 12 2zm4.2 14.2L11 13V7h1.5v5.2l4.5 2.7-.8 1.3z"></path></svg><a href="https://web-dev-hub.com/2021/10/12/python/" rel="bookmark"><time class="entry-date published" datetime="2021-10-12T05:58:46-04:00">October 12, 2021</time><time class="updated" datetime="2021-10-12T05:59:12-04:00">October 12, 2021</time></a></span><span class="cat-links"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M10 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2h-8l-2-2z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><span class="screen-reader-text">Posted in</span><a href="https://web-dev-hub.com/category/uncategorized/" rel="category tag">Uncategorized</a></span><span class="comments-link"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M21.99 4c0-1.1-.89-2-1.99-2H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h14l4 4-.01-18z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><a href="https://web-dev-hub.com/2021/10/12/python/#respond">Leave a comment<span class="screen-reader-text"> on Python</span></a></span><span class="edit-link"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04c.39-.39.39-1.02 0-1.41l-2.34-2.34c-.39-.39-1.02-.39-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><a class="post-edit-link" href="https://wordpress.com/post/web-dev-hub.com/1019">Edit <span class="screen-reader-text">Python</span></a></span> </footer><!-- .entry-footer --> | |
</article><!-- #post-${ID} --> | |
<article id="post-604" class="post-604 post type-post status-publish format-standard hentry category-uncategorized entry"> | |
<header class="entry-header responsive-max-width"> | |
<h2 class="entry-title"><a href="https://web-dev-hub.com/2021/06/11/test/" rel="bookmark">Test</a></h2> </header><!-- .entry-header --> | |
<div class="entry-content"> | |
<p>Testing </p> | |
<p></p> | |
<p></p> | |
</div><!-- .entry-content --> | |
<footer class="entry-footer responsive-max-width"> | |
<span class="byline"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><span class="screen-reader-text">Posted by</span><span class="author vcard"><a class="url fn n" href="https://web-dev-hub.com/author/gunerb1/">bgoonz</a></span></span><span class="posted-on"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><defs><path id="a" d="M0 0h24v24H0V0z"></path></defs><clipPath id="b"><use xlink:href="#a" overflow="visible"></use></clipPath><path clip-path="url(#b)" d="M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10 10-4.5 10-10S17.5 2 12 2zm4.2 14.2L11 13V7h1.5v5.2l4.5 2.7-.8 1.3z"></path></svg><a href="https://web-dev-hub.com/2021/06/11/test/" rel="bookmark"><time class="entry-date published updated" datetime="2021-06-11T05:03:53-04:00">June 11, 2021</time></a></span><span class="cat-links"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M10 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2h-8l-2-2z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><span class="screen-reader-text">Posted in</span><a href="https://web-dev-hub.com/category/uncategorized/" rel="category tag">Uncategorized</a></span><span class="comments-link"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M21.99 4c0-1.1-.89-2-1.99-2H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h14l4 4-.01-18z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><a href="https://web-dev-hub.com/2021/06/11/test/#respond">Leave a comment<span class="screen-reader-text"> on Test</span></a></span><span class="edit-link"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04c.39-.39.39-1.02 0-1.41l-2.34-2.34c-.39-.39-1.02-.39-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><a class="post-edit-link" href="https://wordpress.com/post/web-dev-hub.com/604">Edit <span class="screen-reader-text">Test</span></a></span> </footer><!-- .entry-footer --> | |
</article><!-- #post-${ID} --> | |
<article id="post-585" class="post-585 post type-post status-publish format-standard hentry category-uncategorized entry"> | |
<header class="entry-header responsive-max-width"> | |
</header><!-- .entry-header --> | |
<div class="entry-content"> | |
<p><a href="https://github.com/bgoonz/web-dev-notes-resource-site/blob/master/1-tools/site-building/Convert-arr-2-atags/out.html">github.com/bgoonz/web-dev-notes-resource-site/blob/master/1-tools/site-building/Convert-arr-2-atags/out.html</a></p> | |
</div><!-- .entry-content --> | |
<footer class="entry-footer responsive-max-width"> | |
<span class="byline"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><span class="screen-reader-text">Posted by</span><span class="author vcard"><a class="url fn n" href="https://web-dev-hub.com/author/gunerb1/">bgoonz</a></span></span><span class="posted-on"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><defs><path id="a" d="M0 0h24v24H0V0z"></path></defs><clipPath id="b"><use xlink:href="#a" overflow="visible"></use></clipPath><path clip-path="url(#b)" d="M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10 10-4.5 10-10S17.5 2 12 2zm4.2 14.2L11 13V7h1.5v5.2l4.5 2.7-.8 1.3z"></path></svg><a href="https://web-dev-hub.com/2021/05/05/585/" rel="bookmark"><time class="entry-date published updated" datetime="2021-05-05T10:05:16-04:00">May 5, 2021</time></a></span><span class="cat-links"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M10 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2h-8l-2-2z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><span class="screen-reader-text">Posted in</span><a href="https://web-dev-hub.com/category/uncategorized/" rel="category tag">Uncategorized</a></span><span class="comments-link"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M21.99 4c0-1.1-.89-2-1.99-2H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h14l4 4-.01-18z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><a href="https://web-dev-hub.com/2021/05/05/585/#comments">1 Comment<span class="screen-reader-text"> on </span></a></span><span class="edit-link"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04c.39-.39.39-1.02 0-1.41l-2.34-2.34c-.39-.39-1.02-.39-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><a class="post-edit-link" href="https://wordpress.com/post/web-dev-hub.com/585">Edit <span class="screen-reader-text"></span></a></span> </footer><!-- .entry-footer --> | |
</article><!-- #post-${ID} --> | |
<article id="post-552" class="post-552 post type-post status-publish format-standard has-post-thumbnail hentry category-uncategorized tag-javascript tag-web-development entry"> | |
<header class="entry-header responsive-max-width"> | |
<h2 class="entry-title"><a href="https://web-dev-hub.com/2021/04/12/vscode-extension-readme-compilation/" rel="bookmark">VsCode Extension Readme Compilation</a></h2> </header><!-- .entry-header --> | |
<figure class="post-thumbnail"> | |
<a class="post-thumbnail-inner alignwide" href="https://web-dev-hub.com/2021/04/12/vscode-extension-readme-compilation/" aria-hidden="true" tabindex="-1"> | |
<img width="726" height="419" src="https://webdevhubcom.files.wordpress.com/2021/04/7cdec-15oamo6qxv9dztouc5oe-uq.png?w=726" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="" loading="lazy" srcset="https://webdevhubcom.files.wordpress.com/2021/04/7cdec-15oamo6qxv9dztouc5oe-uq.png 726w, https://webdevhubcom.files.wordpress.com/2021/04/7cdec-15oamo6qxv9dztouc5oe-uq.png?w=150 150w, https://webdevhubcom.files.wordpress.com/2021/04/7cdec-15oamo6qxv9dztouc5oe-uq.png?w=300 300w" sizes="(max-width: 726px) 100vw, 726px" data-attachment-id="580" data-permalink="https://web-dev-hub.com/2021/04/05/notes-from-javascript-the-good-parts/15oamo6qxv9dztouc5oe-uq/" data-orig-file="https://webdevhubcom.files.wordpress.com/2021/04/7cdec-15oamo6qxv9dztouc5oe-uq.png" data-orig-size="726,419" data-comments-opened="0" data-image-meta="{"aperture":"0","credit":"","camera":"","caption":"","created_timestamp":"0","copyright":"","focal_length":"0","iso":"0","shutter_speed":"0","title":"","orientation":"0"}" data-image-title="1*5OamO6QxV9dZTOUC5oe-uQ" data-image-description="" data-image-caption="" data-medium-file="https://webdevhubcom.files.wordpress.com/2021/04/7cdec-15oamo6qxv9dztouc5oe-uq.png?w=300" data-large-file="https://webdevhubcom.files.wordpress.com/2021/04/7cdec-15oamo6qxv9dztouc5oe-uq.png?w=726" /> </a> | |
</figure> | |
<div class="entry-content"> | |
<h3>Markdown PDF</h3> | |
<p>This extension converts Markdown files to pdf, html, png or jpeg files.</p> | |
<p><a href="https://github.com/yzane/vscode-markdown-pdf/blob/master/README.ja.md" target="_blank" rel="noopener">Japanese README</a></p> | |
<h3>Table of Contents</h3> | |
<ul> | |
<li><a href="https://trusting-aryabhata-e5438d.netlify.app/#features" target="_blank" rel="noopener">Features</a></li> | |
<li><a href="https://trusting-aryabhata-e5438d.netlify.app/#install" target="_blank" rel="noopener">Install</a></li> | |
<li><a href="https://trusting-aryabhata-e5438d.netlify.app/#usage" target="_blank" rel="noopener">Usage</a></li> | |
<li><a href="https://trusting-aryabhata-e5438d.netlify.app/#extension-settings" target="_blank" rel="noopener">Extension Settings</a></li> | |
<li><a href="https://trusting-aryabhata-e5438d.netlify.app/#options" target="_blank" rel="noopener">Options</a></li> | |
<li><a href="https://trusting-aryabhata-e5438d.netlify.app/#faq" target="_blank" rel="noopener">FAQ</a></li> | |
<li><a href="https://trusting-aryabhata-e5438d.netlify.app/#known-issues" target="_blank" rel="noopener">Known Issues</a></li> | |
<li><a href="https://trusting-aryabhata-e5438d.netlify.app/#release-notes" target="_blank" rel="noopener">Release Notes</a></li> | |
<li><a href="https://trusting-aryabhata-e5438d.netlify.app/#license" target="_blank" rel="noopener">License</a></li> | |
<li><a href="https://trusting-aryabhata-e5438d.netlify.app/#special-thanks" target="_blank" rel="noopener">Special thanks</a></li> | |
</ul> | |
<h3>Features</h3> | |
<p>Supports the following features * <a href="https://highlightjs.org/static/demo/" target="_blank" rel="noopener">Syntax highlighting</a> * <a href="https://www.webfx.com/tools/emoji-cheat-sheet/" target="_blank" rel="noopener">emoji</a> * <a href="https://github.com/mcecot/markdown-it-checkbox" target="_blank" rel="noopener">markdown-it-checkbox</a> * <a href="https://github.com/markdown-it/markdown-it-container" target="_blank" rel="noopener">markdown-it-container</a> * <a href="https://github.com/camelaissani/markdown-it-include" target="_blank" rel="noopener">markdown-it-include</a> * <a href="https://plantuml.com/" target="_blank" rel="noopener">PlantUML</a> * <a href="https://github.com/gmunguia/markdown-it-plantuml" target="_blank" rel="noopener">markdown-it-plantuml</a> * <a href="https://mermaid-js.github.io/mermaid/" target="_blank" rel="noopener">mermaid</a></p> | |
<p>Sample files * <a href="https://github.com/yzane/vscode-markdown-pdf/blob/master/sample/README.pdf" target="_blank" rel="noopener">pdf</a> * <a href="https://github.com/yzane/vscode-markdown-pdf/blob/master/sample/README.html" target="_blank" rel="noopener">html</a> * <a href="https://github.com/yzane/vscode-markdown-pdf/blob/master/sample/README.png" target="_blank" rel="noopener">png</a> * <a href="https://github.com/yzane/vscode-markdown-pdf/blob/master/sample/README.jpeg" target="_blank" rel="noopener">jpeg</a></p> | |
<h3>markdown-it-container</h3> | |
<p>INPUT</p> | |
<pre><code>::: warning | |
*here be dragons* | |
:::</code></pre> | |
<p>OUTPUT</p> | |
<pre><code><div class="warning"> | |
<p><em>here be dragons</em></p> | |
</div></code></pre> | |
<h3>markdown-it-plantuml</h3> | |
<p>INPUT</p> | |
<pre><code>@startuml | |
Bob -[#red]> Alice : hello | |
Alice -[#0000FF]->Bob : ok | |
@enduml</code></pre> | |
<p>OUTPUT</p> | |
<figure><img src="https://webdevhubcom.files.wordpress.com/2021/04/e2b22-0p64cjfrdlmoa_qsg.png" data-width="161" data-height="174" /></figure> | |
<h3>markdown-it-include</h3> | |
<p>Include markdown fragment files: <code>:[alternate-text](https://github.com/yzane/vscode-markdown-pdf/blob/master/relative-path-to-file.md)</code>.</p> | |
<pre><code>├── [plugins] | |
│ └── README.md | |
├── CHANGELOG.md | |
└── README.md</code></pre> | |
<p>INPUT</p> | |
<pre><code>README Content</code></pre> | |
<pre><code>:[Plugins](https://github.com/yzane/vscode-markdown-pdf/blob/master/./plugins/README.md)</code></pre> | |
<pre><code>:[Changelog](https://github.com/yzane/vscode-markdown-pdf/blob/master/CHANGELOG.md)</code></pre> | |
<p>OUTPUT</p> | |
<pre><code>Content of README.md</code></pre> | |
<pre><code>Content of plugins/README.md</code></pre> | |
<pre><code>Content of CHANGELOG.md</code></pre> | |
<h3>mermaid</h3> | |
<p>INPUT</p> | |
<pre>```mermaid | |
stateDiagram | |
[*] --> First | |
state First { | |
[*] --> second | |
second --> [*] | |
} | |
```</pre> | |
<p>OUTPUT</p> | |
<figure><img src="https://webdevhubcom.files.wordpress.com/2021/04/e741d-0zj3ibfpthth778lh.png" data-width="289" data-height="266" /></figure> | |
<h3>Install</h3> | |
<p>Chromium download starts automatically when Markdown PDF is installed and Markdown file is first opened with Visual Studio Code.</p> | |
<p>However, it is time-consuming depending on the environment because of its large size (~ 170Mb Mac, ~ 282Mb Linux, ~ 280Mb Win).</p> | |
<p>During downloading, the message <code>Installing Chromium</code> is displayed in the status bar.</p> | |
<p>If you are behind a proxy, set the <code>http.proxy</code> option to settings.json and restart Visual Studio Code.</p> | |
<p>If the download is not successful or you want to avoid downloading every time you upgrade Markdown PDF, please specify the installed <a href="https://www.google.co.jp/chrome/" target="_blank" rel="noopener">Chrome</a> or ‘Chromium’ with <a href="https://trusting-aryabhata-e5438d.netlify.app/#markdown-pdfexecutablepath" target="_blank" rel="noopener">markdown-pdf.executablePath</a> option.</p> | |
<h3>Usage</h3> | |
<h3>Command Palette</h3> | |
<ol> | |
<li>Open the Markdown file</li> | |
<li>Press <code>F1</code> or <code>Ctrl+Shift+P</code></li> | |
<li>Type <code>export</code> and select below</li> | |
</ol> | |
<ul> | |
<li><code>markdown-pdf: Export (settings.json)</code></li> | |
<li><code>markdown-pdf: Export (pdf)</code></li> | |
<li><code>markdown-pdf: Export (html)</code></li> | |
<li><code>markdown-pdf: Export (png)</code></li> | |
<li><code>markdown-pdf: Export (jpeg)</code></li> | |
<li><code>markdown-pdf: Export (all: pdf, html, png, jpeg)</code></li> | |
</ul> | |
<figure><img src="https://webdevhubcom.files.wordpress.com/2021/04/3e56c-0kwm2zier68qbjwls.gif" data-width="697" data-height="419" /></figure> | |
<h3>Menu</h3> | |
<ol> | |
<li>Open the Markdown file</li> | |
<li>Right click and select below</li> | |
</ol> | |
<ul> | |
<li><code>markdown-pdf: Export (settings.json)</code></li> | |
<li><code>markdown-pdf: Export (pdf)</code></li> | |
<li><code>markdown-pdf: Export (html)</code></li> | |
<li><code>markdown-pdf: Export (png)</code></li> | |
<li><code>markdown-pdf: Export (jpeg)</code></li> | |
<li><code>markdown-pdf: Export (all: pdf, html, png, jpeg)</code></li> | |
</ul> | |
<figure><img src="https://webdevhubcom.files.wordpress.com/2021/04/b7d5d-0a_o-vh7a_1zrarh5.gif" data-width="697" data-height="419" /></figure> | |
<h3>Auto convert</h3> | |
<ol> | |
<li>Add <code>"markdown-pdf.convertOnSave": true</code> option to <strong>settings.json</strong></li> | |
<li>Restart Visual Studio Code</li> | |
<li>Open the Markdown file</li> | |
<li>Auto convert on save</li> | |
</ol> | |
<h3>Extension Settings</h3> | |
<p><a href="https://code.visualstudio.com/docs/customization/userandworkspace" target="_blank" rel="noopener">Visual Studio Code User and Workspace Settings</a></p> | |
<ol> | |
<li>Select <strong>File > Preferences > UserSettings or Workspace Settings</strong></li> | |
<li>Find markdown-pdf settings in the <strong>Default Settings</strong></li> | |
<li>Copy <code>markdown-pdf.*</code> settings</li> | |
<li>Paste to the <strong>settings.json</strong>, and change the value</li> | |
</ol> | |
<figure><img src="https://webdevhubcom.files.wordpress.com/2021/04/9f90f-0esq2gocyljgawdfp.gif" data-width="837" data-height="534" /></figure> | |
<h3>Options</h3> | |
<h3>List</h3> | |
<p>CategoryOption name<a href="https://code.visualstudio.com/api/references/contribution-points#Configuration-property-schema" target="_blank" rel="noopener">Configuration scope</a><a href="https://trusting-aryabhata-e5438d.netlify.app/#save-options" target="_blank" rel="noopener">Save options</a><a href="https://trusting-aryabhata-e5438d.netlify.app/#markdown-pdftype" target="_blank" rel="noopener">markdown-pdf.type</a><a href="https://trusting-aryabhata-e5438d.netlify.app/#markdown-pdfconvertonsave" target="_blank" rel="noopener">markdown-pdf.convertOnSave</a><a href="https://trusting-aryabhata-e5438d.netlify.app/#markdown-pdfconvertonsaveexclude" target="_blank" rel="noopener">markdown-pdf.convertOnSaveExclude</a><a href="https://trusting-aryabhata-e5438d.netlify.app/#markdown-pdfoutputdirectory" target="_blank" rel="noopener">markdown-pdf.outputDirectory</a><a href="https://trusting-aryabhata-e5438d.netlify.app/#markdown-pdfoutputdirectoryrelativepathfile" target="_blank" rel="noopener">markdown-pdf.outputDirectoryRelativePathFile</a><a href="https://trusting-aryabhata-e5438d.netlify.app/#styles-options" target="_blank" rel="noopener">Styles options</a><a href="https://trusting-aryabhata-e5438d.netlify.app/#markdown-pdfstyles" target="_blank" rel="noopener">markdown-pdf.styles</a><a href="https://trusting-aryabhata-e5438d.netlify.app/#markdown-pdfstylesrelativepathfile" target="_blank" rel="noopener">markdown-pdf.stylesRelativePathFile</a><a href="https://trusting-aryabhata-e5438d.netlify.app/#markdown-pdfincludedefaultstyles" target="_blank" rel="noopener">markdown-pdf.includeDefaultStyles</a><a href="https://trusting-aryabhata-e5438d.netlify.app/#syntax-highlight-options" target="_blank" rel="noopener">Syntax highlight options</a><a href="https://trusting-aryabhata-e5438d.netlify.app/#markdown-pdfhighlight" target="_blank" rel="noopener">markdown-pdf.highlight</a><a href="https://trusting-aryabhata-e5438d.netlify.app/#markdown-pdfhighlightstyle" target="_blank" rel="noopener">markdown-pdf.highlightStyle</a><a href="https://trusting-aryabhata-e5438d.netlify.app/#markdown-options" target="_blank" rel="noopener">Markdown options</a><a href="https://trusting-aryabhata-e5438d.netlify.app/#markdown-pdfbreaks" target="_blank" rel="noopener">markdown-pdf.breaks</a><a href="https://trusting-aryabhata-e5438d.netlify.app/#emoji-options" target="_blank" rel="noopener">Emoji options</a><a href="https://trusting-aryabhata-e5438d.netlify.app/#markdown-pdfemoji" target="_blank" rel="noopener">markdown-pdf.emoji</a><a href="https://trusting-aryabhata-e5438d.netlify.app/#configuration-options" target="_blank" rel="noopener">Configuration options</a><a href="https://trusting-aryabhata-e5438d.netlify.app/#markdown-pdfexecutablepath" target="_blank" rel="noopener">markdown-pdf.executablePath</a><a href="https://trusting-aryabhata-e5438d.netlify.app/#common-options" target="_blank" rel="noopener">Common Options</a><a href="https://trusting-aryabhata-e5438d.netlify.app/#markdown-pdfscale" target="_blank" rel="noopener">markdown-pdf.scale</a><a href="https://trusting-aryabhata-e5438d.netlify.app/#pdf-options" target="_blank" rel="noopener">PDF options</a><a href="https://trusting-aryabhata-e5438d.netlify.app/#markdown-pdfdisplayheaderfooter" target="_blank" rel="noopener">markdown-pdf.displayHeaderFooter</a>resource<a href="https://trusting-aryabhata-e5438d.netlify.app/#markdown-pdfheadertemplate" target="_blank" rel="noopener">markdown-pdf.headerTemplate</a>resource<a href="https://trusting-aryabhata-e5438d.netlify.app/#markdown-pdffootertemplate" target="_blank" rel="noopener">markdown-pdf.footerTemplate</a>resource<a href="https://trusting-aryabhata-e5438d.netlify.app/#markdown-pdfprintbackground" target="_blank" rel="noopener">markdown-pdf.printBackground</a>resource<a href="https://trusting-aryabhata-e5438d.netlify.app/#markdown-pdforientation" target="_blank" rel="noopener">markdown-pdf.orientation</a>resource<a href="https://trusting-aryabhata-e5438d.netlify.app/#markdown-pdfpageranges" target="_blank" rel="noopener">markdown-pdf.pageRanges</a>resource<a href="https://trusting-aryabhata-e5438d.netlify.app/#markdown-pdfformat" target="_blank" rel="noopener">markdown-pdf.format</a>resource<a href="https://trusting-aryabhata-e5438d.netlify.app/#markdown-pdfwidth" target="_blank" rel="noopener">markdown-pdf.width</a>resource<a href="https://trusting-aryabhata-e5438d.netlify.app/#markdown-pdfheight" target="_blank" rel="noopener">markdown-pdf.height</a>resource<a href="https://trusting-aryabhata-e5438d.netlify.app/#markdown-pdfmargintop" target="_blank" rel="noopener">markdown-pdf.margin.top</a>resource<a href="https://trusting-aryabhata-e5438d.netlify.app/#markdown-pdfmarginbottom" target="_blank" rel="noopener">markdown-pdf.margin.bottom</a>resource<a href="https://trusting-aryabhata-e5438d.netlify.app/#markdown-pdfmarginright" target="_blank" rel="noopener">markdown-pdf.margin.right</a>resource<a href="https://trusting-aryabhata-e5438d.netlify.app/#markdown-pdfmarginleft" target="_blank" rel="noopener">markdown-pdf.margin.left</a>resource<a href="https://trusting-aryabhata-e5438d.netlify.app/#png-jpeg-options" target="_blank" rel="noopener">PNG JPEG options</a><a href="https://trusting-aryabhata-e5438d.netlify.app/#markdown-pdfquality" target="_blank" rel="noopener">markdown-pdf.quality</a><a href="https://trusting-aryabhata-e5438d.netlify.app/#markdown-pdfclipx" target="_blank" rel="noopener">markdown-pdf.clip.x</a><a href="https://trusting-aryabhata-e5438d.netlify.app/#markdown-pdfclipy" target="_blank" rel="noopener">markdown-pdf.clip.y</a><a href="https://trusting-aryabhata-e5438d.netlify.app/#markdown-pdfclipwidth" target="_blank" rel="noopener">markdown-pdf.clip.width</a><a href="https://trusting-aryabhata-e5438d.netlify.app/#markdown-pdfclipheight" target="_blank" rel="noopener">markdown-pdf.clip.height</a><a href="https://trusting-aryabhata-e5438d.netlify.app/#markdown-pdfomitbackground" target="_blank" rel="noopener">markdown-pdf.omitBackground</a><a href="https://trusting-aryabhata-e5438d.netlify.app/#plantuml-options" target="_blank" rel="noopener">PlantUML options</a><a href="https://trusting-aryabhata-e5438d.netlify.app/#markdown-pdfplantumlopenmarker" target="_blank" rel="noopener">markdown-pdf.plantumlOpenMarker</a><a href="https://trusting-aryabhata-e5438d.netlify.app/#markdown-pdfplantumlclosemarker" target="_blank" rel="noopener">markdown-pdf.plantumlCloseMarker</a><a href="https://trusting-aryabhata-e5438d.netlify.app/#markdown-pdfplantumlserver" target="_blank" rel="noopener">markdown-pdf.plantumlServer</a><a href="https://trusting-aryabhata-e5438d.netlify.app/#markdown-it-include-options" target="_blank" rel="noopener">markdown-it-include options</a><a href="https://trusting-aryabhata-e5438d.netlify.app/#markdown-pdfmarkdown-it-includeenable" target="_blank" rel="noopener">markdown-pdf.markdown-it-include.enable</a><a href="https://trusting-aryabhata-e5438d.netlify.app/#mermaid-options" target="_blank" rel="noopener">mermaid options</a><a href="https://trusting-aryabhata-e5438d.netlify.app/#markdown-pdfmermaidserver" target="_blank" rel="noopener">markdown-pdf.mermaidServer</a></p> | |
<h3>Save options</h3> | |
<h4><code>markdown-pdf.type</code></h4> | |
<ul> | |
<li>Output format: pdf, html, png, jpeg</li> | |
<li>Multiple output formats support</li> | |
<li>Default: pdf</li> | |
</ul> | |
<pre><code>"markdown-pdf.type": [ | |
"pdf", | |
"html", | |
"png", | |
"jpeg" | |
],</code></pre> | |
<h4><code>markdown-pdf.convertOnSave</code></h4> | |
<ul> | |
<li>Enable Auto convert on save</li> | |
<li>boolean. Default: false</li> | |
<li>To apply the settings, you need to restart Visual Studio Code</li> | |
</ul> | |
<h4><code>markdown-pdf.convertOnSaveExclude</code></h4> | |
<ul> | |
<li>Excluded file name of convertOnSave option</li> | |
</ul> | |
<pre><code>"markdown-pdf.convertOnSaveExclude": [ | |
"^work", | |
"work.md$", | |
"work|test", | |
"[0-9][0-9][0-9][0-9]-work", | |
"work\\test" // All '\' need to be written as '\\' (Windows) | |
],</code></pre> | |
<h4><code>markdown-pdf.outputDirectory</code></h4> | |
<ul> | |
<li>Output Directory</li> | |
<li>All <code>\</code> need to be written as <code>\\</code> (Windows)</li> | |
</ul> | |
<pre><code>"markdown-pdf.outputDirectory": "C:\\work\\output",</code></pre> | |
<ul> | |
<li>Relative path</li> | |
<li>If you open the <code>Markdown file</code>, it will be interpreted as a relative path from the file</li> | |
<li>If you open a <code>folder</code>, it will be interpreted as a relative path from the root folder</li> | |
<li>If you open the <code>workspace</code>, it will be interpreted as a relative path from the each root folder</li> | |
<li>See <a href="https://code.visualstudio.com/docs/editor/multi-root-workspaces" target="_blank" rel="noopener">Multi-root Workspaces</a></li> | |
</ul> | |
<pre><code>"markdown-pdf.outputDirectory": "output",</code></pre> | |
<ul> | |
<li>Relative path (home directory)</li> | |
<li>If path starts with <code>~</code>, it will be interpreted as a relative path from the home directory</li> | |
</ul> | |
<pre><code>"markdown-pdf.outputDirectory": "~/output",</code></pre> | |
<ul> | |
<li>If you set a directory with a <code>relative path</code>, it will be created if the directory does not exist</li> | |
<li>If you set a directory with an <code>absolute path</code>, an error occurs if the directory does not exist</li> | |
</ul> | |
<h4><code>markdown-pdf.outputDirectoryRelativePathFile</code></h4> | |
<ul> | |
<li>If <code>markdown-pdf.outputDirectoryRelativePathFile</code> option is set to <code>true</code>, the relative path set with <a href="https://trusting-aryabhata-e5438d.netlify.app/#markdown-pdfoutputDirectory" target="_blank" rel="noopener">markdown-pdf.outputDirectory</a> is interpreted as relative from the file</li> | |
<li>It can be used to avoid relative paths from folders and workspaces</li> | |
<li>boolean. Default: false</li> | |
</ul> | |
<h3>Styles options</h3> | |
<h4><code>markdown-pdf.styles</code></h4> | |
<ul> | |
<li>A list of local paths to the stylesheets to use from the markdown-pdf</li> | |
<li>If the file does not exist, it will be skipped</li> | |
<li>All <code>\</code> need to be written as <code>\\</code> (Windows)</li> | |
</ul> | |
<pre><code>"markdown-pdf.styles": [ | |
"C:\\Users\\<USERNAME>\\Documents\\markdown-pdf.css", | |
"/home/<USERNAME>/settings/markdown-pdf.css", | |
],</code></pre> | |
<ul> | |
<li>Relative path</li> | |
<li>If you open the <code>Markdown file</code>, it will be interpreted as a relative path from the file</li> | |
<li>If you open a <code>folder</code>, it will be interpreted as a relative path from the root folder</li> | |
<li>If you open the <code>workspace</code>, it will be interpreted as a relative path from the each root folder</li> | |
<li>See <a href="https://code.visualstudio.com/docs/editor/multi-root-workspaces" target="_blank" rel="noopener">Multi-root Workspaces</a></li> | |
</ul> | |
<pre><code>"markdown-pdf.styles": [ | |
"markdown-pdf.css", | |
],</code></pre> | |
<ul> | |
<li>Relative path (home directory)</li> | |
<li>If path starts with <code>~</code>, it will be interpreted as a relative path from the home directory</li> | |
</ul> | |
<pre><code>"markdown-pdf.styles": [ | |
"~/.config/Code/User/markdown-pdf.css" | |
],</code></pre> | |
<ul> | |
<li>Online CSS (<a href="https://xxx/xxx.css" rel="nofollow">https://xxx/xxx.css</a>) is applied correctly for JPG and PNG, but problems occur with PDF <a href="https://github.com/yzane/vscode-markdown-pdf/issues/67" target="_blank" rel="noopener">#67</a></li> | |
</ul> | |
<pre><code>"markdown-pdf.styles": [ | |
"https://xxx/markdown-pdf.css" | |
],</code></pre> | |
<h4><code>markdown-pdf.stylesRelativePathFile</code></h4> | |
<ul> | |
<li>If <code>markdown-pdf.stylesRelativePathFile</code> option is set to <code>true</code>, the relative path set with <a href="https://trusting-aryabhata-e5438d.netlify.app/#markdown-pdfstyles" target="_blank" rel="noopener">markdown-pdf.styles</a> is interpreted as relative from the file</li> | |
<li>It can be used to avoid relative paths from folders and workspaces</li> | |
<li>boolean. Default: false</li> | |
</ul> | |
<h4><code>markdown-pdf.includeDefaultStyles</code></h4> | |
<ul> | |
<li>Enable the inclusion of default Markdown styles (VSCode, markdown-pdf)</li> | |
<li>boolean. Default: true</li> | |
</ul> | |
<h3>Syntax highlight options</h3> | |
<h4><code>markdown-pdf.highlight</code></h4> | |
<ul> | |
<li>Enable Syntax highlighting</li> | |
<li>boolean. Default: true</li> | |
</ul> | |
<h4><code>markdown-pdf.highlightStyle</code></h4> | |
<ul> | |
<li>Set the style file name. for example: github.css, monokai.css …</li> | |
<li><a href="https://github.com/isagalaev/highlight.js/tree/master/src/styles" target="_blank" rel="noopener">file name list</a></li> | |
<li>demo site : <a href="https://highlightjs.org/static/demo/" target="_blank" rel="noopener">https://highlightjs.org/static/demo/</a></li> | |
</ul> | |
<pre><code>"markdown-pdf.highlightStyle": "github.css",</code></pre> | |
<h3>Markdown options</h3> | |
<h4><code>markdown-pdf.breaks</code></h4> | |
<ul> | |
<li>Enable line breaks</li> | |
<li>boolean. Default: false</li> | |
</ul> | |
<h3>Emoji options</h3> | |
<h4><code>markdown-pdf.emoji</code></h4> | |
<ul> | |
<li>Enable emoji. <a href="https://www.webpagefx.com/tools/emoji-cheat-sheet/" target="_blank" rel="noopener">EMOJI CHEAT SHEET</a></li> | |
<li>boolean. Default: true</li> | |
</ul> | |
<h3>Configuration options</h3> | |
<h4><code>markdown-pdf.executablePath</code></h4> | |
<ul> | |
<li>Path to a Chromium or Chrome executable to run instead of the bundled Chromium</li> | |
<li>All <code>\</code> need to be written as <code>\\</code> (Windows)</li> | |
<li>To apply the settings, you need to restart Visual Studio Code</li> | |
</ul> | |
<pre><code>"markdown-pdf.executablePath": "C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe"</code></pre> | |
<h3>Common Options</h3> | |
<h4><code>markdown-pdf.scale</code></h4> | |
<ul> | |
<li>Scale of the page rendering</li> | |
<li>number. default: 1</li> | |
</ul> | |
<pre><code>"markdown-pdf.scale": 1</code></pre> | |
<h3>PDF options</h3> | |
<ul> | |
<li>pdf only. <a href="https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#pagepdfoptions" target="_blank" rel="noopener">puppeteer page.pdf options</a></li> | |
</ul> | |
<h4><code>markdown-pdf.displayHeaderFooter</code></h4> | |
<ul> | |
<li>Enable display header and footer</li> | |
<li>boolean. Default: true</li> | |
</ul> | |
<h4><code>markdown-pdf.headerTemplate</code></h4> | |
<h4><code>markdown-pdf.footerTemplate</code></h4> | |
<ul> | |
<li>HTML template for the print header and footer</li> | |
<li><code><span class='date'></span></code> : formatted print date</li> | |
<li><code><span class='title'></span></code> : markdown file name</li> | |
<li><code><span class='url'></span></code> : markdown full path name</li> | |
<li><code><span class='pageNumber'></span></code> : current page number</li> | |
<li><code><span class='totalPages'></span></code> : total pages in the document</li> | |
</ul> | |
<pre><code>"markdown-pdf.headerTemplate": "<div style=\"font-size: 9px; margin-left: 1cm;\"> <span class='title'></span></div> <div style=\"font-size: 9px; margin-left: auto; margin-right: 1cm; \"> <span class='date'></span></div>",</code></pre> | |
<pre><code>"markdown-pdf.footerTemplate": "<div style=\"font-size: 9px; margin: 0 auto;\"> <span class='pageNumber'></span> / <span class='totalPages'></span></div>",</code></pre> | |
<h4><code>markdown-pdf.printBackground</code></h4> | |
<ul> | |
<li>Print background graphics</li> | |
<li>boolean. Default: true</li> | |
</ul> | |
<h4><code>markdown-pdf.orientation</code></h4> | |
<ul> | |
<li>Paper orientation</li> | |
<li>portrait or landscape</li> | |
<li>Default: portrait</li> | |
</ul> | |
<h4><code>markdown-pdf.pageRanges</code></h4> | |
<ul> | |
<li>Paper ranges to print, e.g., ‘1-5, 8, 11-13’</li> | |
<li>Default: all pages</li> | |
</ul> | |
<pre><code>"markdown-pdf.pageRanges": "1,4-",</code></pre> | |
<h4><code>markdown-pdf.format</code></h4> | |
<ul> | |
<li>Paper format</li> | |
<li>Letter, Legal, Tabloid, Ledger, A0, A1, A2, A3, A4, A5, A6</li> | |
<li>Default: A4</li> | |
</ul> | |
<pre><code>"markdown-pdf.format": "A4",</code></pre> | |
<h4><code>markdown-pdf.width</code></h4> | |
<h4><code>markdown-pdf.height</code></h4> | |
<ul> | |
<li>Paper width / height, accepts values labeled with units(mm, cm, in, px)</li> | |
<li>If it is set, it overrides the markdown-pdf.format option</li> | |
</ul> | |
<pre><code>"markdown-pdf.width": "10cm", | |
"markdown-pdf.height": "20cm",</code></pre> | |
<h4><code>markdown-pdf.margin.top</code></h4> | |
<h4><code>markdown-pdf.margin.bottom</code></h4> | |
<h4><code>markdown-pdf.margin.right</code></h4> | |
<h4><code>markdown-pdf.margin.left</code></h4> | |
<ul> | |
<li>Paper margins.units(mm, cm, in, px)</li> | |
</ul> | |
<pre><code>"markdown-pdf.margin.top": "1.5cm", | |
"markdown-pdf.margin.bottom": "1cm", | |
"markdown-pdf.margin.right": "1cm", | |
"markdown-pdf.margin.left": "1cm",</code></pre> | |
<h3>PNG JPEG options</h3> | |
<ul> | |
<li>png and jpeg only. <a href="https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#pagescreenshotoptions" target="_blank" rel="noopener">puppeteer page.screenshot options</a></li> | |
</ul> | |
<h4><code>markdown-pdf.quality</code></h4> | |
<ul> | |
<li>jpeg only. The quality of the image, between 0-100. Not applicable to png images</li> | |
</ul> | |
<pre><code>"markdown-pdf.quality": 100,</code></pre> | |
<h4><code>markdown-pdf.clip.x</code></h4> | |
<h4><code>markdown-pdf.clip.y</code></h4> | |
<h4><code>markdown-pdf.clip.width</code></h4> | |
<h4><code>markdown-pdf.clip.height</code></h4> | |
<ul> | |
<li>An object which specifies clipping region of the page</li> | |
<li>number</li> | |
</ul> | |
<pre><code>// x-coordinate of top-left corner of clip area | |
"markdown-pdf.clip.x": 0,</code></pre> | |
<pre><code>// y-coordinate of top-left corner of clip area | |
"markdown-pdf.clip.y": 0,</code></pre> | |
<pre><code>// width of clipping area | |
"markdown-pdf.clip.width": 1000,</code></pre> | |
<pre><code>// height of clipping area | |
"markdown-pdf.clip.height": 1000,</code></pre> | |
<h4><code>markdown-pdf.omitBackground</code></h4> | |
<ul> | |
<li>Hides default white background and allows capturing screenshots with transparency</li> | |
<li>boolean. Default: false</li> | |
</ul> | |
<h3>PlantUML options</h3> | |
<h4><code>markdown-pdf.plantumlOpenMarker</code></h4> | |
<ul> | |
<li>Oppening delimiter used for the plantuml parser.</li> | |
<li>Default: @startuml</li> | |
</ul> | |
<h4><code>markdown-pdf.plantumlCloseMarker</code></h4> | |
<ul> | |
<li>Closing delimiter used for the plantuml parser.</li> | |
<li>Default: @enduml</li> | |
</ul> | |
<h4><code>markdown-pdf.plantumlServer</code></h4> | |
<ul> | |
<li>Plantuml server. e.g. <a href="http://localhost:8080" target="_blank" rel="noopener">http://localhost:8080</a></li> | |
<li>Default: <a href="http://www.plantuml.com/plantuml" target="_blank" rel="noopener">http://www.plantuml.com/plantuml</a></li> | |
<li>For example, to run Plantuml Server locally <a href="https://github.com/yzane/vscode-markdown-pdf/issues/139" target="_blank" rel="noopener">#139</a> :</li> | |
<li><code>docker run -d -p 8080:8080 plantuml/plantuml-server:jetty</code></li> | |
<li><a href="https://hub.docker.com/r/plantuml/plantuml-server/" target="_blank" rel="noopener">plantuml/plantuml-server — Docker Hub</a></li> | |
</ul> | |
<h3>markdown-it-include options</h3> | |
<h4><code>markdown-pdf.markdown-it-include.enable</code></h4> | |
<ul> | |
<li>Enable markdown-it-include.</li> | |
<li>boolean. Default: true</li> | |
</ul> | |
<h3>mermaid options</h3> | |
<h4><code>markdown-pdf.mermaidServer</code></h4> | |
<ul> | |
<li>mermaid server</li> | |
<li>Default: <a href="https://unpkg.com/mermaid/dist/mermaid.min.js" target="_blank" rel="noopener">https://unpkg.com/mermaid/dist/mermaid.min.js</a></li> | |
</ul> | |
<h3>FAQ</h3> | |
<h3>How can I change emoji size ?</h3> | |
<ol> | |
<li>Add the following to your stylesheet which was specified in the markdown-pdf.styles</li> | |
</ol> | |
<pre><code>.emoji { | |
height: 2em; | |
}</code></pre> | |
<h3>Auto guess encoding of files</h3> | |
<p>Using <code>files.autoGuessEncoding</code> option of the Visual Studio Code is useful because it automatically guesses the character code. See <a href="https://code.visualstudio.com/updates/v1_11#_auto-guess-encoding-of-files" target="_blank" rel="noopener">files.autoGuessEncoding</a></p> | |
<pre><code>"files.autoGuessEncoding": true,</code></pre> | |
<h3>Output directory</h3> | |
<p>If you always want to output to the relative path directory from the Markdown file.</p> | |
<p>For example, to output to the “output” directory in the same directory as the Markdown file, set it as follows.</p> | |
<pre><code>"markdown-pdf.outputDirectory" : "output", | |
"markdown-pdf.outputDirectoryRelativePathFile": true,</code></pre> | |
<h3>Page Break</h3> | |
<p>Please use the following to insert a page break.</p> | |
<pre><code><div class="page"/></code></pre> | |
<h3>Known Issues</h3> | |
<h3><code>markdown-pdf.styles</code> option</h3> | |
<ul> | |
<li>Online CSS (<a href="https://xxx/xxx.css" rel="nofollow">https://xxx/xxx.css</a>) is applied correctly for JPG and PNG, but problems occur with PDF. <a href="https://github.com/yzane/vscode-markdown-pdf/issues/67" target="_blank" rel="noopener">#67</a></li> | |
</ul> | |
<h3><a href="https://github.com/yzane/vscode-markdown-pdf/blob/master/CHANGELOG.md" target="_blank" rel="noopener">Release Notes</a></h3> | |
<h3>1.4.4 (2020/03/19)</h3> | |
<ul> | |
<li>Change: mermaid javascript reads from URL instead of from local file</li> | |
<li>Add: <code>markdown-pdf.mermaidServer</code> option</li> | |
<li>add an option to disable mermaid <a href="https://github.com/yzane/vscode-markdown-pdf/issues/175" target="_blank" rel="noopener">#175</a></li> | |
<li>Add: <code>markdown-pdf.plantumlServer</code> option</li> | |
<li>support configuration of plantUML server <a href="https://github.com/yzane/vscode-markdown-pdf/issues/139" target="_blank" rel="noopener">#139</a></li> | |
<li>Add: configuration scope</li> | |
<li>extend setting ‘headerTemplate’ with scope… <a href="https://github.com/yzane/vscode-markdown-pdf/pull/184" target="_blank" rel="noopener">#184</a></li> | |
<li>Update: <a href="https://github.com/yzane/vscode-markdown-pdf/commit/3f4aeaa724999c46fc37423d4b188fd7ce72ffce" target="_blank" rel="noopener">slug</a> for markdown-it-named-headers</li> | |
<li>Update: markdown.css, markdown-pdf.css</li> | |
<li>Update: dependent packages</li> | |
<li>Fix: Fix for issue #186 <a href="https://github.com/yzane/vscode-markdown-pdf/pull/187" target="_blank" rel="noopener">#187</a></li> | |
<li>Fix: move the Meiryo font to the end of the font-family setting</li> | |
<li>Meiryo font causing \ to show as ¥ <a href="https://github.com/yzane/vscode-markdown-pdf/issues/83" target="_blank" rel="noopener">#83</a></li> | |
<li>Backslash false encoded <a href="https://github.com/yzane/vscode-markdown-pdf/issues/124" target="_blank" rel="noopener">#124</a></li> | |
<li>Errors in which 한글(korean word) is not properly printed <a href="https://github.com/yzane/vscode-markdown-pdf/issues/148" target="_blank" rel="noopener">#148</a></li> | |
<li>Fix: Improve the configuration schema of package.json</li> | |
<li>Some settings can now be set from the settings editor.</li> | |
</ul> | |
<figure><img src="https://webdevhubcom.files.wordpress.com/2021/04/b6c22-0xiwcipeujuw-ghyc.gif" data-width="781" data-height="22" /></figure> | |
<hr /> | |
<p>NEXT</p> | |
<hr /> | |
<h3>Ruby for Visual Studio Code</h3> | |
<p>This extension provides enhanced Ruby language and debugging support for Visual Studio Code.</p> | |
<h3>Features</h3> | |
<ul> | |
<li>Automatic Ruby environment detection with support for rvm, rbenv, chruby, and asdf</li> | |
<li>Lint support via RuboCop, Standard, and Reek</li> | |
<li>Format support via RuboCop, Standard, Rufo, Prettier and RubyFMT</li> | |
<li>Semantic code folding support</li> | |
<li>Semantic highlighting support</li> | |
<li>Basic Intellisense support</li> | |
</ul> | |
<h3>Installation</h3> | |
<p>Search for <code>ruby</code> in the <a href="https://code.visualstudio.com/docs/editor/extension-gallery" target="_blank" rel="noopener">VS Code Extension Gallery</a> and install it!</p> | |
<h3>Initial Configuration</h3> | |
<p>By default, the extension provides sensible defaults for developers to get a better experience using Ruby in Visual Studio Code. However, these defaults do not include settings to enable features like formatting or linting. Given how dynamic Ruby projects can be (are you using rvm, rbenv, chruby, or asdf? Are your gems globally installed or via bundler? etc), the extension requires additional configuration for additional features to be available.</p> | |
<h3>Using the Language Server</h3> | |
<p>It is <strong>highly recommended</strong> that you enable the Ruby language server (via the Use Language Server setting or <code>ruby.useLanguageServer</code> config option). The server does not default to enabled while it is under development but it provides a significantly better experience than the legacy extension functionality. See <a href="https://github.com/rubyide/vscode-ruby/blob/master/docs/language-server.md" target="_blank" rel="noopener">docs/language-server.md</a> for more information on the language server.</p> | |
<p>Legacy functionality will most likely not receive additional improvements and will be fully removed when the extension hits v1.0</p> | |
<h3>Example Initial Configuration:</h3> | |
<pre><code>"ruby.useBundler": true, //run non-lint commands with bundle exec | |
"ruby.useLanguageServer": true, // use the internal language server (see below) | |
"ruby.lint": { | |
"rubocop": { | |
"useBundler": true // enable rubocop via bundler | |
}, | |
"reek": { | |
"useBundler": true // enable reek via bundler | |
} | |
}, | |
"ruby.format": "rubocop" // use rubocop for formatting</code></pre> | |
<p>Reviewing the <a href="https://github.com/rubyide/vscode-ruby/blob/master/docs/linting.md" target="_blank" rel="noopener">linting</a>, <a href="https://github.com/rubyide/vscode-ruby/blob/master/docs/formatting.md" target="_blank" rel="noopener">formatting</a>, and <a href="https://github.com/rubyide/vscode-ruby/blob/master/docs/language-server.md" target="_blank" rel="noopener">environment detection</a> docs is recommended</p> | |
<p>For full details on configuration options, please take a look at the <code>Ruby</code> section in the VS Code settings UI. Each option is associated with a name and description.</p> | |
<h3>Debug Configuration</h3> | |
<p>See <a href="https://github.com/rubyide/vscode-ruby/blob/master/docs/debugger.md" target="_blank" rel="noopener">docs/debugger.md</a>.</p> | |
<h3>Legacy Configuration</h3> | |
<p><a href="https://github.com/rubyide/vscode-ruby/blob/master/docs/legacy.md" target="_blank" rel="noopener">docs/legacy.md</a> contains the documentation around the legacy functionality</p> | |
<h3>Troubleshooting</h3> | |
<p>See <a href="https://github.com/rubyide/vscode-ruby/blob/master/docs/troubleshooting.md" target="_blank" rel="noopener">docs/troubleshooting.md</a></p> | |
<h3>Other Notable Extensions</h3> | |
<ul> | |
<li><a href="https://marketplace.visualstudio.com/items?itemName=castwide.solargraph" target="_blank" rel="noopener">Ruby Solargraph</a> — Solargraph is a language server that provides intellisense, code completion, and inline documentation for Ruby.</li> | |
<li><a href="https://github.com/kaiwood/vscode-endwise" target="_blank" rel="noopener">VSCode Endwise</a> — Wisely add “end” in Ruby</li> | |
</ul> | |
<figure><img src="https://webdevhubcom.files.wordpress.com/2021/04/eb632-0wc4kcdykcjnhxfzj.png" data-width="256" data-height="256" /></figure> | |
<h3>Comment Divider</h3> | |
<p>This is <a href="https://github.com/Microsoft/vscode" target="_blank" rel="noopener"><strong>Visual Studio Code</strong></a> extension, which provides commands for generating comment-wrapped separators from line content.</p> | |
<p><a href="https://trusting-aryabhata-e5438d.netlify.app/#language-support" target="_blank" rel="noopener"><strong>Supports all common languages</strong></a><strong>.</strong></p> | |
<h3>Install</h3> | |
<p><a href="https://marketplace.visualstudio.com/items?itemName=stackbreak.comment-divider" target="_blank" rel="noopener">https://marketplace.visualstudio.com/items?itemName=stackbreak.comment-divider</a></p> | |
<h3>Demo</h3> | |
<figure><img src="https://webdevhubcom.files.wordpress.com/2021/04/a17da-0oeigp8g4f3wcdv8g.gif" data-width="1140" data-height="410" /></figure> | |
<h3>Commands</h3> | |
<h3>Make main header</h3> | |
<ul> | |
<li>Default Shortcut:</li> | |
<li><code><strong>Shift</strong></code> + <code><strong>Alt</strong></code> + <code><strong>X</strong></code></li> | |
<li>Default Style:</li> | |
<li><code>/* -------------------------------------------------------------------------- */ /* Example text */ /* -------------------------------------------------------------------------- */</code></li> | |
</ul> | |
<h3>Make subheader</h3> | |
<ul> | |
<li>Default Shortcut:</li> | |
<li><code><strong>Alt</strong></code> + <code><strong>X</strong></code></li> | |
<li>Default Style:</li> | |
<li><code>/* ------------------------------ Example text ------------------------------ */</code></li> | |
</ul> | |
<h3>Insert solid line</h3> | |
<ul> | |
<li>Default Shortcut:</li> | |
<li><code><strong>Alt</strong></code> + <code><strong>Y</strong></code></li> | |
<li>Default Style:</li> | |
<li><code>/* -------------------------------------------------------------------------- */</code></li> | |
</ul> | |
<h3>Language Support</h3> | |
<p>Extension uses relevant comment characters for all common languages.</p> | |
<p>For example, in python files subheader looks like</p> | |
<pre><code># ------------------------------ python example ------------------------------ #</code></pre> | |
<p>or in html files</p> | |
<pre><code><!-- ---------------------------- html example ----------------------------- --></code></pre> | |
<p><strong>Also, you can easily </strong><a href="https://trusting-aryabhata-e5438d.netlify.app/#languages-configuration" target="_blank" rel="noopener"><strong>add support</strong></a><strong> for any missing language or override the default preset.</strong></p> | |
<h3>Default Configuration</h3> | |
<h3>Common</h3> | |
<pre><code>// Set line length for all dividers. | |
"comment-divider.length": 80,</code></pre> | |
<h3>Main Header</h3> | |
<pre><code>// "Set symbol for main header line filling (only one). | |
"comment-divider.mainHeaderFiller": "-",</code></pre> | |
<pre><code> // Set main header vertical style. | |
"comment-divider.mainHeaderHeight": "block",</code></pre> | |
<pre><code> // Set main header text align. | |
"comment-divider.mainHeaderAlign": "center",</code></pre> | |
<pre><code> // Set main header text transform style. | |
"comment-divider.mainHeaderTransform": "none",</code></pre> | |
<h3>Subheader</h3> | |
<pre><code>// "Set symbol for subheader line filling (only one). | |
"comment-divider.subheaderFiller": "-",</code></pre> | |
<pre><code> // Set subheader vertical style. | |
"comment-divider.subheaderHeight": "line",</code></pre> | |
<pre><code> // Set subheader text align. | |
"comment-divider.subheaderAlign": "center",</code></pre> | |
<pre><code> // Set subheader text transform style. | |
"comment-divider.subheaderTransform": "none",</code></pre> | |
<h3>Solid Line</h3> | |
<pre><code>// Set symbol for solid line filling. | |
"comment-divider.lineFiller": "-",</code></pre> | |
<h3>Languages Configuration</h3> | |
<p>If some language is not supported out of the box, or you want to change default comment characters for an already supported language, it is possible to do it in the settings.</p> | |
<pre><code>"comment-divider.languagesMap": { | |
"toml": ["#", "#"], | |
"scss": ["//"] | |
}</code></pre> | |
<p>The item name is the language mode name and is associated with an array of 1 or 2 elements. The first element is the start of the line. The second, if defined, is the end.</p> | |
<p>The example above defines the right characters for <code>toml</code> and overrides <code>scss</code> defaults. As a result, the subheaders for these languages look like this:</p> | |
<pre><code># ------------------------------ toml subheader ------------------------------ #</code></pre> | |
<pre><code>// ----------------------------- scss subheader --------------------------------</code></pre> | |
<h3>Issues</h3> | |
<p>Request features and report bugs using <a href="https://github.com/stackbreak/comment-divider/issues" target="_blank" rel="noopener">GitHub</a>.</p> | |
<figure><img src="https://webdevhubcom.files.wordpress.com/2021/04/8f2d5-0ummqshaddas51l_x.gif" data-width="781" data-height="22" /></figure> | |
<hr /> | |
<p>NEXT</p> | |
<hr /> | |
<h3>Auto Import — ES6, TS, JSX, TSX (VSCode Extension)</h3> | |
<p>Automatically finds, parses and provides code actions and code completion for all available imports. Works with JavaScript (ES6) and TypeScript (TS). Forker from old repo <a href="https://github.com/martinoppitz/vscode-extension-auto-import" target="_blank" rel="noopener">vscode-extension-auto-import</a></p> | |
<figure><img src="https://webdevhubcom.files.wordpress.com/2021/04/e32dc-0qlapcdgufwrpwneh.gif" data-width="480" data-height="287" /></figure> | |
<hr /> | |
<h3>PostgreSQL for Visual Studio Code</h3> | |
<p>Welcome to PostgreSQL for Visual Studio Code! An extension for developing PostgreSQL with functionalities including:</p> | |
<ul> | |
<li>Connect to PostgreSQL instances</li> | |
<li>Manage connection profiles</li> | |
<li>Connect to a different Postgres instance or database in each tab</li> | |
<li>View object DDL with ‘Go to Definition’ and ‘Peek Definition’</li> | |
<li>Write queries with IntelliSense</li> | |
<li>Run queries and save results as JSON, csv, or Excel</li> | |
</ul> | |
<p>Install link: <a href="https://marketplace.visualstudio.com/items?itemName=ms-ossdata.vscode-postgresql" target="_blank" rel="noopener">https://marketplace.visualstudio.com/items?itemName=ms-ossdata.vscode-postgresql</a></p> | |
<h3>Quickstart</h3> | |
<ol> | |
<li>Open the Command Palette (Ctrl + Shift + P).</li> | |
<li>Search and select ‘PostgreSQL: New Query’</li> | |
<li>In the command palette, select ‘Create Connection Profile’. Follow the prompts to enter your Postgres instance’s hostname, database, username, and password.</li> | |
</ol> | |
<p>You are now connected to your Postgres database. You can confirm this via the Status Bar (the ribbon at the bottom of the VS Code window). It will show your connected hostname, database, and user.</p> | |
<ol> | |
<li>You can type a query like ‘SELECT * FROM pg_stat_activity’;</li> | |
<li>Right-click, select ‘Execute Query’ and the results will show in a new window.</li> | |
</ol> | |
<p>You can save the query results to JSON, csv or Excel.</p> | |
<h3>Offline Installation</h3> | |
<p>The extension will download and install a required PostgreSQL Tools Service package during activation. For machines with no Internet access, you can still use the extension by choosing the <code>Install from VSIX...</code> option in the Extension view and installing a bundled release from our <a href="https://github.com/Microsoft/vscode-postgresql/releases" target="_blank" rel="noopener">Releases</a> page. Each operating system has a .vsix file with the required service included. Pick the file for your OS, download and install to get started. We recommend you choose a full release and ignore any alpha or beta releases as these are our daily builds used in testing.</p> | |
<h3>Support</h3> | |
<p>Support for this extension is provided on our <a href="https://github.com/Microsoft/vscode-postgresql/issues" target="_blank" rel="noopener">GitHub Issue Tracker</a>. You can submit a <a href="https://github.com/Microsoft/vscode-postgresql/issues/new" target="_blank" rel="noopener">bug report</a>, a <a href="https://github.com/Microsoft/vscode-postgresql/issues/new" target="_blank" rel="noopener">feature suggestion</a> or participate in [discussions].</p> | |
<figure><img src="https://webdevhubcom.files.wordpress.com/2021/04/0b82b-0hmzlbjpk1aqwh_cf.gif" data-width="781" data-height="22" /></figure> | |
<hr /> | |
<h3>JS JSX Snippets</h3> | |
<h3>Supported languages (file extensions)</h3> | |
<ul> | |
<li>JavaScript (.js)</li> | |
<li>TypeScript (.ts)</li> | |
<li>JavaScript React (.jsx)</li> | |
<li>TypeScript React (.tsx)</li> | |
</ul> | |
<h3>Usage</h3> | |
<p>After install this snippets add this inside your settings</p> | |
<pre><code>"editor.snippetSuggestions": "top",</code></pre> | |
<h3>Snippets</h3> | |
<h3>Import and export</h3> | |
<p>TriggerContent<code>impimport name from 'module';imdimport { } from 'module';</code></p> | |
<h3>Import package</h3> | |
<p>TriggerContentDescription<code>imrimport React from 'react';</code>useful in test<code>iptimport PropTypes from 'prop-types';</code></p> | |
<h3>Basic methods</h3> | |
<p>TriggerContent<code>com</code>Comment Block<code>clgconsole.log()</code></p> | |
<h3>React components</h3> | |
<p>Only contain class component and function component.</p> | |
<p>TriggerContent<code>rcc</code>class component skeleton<code>rccp</code>class component skeleton with prop types after the class<code>rfc</code>function component skeleton<code>rfcp</code>function component with prop types skeleton<code>con</code>class default constructor with props<code>est</code>empty state object<code>cdmcomponentDidMount methodscushouldComponentUpdate methodcdupcomponentDidUpdate methodcwuncomponentWillUnmount methodgsbugetSnapshotBeforeUpdate methodgdsfpstatic getDerivedStateFromProps methodcdccomponentDidCatch methodsstthis.setState with object as parameterssfthis.setState with function as parameterpropsthis.propsstatethis.statebndbinds the this of method inside the constructoruseState</code>useState block<code>useEffect</code>useEffect block<code>useContext</code>useContext block</p> | |
<h3>Jest</h3> | |
<p>TriggerContent<code>describe</code>describe Block<code>test</code>test Block<code>it</code>it Block</p> | |
<h3>PropTypes</h3> | |
<p>TriggerContent<code>ptaPropTypes.array,ptarPropTypes.array.isRequired,ptoPropTypes.object.,ptorPropTypes.object.isRequired,ptbPropTypes.bool,ptbrPropTypes.bool.isRequired,ptfPropTypes.func,ptfrPropTypes.func.isRequired,ptnPropTypes.number,ptnrPropTypes.number.isRequired,ptsPropTypes.string,ptsrPropTypes.string.isRequired,ptndPropTypes.node,ptndrPropTypes.node.isRequired,ptelPropTypes.element,ptelrPropTypes.element.isRequired,ptiPropTypes.instanceOf(ClassName),ptirPropTypes.instanceOf(ClassName).isRequired,ptePropTypes.oneOf(['News', 'Photos']),pterPropTypes.oneOf(['News', 'Photos']).isRequired,ptetPropTypes.oneOfType([PropTypes.string, PropTypes.number]),ptetrPropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,ptaoPropTypes.arrayOf(PropTypes.number),ptaorPropTypes.arrayOf(PropTypes.number).isRequired,ptooPropTypes.objectOf(PropTypes.number),ptoorPropTypes.objectOf(PropTypes.number).isRequired,ptshPropTypes.shape({color: PropTypes.string, fontSize: PropTypes.number}),ptshrPropTypes.shape({color: PropTypes.string, fontSize: PropTypes.number}).isRequired,</code></p> | |
<figure><img src="https://webdevhubcom.files.wordpress.com/2021/04/fec80-0feudrdiwsq5fn9zc.gif" data-width="781" data-height="22" /></figure> | |
<hr /> | |
<p>NEXT</p> | |
<hr /> | |
<h3>Indent-Rainbow</h3> | |
<h3>A simple extension to make indentation more readable</h3> | |
<p>If you like this plugin, please consider a small donation:</p> | |
<figure><img src="https://webdevhubcom.files.wordpress.com/2021/04/912b7-0oyuoktkyg5xyl8ku.gif" data-width="147" data-height="47" /></figure> | |
<hr /> | |
<p>This extension colorizes the indentation in front of your text alternating four different colors on each step. Some may find it helpful in writing code for Nim or Python.</p> | |
<figure><img src="https://webdevhubcom.files.wordpress.com/2021/04/b0a4a-0jopzwr3l1nwouh3d.png" data-width="262" data-height="322" /></figure> | |
<p>Get it here: <a href="https://marketplace.visualstudio.com/items?itemName=oderwat.indent-rainbow" target="_blank" rel="noopener">Visual Studio Code Marketplace</a></p> | |
<p>It uses the current editor window tab size and can handle mixed tab + spaces but that is not recommended. In addition it visibly marks lines where the indentation is not a multiple of the tab size. This should help to find problems with indentation in some situations.</p> | |
<h3>Configuration</h3> | |
<p>Although you can just use it as it is there is the possibility to configure some aspects of the extension:</p> | |
<pre><code>// For which languages indent-rainbow should be activated (if empty it means all). | |
"indentRainbow.includedLanguages": [] // for example ["nim", "nims", "python"]</code></pre> | |
<pre><code> // For which languages indent-rainbow should be deactivated (if empty it means none). | |
"indentRainbow.excludedLanguages": ["plaintext"]</code></pre> | |
<pre><code> // The delay in ms until the editor gets updated. | |
"indentRainbow.updateDelay": 100 // 10 makes it super fast but may cost more resources</code></pre> | |
<p><em>Notice: Defining both </em><code><em>includedLanguages</em></code><em> and </em><code><em>excludedLanguages</em></code><em> does not make much sense. Use one of both!</em></p> | |
<p>You can configure your own colors by adding and tampering with the following code:</p> | |
<pre><code>// Defining custom colors instead of default "Rainbow" for dark backgrounds. | |
// (Sorry: Changing them needs an editor restart for now!) | |
"indentRainbow.colors": [ | |
"rgba(255,255,64,0.07)", | |
"rgba(127,255,127,0.07)", | |
"rgba(255,127,255,0.07)", | |
"rgba(79,236,236,0.07)" | |
]</code></pre> | |
<pre><code> // The indent color if the number of spaces is not a multiple of "tabSize". | |
"indentRainbow.errorColor": "rgba(128,32,32,0.6)"</code></pre> | |
<pre><code> // The indent color when there is a mix between spaces and tabs. | |
// To be disabled this coloring set this to an empty string. | |
"indentRainbow.tabmixColor": "rgba(128,32,96,0.6)"</code></pre> | |
<blockquote><p><em>Notice: </em><code><em>errorColor</em></code><em> was renamed from </em><code><em>error_color</em></code><em> in earlier versions.</em></p></blockquote> | |
<p>Skip error highlighting for RegEx patterns. For example, you may want to turn off the indent errors for JSDoc’s valid additional space (disabled by default), or comment lines beginning with <code>//</code></p> | |
<pre><code>// Example of regular expression in JSON (note double backslash to escape characters) | |
"indentRainbow.ignoreLinePatterns" : [ | |
"/[ \t]* [*]/g", // lines begining with <whitespace><space>* | |
"/[ \t]+[/]{2}/g" // lines begininning with <whitespace>// | |
]</code></pre> | |
<p>Skip error highlighting for some or all languages. For example, you may want to turn off the indent errors for <code>markdown</code> and <code>haskell</code> (which is the default)</p> | |
<pre><code>"indentRainbow.ignoreErrorLanguages" : [ | |
"markdown", | |
"haskell" | |
]</code></pre> | |
<p>If error color is disabled, indent colors will be rendered until the length of rendered characters (white spaces, tabs, and other ones) is divisible by tabsize. Turn on this option to render white spaces and tabs only.</p> | |
<pre><code>"indentRainbow.colorOnWhiteSpaceOnly": true // false is the default</code></pre> | |
<p>Build with:</p> | |
<pre><code>npm install | |
npm run vscode:prepublish</code></pre> | |
<p>Running <code>npm run compile</code> makes the compiler recompile on file change.</p> | |
<figure><img src="https://webdevhubcom.files.wordpress.com/2021/04/d9758-0hge_ezptazcccgux.gif" data-width="781" data-height="22" /></figure> | |
<hr /> | |
<p>NEXT</p> | |
<hr /> | |
<h3>Path Intellisense</h3> | |
<p>Visual Studio Code plugin that autocompletes filenames.</p> | |
<h3>Sponsors</h3> | |
<figure><img src="https://webdevhubcom.files.wordpress.com/2021/04/ec634-0pcurf5a3ltjthek2.png" data-width="294" data-height="45" /></figure> | |
<p>Eliminate context switching and costly distractions. Create and merge PRs and perform code reviews from inside your IDE while using jump-to-definition, your favorite keybindings, and other IDE tools.<br /> | |
<a title="Try CodeStream" href="https://sponsorlink.codestream.com/?utm_source=vscmarket&utm_campaign=pathintel&utm_medium=banner" target="_blank" rel="noopener">Learn more</a></p> | |
<h3>Installation</h3> | |
<p>In the command palette (cmd-shift-p) select Install Extension and choose Path Intellisense.</p> | |
<p>To use Path Intellisense instead of the default autocompletion, the following configuration option must be added to your settings:</p> | |
<pre><code>{ "typescript.suggest.paths": false }</code></pre> | |
<h3>Usage</h3> | |
<figure><img src="https://webdevhubcom.files.wordpress.com/2021/04/c6dbe-0tlylrlqtyv3zdein.gif" data-width="480" data-height="270" /></figure> | |
<h3>Node packages intellisense</h3> | |
<p>Use <a href="https://marketplace.visualstudio.com/items?itemName=christian-kohler.npm-intellisense" target="_blank" rel="noopener">npm intellisense</a></p> | |
<h3>BaseUrl</h3> | |
<p>Pathintellisense uses the ts.config.compilerOptions.baseUrl as a mapping. So no need to define it twice. There is no support for paths at the moment.</p> | |
<p>For example:</p> | |
<pre><code>{ | |
"baseUrl": "src", | |
}</code></pre> | |
<p>would allow to type:</p> | |
<pre><code>{ | |
import {} from "src/mymodule"; | |
}</code></pre> | |
<h3>Settings</h3> | |
<h3>File extension in import statements</h3> | |
<p>Path Intellisense removes the file extension by default if the statement is a import statement. To enable file extensions set the following setting to true:</p> | |
<pre><code>{ | |
"path-intellisense.extensionOnImport": true, | |
}</code></pre> | |
<h3>Show hidden files</h3> | |
<p>Per default, hidden files are not displayed. Set this to true to show hidden files.</p> | |
<pre><code>{ | |
"path-intellisense.showHiddenFiles": true, | |
}</code></pre> | |
<p>If set to false, PathIntellisense ignores the default “files.exclude” as well:</p> | |
<pre><code>{ | |
"files.exclude": { | |
"**/*.map.js": true | |
} | |
}</code></pre> | |
<h3>Auto slash when navigating to folder</h3> | |
<p>Per default, the autocompletion does not add a slash after a directory.</p> | |
<pre><code>{ | |
"path-intellisense.autoSlashAfterDirectory": false, | |
}</code></pre> | |
<h3>Absolute paths</h3> | |
<p>Per default, absolute paths are resolved within the current workspace root path. Set it to false to resolve absolute paths to the disk root path.</p> | |
<pre><code>{ | |
"path-intellisense.absolutePathToWorkspace": true, | |
}</code></pre> | |
<h3>Mappings</h3> | |
<p>Define custom mappings which can be useful for using absolute paths or in combination with webpack resolve options.</p> | |
<pre><code>{ | |
"path-intellisense.mappings": { | |
"/": "${workspaceFolder}", | |
"lib": "${workspaceFolder}/lib", | |
"global": "/Users/dummy/globalLibs" | |
}, | |
}</code></pre> | |
<p>Use ${workspaceFolder} when the path should be relative to the current root of the current project. V2.2.1 and lower used ${workspaceRoot}. Newer version support both placeholders.</p> | |
<figure><img src="https://webdevhubcom.files.wordpress.com/2021/04/e275d-0ehx7lejfahj37qh-.gif" data-width="781" data-height="22" /></figure> | |
<hr /> | |
<h3>turbo-js</h3> | |
<p>Turbo-js for vscode is forked from <a href="https://github.com/extrabacon/atom-turbo-javascript" target="_blank" rel="noopener">atom-turbo-javascript</a></p> | |
<h3>Declarations</h3> | |
<h4><code>l=⇥</code> let assignment</h4> | |
<pre><code>let ${1:name} = ${2:value}</code></pre> | |
<h4><code>co⇥</code> const statement</h4> | |
<pre><code>const ${1:name}</code></pre> | |
<h4><code>co=⇥</code> const assignment</h4> | |
<pre><code>const ${1:name} = ${2:value}</code></pre> | |
<h3>Flow Control</h3> | |
<h4><code>if⇥</code> if statement</h4> | |
<pre><code>if (${1:condition}) { | |
${0} | |
}</code></pre> | |
<h4><code>ife⇥</code> else statement</h4> | |
<pre><code>if (${1:condition}) { | |
${0} | |
} else {</code></pre> | |
<pre><code>}</code></pre> | |
<h4><code>fo⇥</code> for of loop (ES6)</h4> | |
<pre><code>for (let ${1:key} of ${2:source}) { | |
${0} | |
}</code></pre> | |
<h4><code>wl⇥</code> while loop</h4> | |
<pre><code>while (${1:condition}) { | |
${0} | |
}</code></pre> | |
<h4><code>tc⇥</code> try/catch</h4> | |
<pre><code>try { | |
${0} | |
} catch (${1:err}) {</code></pre> | |
<pre><code>}</code></pre> | |
<h3>Functions</h3> | |
<h4><code>fn⇥</code> named function</h4> | |
<pre><code>function ${1:name}(${2:arguments}) { | |
${0} | |
}</code></pre> | |
<h4><code>iife⇥</code> immediately-invoked function expression (IIFE)</h4> | |
<pre><code>(function (${1:arguments}) { | |
${0} | |
})(${2});</code></pre> | |
<h4><code>af⇥</code> arrow function (ES6)</h4> | |
<pre><code>(${1:arguments}) => ${2:statement}</code></pre> | |
<h4><code>afb⇥</code> arrow function with body (ES6)</h4> | |
<pre><code>(${1:arguments}) => { | |
\t${0} | |
}</code></pre> | |
<h3>Iterables</h3> | |
<h4><code>fe⇥</code> forEach loop (chainable)</h4> | |
<pre><code>${1:iterable}.forEach((${2:item}) => { | |
${0} | |
});</code></pre> | |
<h4><code>reduce⇥</code> reduce function (chainable)</h4> | |
<pre><code>${1:iterable}.reduce((${2:previous}, ${3:current}) => { | |
${0} | |
}${4:, initial});</code></pre> | |
<h4><code>filter⇥</code> filter function (chainable)</h4> | |
<pre><code>${1:iterable}.filter((${2:item}) => { | |
${0} | |
});</code></pre> | |
<h4><code>find⇥</code> ES6 find function (chainable)</h4> | |
<pre><code>${1:iterable}.find((${2:item}) => { | |
${0} | |
});</code></pre> | |
<h3>Objects and classes</h3> | |
<h4><code>cls⇥</code> class (ES6)</h4> | |
<pre><code>class ${1:name} { | |
constructor(${2:arguments}) { | |
${0} | |
} | |
}</code></pre> | |
<h4><code>cex⇥</code> child class (ES6)</h4> | |
<pre><code>class ${1:name} extends ${2:base} { | |
constructor(${2:arguments}) { | |
super(${2:arguments}); | |
${0} | |
} | |
}</code></pre> | |
<h4><code>med⇥</code> method (ES6 syntax)</h4> | |
<pre><code>${1:method}(${2:arguments}) { | |
${0} | |
}</code></pre> | |
<h4><code>get⇥</code> getter (ES6 syntax)</h4> | |
<pre><code>get ${1:property}() { | |
${0} | |
}</code></pre> | |
<h4><code>set⇥</code> setter (ES6 syntax)</h4> | |
<pre><code>set ${1:property}(${2:value}) { | |
${0} | |
}</code></pre> | |
<h4><code>proto⇥</code> prototype method (chainable)</h4> | |
<pre><code>${1:Class}.prototype.${2:methodName} = function (${3:arguments}) { | |
${0} | |
};</code></pre> | |
<h4><code>oa⇥</code> Object assign</h4> | |
<pre><code>Object.assign(${1:dest}, ${2:source})</code></pre> | |
<h4><code>ok⇥</code> Object.keys</h4> | |
<pre><code>Object.keys(${1:obj})</code></pre> | |
<h3>Promises</h3> | |
<h4><code>rp⇥</code> return Promise (ES6)</h4> | |
<pre><code>return new Promise((resolve, reject) => { | |
${0} | |
});</code></pre> | |
<h3>ES6 modules</h3> | |
<h4><code>ex⇥</code> module export</h4> | |
<pre><code>export ${1:member};</code></pre> | |
<h4><code>exd⇥</code> module default export</h4> | |
<pre><code>export default ${1:member};</code></pre> | |
<h4><code>im⇥</code> module import</h4> | |
<pre><code>import ${1:*} from '${2:module}';</code></pre> | |
<h4><code>ima⇥</code> module import as</h4> | |
<pre><code>import ${1:*} as ${2:name} from '${3:module}';</code></pre> | |
<h3>Console</h3> | |
<h4><code>cl⇥</code> console.log</h4> | |
<pre><code>console.log(${0});</code></pre> | |
<h4><code>ce⇥</code> console.error</h4> | |
<pre><code>console.error(${0});</code></pre> | |
<h4><code>cw⇥</code> console.warn</h4> | |
<pre><code>console.warn(${0});</code></pre> | |
<h3>Timers</h3> | |
<h4><code>st⇥</code> setTimeout</h4> | |
<pre><code>setTimeout(() => { | |
${0} | |
}, ${1:delay});</code></pre> | |
<h4><code>si⇥</code> setInterval</h4> | |
<pre><code>setInterval(() => { | |
${0} | |
}, ${1:delay});</code></pre> | |
<h4><code>sim⇥</code> setImmediate</h4> | |
<pre><code>setImmediate(() => { | |
${0} | |
});</code></pre> | |
<h3>Node.js specifics</h3> | |
<h4><code>re⇥</code> require a module</h4> | |
<pre><code>require('${1:module}');</code></pre> | |
<h4><code>cre⇥</code> require a module</h4> | |
<pre><code>const ${1:name} = require('${2:module}');</code></pre> | |
<h4><code>me⇥</code> module.exports</h4> | |
<pre><code>module.exports = ${1:name};</code></pre> | |
<h3>Miscellaneous</h3> | |
<h4><code>us⇥</code> use strict</h4> | |
<pre><code>'use strict';</code></pre> | |
<h3>vscode-standardjs-snippets</h3> | |
<p>Optinionated set of JS snippets. Originally forked from <a href="https://github.com/gaboesquivel/atom-standardjs-snippets," target="_blank" rel="noopener">https://github.com/gaboesquivel/atom-standardjs-snippets,</a> but we’ve added couple more. Also these are not using special characters because vscode doesn’t accept them in the snippets.</p> | |
<h3>Standard JavaScript Snippets for Visual studio code</h3> | |
<p>A collection of javascript and react snippets for faster JavaScript development in <a href="https://code.visualstudio.com/" target="_blank" rel="noopener">Visual studio Code</a>.</p> | |
<p>This collection is complementary to <a href="https://github.com/atom/language-javascript" target="_blank" rel="noopener">atom/language-javascript</a>. It’s based on <a href="https://github.com/extrabacon/atom-turbo-javascript" target="_blank" rel="noopener">extrabacon/atom-turbo-javascript</a>.</p> | |
<h3>Code style</h3> | |
<p><strong>Yes!, no semicolons:</strong></p> | |
<ul> | |
<li><a href="https://www.youtube.com/watch?v=gsfbh17Ax9I" target="_blank" rel="noopener">Are Semicolons Necessary in JavaScript?</a></li> | |
<li><a href="http://blog.izs.me/post/2353458699/an-open-letter-to-javascript-leaders-regarding" target="_blank" rel="noopener">An Open Letter to JavaScript Leaders Regarding Semicolons</a></li> | |
<li><a href="http://inimino.org/~inimino/blog/javascript_semicolons" target="_blank" rel="noopener">JavaScript Semicolon Insertion — Everything You Need to Know</a></li> | |
</ul> | |
<h3>Snippets</h3> | |
<p>Snippets are optimized to be short and easy to remember. Shortest are the ones you should be using most often. Note that these links work only on github, not on VSCode marketplace:</p> | |
<ul> | |
<li><a href="https://trusting-aryabhata-e5438d.netlify.app/#declarations" target="_blank" rel="noopener">declarations</a></li> | |
<li><a href="https://trusting-aryabhata-e5438d.netlify.app/#flow-control" target="_blank" rel="noopener">flow control</a></li> | |
<li><a href="https://trusting-aryabhata-e5438d.netlify.app/#functions" target="_blank" rel="noopener">functions</a></li> | |
<li><a href="https://trusting-aryabhata-e5438d.netlify.app/#iterables" target="_blank" rel="noopener">iterables</a></li> | |
<li><a href="https://trusting-aryabhata-e5438d.netlify.app/#objects-and-classes" target="_blank" rel="noopener">objects and classes</a></li> | |
<li><a href="https://trusting-aryabhata-e5438d.netlify.app/#returning-values" target="_blank" rel="noopener">returning values</a></li> | |
<li><a href="https://trusting-aryabhata-e5438d.netlify.app/#types" target="_blank" rel="noopener">types</a></li> | |
<li><a href="https://trusting-aryabhata-e5438d.netlify.app/#promises" target="_blank" rel="noopener">promises</a></li> | |
<li><a href="https://trusting-aryabhata-e5438d.netlify.app/#es6-modules" target="_blank" rel="noopener">ES6 modules</a></li> | |
<li><a href="https://trusting-aryabhata-e5438d.netlify.app/#testing" target="_blank" rel="noopener">testing</a></li> | |
<li><a href="https://trusting-aryabhata-e5438d.netlify.app/#console" target="_blank" rel="noopener">console</a></li> | |
<li><a href="https://trusting-aryabhata-e5438d.netlify.app/#timers" target="_blank" rel="noopener">timers</a></li> | |
<li><a href="https://trusting-aryabhata-e5438d.netlify.app/#dom" target="_blank" rel="noopener">DOM</a></li> | |
<li><a href="https://trusting-aryabhata-e5438d.netlify.app/#nodejs" target="_blank" rel="noopener">Node.js</a></li> | |
<li><a href="https://trusting-aryabhata-e5438d.netlify.app/#miscellaneous" target="_blank" rel="noopener">miscellaneous</a></li> | |
</ul> | |
<h3>Declarations</h3> | |
<h4><code>v⇥</code> var statement</h4> | |
<pre><code>var ${1:name}</code></pre> | |
<h4><code>va⇥</code> var assignment</h4> | |
<pre><code>var ${1:name} = ${2:value}</code></pre> | |
<h4><code>l⇥</code> let statement</h4> | |
<pre><code>let ${1:name}</code></pre> | |
<h4><code>la⇥</code> let assignment awaited</h4> | |
<pre><code>let ${1:name} = await ${2:value}</code></pre> | |
<h4><code>ly⇥</code> let yielded assignment</h4> | |
<pre><code>let ${1:name} = yield ${2:value}</code></pre> | |
<h4><code>c⇥</code> const statement</h4> | |
<pre><code>const ${1:name}</code></pre> | |
<h4><code>cd⇥</code> const from destructuring</h4> | |
<pre><code>const { ${1:name} } = ${2:value}</code></pre> | |
<h4><code>ca⇥</code> const assignment awaited</h4> | |
<pre><code>const ${1:name} = await ${2:value}</code></pre> | |
<h4><code>cd⇥</code> const from destructuring awaited</h4> | |
<pre><code>const { ${1:name} } = await ${2:value}</code></pre> | |
<h4><code>cf⇥</code> const arrow function assignment</h4> | |
<pre><code>const ${1:name} = (${2:arguments}) => {\n\treturn ${0}\n}</code></pre> | |
<h4><code>cy⇥</code> const yielded assignment</h4> | |
<pre><code>const ${1:name} = yield ${2:value}</code></pre> | |
<h3>Flow Control</h3> | |
<h4><code>i⇥</code> if statement</h4> | |
<pre><code>if (${1:condition}) { | |
${0} | |
}</code></pre> | |
<h4><code>te⇥</code> ternary statement</h4> | |
<pre><code>${1:cond} ? ${2:true} : ${3: false}</code></pre> | |
<h4><code>ta⇥</code> ternary statement</h4> | |
<pre><code>const ${0} = ${1:cond} ? ${2:true} : ${3: false}</code></pre> | |
<h4><code>el⇥</code> else statement</h4> | |
<pre><code>else { | |
${0} | |
}</code></pre> | |
<h4><code>ife⇥</code> else statement</h4> | |
<pre><code>if (${1:condition}) { | |
${0} | |
} else {</code></pre> | |
<pre><code>}</code></pre> | |
<h4><code>ei⇥</code> else if statement</h4> | |
<pre><code>else if (${1:condition}) { | |
${0} | |
}</code></pre> | |
<h4><code>fl⇥</code> for loop (ES6)</h4> | |
<pre><code>for (let ${1:i} = 0, ${2:len} = ${3:iterable}.length ${1:i} < ${2:len}; ${1:i}++) { | |
${0} | |
}</code></pre> | |
<h4><code>fi⇥</code> for in loop (ES6)</h4> | |
<pre><code>for (let ${1:key} in ${2:source}) { | |
if (${2:source}.hasOwnProperty(${1:key})) { | |
${0} | |
} | |
}</code></pre> | |
<h4><code>fo⇥</code> for of loop (ES6)</h4> | |
<pre><code>for (const ${1:key} of ${2:source}) { | |
${0} | |
}</code></pre> | |
<h4><code>wl⇥</code> while loop</h4> | |
<pre><code>while (${1:condition}) { | |
${0} | |
}</code></pre> | |
<h4><code>wid⇥</code> while iteration decrementing</h4> | |
<pre><code>let ${1:array}Index = ${1:array}.length | |
while (${1:array}Index--) { | |
${0} | |
}</code></pre> | |
<h4><code>tc⇥</code> try/catch</h4> | |
<pre><code>try { | |
${0} | |
} catch (${1:err}) {</code></pre> | |
<pre><code>}</code></pre> | |
<h4><code>tf⇥</code> try/finally</h4> | |
<pre><code>try { | |
${0} | |
} finally {</code></pre> | |
<pre><code>}</code></pre> | |
<h4><code>tcf⇥</code> try/catch/finally</h4> | |
<pre><code>try { | |
${0} | |
} catch (${1:err}) {</code></pre> | |
<pre><code>} finally {</code></pre> | |
<pre><code>}</code></pre> | |
<h3>Functions</h3> | |
<h4><code>fan⇥</code> anonymous function</h4> | |
<pre><code>function (${1:arguments}) {${0}}</code></pre> | |
<h4><code>fn⇥</code> named function</h4> | |
<pre><code>function ${1:name}(${2:arguments}) { | |
${0} | |
}</code></pre> | |
<h4><code>asf⇥</code> async function</h4> | |
<pre><code>async function (${1:arguments}) { | |
${0} | |
}</code></pre> | |
<h4><code>aa⇥</code> async arrow function with</h4> | |
<pre><code>async (${1:arguments}) => { | |
${0} | |
}</code></pre> | |
<h4><code>iife⇥</code> immediately-invoked function expression (IIFE)</h4> | |
<pre><code>;(function (${1:arguments}) { | |
${0} | |
})(${2})</code></pre> | |
<h4><code>aiife⇥</code> async immediately-invoked function expression</h4> | |
<pre><code>;(async (${1:arguments}) => { | |
${0} | |
})(${2})</code></pre> | |
<h4><code>fa⇥</code> function apply</h4> | |
<pre><code>${1:fn}.apply(${2:this}, ${3:arguments})</code></pre> | |
<h4><code>fc⇥</code> function call</h4> | |
<pre><code>${1:fn}.call(${2:this}, ${3:arguments})</code></pre> | |
<h4><code>fb⇥</code> function bind</h4> | |
<pre><code>${1:fn}.bind(${2:this}, ${3:arguments})</code></pre> | |
<h4><code>af⇥</code> arrow function (ES6)</h4> | |
<pre><code>(${1:arguments}) => ${2:statement}</code></pre> | |
<h4><code>fd⇥</code> arrow function with destructuring</h4> | |
<pre><code>({${1:arguments}}) => ${2:statement}</code></pre> | |
<h4><code>fdr⇥</code> arrow function with destructuring returning destructured</h4> | |
<pre><code>({${1:arguments}}) => ${1:arguments}</code></pre> | |
<h4><code>f⇥</code> arrow function with body (ES6)</h4> | |
<pre><code>(${1:arguments}) => { | |
${0} | |
}</code></pre> | |
<h4><code>fr⇥</code> arrow function with return (ES6)</h4> | |
<pre><code>(${1:arguments}) => { | |
return ${0} | |
}</code></pre> | |
<h4><code>gf⇥</code> generator function (ES6)</h4> | |
<pre><code>function* (${1:arguments}) { | |
${0} | |
}</code></pre> | |
<h4><code>gfn⇥</code> named generator function (ES6)</h4> | |
<pre><code>function* ${1:name}(${1:arguments}) { | |
${0} | |
}</code></pre> | |
<h3>Iterables</h3> | |
<h4><code>fe⇥</code> forEach loop</h4> | |
<pre><code>${1:iterable}.forEach((${2:item}) => { | |
${0} | |
})</code></pre> | |
<h4><code>map⇥</code> map function</h4> | |
<pre><code>${1:iterable}.map((${2:item}) => { | |
${0} | |
})</code></pre> | |
<h4><code>reduce⇥</code> reduce function</h4> | |
<pre><code>${1:iterable}.reduce((${2:previous}, ${3:current}) => { | |
${0} | |
}${4:, initial})</code></pre> | |
<h4><code>filter⇥</code> filter function</h4> | |
<pre><code>${1:iterable}.filter((${2:item}) => { | |
${0} | |
})</code></pre> | |
<h4><code>find⇥</code> ES6 find function</h4> | |
<pre><code>${1:iterable}.find((${2:item}) => { | |
${0} | |
})</code></pre> | |
<h4><code>every⇥</code> every function</h4> | |
<pre><code>${1:iterable}.every((${2:item}) => { | |
${0} | |
})</code></pre> | |
<h4><code>some⇥</code> some function</h4> | |
<pre><code>${1:iterable}.some((${2:item}) => { | |
${0} | |
})</code></pre> | |
<h3>Objects and classes</h3> | |
<h4><code>cs⇥</code> class (ES6)</h4> | |
<pre><code>class ${1:name} { | |
constructor(${2:arguments}) { | |
${0} | |
} | |
}</code></pre> | |
<h4><code>csx⇥</code> extend a class (ES6)</h4> | |
<pre><code>class ${1:name} extends ${2:base} { | |
constructor(${2:arguments}) { | |
super(${2:arguments}) | |
${0} | |
} | |
}</code></pre> | |
<h4><code>m⇥</code> method (ES6 syntax)</h4> | |
<pre><code>${1:method} (${2:arguments}) { | |
${0} | |
}</code></pre> | |
<h4><code>get⇥</code> getter (ES6 syntax)</h4> | |
<pre><code>get ${1:property} () { | |
${0} | |
}</code></pre> | |
<h4><code>set⇥</code> setter (ES6 syntax)</h4> | |
<pre><code>set ${1:property} (${2:value}) { | |
${0} | |
}</code></pre> | |
<h4><code>gs⇥</code> getter and setter (ES6 syntax)</h4> | |
<pre><code>get ${1:property} () { | |
${0} | |
} | |
set ${1:property} (${2:value}) {</code></pre> | |
<pre><code>}</code></pre> | |
<h4><code>proto⇥</code> prototype method</h4> | |
<pre><code>${1:Class}.prototype.${2:methodName} = function (${3:arguments}) { | |
${0} | |
}</code></pre> | |
<h4><code>ok</code> Object.keys</h4> | |
<pre><code>Object.keys(${1:obj})</code></pre> | |
<h4><code>ov</code> Object.values</h4> | |
<pre><code>Object.values(${1:obj})</code></pre> | |
<h4><code>oe</code> Object.entries</h4> | |
<pre><code>Object.entries(${1:obj})</code></pre> | |
<h4><code>oc</code> Object.create</h4> | |
<pre><code>Object.create(${1:obj})</code></pre> | |
<h4><code>oa</code> Object.assign</h4> | |
<pre><code>Object.assign(${1:dest}, ${2:source})</code></pre> | |
<h4><code>og</code> Object.getOwnPropertyDescriptor</h4> | |
<pre><code>Object.getOwnPropertyDescriptor(${1:dest}, '${2:prop}')</code></pre> | |
<h4><code>od</code> Object.defineProperty</h4> | |
<pre><code>Object.defineProperty(${1:dest}, '${2:prop}', { | |
${0} | |
})</code></pre> | |
<h3>Returning values</h3> | |
<h4><code>r⇥</code> return</h4> | |
<pre><code>return ${0}</code></pre> | |
<h4><code>rt⇥</code> return this</h4> | |
<pre><code>return this</code></pre> | |
<h4><code>rn⇥</code> return null</h4> | |
<pre><code>return null</code></pre> | |
<h4><code>ro⇥</code> return new object</h4> | |
<pre><code>return { | |
${0} | |
}</code></pre> | |
<h4><code>ra⇥</code> return new array</h4> | |
<pre><code>return [ | |
${0} | |
]</code></pre> | |
<h4><code>rp⇥</code> return Promise (ES6)</h4> | |
<pre><code>return new Promise((resolve, reject) => { | |
${0} | |
})</code></pre> | |
<h4><code>tof⇥</code> typeof comparison</h4> | |
<pre><code>typeof ${1:source} === '${2:undefined}'</code></pre> | |
<h4><code>tf⇥</code> this</h4> | |
<pre><code>this.</code></pre> | |
<h4><code>iof⇥</code> instanceof comparison</h4> | |
<pre><code>${1:source} instanceof ${2:Object}</code></pre> | |
<h4><code>ia⇥</code> isArray</h4> | |
<pre><code>Array.isArray(${1:source})</code></pre> | |
<h3>Promises</h3> | |
<h4><code>pa⇥</code> Promise.all</h4> | |
<pre><code>Promise.all(${1:value})</code></pre> | |
<h4><code>p⇥</code> new Promise (ES6)</h4> | |
<pre><code>new Promise((resolve, reject) => { | |
${0} | |
})</code></pre> | |
<h4><code>pt⇥</code> Promise.then</h4> | |
<pre><code>${1:promise}.then((${2:value}) => { | |
${0} | |
})</code></pre> | |
<h4><code>pc⇥</code> Promise.catch</h4> | |
<pre><code>${1:promise}.catch(error => { | |
${0} | |
})</code></pre> | |
<h3>ES6 modules</h3> | |
<h4><code>e⇥</code> module export</h4> | |
<pre><code>export ${1:member}</code></pre> | |
<h4><code>ed⇥</code> module default export</h4> | |
<pre><code>export default ${1:member}</code></pre> | |
<h4><code>edf⇥</code> module default export function</h4> | |
<pre><code>export default function ${1:name} (${2:arguments}) {\n\t${0}\n}</code></pre> | |
<h4><code>ec⇥</code> module export const</h4> | |
<pre><code>export const ${1:member} = ${2:value}</code></pre> | |
<h4><code>ef⇥</code> module export const</h4> | |
<pre><code>export function ${1:member} (${2:arguments}) {\n\t${0}\n}</code></pre> | |
<h4><code>im⇥</code> module import</h4> | |
<pre><code>import ${1:*} from '${2:module}'</code></pre> | |
<h4><code>ia⇥</code> module import as</h4> | |
<pre><code>import ${1:*} as ${2:name} from '${3:module}'</code></pre> | |
<h4><code>id⇥</code> module import destructuring</h4> | |
<pre><code>import { $1 } from '${2:module}'</code></pre> | |
<h3>BDD testing (Mocha, Jasmine, etc.)</h3> | |
<h4><code>desc⇥</code> describe</h4> | |
<pre><code>describe('${1:description}', function () { | |
${0} | |
})</code></pre> | |
<h4><code>it⇥</code> asynchronous “it”</h4> | |
<pre><code>it('${1:description}', async () => { | |
${0} | |
})</code></pre> | |
<h4><code>itd⇥</code> “it” with callback</h4> | |
<pre><code>it('${1:description}', (done) => { | |
${0} | |
})</code></pre> | |
<h4><code>its⇥</code> “it” synchronous</h4> | |
<pre><code>it('${1:description}', () => { | |
${0} | |
})</code></pre> | |
<h4><code>bf⇥</code> before test suite</h4> | |
<pre><code>before(function () { | |
${0} | |
})</code></pre> | |
<h4><code>bfe⇥</code> before each test</h4> | |
<pre><code>beforeEach(function () { | |
${0} | |
})</code></pre> | |
<h4><code>aft⇥</code> after test suite</h4> | |
<pre><code>after(function () { | |
${0} | |
})</code></pre> | |
<h4><code>afe⇥</code> after each test</h4> | |
<pre><code>afterEach(function () { | |
${0} | |
})</code></pre> | |
<h3>Timers</h3> | |
<h4><code>st⇥</code> setTimeout</h4> | |
<pre><code>setTimeout(() => { | |
${0} | |
}, ${1:delay})</code></pre> | |
<h4><code>si⇥</code> setInterval</h4> | |
<pre><code>setTimeout(() => { | |
${0} | |
}, ${1:delay})</code></pre> | |
<h4><code>sim⇥</code> setImmediate</h4> | |
<pre><code>setImmediate(() => { | |
${0} | |
})</code></pre> | |
<h3>DOM</h3> | |
<h4><code>ae⇥</code> addEventListener</h4> | |
<pre><code>${1:document}.addEventListener('${2:event}', ${3:ev} => { | |
${0} | |
})</code></pre> | |
<h4><code>rel⇥</code> removeEventListener</h4> | |
<pre><code>${1:document}.removeEventListener('${2:event}', ${3:listener})</code></pre> | |
<h4><code>evc</code> dom event cancel default and propagation</h4> | |
<pre><code>ev.preventDefault() | |
ev.stopPropagation() | |
return false</code></pre> | |
<h4><code>gi⇥</code> getElementById</h4> | |
<pre><code>${1:document}.getElementById('${2:id}')</code></pre> | |
<h4><code>gc⇥</code> getElementsByClassName</h4> | |
<pre><code>Array.from(${1:document}.getElementsByClassName('${2:class}'))</code></pre> | |
<h4><code>gt⇥</code> getElementsByTagName</h4> | |
<pre><code>Array.from(${1:document}.getElementsByTagName('${2:tag}'))</code></pre> | |
<h4><code>qs⇥</code> querySelector</h4> | |
<pre><code>${1:document}.querySelector('${2:selector}')</code></pre> | |
<h4><code>qsa⇥</code> querySelectorAll</h4> | |
<pre><code>Array.from(${1:document}.querySelectorAll('${2:selector}'))</code></pre> | |
<h4><code>cdf⇥</code> createDocumentFragment</h4> | |
<pre><code>${1:document}.createDocumentFragment(${2:elem});</code></pre> | |
<h4><code>cel⇥</code> createElement</h4> | |
<pre><code>${1:document}.createElement(${2:elem});</code></pre> | |
<h4><code>heac⇥</code> appendChild</h4> | |
<pre><code>${1:document}.appendChild(${2:elem});</code></pre> | |
<h4><code>herc⇥</code> removeChild</h4> | |
<pre><code>${1:document}.removeChild(${2:elem});</code></pre> | |
<h4><code>hecla⇥</code> classList.add</h4> | |
<pre><code>${1:document}.classList.add('${2:class}');</code></pre> | |
<h4><code>hect⇥</code> classList.toggle</h4> | |
<pre><code>${1:document}.classList.toggle('${2:class}');</code></pre> | |
<h4><code>heclr⇥</code> classList.remove</h4> | |
<pre><code>${1:document}.classList.remove('${2:class}');</code></pre> | |
<h4><code>hega⇥</code> getAttribute</h4> | |
<pre><code>${1:document}.getAttribute('${2:attr}');</code></pre> | |
<h4><code>hesa⇥</code> setAttribute</h4> | |
<pre><code>${1:document}.setAttribute('${2:attr}', ${3:value});</code></pre> | |
<h4><code>hera⇥</code> removeAttribute</h4> | |
<pre><code>${1:document}.removeAttribute('${2:attr}');</code></pre> | |
<h3>Node.js</h3> | |
<h4><code>cb⇥</code> Node.js style callback</h4> | |
<pre><code>function (err, ${1:value}) { | |
if (err) throw err | |
t${0} | |
}</code></pre> | |
<h4><code>rq⇥</code> require a module</h4> | |
<pre><code>require('${1:module}')</code></pre> | |
<h4><code>cr⇥</code> require and assign a module</h4> | |
<pre><code>const ${1:module} = require('${1:module}')</code></pre> | |
<h4><code>em⇥</code> export member</h4> | |
<pre><code>exports.${1:name} = ${2:value}</code></pre> | |
<h4><code>me⇥</code> module.exports</h4> | |
<pre><code>module.exports = ${1:name}</code></pre> | |
<h4><code>on⇥</code> attach an event handler</h4> | |
<pre><code>${1:emitter}.on('${2:event}', (${3:arguments}) => { | |
${0} | |
})</code></pre> | |
<h3>Miscellaneous</h3> | |
<h4><code>uss⇥</code> use strict</h4> | |
<pre><code>'use strict'</code></pre> | |
<h4><code>js⇥</code> JSON Stringify</h4> | |
<pre><code>JSON.stringify($0)</code></pre> | |
<h4><code>jp⇥</code> JSON Parse</h4> | |
<pre><code>JSON.parse($0)</code></pre> | |
<h4><code>a⇥</code> await</h4> | |
<pre><code>await ${0}</code></pre> | |
<h4><code>apa⇥</code> Promise.all</h4> | |
<pre><code>await Promise.all(${1:value})</code></pre> | |
<h4><code>apm⇥</code> Promise.all map</h4> | |
<pre><code>await Promise.all(${1:array}.map((async ${2:value}) => {\n\t${0}\n}))</code></pre> | |
<h4><code>ast⇥</code> Promise sleep</h4> | |
<pre><code>await new Promise((r) => setTimeout(r, ${0}))</code></pre> | |
<h3>Console</h3> | |
<h4><code>cl⇥</code> console.log</h4> | |
<pre><code>console.log(${0})</code></pre> | |
<h4><code>cv⇥</code> console.log</h4> | |
<pre><code>console.log('${0}:', ${0})</code></pre> | |
<h4><code>ce⇥</code> console.error</h4> | |
<pre><code>console.error(${0})</code></pre> | |
<h4><code>cw⇥</code> console.warn</h4> | |
<pre><code>console.warn(${0})</code></pre> | |
<h4><code>cod⇥</code> console.dir</h4> | |
<pre><code>console.dir(${0})</code></pre> | |
<hr /> | |
<h3>React snippets</h3> | |
<p>Are only enabled in <code>jsx</code> or <code>tsx</code> files. If you write your jsx in <code>js</code> files, you need to copy the <code>react.json</code> files manually and add it to your custom snippets.</p> | |
<h3>Why do we include them here?</h3> | |
<p>If you’re not writing react, including them should not really bother you because they are not short as the regular JS snippets. Also IMHO react is the leading solution for FE apps deserves to be included by default, because any JS dev will have to write some react eventually over the course of his/her careeer. By having them in a single package we can easily make sure -there aren’t any conflicts in the trigger prefixes.</p> | |
<h3>Supported languages (file extensions)</h3> | |
<ul> | |
<li>JavaScript (.js)</li> | |
<li>TypeScript (.ts)</li> | |
<li>JavaScript React (.jsx)</li> | |
<li>TypeScript React (.tsx)</li> | |
</ul> | |
<p>These were originally taken from <a href="https://github.com/TimonVS/vscode-react-standard" target="_blank" rel="noopener">https://github.com/TimonVS/vscode-react-standard</a> because the maintainer wasn’t able to publish a new version for months even when there was a considerable flaw in the released version. Below is a list of all available snippets and the triggers of each one.</p> | |
<p>TriggerContent<code>j</code>jsx element<code>dp</code>destructuring of props<code>ds</code>destructuring of props<code>jc</code>jsx self-closed element<code>jmjsx elements mapjmrjsx elements map with returnrfc</code>functional component. Prefer for 99% of new react component<code>rfce</code>functional component with emotion css import<code>rcc</code>class component skeleton<code>rccp</code>class component skeleton with prop types after the class<code>rcjc</code>class component skeleton without import and default export lines<code>rcfc</code>class component skeleton that contains all the lifecycle methods<code>rfcp</code>stateless component with prop types skeleton<code>rpt</code>empty propTypes declaration<code>con</code>class default constructor with props<code>conc</code>class default constructor with props and context<code>est</code>empty state object<code>cwmcomponentWillMount methodcdmcomponentDidMount methodcwrcomponentWillReceiveProps methodcgdcomponentGetDerivedStateFromProps methodscushouldComponentUpdate methodcwupcomponentWillUpdate methodcdupcomponentDidUpdate methodcwuncomponentWillUnmount methodrenrender methodsstthis.setState with object as parameterssfthis.setState with function as parametertpthis.propststhis.stateususeStateueuseEffectuecuseEffect</code> with a cleanup function<code>uruseRefcccreateContextucuseContextumeuseMemo</code>——-—————————————————————-<code>uquseQuery</code> to be used with graphql-codegen<code>uqcuseQuery</code> that loads up data for current component, to be used with graphql-codegen<code>umuseMutation</code> to be used with graphql-codegen<code>uqguseQuery with raw gqlumguseMutation with raw gql</code></p> | |
<p>There are also snippets to be triggered with a text selection(trigger via insert snippet command):</p> | |
<pre><code>jsx element wrap selection</code></pre> | |
<p>The following table lists all the snippets that can be used for prop types. Every snippet regarding prop types begins with <code>pt</code> so it’s easy to group it all together and explore all the available options. On top of that each prop type snippets has one equivalent when we need to declare that this property is also required. For example <code>pta</code> creates the <code>PropTypes.array</code> and <code>ptar</code> creates the <code>PropTypes.array.isRequired</code></p> | |
<p>TriggerContent<code>ptaPropTypes.array,ptarPropTypes.array.isRequired,ptbPropTypes.bool,ptbrPropTypes.bool.isRequired,ptfPropTypes.func,ptfrPropTypes.func.isRequired,ptnPropTypes.number,ptnrPropTypes.number.isRequired,ptoPropTypes.object.,ptorPropTypes.object.isRequired,ptsPropTypes.string,ptsrPropTypes.string.isRequired,ptndPropTypes.node,ptndrPropTypes.node.isRequired,ptelPropTypes.element,ptelrPropTypes.element.isRequired,ptiPropTypes.instanceOf(ClassName),ptirPropTypes.instanceOf(ClassName).isRequired,ptePropTypes.oneOf(['News', 'Photos']),pterPropTypes.oneOf(['News', 'Photos']).isRequired,ptetPropTypes.oneOfType([PropTypes.string, PropTypes.number]),ptetrPropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,ptaoPropTypes.arrayOf(PropTypes.number),ptaorPropTypes.arrayOf(PropTypes.number).isRequired,ptooPropTypes.objectOf(PropTypes.number),ptoorPropTypes.objectOf(PropTypes.number).isRequired,ptshPropTypes.shape({color: PropTypes.string, fontSize: PropTypes.number}),ptshrPropTypes.shape({color: PropTypes.string, fontSize: PropTypes.number}).isRequired,</code></p> | |
<figure><img src="https://webdevhubcom.files.wordpress.com/2021/04/c389e-08xivi5tevdat7lmo.gif" data-width="781" data-height="22" /></figure> | |
<hr /> | |
<h3>C/C++ for Visual Studio Code</h3> | |
<h4><a href="https://github.com/microsoft/vscode-cpptools" target="_blank" rel="noopener">Repository</a> | <a href="https://github.com/microsoft/vscode-cpptools/issues" target="_blank" rel="noopener">Issues</a> | <a href="https://code.visualstudio.com/docs/languages/cpp" target="_blank" rel="noopener">Documentation</a> | <a href="https://github.com/microsoft/vscode-cpptools/tree/master/Code%20Samples" target="_blank" rel="noopener">Code Samples</a> | <a href="https://github.com/microsoft/vscode-cpptools/releases" target="_blank" rel="noopener">Offline Installers</a></h4> | |
<p>The C/C++ extension adds language support for C/C++ to Visual Studio Code, including features such as IntelliSense and debugging.</p> | |
<h3>Overview and tutorials</h3> | |
<ul> | |
<li><a href="https://code.visualstudio.com/docs/languages/cpp" target="_blank" rel="noopener">C/C++ extension overview</a></li> | |
</ul> | |
<p>C/C++ extension tutorials per compiler and platform * <a href="https://code.visualstudio.com/docs/cpp/config-msvc" target="_blank" rel="noopener">Microsoft C++ compiler (MSVC) on Windows</a> * <a href="https://code.visualstudio.com/docs/cpp/config-mingw" target="_blank" rel="noopener">GCC and Mingw-w64 on Windows</a> * <a href="https://code.visualstudio.com/docs/cpp/config-wsl" target="_blank" rel="noopener">GCC on Windows Subsystem for Linux (WSL)</a> * <a href="https://code.visualstudio.com/docs/cpp/config-linux" target="_blank" rel="noopener">GCC on Linux</a> * <a href="https://code.visualstudio.com/docs/cpp/config-clang-mac" target="_blank" rel="noopener">Clang on macOS</a></p> | |
<h3>Quick links</h3> | |
<ul> | |
<li><a href="https://code.visualstudio.com/docs/cpp/cpp-ide" target="_blank" rel="noopener">Editing features (IntelliSense)</a></li> | |
<li><a href="https://code.visualstudio.com/docs/cpp/customize-default-settings-cpp" target="_blank" rel="noopener">IntelliSense configuration</a></li> | |
<li><a href="https://code.visualstudio.com/docs/cpp/colorization-cpp" target="_blank" rel="noopener">Enhanced colorization</a></li> | |
<li><a href="https://code.visualstudio.com/docs/cpp/cpp-debug" target="_blank" rel="noopener">Debugging</a></li> | |
<li><a href="https://code.visualstudio.com/docs/cpp/launch-json-reference" target="_blank" rel="noopener">Debug configuration</a></li> | |
<li><a href="https://code.visualstudio.com/docs/cpp/enable-logging-cpp" target="_blank" rel="noopener">Enable logging for IntelliSense or debugging</a></li> | |
</ul> | |
<h3>Questions and feedback</h3> | |
<p><a href="https://code.visualstudio.com/docs/cpp/faq-cpp" target="_blank" rel="noopener"><strong>FAQs</strong></a><br /> | |
Check out the FAQs before filing a question.</p> | |
<p><a href="https://github.com/microsoft/vscode-cpptools/issues/new/choose" target="_blank" rel="noopener"><strong>Provide feedback</strong></a><br /> | |
File questions, issues, or feature requests for the extension.</p> | |
<p><a href="https://github.com/Microsoft/vscode-cpptools/issues" target="_blank" rel="noopener"><strong>Known issues</strong></a><br /> | |
If someone has already filed an issue that encompasses your feedback, please leave a 👍 or 👎 reaction on the issue to upvote or downvote it to help us prioritize the issue.</p> | |
<p><a href="https://www.research.net/r/VBVV6C6" target="_blank" rel="noopener"><strong>Quick survey</strong></a><br /> | |
Let us know what you think of the extension by taking the quick survey.</p> | |
<h3>Offline installation</h3> | |
<p>The extension has platform-specific binary dependencies, therefore installation via the Marketplace requires an Internet connection in order to download additional dependencies. If you are working on a computer that does not have access to the Internet or is behind a strict firewall, you may need to use our platform-specific packages and install them by running VS Code’s <code>"Install from VSIX..."</code> command. These “offline’ packages are available at: <a href="https://github.com/Microsoft/vscode-cpptools/releases." target="_blank" rel="noopener">https://github.com/Microsoft/vscode-cpptools/releases.</a></p> | |
<p>PackagePlatform<code>cpptools-linux.vsix</code>Linux 64-bit<code>cpptools-linux-armhf.vsix</code>Linux ARM 32-bit<code>cpptools-linux-aarch64.vsix</code>Linux ARM 64-bit<code>cpptools-osx.vsix</code>macOS<code>cpptools-win32.vsix</code>Windows 64-bit & 32-bit<code>cpptools-win-arm64.vsix</code>Windows ARM64<code>cpptools-linux32.vsix</code>Linux 32-bit (<a href="https://github.com/microsoft/vscode-cpptools/issues/5346" target="_blank" rel="noopener">available up to version 0.27.0</a>)</p> | |
<h3>Contribution</h3> | |
<p>Contributions are always welcome. Please see our <a href="https://github.com/Microsoft/vscode-cpptools/blob/master/CONTRIBUTING.md" target="_blank" rel="noopener">contributing guide</a> for more details.</p> | |
<h3>Microsoft Open Source Code of Conduct</h3> | |
<p>This project has adopted the <a href="https://opensource.microsoft.com/codeofconduct/" target="_blank" rel="noopener">Microsoft Open Source Code of Conduct</a>. For more information see the <a href="https://opensource.microsoft.com/codeofconduct/faq/" target="_blank" rel="noopener">Code of Conduct FAQ</a> or contact opencode@microsoft.com with any additional questions or comments.</p> | |
<h3>Data and telemetry</h3> | |
<p>This extension collects usage data and sends it to Microsoft to help improve our products and services. Collection of telemetry is controlled via the same setting provided by Visual Studio Code: <code>"telemetry.enableTelemetry"</code>. Read our <a href="https://privacy.microsoft.com/en-us/privacystatement" target="_blank" rel="noopener">privacy statement</a> to learn more.</p> | |
<figure><img src="https://webdevhubcom.files.wordpress.com/2021/04/3100b-0kt-50guahwymrk3d.gif" data-width="781" data-height="22" /></figure> | |
<hr /> | |
<p>NEXT</p> | |
<hr /> | |
<h3>Visual Studio IntelliCode</h3> | |
<p>The <a href="https://go.microsoft.com/fwlink/?linkid=872679" target="_blank" rel="noopener">Visual Studio IntelliCode</a> extension provides AI-assisted development features for Python, TypeScript/JavaScript and Java developers in Visual Studio Code, with insights based on understanding your code context combined with machine learning.</p> | |
<p>You’ll need Visual Studio Code October 2018 Release 1.29.1 or later to use this extension. For each supported language, please refer to the “Getting Started” section below to understand any other pre-requisites you’ll need to install and configure to get IntelliCode completions.</p> | |
<p>For C#, C++, TypeScript/JavaScript, and XAML support in the Visual Studio IDE, check out the <a href="https://marketplace.visualstudio.com/items?itemName=VisualStudioExptTeam.VSIntelliCode" target="_blank" rel="noopener">IntelliCode extension on the Visual Studio Marketplace</a>.</p> | |
<h3>About IntelliCode</h3> | |
<p>This extension provides AI-assisted IntelliSense by showing recommended completion items for your code context at the top of the completions list. The example below shows this in action for Python code.</p> | |
<figure><img src="https://cdn-images-1.medium.com/max/800/0*CQQaJIXL4J2cvEzF" data-width="1180" data-height="524" /></figure> | |
<p>When it comes to overloads, rather than taking the time to cycle through the alphabetical list of member, IntelliCode presents the most relevant one first. In the example shown above, you can see that the predicted APIs that <strong>IntelliCode</strong> elevates appear in a new section of the list at the top with members prefixed by a star icon. Similarly, a member’s signature or overloads shown in the IntelliSense tool-tip will have additional text marked by a small star icon and wording to explain the recommended status. This visual experience for members in the list and the tool-tip that <strong>IntelliCode</strong> provides is not intended as final — it is intended to provide you with a visual differentiation for feedback purposes only.</p> | |
<p>Contextual recommendations are based on practices developed in thousands of high quality, open-source projects on GitHub each with high star ratings. This means you get context-aware code completions, tool-tips, and signature help rather than alphabetical or most-recently-used lists. By predicting the most likely member in the list based on your coding context, AI-assisted IntelliSense stops you having to hunt through the list yourself.</p> | |
<h3>Getting Started</h3> | |
<p>Install the Visual Studio IntelliCode extension by clicking the install link on this page, or install from the Extensions tab in Visual Studio Code. Then follow the language-specific instructions below.</p> | |
<h3>For TypeScript/JavaScript users:</h3> | |
<p>That’s it — just open a TypeScript or JavaScript file, and start editing.</p> | |
<h3>For Python users:</h3> | |
<ol> | |
<li>Set up the Python extension by following the steps in the <a href="https://code.visualstudio.com/docs/python/python-tutorial#_prerequisites" target="_blank" rel="noopener">Python tutorial</a></li> | |
<li>Start editing Python files, you should get a prompt to enable the Microsoft Python Language Server, which itself is a preview release.</li> | |
<li>Reload Visual Studio Code after enabling the language server</li> | |
<li>After the language server finishes initializing, you should now see recommended completions</li> | |
</ol> | |
<h3>For Java users:</h3> | |
<ol> | |
<li>Set up the Java extension for Visual Studio Code by following the steps in the <a href="https://code.visualstudio.com/docs/java/java-tutorial" target="_blank" rel="noopener">Java Tutorial</a></li> | |
<li>Make sure that you have a minimum of Java 8 Update 151 installed</li> | |
<li>Reload Visual Studio Code after enabling the Java extension</li> | |
<li>After the Java language server finishes initializing, you should now see recommended completions</li> | |
</ol> | |
<h4>If you found this guide helpful feel free to checkout my github/gists where I host similar content:</h4> | |
<p><a href="https://gist.github.com/bgoonz" target="_blank" rel="noopener">bgoonz’s gists · GitHub</a></p> | |
</div><!-- .entry-content --> | |
<footer class="entry-footer responsive-max-width"> | |
<span class="byline"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><span class="screen-reader-text">Posted by</span><span class="author vcard"><a class="url fn n" href="https://web-dev-hub.com/author/gunerb1/">bgoonz</a></span></span><span class="posted-on"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><defs><path id="a" d="M0 0h24v24H0V0z"></path></defs><clipPath id="b"><use xlink:href="#a" overflow="visible"></use></clipPath><path clip-path="url(#b)" d="M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10 10-4.5 10-10S17.5 2 12 2zm4.2 14.2L11 13V7h1.5v5.2l4.5 2.7-.8 1.3z"></path></svg><a href="https://web-dev-hub.com/2021/04/12/vscode-extension-readme-compilation/" rel="bookmark"><time class="entry-date published" datetime="2021-04-12T16:30:46-04:00">April 12, 2021</time><time class="updated" datetime="2021-07-05T03:08:06-04:00">July 5, 2021</time></a></span><span class="cat-links"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M10 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2h-8l-2-2z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><span class="screen-reader-text">Posted in</span><a href="https://web-dev-hub.com/category/uncategorized/" rel="category tag">Uncategorized</a></span><span class="tags-links"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M21.41 11.58l-9-9C12.05 2.22 11.55 2 11 2H4c-1.1 0-2 .9-2 2v7c0 .55.22 1.05.59 1.42l9 9c.36.36.86.58 1.41.58.55 0 1.05-.22 1.41-.59l7-7c.37-.36.59-.86.59-1.41 0-.55-.23-1.06-.59-1.42zM5.5 7C4.67 7 4 6.33 4 5.5S4.67 4 5.5 4 7 4.67 7 5.5 6.33 7 5.5 7z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><span class="screen-reader-text">Tags:</span><a href="https://web-dev-hub.com/tag/javascript/" rel="tag">Javascript</a>, <a href="https://web-dev-hub.com/tag/web-development/" rel="tag">Web Development</a></span><span class="comments-link"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M21.99 4c0-1.1-.89-2-1.99-2H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h14l4 4-.01-18z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><a href="https://web-dev-hub.com/2021/04/12/vscode-extension-readme-compilation/#respond">Leave a comment<span class="screen-reader-text"> on VsCode Extension Readme Compilation</span></a></span><span class="edit-link"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04c.39-.39.39-1.02 0-1.41l-2.34-2.34c-.39-.39-1.02-.39-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><a class="post-edit-link" href="https://wordpress.com/post/web-dev-hub.com/552">Edit <span class="screen-reader-text">VsCode Extension Readme Compilation</span></a></span> </footer><!-- .entry-footer --> | |
</article><!-- #post-${ID} --> | |
<article id="post-579" class="post-579 post type-post status-publish format-standard hentry category-uncategorized tag-computer-science tag-javascript tag-technology tag-tutorial tag-web-development entry"> | |
<header class="entry-header responsive-max-width"> | |
<h2 class="entry-title"><a href="https://web-dev-hub.com/2021/04/05/notes-from-javascript-the-good-parts/" rel="bookmark">Notes from JavaScript the Good Parts</a></h2> </header><!-- .entry-header --> | |
<div class="entry-content"> | |
<h4>A condensed summary of the entire “JavaScript the Good Parts” book</h4> | |
<p>I hope these notes help shed some light and save some time… (this is the most I could condense an entire book)</p> | |
<figure><img src="https://webdevhubcom.files.wordpress.com/2021/04/7cdec-15oamo6qxv9dztouc5oe-uq.png" data-width="726" data-height="419"></figure> | |
<h3>Chapter 1 — Good Parts</h3> | |
<blockquote><p><em>Most programming languages contain good parts and bad parts. I discovered that I could be a better programmer by using only the good parts and avoiding the bad parts. After all, how can you build something good out of bad parts?</em></p></blockquote> | |
<p>The best parts of Javascript include:</p> | |
<ul> | |
<li>functions</li> | |
<li>loose typing (variables are declared as variables, without a type)</li> | |
<li>dynamic objects</li> | |
<li>object literal notation (where you can create an object already with a list of key/value pairs inside curly braces)</li> | |
</ul> | |
<p>The worst parts include global variables — there is a common <em>global object</em> namespace where they’re all lumped together and they’re essential to the language.</p> | |
<p>Javascript has a <em>class free</em> object makeup, relying instead on objects inheriting properties directly from other objects — this is prototypal inheritance.</p> | |
<h3>Chapter 2 — Grammar</h3> | |
<p>Always use // for comments, even multi-line ones to avoid having to escape <code>/*</code> characters.</p> | |
<h3>Numbers</h3> | |
<ul> | |
<li>There is a single, 64-bit floating point number type.</li> | |
<li><code>NaN</code> (Not-a-Number) is not equal to any value (including itself) and is essentially an illegal number value, but <em>typeOf(NaN)===number is true</em></li> | |
<li>Use <code>isNaN(number)</code> to check for NaNs</li> | |
</ul> | |
<p>Number methods are discussed in <a href="https://github.com/Lambda-April/Unsorted-Notes/blob/main" target="_blank">Chapter 8</a>.</p> | |
<h3>Strings</h3> | |
<ul> | |
<li>16-bit character set and don’t have character types.</li> | |
<li>Backslashes (\) are used for escaping characters that could cause problems in strings.</li> | |
<li>Strings are immutable.</li> | |
</ul> | |
<p>Single quotes are often used to define a String in JavaScript, but if a person’s name has an apostrophe (and the developer does not know the difference between an apostrophe and single quote) it is useful to “escape” the apostrophe character:</p> | |
<pre>var name = 'Patrick O\'Brian'; // using a backslash in front of the apostrophe | |
console.log('name:', name); // name: Patrick O'Brian</pre> | |
<p>further reading: <a href="https://webdesignledger.com/common-typography-mistakes-apostrophes-versus-quotation-marks" target="_blank">https://webdesignledger.com/common-typography-mistakes-apostrophes-versus-quotation-marks</a></p> | |
<figure><img src="https://webdevhubcom.files.wordpress.com/2021/04/f1e58-0flaxqcb0qgspdam_.png" data-width="470" data-height="462"></figure> | |
<p>String methods are discussed in <a href="https://github.com/Lambda-April/Unsorted-Notes/blob/main" target="_blank">Chapter 8</a>.</p> | |
<h3>Statements</h3> | |
<ul> | |
<li><em>Inside</em> a function, the var statement creates variables local to that function</li> | |
<li><em>switch, while, for</em> and <em>do</em> statements can have an optional label which can be used with <code>break</code> and <code>continue</code> to provide more precise <a href="http://www.tutorialspoint.com/cgi-bin/practice.cgi?file=javascript_19" target="_blank">control over exactly which statement to break or continue</a>. Format: <code>labelname: statement</code> and then <code>continue labelname;</code></li> | |
<li>ES2015 presents two new keywords for declaring variables, <em>let</em> and <em>const</em>. Whereas the <em>var</em> keyword is function scoped (the variables are local to the function), <em>let</em> and <em>const</em> are both block scoped, which means they are local to any statement with {}.</li> | |
<li><em>falsy</em> values:</li> | |
<li>false</li> | |
<li>null</li> | |
<li>undefined</li> | |
<li>Empty string ‘ ‘</li> | |
<li>The number 0</li> | |
<li>The number NaN</li> | |
<li>All other values are <em>truthy</em> including all objects & the string ‘false’</li> | |
<li>If no matches are found in <code>case</code> statements, the optional default statement is executed, otherwise the matching case statement is carried out</li> | |
<li>When using a <em>for in</em> loop, usually a good idea to use <code>hasOwnProperty(variable)</code> to make sure the property belongs to the object you want and is not instead an inherited property from the prototype chain:</li> | |
</ul> | |
<pre>for (myvariable in object) { | |
if (object.hasOwnProperty(myvariable)) { | |
//....statements to be executed | |
} | |
}</pre> | |
<ul> | |
<li>A <em>do while</em> statement is always executed at least once as the while condition is only checked after the first iteration of the loop</li> | |
<li><code>catch</code> clause in a <em>try</em> statement must create a new variable that will catch the exception object</li> | |
<li>Scope of <code>throw</code> statement is the <code>try</code> block it’s in, or the <code>try</code> of the function it’s in</li> | |
<li>If there is no <code>return</code> statement, <code>return===undefined</code></li> | |
<li><code>break</code> exits the statement and <code>continue</code> forces a new iteration of the loop, both with the optional <em>label</em> mentioned above</li> | |
</ul> | |
<h3>Expressions</h3> | |
<ul> | |
<li>For <code>expression ? expression2 : expression3</code>, if expression is <em>truthy</em>, execute expresion2; if it’s <em>falsy</em>, execute expression3</li> | |
<li><em>Invocation</em> is <code>(expression1, expression2, etc)</code></li> | |
<li><em>refinement</em> is either <code>.name</code> or <code>[expression]</code> as used in an array</li> | |
</ul> | |
<h3>Literals</h3> | |
<ul> | |
<li><em>Names</em> or <em>strings</em> used for specifying new objects (<a href="https://github.com/Lambda-April/Unsorted-Notes/blob/main" target="_blank">object literals</a>) or arrays (<a href="https://github.com/Lambda-April/Unsorted-Notes/blob/main" target="_blank">array literals</a>)</li> | |
<li>Properties of the object are expressions and must be known at compile time</li> | |
</ul> | |
<h3>Functions</h3> | |
<ul> | |
<li>A function literal defines a function value</li> | |
<li>More details in <a href="https://github.com/Lambda-April/Unsorted-Notes/blob/main" target="_blank">Chapter 4</a></li> | |
</ul> | |
<h3>Chapter 3 — Objects</h3> | |
<p>Javascript simple types:</p> | |
<ul> | |
<li>numbers <em>(has object-like methods but they are immutable)</em></li> | |
<li>strings <em>(has object-like methods but they are immutable)</em></li> | |
<li>booleans <em>(has object-like methods but they are immutable)</em></li> | |
<li>null</li> | |
<li>undefined</li> | |
</ul> | |
<p>All other values are <em>objects</em> including arrays and functions.</p> | |
<p>Objects are class free, can contain other objects and can inherit properties from their prototypes (which can <em>reduce object initialisation time and memory consumption</em>).</p> | |
<h3>Object Literals</h3> | |
<ul> | |
<li>An object literal is <em>zero or more comma-separated name/value pairs surrounded by curly braces</em> {}</li> | |
</ul> | |
<pre>var empty_object = {};</pre> | |
<pre>var today = { | |
day: "Wednesday", | |
month: "April", | |
year: 2014,</pre> | |
<pre> weather: { //objects can contain nested objects like this one | |
morning: "sunny", | |
afternoon: "cloudy" | |
} | |
}</pre> | |
<h3>Retrieval</h3> | |
<ul> | |
<li>Can be done with either dot notation <code>today.weather.morning</code> or with square brackets <code>today['month']</code></li> | |
<li>Or operand (||) can be used to fill in default values for nonexistent data to prevent and <em>undefined</em> error: <code>var weath = today.weather.evening || "unknown"</code></li> | |
</ul> | |
<h3>Update</h3> | |
<ul> | |
<li>Assigning a property value to an object overwrites any existing property values with that property name</li> | |
</ul> | |
<h3>Reference</h3> | |
<ul> | |
<li>Objects refer to each other, they don’t hold duplicate copies of data</li> | |
</ul> | |
<h3>Prototype</h3> | |
<ul> | |
<li>Every object has a prototype object from which it inherits properties</li> | |
<li><em>Object.prototype</em> comes standard with Javascript and is almost like a ‘root parent’</li> | |
</ul> | |
<figure><img src="https://cdn-images-1.medium.com/max/800/0*1MKtZt0a5gREie59" data-width="960" data-height="207"></figure> | |
<ul> | |
<li>The <code>Object.create</code> method is now available in ES5 (but the method is in the book if required for older versions)</li> | |
<li>If an object does not have a property you ask it for, it will keep looking up the prototype chain until it finds it</li> | |
<li>If the property <em>does note exist</em> anywhere in the chain, it will return <em>undefined</em></li> | |
<li>A new property is <em>immediately visible</em> to all of the objects below it in the chain once created</li> | |
</ul> | |
<p>More details in <a href="https://github.com/Lambda-April/Unsorted-Notes/blob/main" target="_blank">Chapter 6</a></p> | |
<h3>Reflection</h3> | |
<ul> | |
<li>Determining what properties an object has</li> | |
<li>Using <code>typeof</code> includes all properties in the prototype chain including functions</li> | |
<li>To avoid inherited properties, use <code>hasOwnProperty(type);</code> which returns <em>true</em> if that property exists only in that object itself (not the chain)</li> | |
</ul> | |
<pre>today.hasOwnProperty(‘number’) //will return true today.hasOwnProperty(‘constructor’) //will return false</pre> | |
<h3>Enumeration</h3> | |
<ul> | |
<li>Best way to enumerate all the properties you want is a for loop:</li> | |
</ul> | |
<pre>let i; | |
var properties = [ ‘day’, ‘month’, ‘year’ ]; | |
for (i = 0; i < properties.length; i++) { | |
document.writeIn(properties[i] + ‘:’ + today[properties[i]]); | |
}</pre> | |
<ul> | |
<li>This ensures you get the properties you want (i.e. not up the prototype chain) and in the order you want, as opposed to a <em>for in</em> loop which achieves neither of these</li> | |
</ul> | |
<h3>Delete</h3> | |
<ul> | |
<li>Removes property from object, but also reveals property from further up the prototype chain if it exists</li> | |
<li>Format: <code>delete today.month</code></li> | |
</ul> | |
<h3>Global Abatement</h3> | |
<ul> | |
<li>One way to mitigate the risks of global variables is to <em>create a single global variable</em> which then contains your whole application</li> | |
</ul> | |
<pre>let MYAPP = {}</pre> | |
<pre>MYAPP.today = { | |
day: "Wednesday", | |
month: "April", | |
year: 2014,</pre> | |
<pre> weather: { //objects can contain nested objects like this one | |
morning: "sunny", | |
afternoon: "cloudy" | |
} | |
} | |
//Making sure all other variables (like today) are contained within this one global variable (MYAPP) means none of them have global scope and therefore the risk of naming conflicts, etc in your application is reduced</pre> | |
<ul> | |
<li><a href="https://github.com/Lambda-April/Unsorted-Notes/blob/main" target="_blank">Closures</a> are also a way of mitigating the risks of global variables</li> | |
<li>Note: Most <a href="http://coding.smashingmagazine.com/2012/07/27/journey-through-the-javascript-mvc-jungle/" target="_blank">Javascript MVCs</a> these days (2014) will take care of wrapping your app for you</li> | |
</ul> | |
<h3>Chapter 4 — Functions</h3> | |
<blockquote><p><em>The best thing about JavaScript is its implementation of functions.</em></p></blockquote> | |
<h3>Function Objects</h3> | |
<ul> | |
<li>Functions are objects linked to <em>function.prototype</em> (which is linked to <em>Object.prototype</em>).</li> | |
<li>As well as usual object behaviour, they can be invoked.</li> | |
</ul> | |
<h3>Function Literal</h3> | |
<ul> | |
<li>A function literal has 4 parts:</li> | |
<li>The (reserved) word <code>function</code> itself</li> | |
<li>An <em>optional</em> name (un-named functions are considered <em>anonymous</em> functions)</li> | |
<li>Comma-seperated parameters of the function, in parentheses —<code>(parameters)</code></li> | |
<li>Set of statements in curly brackets to be carried out when the function is invoked —<code>{statements}</code></li> | |
</ul> | |
<pre>//Format of a function | |
function name (parameterA, parameterB){ | |
statements; | |
}</pre> | |
<ul> | |
<li>Functions can be nested within functions and the inner function can access all the parameters of the outer function as well as its own</li> | |
</ul> | |
<h3>Invocation</h3> | |
<ul> | |
<li>Stops the current function from running and tells the function you have invoked both to start and to use the arguments (values in parentheses) you have passed it in the invocation <code>function (parameters)</code></li> | |
<li>If arguments > number of arguments expected, the extra values will be ignored</li> | |
<li>If arguments < number of arguments expected, the function will assume undefined in place of the missing arguments</li> | |
<li>No error is thrown</li> | |
<li>Note: The difference between an <em>argument</em> and a <em>parameter</em> is that a parameter is usually what is used in the function literal, when you’re setting up the function (almost like the placeholder for the actual values that the function will use when it is active) and an argument is usually the value passed to a function at the time it is invoked</li> | |
<li>Parameters <code>this</code> and <code>arguments</code> are also passed to the function when it is invoked, but their value depends on how the function is invoked</li> | |
</ul> | |
<h4>Method Invocation Pattern</h4> | |
<ul> | |
<li>When a function is stored as the property of the object (invoked with a dot . expression) it is called on and is called a <em>method</em></li> | |
</ul> | |
<pre>myObject.incrementFunction();</pre> | |
<ul> | |
<li>The method is bound to the object and therefore can use <code>this</code> to retrieve or update values from the object</li> | |
<li>These methods are highly reusable</li> | |
<li>Because their <em>object context</em> comes from <code>this</code> they are considered <em>public methods</em></li> | |
</ul> | |
<h4>Function Invocation Pattern</h4> | |
<ul> | |
<li>When a function is <em>not</em> the property of an object, it is invoked as a <em>function</em></li> | |
</ul> | |
<pre>var sum = add(3, 4);</pre> | |
<ul> | |
<li>These functions are bound to the global object (<em>a “mistake in the design of the language” according to Douglas Crockford)</em> and consequently so is <code>this</code><a href="https://github.com/Lambda-April/Unsorted-Notes/blob/main" target="_blank">even in inner functions</a></li> | |
<li>Invoking <code>this</code> within an inner function will therefore refer to its <em>own</em> <code>this</code> and not the one in global scope</li> | |
</ul> | |
<p>Workaround: Artificially create a new <code>this</code>:</p> | |
<pre>myObject.double = function() { | |
//in the book, the var here is called `that` but name changed for clarity | |
var globalScopeThis = this; //workaround</pre> | |
<pre> var innerFunc = function() { | |
globalScopeThis.value = add(globalScopeThis.value, globalScopeThis.value); | |
};</pre> | |
<pre> innerFunc(); //invoke innerFunc as function | |
};</pre> | |
<pre>myObject.double(); | |
console.log(myObject.value);</pre> | |
<h4>Constructor Invocation Pattern</h4> | |
<ul> | |
<li>When a function is created with <code>new</code>, that function contains a link to the function’s prototype</li> | |
<li>This means that methods that were created for the prototype function are also available to the function created using <code>new</code></li> | |
</ul> | |
<pre>//create a function Quo that takes a string - Quo will be our prototype function as we will see | |
var Quo = function (string){ | |
this.status = string; | |
}</pre> | |
<pre>//Now create a get_status method for Quo - this will be a public method | |
Quo.prototype.get_status = function () { | |
return this.status; | |
}</pre> | |
<pre>//create a new instance of Quo using the prefix NEW | |
var myQuo = new Quo("happy");</pre> | |
<pre>//because of the use of the new prefix, myQuo is an instance of Quo which means it can access the public method get_status from it's prototype | |
document.writeIn(myQuo.get_status()); //returns 'happy'</pre> | |
<ul> | |
<li>This style of constructor pattern is not recommended, there will be better examples in <a href="https://github.com/Lambda-April/Unsorted-Notes/blob/main" target="_blank">Chapter 5</a>— this is noted again in <a href="https://github.com/Lambda-April/Unsorted-Notes/blob/main" target="_blank">Appendix B</a></li> | |
<li>The first letter of a constructor function (in this case Quo) must <em>always</em> be capitalized</li> | |
</ul> | |
<h4>Apply Invocation Pattern</h4> | |
<ul> | |
<li>The <code>apply</code> method lets you choose the value to be bound to <code>this</code></li> | |
<li>It also takes the parameters for a function in an array</li> | |
<li>Format: <code>function.apply(valueForThis, arrayOfParamentersForFunction);</code></li> | |
</ul> | |
<pre>var array = [5, 2] //will be the parameters for our function | |
var sum = add.apply(null, array); //value of 'this' is null and value of sum is 7 as the 'apply' method passes 5 and 2 to the 'add' method</pre> | |
<h3>Arguments</h3> | |
<ul> | |
<li>Another default parameter of functions is the <code>arguments</code> array which contains all the arguments that were supplied when the function was invoked</li> | |
<li>This means you don’t have to know the exact number of arguments when you build a function because you can loop through all the arguments provided at invocation with the use of the default <code>arguments</code> array</li> | |
</ul> | |
<pre>//inside the function for (i = 0; i < arguments.length; i++) { dosomething; //e.g. sum +=arguments[i] }</pre> | |
<ul> | |
<li><code>arguments</code> lacks all the array methods except .length because of a bug</li> | |
</ul> | |
<h3>Return</h3> | |
<ul> | |
<li>When a function gets to a <code>return</code> statement, it returns immediately without carrying out the remaining statements in the function</li> | |
<li>A function always returns a <code>value</code> or if unspecified, it returns <code>undefined</code></li> | |
<li>“If the function was invoked with the <code>new</code> prefix (used when creating a new object so it must return an object) and the <code>return</code> value is not an object, then <code>this</code> (the new object) is returned instead.”</li> | |
</ul> | |
<h3>Exceptions</h3> | |
<ul> | |
<li>A <code>throw</code> statement interrupts the execution of the code is used to handle expected exceptions like an incorrect type of argument (e.g. a string where a number is expected)</li> | |
<li>Each <code>throw</code> statement should have an exception object with a <code>name</code> holding the type of exception and a <code>message</code> with an explanation of it + any other properties you like</li> | |
</ul> | |
<pre>//Thinking through what exceptions could happen in an add function, the main function contains the throw statement with the exception object | |
let add = function (a,b) { | |
if (typeof a !== ‘number’ || typeof b !== ‘number’){ | |
throw { | |
name: ‘TypeError’; | |
message: ‘The add function requires numbers’; | |
} | |
} | |
return a + b; | |
}</pre> | |
<ul> | |
<li>When you write a function to use <em>add()</em>, you include a <code>try</code> block where the exception object from the <code>throw</code> statement in <em>add()</em> will pass control to a single catch clause for all exceptions</li> | |
</ul> | |
<pre>//When you use the function later on, add a try block with a catch clause to catch the exception object | |
var try_it = function () { | |
try{ | |
add("seven"); //will throw an exception as it is not a number | |
} | |
catch (e) { | |
document.writeIn(e.name + ':' + e.message); | |
} | |
}</pre> | |
<pre>try_it(); //you could rewrite this function so the argument is passed in here where it is invoked</pre> | |
<h3>Augmenting Types</h3> | |
<ul> | |
<li>Adding a method to the prototype of an object <code>Object.prototype</code> (or function, array, string, number, regular expression or boolean), you make it available to all the instances of that object so you don’t have to use the <code>prototype</code> property again</li> | |
<li>By augmenting the <em>basic types</em> (essentially the root prototypes), we can improve Javascript overall</li> | |
<li>For example, adding a method named <em>trim</em> to remove spaces from the end of strings, available to all String instances in your code:</li> | |
</ul> | |
<pre>String.method (‘trim’, function () { return this.replace(/ˆ\s+|\s+$/g, ‘’); //uses regular expression });</pre> | |
<ul> | |
<li>To be on the safe side, create a method conditionally, only when you know the method is missing</li> | |
</ul> | |
<pre>//Makes a method available to all functions, ONLY when it definitely does not already exist</pre> | |
<pre>Function.prototype.method (methodName, func) { | |
if (!this.prototype[methodName]){ | |
this.prototype[methodName] = func; | |
return this; | |
} | |
};</pre> | |
<ul> | |
<li>Remember that <em>for in</em> statements don’t work well with prototypes</li> | |
</ul> | |
<h3>Recursion</h3> | |
<ul> | |
<li>Used when a task can be divided into simple sub-problems and a function can <em>call itself repeatedly</em> to solve them</li> | |
<li>Takes the format:</li> | |
</ul> | |
<pre>var variable = function functionName (parameters){ | |
//wrap the statements to be executed and the recursive call in a loop statement so it doesn't recurse forever | |
//statements to be executed in the function; | |
functionName(arguments); | |
};</pre> | |
<pre>functionName (initialArguments); //initial call to the function</pre> | |
<ul> | |
<li>Javascript does not have <em>tail recursion optimization</em> and therefore does not optimize recursive functions — this also means they sometimes fail if they “recurse very deeply”; On a side note, <em>tail call optimization</em> is now supported in <a href="https://www.ecma-international.org/ecma-262/7.0/index.html#sec-tail-position-calls" target="_blank">ECMA-262</a></li> | |
</ul> | |
<h3>Scope</h3> | |
<ul> | |
<li>A <em>block</em> is a set of statements contained in curly brackets {}</li> | |
<li>Javascript does not have block scope but does have function scope</li> | |
<li>All variables declared <em>anywhere</em> within a function are available everywhere in that function — i.e. and inner function will have access to the variables of the outer function in which it is defined</li> | |
<li>A variable can be <em>overwritten</em> with a new value in an inner function and that new value’s scope will be just the body of the inner function — as soon as you’re back out to the outer function, the value of that variable will revert to what it was before the inner function began its execution</li> | |
<li>All variable should be declared at the top of the function body</li> | |
</ul> | |
<h3>Closure</h3> | |
<ul> | |
<li>Inner functions have access to the actual parameters of the outer functions (not copies)</li> | |
<li>If an object is created as a result of a function and assigned to myObject, myObject continues to share access to the variables in the functions that created it (actual variables, not copies)</li> | |
<li>It has access to <em>the context in which it was created</em>— this is <em>closure</em></li> | |
<li>This includes later on, even if <em>the outer function has completed its execution and returned</em>, when the inner function is called, it will still have access to all the variables it had access to at the time it was defined (i.e. the variables that were <em>in context</em> when the inner function was defined)</li> | |
</ul> | |
<h3>Callbacks</h3> | |
<ul> | |
<li>A <em>callback function</em> is a function passed to another function as a parameter and executed in this other function</li> | |
<li>When making a request to a server, use an <em>asynchronous request</em> as asynchronous functions return immediately, therefore freeing up the client</li> | |
<li>In this example, we pass the callback function to the asynchronous request as a parameter so the callback function will only be called when a response is available</li> | |
</ul> | |
<pre>request = prepare_the_request(); | |
send_request_asynchronously(request, function(response){ | |
//function being passed in as a parameter | |
display(response); | |
} | |
);</pre> | |
<h3>Module</h3> | |
<ul> | |
<li>A module is a function or object whose contents can be used, but its state and implementation are hidden</li> | |
<li>It is essentially using function scope and closures keep the variables and functions contained within as private as well as binding them to a non-global object — whilst still being accessible</li> | |
<li>Using the <em>module pattern</em> is widely used and good practice as it promotes information hiding (avoiding naming conflicts, etc) and encapsulation</li> | |
<li>This is a <a href="http://css-tricks.com/how-do-you-structure-javascript-the-module-pattern-edition/" target="_blank">good article on how to use the module pattern</a> with examples</li> | |
<li>It can also be used to produce secure objects (see <a href="https://github.com/Lambda-April/Unsorted-Notes/blob/main" target="_blank">durable objects</a> below)</li> | |
<li>Methods contained in the object do not make use of <code>this</code> or <code>that</code> so it becomes impossible to change them from outside of the object except in ways explicitly permitted by the methods (like passing them a parameter)</li> | |
<li>The methods can be <em>replaced</em> but the secrets of how these methods function (like how they generate a number for example) can’t be revealed because they are not tied to a global object</li> | |
</ul> | |
<pre>var Serial_maker = function() { | |
//all variables defined in this object are now fixed and hidden from anything outside this function | |
//see page 42 of book for full example | |
}; | |
//calls to methods passing them parameters are made here</pre> | |
<ul> | |
<li>Note: Whilst Javascript variables are usually lowercase, there is some convention around capitalizing the first letter of a Module</li> | |
</ul> | |
<h3>Cascade</h3> | |
<ul> | |
<li>Some methods return nothing, albeit <code>undefined</code></li> | |
<li>If we alter these methods to return <code>this</code> instead of <code>undefined</code>, they return the object which can then be passed to the next method, e.g <code>getElement(myBox).move(350,150)</code> gets the element and then passes is to the <em>move</em> function for the next action</li> | |
<li>This enables <em>cascades</em>, where you call many methods on the same object in sequence because the object is passed from one method to the next (usually separated by <code>.</code> as above)</li> | |
<li>Cascades also stop you from trying to do too much in one method and makes your code more descriptive</li> | |
</ul> | |
<h3>Curry</h3> | |
<ul> | |
<li>A <code>curry</code> method allows you to <em>partially evaluate</em> an existing function</li> | |
<li>An example is below where the function <em>expects two arguments</em>, but it is first invoked with only one (in this case using <code>curry</code> as in <code>add.curry(10);</code>) and then later passed the second argument</li> | |
<li>It can also be explained as transforming a function that takes multiple arguments (<code>add(a,b)</code>) into a chain of functions that take a single argument each (<code>addA = add(A); addA(B);</code> where the two functions are now <code>add()</code> & <code>addA()</code>)</li> | |
</ul> | |
<pre>//set up a simple function that we will customise with curry | |
var add = function (a,b){ | |
return a + b; | |
}</pre> | |
<pre>var addTen = add.curry(10); //passes 10 as the first argument to the add() function | |
addTen(20); //The use of the curry method in addTen means addTen === add(10, 20);</pre> | |
<ul> | |
<li>Javascript does not have a <code>curry</code> method natively but this can be added to the <code>Function.protoype</code>:</li> | |
</ul> | |
<pre>Function.method('curry', function() { | |
var slice = Array.prototype.slice, | |
args = slice.apply(arguments), | |
that = this; | |
return function() { | |
return that.apply(null, args.concat(slice.apply(arguments))); | |
} | |
});</pre> | |
<h3>Memoization</h3> | |
<ul> | |
<li>Storing the results of previous operations in objects (such as arrays) allows them to be reused without having to keep recalculating the value — this optimization is called <em>memoization</em></li> | |
<li>Adding an object to store the results <em>memoizes the function</em></li> | |
<li>Particularly useful when a function is recursive and uses the results of its previous iteration in the current iteration</li> | |
<li>A <em>memoizer</em> function can be created to help memoize future functions:</li> | |
</ul> | |
<pre>var meoizer = function(memo, fundamental) { | |
var shell = function(n) { | |
var result = memo[n]; | |
if (typeof result !== 'number') { | |
result = fundamental(shell, n); | |
memo[n] = result; | |
} | |
return result; | |
} | |
return shell; | |
}</pre> | |
<h3>Chapter 5 — Inheritance</h3> | |
<blockquote><p><em>Javascript is a prototypal language, which means that objects inherit directly from other objects</em></p></blockquote> | |
<p>Main benefit of inheritance is code reuse — you only have to specify differences.</p> | |
<p>Javascript can <em>mimic</em> classical inheritance but has a much richer set of code reuse patterns</p> | |
<ul> | |
<li>This chapter looks at the more straightforward patterns but it is always best to keep it simple</li> | |
</ul> | |
<h3>Pseudoclassical</h3> | |
<ul> | |
<li>The pseudoclassical code reuse pattern essentially has constructor functions (functions invoked using the <code>new</code> prefix) work like classes to mimic the classical structure</li> | |
<li>All properties are public</li> | |
<li>If you forget to use the <code>new</code> prefix, <code>this</code> is not bound to the new object – it is instead bound to the global object and you’ll be unwittingly altering these instead!</li> | |
<li>There is no need to use it, there are better code reuse patterns in JavaScript</li> | |
</ul> | |
<h3>Object Specifiers</h3> | |
<p>Rather than: <code>var myObject = maker (f, l, m, c, s)</code> which has too many parameters to remember in the right order, use an <em>object specifier</em>:</p> | |
<pre>var myObject = maker ({ //note curly braces | |
first: f, | |
last: l, | |
state: s, | |
city: c | |
} | |
;)</pre> | |
<p>to contain them. They can now be listed in any order</p> | |
<p>Also useful to pass object specifiers to JSON (<a href="https://github.com/Lambda-April/Unsorted-Notes/blob/main" target="_blank">see Appendix E notes</a>)</p> | |
<h3>Prototypal</h3> | |
<ul> | |
<li>Zero classes, one object inherits from another</li> | |
<li>Create an object literal of a useful object and then make an instance of it using the format <code>var myObject = Object.create(originalObjectName)</code></li> | |
<li>When you then customise the new object (adding properties or methods through the dot notation for example), this is <em>differential inheritance</em>, where you specify the differences from the original object</li> | |
</ul> | |
<h3>Functional</h3> | |
<ul> | |
<li>All properties of an object are visible (Javascript has no classes so there is no such thing as a ‘private variable’ which can only be seen within a class as per other languages)</li> | |
<li>When you use a <em>function</em> to create your original object and the same with the object instances, you’re essentially utilising Javascript functional scope to create private properties and methods</li> | |
<li>The below is an example of how you would create an original object, the <code>name</code> and <code>saying</code> properties are now completely private and only accessible to the <code>get_name</code> and <code>says</code> method</li> | |
</ul> | |
<pre>var mammal = function (spec) { | |
var that = {}; //that is a new object which is basically a container of 'secrets' shared to the rest of the inheritance chain</pre> | |
<pre> that.get_name = function () { | |
return spec.name; | |
};</pre> | |
<pre> that.says = function () { | |
return spec.saying || ''; //returns an empty string if no 'saying' argument is passed through the spec object when calling mammal | |
}; | |
return that; //returns the object that contains the now private properties and methods (under functional scope) | |
}</pre> | |
<pre>var myMammal = mammal({name: 'Herb'});</pre> | |
<p>Creating an object ‘cat’ can now inherit from the <code>mammal</code> constructor and only pay attention to the differences between it and <code>mammal</code>:</p> | |
<pre>var cat = function (spec) { | |
spec.saying = spec.saying || 'meow'; //if spec.saying doesn't already exists, make it 'meow' | |
var that = mammal(spec); //here the object 'container of secrets' is set up inheriting from mammal already</pre> | |
<pre> //functions and property augmentations happen here</pre> | |
<pre> return that; //as above | |
}</pre> | |
<ul> | |
<li>Requires less effort and gives better encapsulation and information hiding than the pseudoclassical pattern, as well as access to super methods (see page 54 of book for super method example)</li> | |
<li>An object created using the functional pattern <em>and</em> making no use of <code>this</code> or <code>that</code> is a <em>durable object</em> and cannot be compromised by attackers</li> | |
<li>Briefly also discussed in <a href="https://github.com/Lambda-April/Unsorted-Notes/blob/main" target="_blank">Module</a> section above</li> | |
<li>If you do want something to have access to the object’s private properties and methods, you pass it the <code>that</code> bundle (i.e. your ‘container of secrets’)</li> | |
</ul> | |
<h3>Parts</h3> | |
<ul> | |
<li>An object can be composed out of a set of parts</li> | |
<li>For example, you can create a function that provides the object it is passed with a number of methods (which are defined in this function), where each method is a part that is added to the object</li> | |
</ul> | |
<h3>Chapter 6 — Arrays</h3> | |
<p>Javascript only has array-like objects which are slower than ‘real’ arrays.</p> | |
<p>Retrieval and updating of properties works the same as with an object <em>except with integer property names</em>.</p> | |
<p>Arrays have their own literal format and their own set of methods (<a href="https://github.com/Lambda-April/Unsorted-Notes/blob/main" target="_blank">Chapter 8 — Methods</a>).</p> | |
<h3>Array Literals</h3> | |
<ul> | |
<li>An array literal is a pair of square brackets surrounding zero or more comma-seperated values <code>[a, b, c, etc]</code></li> | |
<li>The first value will get the property name ‘0’, the second will be ‘1’ and so on</li> | |
<li>Javascript allows an array to contain any mixture of values</li> | |
</ul> | |
<h3>Length</h3> | |
<ul> | |
<li>If you add to the array, the <code>length</code> property will increase to contain the new element – it will not give an error</li> | |
<li>If you set the <code>.length</code> to a smaller number than the current length of the array, it will delete any properties with a subscript >= the new <code>length</code></li> | |
<li>The <code>push()</code> method is sometimes useful to add an element to the end of an array</li> | |
<li><code>numbers.push('go') //adds the element 'go' to the end of the numbers array</code></li> | |
</ul> | |
<h3>Delete</h3> | |
<ul> | |
<li>Elements can be deleted from the array object using <code>delete</code> but this leaves a hole in the array</li> | |
<li>Use <code>array.splice(keyInArray, howManyElementsToDelete)</code> which changes the keys for the remaining values in the array so there is no hole left</li> | |
<li>May be <em>slow</em></li> | |
</ul> | |
<h3>Enumeration</h3> | |
<ul> | |
<li>A <code>for</code> statement can be used to iterate over all the properties of an array (as it is an object)</li> | |
<li>Do not use <code>for in</code> as it does not iterate through the properties in order and sometimes pulls in from further up the prototype chain</li> | |
</ul> | |
<h3>Confusion</h3> | |
<blockquote><p><em>The rule is simple: when the property names [keys] are small sequential integers, you should use an array. Otherwise, use an object.</em></p></blockquote> | |
<ul> | |
<li>Arrays are most useful when property names are integers <em>but</em> they can also accept strings as property names</li> | |
<li>Javascript doesn’t have a good way of telling an object from an array as <code>typeof array === object</code></li> | |
<li>To accurately detect arrays, have to define our own function:</li> | |
</ul> | |
<pre>var is_array = function(value) { | |
return Object.prototype.toString.apply(value) === '[object Array]'; | |
//apply(value) binds `value` to `this` & returns true if `this` is an array }</pre> | |
<h3>Methods</h3> | |
<ul> | |
<li>Array methods are stored in <code>Array.prototype</code> which can be augmented using the format:</li> | |
</ul> | |
<pre>//capital A in Array means this refers to the prototype | |
Array.method('reduce', function(parameters) { | |
//define variables and function | |
//return a value | |
});</pre> | |
<ul> | |
<li>Remember, every array inherits and can use the methods you add to <code>Array.prototype</code></li> | |
<li>You can also add methods <em>directly to an array</em> because they are objects</li> | |
<li><code>myArray.total = function () { //statements to execute; }</code> adds a ‘total’ function to the array <code>myArray</code></li> | |
<li>DO NOT USE: <code>Object.create()</code> will create an object – lacking the <code>length</code> property – not an array.</li> | |
</ul> | |
<h3>Dimensions</h3> | |
<ul> | |
<li>Using <code>[]</code> will create an empty array as they are not initialized in JavaScript</li> | |
<li>Accessing a missing element will give you <code>undefined</code></li> | |
<li>If you have an algorithm that relies on the array not being empty and not having <code>undefined</code> values, you can write a function that will prep your array to have a certain number of defined values, essentially initializing it with certain values in place</li> | |
<li>An <code>Array.dim</code> function is outlined on page 63 which will allow <code>var myArray = Array.dim(10,0)</code> to make an array with 10 zeroes starting from the first position in the array(0)</li> | |
<li>Javascript only has one dimensional arrays but <em>can</em> have array of arrays</li> | |
<li>Two dimensional arrays (matrices) will have to be set up by the programmer</li> | |
<li>page 63 gives a method for this and for explicitly setting cell values so as not to have an empty matrix</li> | |
</ul> | |
<h3>Chapter 7 — Regular Expressions</h3> | |
<blockquote><p><em>A </em>regular expression<em> is the specification of the syntax of a simple language</em></p></blockquote> | |
<p>Used with <code>regexp.exec</code>, <code>regexp.test</code>, <code>string.match</code>, <code>string.replace</code>, <code>string.search</code> and <code>string.split</code> to interact with string (more in <a href="https://github.com/Lambda-April/Unsorted-Notes/blob/main" target="_blank">Chapter 8 – Methods</a>)</p> | |
<p>Quite convoluted and difficult to read as they do not allow comments or whitespace so a JavaScript regular expression must be on a single line</p> | |
<h3>An Example</h3> | |
<p><code>/ˆ(?:([A-Za-z]+):)?(\/{0,3})([0-9.\-A-Za-z]+)(?::(\d+))?(?:\/([ˆ?#]*))?(?:\?([ˆ#]*))?(?:#(.*))?$/</code></p> | |
<p>Breaking it down one portion (<a href="https://github.com/Lambda-April/Unsorted-Notes/blob/main" target="_blank">factor</a>) at a time:</p> | |
<ul> | |
<li>Note that the string starts and ends with a slash <code>/</code></li> | |
<li><code>ˆ</code> indicates the beginning of a string</li> | |
<li><code>(?:([A-Za-z]+):)?</code></li> | |
<li><code>(?:...)</code> indicates a <em><a href="https://github.com/Lambda-April/Unsorted-Notes/blob/main" target="_blank">noncapturing group</a></em>, where the ‘…’ is replaced by the group that you wish to match, but not save to anywhere</li> | |
<li>Suffix <code>?</code> indicates the group is optional, so it could or could not exist in the string – it could even exist more than once</li> | |
<li><code>()</code> around the <em>([A-Za-z]+)</em> indicates a <em><a href="https://github.com/Lambda-April/Unsorted-Notes/blob/main" target="_blank">capturing group</a></em> which is therefore captured and placed in the <code>result</code> array</li> | |
<li>They groups are placed in the array in order, so the first will appear in <code>result[1]</code></li> | |
<li>Noncapturing groups are preferred to capturing groups because capturing groups have a performance penalty (on account of saving to the result array)</li> | |
<li>You can also have capturing groups <em>within</em> noncapturing groups such as <a href="http://www.rexegg.com/regex-disambiguation.html" target="_blank"><code>(?:Bob says: (\w+))</code></a></li> | |
<li><code>[...]</code> indicates a character class</li> | |
<li><code>A-Za-z</code> is a character class containing all 26 letters of the alphabet in both upper and lower case</li> | |
<li>Suffix <code>+</code> means character class will be matched <em>one or more times</em></li> | |
<li>Suffix <code>:</code> is matched literally (so the letters will be followed by a colon in this case)</li> | |
<li><code>(\/{0,3})</code></li> | |
<li><code>\/</code> The backslash <code>\</code> <em>escapes</em> the forward slash <code>/</code> (which traditionally symbolises the end of the regular expression literal) and together they indicate that the forward slash <code>/</code> should be matched</li> | |
<li>Suffix <code>{0,3}</code> means the slash <code>/</code> will be matched between 0 and 3 times</li> | |
<li><code>([0-9.\-A-Za-z]+)</code></li> | |
<li>String made up of one or more (note the <code>+</code> at the end denoting possible multiple occurrences) digits, letters (upper or lower case), full stops (.) or hyphens (-)</li> | |
<li>Note that the hyphen was escaped with a backslash <code>\-</code> as hyphens usually denote a <em>range</em> but in this case is a hyphen within the expression</li> | |
<li><code>(?::(\d+))?</code></li> | |
<li><code>\d</code> represents a <em>digit character</em> so this will be a sequence of <em>one or more</em> digit characters (as per the <code>+</code>)</li> | |
<li>The digit characters will be immediately preceded by a colon <code>:</code></li> | |
<li><code>(\d+)</code> will be the fourth capturing group in this expression, it is also <em>optional</em> (<code>?</code>) and inside a non-capturing group <code>(?:...)</code></li> | |
<li><code>(?:\/([ˆ?#]*))?</code></li> | |
<li>Another optional group (<code>?</code>), beginning with a literal slash <code>/</code> (escaped by the backslash)</li> | |
<li>The <code>ˆ</code> at the beginning of character class <code>[ˆ?#]</code> means it includes <em>all</em> characters <em>except</em> ? and #</li> | |
<li>This actually leaves the regexp open to attack because too many characters are included in the character class</li> | |
<li>The <code>*</code> indicates the character class will appear <em>zero or more</em> times</li> | |
<li><code>(?:\?([ˆ#]*))?</code></li> | |
<li>We’ve seen everything here before: An optional capturing group starting with a literal <code>?</code> (escaped by the backslash) with zero or more characters that are not #</li> | |
<li><code>(?:#(.*))?</code></li> | |
<li>Final optional group beginning with a <code>#</code></li> | |
<li><code>.</code> matches any character <em>except a line ending character</em></li> | |
<li><code>$</code> represents the end of a string</li> | |
<li>Note: <code>ˆ</code> and <code>$</code> are important because they anchor the regexp and checks whether the string matched against it contains <em>only</em> what is in the regexp</li> | |
<li>If <code>ˆ</code> and <code>$</code> weren’t present, it would check that the string <em>contained</em> the regexp but wouldn’t necessarily be only made up of this</li> | |
<li>Using only <code>ˆ</code> checks the string <em>starts</em> with the regexp</li> | |
<li>Using only <code>$</code> checks the string <em>ends</em> with the regexp</li> | |
</ul> | |
<blockquote><p>Another example <code>/ˆ-?\d+(?:\.\d*)?(?:e[+\-]?\d+)?$/i;</code></p></blockquote> | |
<p>Most of this we have seen before but here are the new bits:</p> | |
<ul> | |
<li>The <code>i</code> at the end means <em>ignore case</em> when matching letters</li> | |
<li><code>-?</code> means the minus sign is optional</li> | |
<li><code>(?:\.\d*)</code> matches a decimal point followed by <em>zero or more</em> digits (123.6834.4442284 <em>does not match</em>)</li> | |
<li>Note this expression only uses <em>noncapturing</em> groups</li> | |
</ul> | |
<h3>Construction</h3> | |
<p>3 flags exist in regular expressions: <code>i</code> means insensitive – ignore the character case, <code>g</code> means global – to match multiple items and <code>m</code> means multiline – where ˆ and $ can match line-ending characters</p> | |
<p>Two ways to build a regular expression: 1. <em>Regular Expression literals</em> as per the examples above start and end with a slash <code>/</code></p> | |
<ul> | |
<li>Here the flags are appended after the final slash, for example <code>/i</code></li> | |
<li>Be careful: <code>RegExp</code> objects made by regular expression literals share a single instance</li> | |
</ul> | |
<ol> | |
<li>Use <code>RegExp</code> constructor</li> | |
</ol> | |
<ul> | |
<li>The first parameter is the string to be made into a <code>RegExp</code> object, the second is the flag</li> | |
<li>Useful when all information for creating the regular expression is not available at time of programming</li> | |
<li>Backslashes mean something in the constructor, so these must be doubled and quotes must be escaped</li> | |
</ul> | |
<pre>//example creating a regular expression object that matches a JavaScript string</pre> | |
<pre>var my_regexp = new RegExp("'(?:\\\\.|[ˆ\\\\\\'])*'", 'g');</pre> | |
<h3>Elements</h3> | |
<h4>Regexp Choice</h4> | |
<p><code>|</code> provides a match if any of the sequences provided match.</p> | |
<p>In <code>"into".match(/in|int/);</code>, the <em>in</em> will be a match so it doesn’t even look at the <em>int</em>.</p> | |
<h4>Regexp Sequence</h4> | |
<p>A <em>regexp sequence</em> is made up of one or more regexp <a href="https://github.com/Lambda-April/Unsorted-Notes/blob/main" target="_blank">factors</a>. If there are no quantifiers after the factor (like <code>?</code>, <code>*</code> or <code>+</code>), the factor will be matched one time.</p> | |
<h4>Regexp Factor</h4> | |
<blockquote><p><em>A </em>regexp factor<em> can be a character, a parenthesized group, a character class, or an escape sequence.</em></p></blockquote> | |
<p>It’s essentially a portion of the full <code>RegExp</code>, like what we broke down the regexp above into.</p> | |
<ul> | |
<li>The following special characters must all be <em>escaped</em> with a backslash <code>\</code> to be taken literally, or they will take on an alternative meaning: / [ ] ( ) { } ? + * | . ˆ$</li> | |
<li>The <code>\</code> prefix does not make letters or digits literal</li> | |
<li>When unescaped:</li> | |
<li><code>.</code> matches any character except line-ending</li> | |
<li><code>ˆ</code> matches the beginning of the text when <code>lastIndex</code> property is zero, or matches line-ending character when the <code>m</code> flag is present</li> | |
<li>Having <code>ˆ</code> inside a <a href="https://github.com/Lambda-April/Unsorted-Notes/blob/main" target="_blank">character class</a> means NOT, so [ˆ0-9] means <em>does not</em> match a digit</li> | |
<li><code>$</code> matches the beginning of the text or a line-ending character when the <code>m</code> flag is present</li> | |
</ul> | |
<h4>Regexp Escape</h4> | |
<p>As well as escaping special characters in regexp factors, the backslash has additional uses:</p> | |
<ul> | |
<li>As in strings, <code>\f</code> is the formfeed character, <code>\n</code> is new line, <code>\r</code> is carriage return, <code>\t</code> is tab and <code>\u</code> specifies Unicode as a 16-bit hex. But <code>\b</code> is <em>not</em> a backspace character</li> | |
<li><code>\d</code> === [0-9] and <code>\D</code> is the opposite, NOT (ˆ) a digit, [ˆ0-9]</li> | |
<li><code>\s</code> matches is a partial set of Unicode whitespace characters and <code>\S</code> is the opposite</li> | |
<li><code>\w</code> === [0-9A-Za-z] and <code>\W</code> === [ˆ0-9A-Za-z] but useless for any real world language (because of accents on letters, etc)</li> | |
<li><code>\1</code> refers to the text captured in group 1 so it is matched again later on in the regexp</li> | |
<li><code>\2</code> refers to group 2, <code>\3</code> to group 3 and so on</li> | |
</ul> | |
<p>*<code>\b</code> is a <em>bad part</em>. It was supposed to be a word-boundary anchor but is useless for multilingual applications</p> | |
<h4>Regexp Group</h4> | |
<p>Four kinds of groups:</p> | |
<ul> | |
<li>Capturing: <code>(...)</code> where each group is captured into the <code>result</code> array – the first capturing group in the regexp goes into <code>result[1]</code>, the second into <code>result[2]</code> and so on</li> | |
<li>Noncapturing <code>(?:...)</code> where the text is matched, but not captured and saved anywhere, making is <em>slightly faster</em> than a capturing group (has no bearing on numbering of capturing groups)</li> | |
<li><em>Positive lookahead</em>, a bad part: <code>(?=...)</code> acts like a noncapturing group except after the match is made, it goes back to where text started</li> | |
<li><em>Negative lookahead</em>, a bad part: <code>(?!...)</code> is like a positive lookahead but only matches if there is no match with what is in it</li> | |
</ul> | |
<h4>Regexp Class</h4> | |
<ul> | |
<li>Conveniently and easily specifies one of a set of characters using square brackets <code>[]</code>, for example vowels: <code>[aeiou]</code></li> | |
<li>Can shorten specification of all 32 ASCII special characters to [!-/:-@[-`{-˜] (note that the ` in this piece of code is a back-tick)</li> | |
<li>Also allows <code>ˆ</code> as the first character after the opening <code>[</code> to mean <em>NOT</em> the characters in the character set</li> | |
</ul> | |
<h4>Regexp Class Escape</h4> | |
<p>There are <em>specific</em> characters that must be escaped in a character class: — / [ ] ˆ</p> | |
<h4>Regexp Quantifier</h4> | |
<p>A <em>quantifier</em> at the end of a factor indicates how many times the factor should be matched</p> | |
<ul> | |
<li>A number in curly braces means the factor should match that many times, so <code>/o{3}</code> matches <em>ooo</em></li> | |
<li>Two comma-seperated numbers in curly braces provide the <em>range</em> of times a factor should match, so <code>{3,5}</code> indicates it will match 3, 4 or 5 times</li> | |
<li><em>Zero or one</em> times (same thing as saying something is optional) can be <code>?</code> or <code>{0,1}</code></li> | |
<li><em>Zero or more</em> times can be <code>*</code> or <code>{0,}</code></li> | |
<li><em>One or more</em> times can be <code>+</code> or <code>{1,}</code></li> | |
</ul> | |
<p>Prefer to use ‘zero or more’ or ‘one or more’ matching over the ‘zero or one’ matching — i.e. prefer <em>greedy</em> matching over <em>lazy</em> matching</p> | |
<h3>Chapter 8 — Methods</h3> | |
<h3>Arrays</h3> | |
<h4>array.concat(item…)</h4> | |
<p>Produces new array copying the original array with the <code>items</code> appended to it (does not modify the original array like <code>array.push(item)</code> does). If the <code>item</code> is an array, its elements are appended.</p> | |
<h4>array.join(separator)</h4> | |
<p>Creates a string of all the array’s elements, separated by the <code>separator</code>. Use an empty string <code>separator</code> (”) to join without separation.</p> | |
<h4>array.pop()</h4> | |
<p>Removes <em>last element</em> of array. Returns <code>undefined</code> for empty arrays.</p> | |
<h4>array.push(item…)</h4> | |
<p>Modifies the <em>array</em>, appending <code>items</code> onto the end. Returns the new <code>length</code> of the array.</p> | |
<h4>array.reverse()</h4> | |
<p><em>Modifies</em> the array by reversing the order of the elements.</p> | |
<h4>array.shift()</h4> | |
<p>Removes the <em>first</em> element of the array (does not leave a hole in the array — same effect as using the <code>.splice(a,b)</code> method) and returns that first element.</p> | |
<h4>array.slice(start, end)</h4> | |
<p>Different to <code>splice</code>.</p> | |
<p>‘slice’ creates a new array, copying from the <code>start</code> element and stopping at the element <em>before</em> the <code>end</code> value given. If no <code>end</code> is given, default is <code>array.length</code>.</p> | |
<p>Negative values for <code>start</code> and <code>end</code> will have <code>array.length</code> added to them and if <code>start</code>><code>end</code>, it will return an empty array.</p> | |
<h4>array.sort(comparefn)</h4> | |
<p>JavaScript has a <code>sort()</code> method which was created only to compare strings and therefore sorts numbers incorrectly (it will sort them as 1, 15, 2, 23, 54 for example). Therefore, we have to write a comparison function which returns <em>0</em> if the two elements you are comparing are equal, a <em>positive number</em> if the first element should come first and a <em>negative number</em> if the second element should come first. Then pass this comparison function to <code>sort()</code> as a parameter to allow it to sort array elements <em>intelligently</em>.</p> | |
<p>Page 80-82 in the book takes you through various iterations of the comparison functions — for numbers, simple strings, objects and objects with multiple keys (for example if you want to sort objects by first <em>and</em> last names). These should be taken from the book when required.</p> | |
<h4>array.splice(start, deleteCount, item…)</h4> | |
<p>Removes elements from the array making sure there are no holes left in the array. It is most popularly used for deleting elements from an array.</p> | |
<p>It removes the <code>deleteCount</code> number of elements from the array starting from the <code>start</code> position. If there are <code>item</code> parameters passed to it, it will replace the deleted elements in the array with the <code>items</code>.</p> | |
<p>It returns an array containing the deleted elements.</p> | |
<h4>array.unshift(item…)</h4> | |
<p>Works like <code>push</code> but adds items to the front of the array instead of the end. Returns the new <code>length</code> of the array.</p> | |
<h3>Function</h3> | |
<h4>function.apply(thisArg, [argArray])</h4> | |
<p>The <code>apply</code> method invokes a function, passing in the object that will be bound to <code>this</code> and <em>optional</em> array of arguments.</p> | |
<h3>Number</h3> | |
<h4>number.toExponentional(fractionDigits)</h4> | |
<p>Converts <em>number</em> to a string in exponential form (e.g. 3.14e+0). <code>fractionDigits</code> (from 0 to 20) gives the number of decimal places.</p> | |
<h4>number.toFixed(fractionDigits)</h4> | |
<p>Converts <em>number</em> to a string in decimal form (e.g. 3.1415927). <code>fractionDigits</code> (from 0 to 20) gives the number of decimal places.</p> | |
<h4>number.toPrecision(precision)</h4> | |
<p>Converts <em>number</em> to a string in decimal form (e.g. 3.1415927). The difference from <code>toFixed</code> is that <code>precision</code> (from 0 to 21) gives the number of total digits.</p> | |
<h4>number.toString(radix)</h4> | |
<p>Converts <em>number</em> to a string. <code>radix</code> is an <em>optional</em> parameter between 2 and 36 and gives the <em>base</em>. The default radix is 10.</p> | |
<h3>Object</h3> | |
<h4>object.hasOwnProperty(name)</h4> | |
<p>Does not look at the property chain. Returns true if the <em>object</em> contains the property <code>name</code>.</p> | |
<h3>RegExp</h3> | |
<h4>regexp.exec(string)</h4> | |
<p>Most powerful (and <em>slowest</em>) regexp method.</p> | |
<p>Checks the <code>string</code> against the <em>regexp</em> (starting at position 0) and returns an array containing the matches. The <em>regexp</em> is set up with various capturing groups and these determine the elements that go in the array:</p> | |
<ul> | |
<li>the 0 element of the array will contain the part of <code>string</code> that matched the <em>regexp</em></li> | |
<li>element 1 of the array will contain the text captured by the first capturing group in <em>regexp</em></li> | |
<li>element 2 of the array will contain the text captured by the second capturing group in <em>regexp</em> and so on</li> | |
<li>if the match fails, it returns <code>null</code></li> | |
</ul> | |
<p>If the <em>regexp</em> contains a <code>g</code> flag (e.g. <code>var regexp = /[ˆ<>]+|<(\/?)([A-Za-z]+)([ˆ<>]*)>/g;</code>), there is a lot more to look out for:</p> | |
<ul> | |
<li>Searching begins at <code>regexp.lastIndex</code> (initially zero)</li> | |
<li>If a match is found, <code>lastIndex</code> becomes the position of the <em>first character of the match</em></li> | |
<li>If no match is found, <code>lastIndex</code> is reset to zero</li> | |
<li>If searching for multiple occurrences of a pattern by calling <code>exec</code> in a loop, ensure you <em>reset <code>lastIndex</code></em> when exiting the loop and remember <code>ˆ</code> only matches <em>when <code>lastIndex</code> is equal to zero</em></li> | |
</ul> | |
<p>Example on page 87 of the book is worth reading to improve understanding.</p> | |
<h4>regexp.test(string)</h4> | |
<p>Simplest (and <em>fastest</em>) regexp method.</p> | |
<p>If <em>regexp</em> matches the <code>string</code> it returns <em>true</em>. Otherwise it returns <em>false</em>. Do not use the <code>g</code> flag with this method.</p> | |
<h3>String</h3> | |
<h4>string.charAt(pos)</h4> | |
<p>Returns character at position <code>pos</code> in the string <em>starting from 0</em>. If <code>pos</code> is less than zero or bigger than the string itself it return an empty string.</p> | |
<h4>string.charCodeAt(pos)</h4> | |
<p>Same as <code>charAt</code> except it returns the integer that represents the <em>code point value of the character at position <code>pos</code></em>. Returns <code>NaN</code> if <em>string</em>.length < <code>pos</code> < 0.</p> | |
<h4>string.concat(string…)</h4> | |
<p>Creates new string concatenating various strings. <code>+</code> tends to be used instead of this method (e.g. <code>var cat = 'c'+'a'+'t';</code>)</p> | |
<h4>string.indexOf(searchString, position)</h4> | |
<p>Searches for <code>searchString</code> within <em>string</em> starting at position <code>position</code> (an optional parameter). If <code>position</code> is not provided, search starts at the beginning of the <em>string</em>. Returns the integer <em>position of the first matched character</em> or <em>-1</em> if no match is found.</p> | |
<h4>string.lastIndexOf(searchString, position)</h4> | |
<p>Same as <code>indexOf</code> but searches from the end of the string instead of the beginning.</p> | |
<h4>string.localeCompare(that)</h4> | |
<p>Compares <em>string</em> to <code>that</code> parameter and returns:</p> | |
<ul> | |
<li>0 if <em>string</em> === <code>that</code></li> | |
<li>-1 if <em>string</em> < <code>that</code></li> | |
</ul> | |
<p><em>NB. ‘a’ < ‘A’, comparison is not just in length.</em></p> | |
<h4>string.match(regexp)</h4> | |
<p>Works the same way as <code>regexp.exec(string)</code> if there is no <code>g</code> flag in the <code>regexp</code>.</p> | |
<p>If there is a <code>g</code> flag in teh <code>regexp</code>, it produces an array of the matches but excludes the capturing groups</p> | |
<h4>string.replace(searchValue, replaceValue)</h4> | |
<p>Searches for the <code>searchValue</code> in <em>string</em> and replaces it with the <code>replaceValue</code>.</p> | |
<p>If <code>searchValue</code> is a:</p> | |
<ul> | |
<li>string, only its <em>first occurrence</em> will be replaced with the <code>replaceValue</code></li> | |
<li>regexp with a g flag, <em>all occurrences</em> will be replaced with the <code>replaceValue</code>; otherwise, only the <em>first occurrence</em> will be replaced</li> | |
</ul> | |
<p>If <code>replaceValue</code> is a:</p> | |
<ul> | |
<li>string, a <code>$</code> value has a special meaning when used in the <code>replaceValue</code> that conveys what to replace – see table on page 90 for possible variations on <code>$</code></li> | |
<li>function, it is called for each match and the <em>string result of the function</em> is used as the replacement text</li> | |
<li>string result of the first call will replace capture group 1 of the <em>string</em> and so on</li> | |
</ul> | |
<h4>string.search(regexp)</h4> | |
<p>Similar to <code>.indexOf(string)</code> but takes a <code>regexp</code> instead of a <code>string</code>, returning the position of the first match (or -1 if there is no match). The <code>g</code> flag is ignored.</p> | |
<h4>string.slice(start, end)</h4> | |
<p>Creates a new string by copying the characters from the <code>start</code> position to the character before the <code>end</code> position in <em>string</em>.</p> | |
<p>The <code>end</code> parameter is <em>optional</em> and defaults to <em>string</em>.length. If either parameter is negative, <em>string</em>.length is added to it.</p> | |
<h4>string.split(separator, limit)</h4> | |
<p>Creates an array of strings by splitting apart <em>string</em> at the points where the <code>separator</code> appears (e.g. if the separator is ‘.’, ab.cd’ becomes [‘ab’, ‘cd’]).</p> | |
<ul> | |
<li>If separator is an <em>empty string</em>, an array of single characters is produced.</li> | |
<li><code>limit</code> is <em>optional</em> and determines how many pieces are to be split off from the original <em>string</em>.</li> | |
<li>The <code>separator</code> can be a <code>regexp</code> but</li> | |
<li>text from capturing groups within the regexp will be included in the split — e.g. in <code>var e = text.split(/\s*(,)\s*/);</code> the commas (,) will each be included as a separate element in the resulting array</li> | |
<li>some systems <em>ignore empty strings</em> when the <code>separator</code> is a <code>regexp</code></li> | |
</ul> | |
<h4>string.substring(start, end)</h4> | |
<p>No reason to use, use <code>slice</code> instead.</p> | |
<h4>string.toLocaleLowerCase()</h4> | |
<p>Produces a new string converted to lower case, <em>using the rules for the particular locale</em> (geography).</p> | |
<h4>string.toLocaleUpperCase()</h4> | |
<p>Produces a new string converted to upper case, <em>using the rules for the particular locale</em> (geography).</p> | |
<h4>string.toLowerCase()</h4> | |
<p>Produces a new string converted to lower case.</p> | |
<h4>string.toUpperCase()</h4> | |
<p>Produces a new string converted to upper case.</p> | |
<h4>String.fromCharCode(char…)</h4> | |
<p>Produces a new string from a series of numbers. <code>var a = String.fromCharCode(67, 97, 116); //a === 'Cat'</code> <em>NB. You’re calling the prototype here, not replacing ‘String’ with your own variable.</em></p> | |
<h3>Chapter 9 — Style</h3> | |
<h4><em>JavaScripts’s loose typing and excessive error tolerance provide little compile-time assurance of our programs’ quality, so to compensate, we should code with strict discipline.</em></h4> | |
<blockquote><p>We should avoid the <em>bad parts</em> of JavaScript, but also the useful parts that can be occasionally dangerous</p></blockquote> | |
<blockquote><p>the likelihood a program will work [as intended] is significantly enhanced by our ability to read it</p></blockquote> | |
<blockquote><p>Must be written in a clear, consistent style, including:</p></blockquote> | |
<blockquote><p>Good use of whitespace</p></blockquote> | |
<blockquote><p>Put at most one statement on a line</p></blockquote> | |
<blockquote><p>If you have to break a statement into 2 or more lines, indent the 2nd line onwards (an extra four spaces)</p></blockquote> | |
<blockquote><p><em>Always</em> use blocks (curly braces {}) with structured statements like <em><code>if</code></em> and <em><code>while</code></em> to avoid confusion on what the statement is actually doing</p></blockquote> | |
<blockquote><p>Put the opening brace <em><code>{</code></em> on the same (first) line as the statement to avoid JavaScript’s <a href="https://github.com/Lambda-April/Unsorted-Notes/blob/main" target="_blank">semicolon insertion</a> issues – i.e <em><code>if (a) { ...</code></em></p></blockquote> | |
<blockquote><p>Use line comments <em><code>//comment</code></em> and not block commenting (unless you’re <em>commenting out</em> code)</p></blockquote> | |
<blockquote><p>Declare all your variables at the beginning of the function, due to JavaScript’s functional scope</p></blockquote> | |
<ul> | |
<li>I use a single global variable to contain an application or library. Every object has its own namespace, so it is easy to use objects to organize my code. Use of closure provides further information hiding, increasing the strength of my modules.</li> | |
</ul> | |
<h3>Chapter 10 — Beautiful Features</h3> | |
<p>Each feature you add to something has a lot of different costs (documentation costs, specification, design, testing and development costs) and these are often not properly accounted for.</p> | |
<blockquote><p><em>Features that offer value to a minority of users impose a cost on all users</em></p></blockquote> | |
<blockquote><p><em>We cope with the complexity of feature-driven design by finding and sticking with the good parts. For example, microwaves do a ton of different things, but most people just use one setting, the timer and the clock. So why not design with just the good parts?</em></p></blockquote> | |
<h3>Appendix A — the Awful Parts</h3> | |
<p>Need to know what all the pitfalls are with these parts.</p> | |
<h3>Global variables</h3> | |
<p>These are variables that are visible throughout the code in any scope. They can be changed at any time by any part of the program which makes them unreliable in larger complex programs. This can also lead to naming conflicts which can cause your code to fail or you to accidentally overwrite a global variable.</p> | |
<p>Defined in three ways:</p> | |
<ul> | |
<li>Using a <code>var</code> statement outside of any function; <code>var foo = value</code>;</li> | |
<li>By adding a property to the global object (container of all global variables), such as <code>window</code> in browsers; <code>window.foo = value;</code></li> | |
<li>Using a variable without declaring it with <code>var</code>, which makes it an <em>implied global</em>; <code>foo = value</code></li> | |
</ul> | |
<h3>Scope</h3> | |
<p>Although JavaScript has block <em>syntax</em> (i.e. is written in blocks) like a lot of other programming languages, it has functional scope and <em>not</em> block scope.</p> | |
<p>Variables should all be declared at the top of the function and not littered throughout the block.</p> | |
<h3>Semicolon Insertion</h3> | |
<p>Attempts to correct faulty programs by automatically inserting semicolons. Do not depend on this as it can hide underlying issues.</p> | |
<p>Also ensure opening curly braces ({) are on the first line of a statement, otherwise semicolons will be erroneously inserted and cause problems:</p> | |
<pre>//Ensure curly braces open on the first line of a statement | |
return { | |
status: true //for example | |
}; | |
//instead of | |
return | |
{ | |
status:true | |
};</pre> | |
<h3>Reserved Words</h3> | |
<p>Most JavaScript reserved words are not used in the language but cannot be used to name variables or parameters.</p> | |
<p>If used as the key in object literals, they <em>must</em> be quoted. For example <code>object - {'case' : value};</code> or <code>object['final'] = value;</code> as <em>case</em> and <em>final</em> are both reserved words.</p> | |
<h3>Unicode</h3> | |
<p>JavaScript characters are 16 bits which only cover the original Unicode Basic Multilingual Place.</p> | |
<h3>typeof</h3> | |
<p>Watch out for:</p> | |
<ul> | |
<li><code>typeof null</code> which returns ‘object’ instead of ‘null’</li> | |
<li>incorrect reporting on typeof regular expressions, with some implementations returning ‘object’ and some returning ‘function’</li> | |
<li>arrays are objects in JavaScript so <code>typeof array</code> will return ‘object’</li> | |
</ul> | |
<p>All <code>object</code>s are <em>truthy</em> and <code>null</code> is <em>falsy</em>, so you can use the following to tell them apart:</p> | |
<pre>if (my_value && typeof my_value === 'object') { | |
//then my value is definitely an object or an array because not only is its 'typeof' an object but it's also truthy (first statement) | |
}</pre> | |
<h3>NaN</h3> | |
<ul> | |
<li><code>typeof NaN === 'number'</code> even though it stands for <em>not-a-number</em></li> | |
<li>If you have a chain of formulas that together produce a <code>NaN</code> then at least <em>one</em> of them will have generated <code>NaN</code></li> | |
<li>Surprisingly <code>NaN !=== NaN</code></li> | |
<li><code>isNaN(value)</code> can be used to distinguish numbers from NaN</li> | |
</ul> | |
<p>For numbers, best use your own isNumber formula:</p> | |
<pre>var isNumber = function isNumber(value) { | |
return typeof value === 'number' && isFinite(value); //isFinite() rejects NaN and Infinity, but is only good for numbers, not strings | |
}</pre> | |
<h3>Phony Arrays</h3> | |
<p>JavaScript doesn’t have real arrays, it has <em>array-like objects</em>.</p> | |
<ul> | |
<li>Good: No need to give them dimensions and don’t generate out-of-bounds errors</li> | |
<li>Bad: Slower than ‘real’ arrays</li> | |
</ul> | |
<p>To test if value is an array:</p> | |
<pre>if (my_value && typeof my_value === 'object' && typeof my_value.length === 'number' && | |
!(my_value.propertyIsEnumerable('length'))) { | |
//my_value is definitely an array! | |
}</pre> | |
<p>The <code>arguments</code> array isn’t an array, just an object with a length property.</p> | |
<h3>Falsy Values</h3> | |
<p><code>0</code>, <code>NaN</code>, <code>''</code>, <code>false</code>, <code>null</code> and <code>undefined</code> are all <em>falsy</em> values, but they are not interchangeable. When testing for a missing member of an object for example, you need to use <code>undefined</code> and not <code>null</code>.</p> | |
<p><code>undefined</code> and <code>NaN</code> are actually global variables instead of constants but don’t change their values.</p> | |
<h3>Object</h3> | |
<p>JavaScript objects inherit members from the prototype chain so they are <em>never truly empty</em>.</p> | |
<p>To test for membership without prototype chain involvement, use the <code>hasOwnProperty</code> method or limit your results (for example, to specific types like number so you know you’re not dragging in object members from up the prototype for example if that’s what’s causing the problem).</p> | |
<h3>Appendix B — the Bad Parts</h3> | |
<p>Avoid these altogether</p> | |
<ul> | |
<li><code>==</code> and <code>!=</code>: Don’t function properly when result is false, use <code>===</code> or <code>!==</code> instead</li> | |
<li><code>with</code> statement: Intended to provide a shortcut to properties of an object but results vary every time it is run</li> | |
<li><code>eval</code>: Adds unnecessary complication and compromises the security of the application</li> | |
<li>Giving string arguments to <code>setTimeout</code> and <code>setInterval</code> should also be avoided as this makes them act like <code>eval</code></li> | |
<li><code>continue</code> statement: Forces a loop into its next iteration but the code is usually much improved when re-written <em>without</em> <code>continue</code></li> | |
<li><code>switch</code> fall through: In a <code>switch</code> statement, each <code>case</code> falls through to the next <code>case</code> unless you explicitly disrupt the flow, but using these <em>intentional</em> fall throughs makes the <em>unintentional</em> ones that are causing errors basically impossible to find</li> | |
<li>This is one of those parts of JavaScript that appears useful but you’re better off avoiding because it’s occasionally very dangerous</li> | |
<li>Block-less statements: <em>Always</em> use curly braces <code>{}</code> to block in statements so as to avoid misinterpretation and aid error finding</li> | |
<li>Bitwise operators: Shouldn’t really be doing this kind of manipulations because they are quite slow in JavaScript, therefore there shouldn’t be a need to use <code>&</code>, <code>|</code>, <code>ˆ</code>, <code>˜</code>, <code>>></code>, <code>>>></code> or <code><<</code></li> | |
<li>This doesn’t mean you can’t use <code>&&</code> for example</li> | |
<li><code>++</code> and <code>--</code>: This one seems debatable to me; Douglas Crockford finds it makes his coding style much more cryptic and difficult to read (the book uses <code>+=1</code> and <code>-=1</code> instead)</li> | |
</ul> | |
<p>The function statement vs the function expression: To use JavaScript well, important to understand that functions are values.</p> | |
<ul> | |
<li>A function <em>statement</em> is shorthand for a var statement with a function value, so <code>function foo() {}</code> (a function statement) means pretty much the same as <code>var foo = function foo(){};</code> (a function expression)</li> | |
<li>Logically, to write the language well you should define a function before using it, but in JavaScript, function statements (using just <code>function foo(){}</code>) are <em>hoisted</em> to the top of the scope in which they are defined – this encourages sloppy programming and should be avoided</li> | |
<li>function statements also don’t function consistently in <code>if</code> statements</li> | |
<li>if you need to start a function expression with the word <em>function</em>, wrap it in parentheses (), or JavaScript assumes it’s a function <em>statement</em></li> | |
</ul> | |
<p>Typed wrappers: Don’t use <code>new Boolean</code> or <code>new String</code> or <code>new Number</code>, it’s completely unnecessary. Also avoid <code>new Object</code> and <code>new Array</code> and use <code>{}</code> and <code>[]</code> instead.</p> | |
<p><code>new</code> operator: Functions that are intended to be used with <code>new</code> (conventionally starting with a capital letter) should be avoided (don’t define them) as they can cause all kinds of issues and complex bugs which are difficult to catch.</p> | |
<p>void: In JavaScript, this actually <em>takes</em> a value and <em>returns</em> <code>undefined</code>, which is hugely confusing and not helpful. Don’t use it.</p> | |
<h3>Appendix C — JSLint</h3> | |
<p>JSLint is a code quality tool for JavaScript which checks your syntax.</p> | |
<p>Having read through this appendix (you can read more about <a href="http://www.jslint.com/" target="_blank">JSLint here</a>), I tend more towards <em><a href="http://jshint.com/about/" target="_blank">JSHint</a></em>, a <em>fork</em> of JSLint. It allows programmers to customise for themselves which the good parts and bad parts are and define their own subset, although naturally there are a number of pre-defined options. <a href="https://github.com/nelsonic/learn-jshint" target="_blank">This is a really fantastic article on using JSHint</a>; it’s simple and aimed at having you using JSHint in a few minutes as well as providing various sources for pre-defined subsets.</p> | |
<h4>Further resources:</h4> | |
<p><a href="https://bryanguner.medium.com/a-list-of-all-of-my-articles-to-link-to-future-posts-1f6f88ebdf5b">https://bryanguner.medium.com/a-list-of-all-of-my-articles-to-link-to-future-posts-1f6f88ebdf5b</a><a href="https://bryanguner.medium.com/a-list-of-all-of-my-articles-to-link-to-future-posts-1f6f88ebdf5b">https://bryanguner.medium.com/a-list-of-all-of-my-articles-to-link-to-future-posts-1f6f88ebdf5b</a><a href="https://bryanguner.medium.com/a-list-of-all-of-my-articles-to-link-to-future-posts-1f6f88ebdf5b">https://bryanguner.medium.com/a-list-of-all-of-my-articles-to-link-to-future-posts-1f6f88ebdf5b</a><a href="https://bryanguner.medium.com/a-list-of-all-of-my-articles-to-link-to-future-posts-1f6f88ebdf5b">https://bryanguner.medium.com/a-list-of-all-of-my-articles-to-link-to-future-posts-1f6f88ebdf5b</a></p> | |
</div><!-- .entry-content --> | |
<footer class="entry-footer responsive-max-width"> | |
<span class="byline"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><span class="screen-reader-text">Posted by</span><span class="author vcard"><a class="url fn n" href="https://web-dev-hub.com/author/gunerb1/">bgoonz</a></span></span><span class="posted-on"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><defs><path id="a" d="M0 0h24v24H0V0z"></path></defs><clipPath id="b"><use xlink:href="#a" overflow="visible"></use></clipPath><path clip-path="url(#b)" d="M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10 10-4.5 10-10S17.5 2 12 2zm4.2 14.2L11 13V7h1.5v5.2l4.5 2.7-.8 1.3z"></path></svg><a href="https://web-dev-hub.com/2021/04/05/notes-from-javascript-the-good-parts/" rel="bookmark"><time class="entry-date published" datetime="2021-04-05T02:47:41-04:00">April 5, 2021</time><time class="updated" datetime="2021-11-27T16:51:29-05:00">November 27, 2021</time></a></span><span class="cat-links"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M10 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2h-8l-2-2z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><span class="screen-reader-text">Posted in</span><a href="https://web-dev-hub.com/category/uncategorized/" rel="category tag">Uncategorized</a></span><span class="tags-links"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M21.41 11.58l-9-9C12.05 2.22 11.55 2 11 2H4c-1.1 0-2 .9-2 2v7c0 .55.22 1.05.59 1.42l9 9c.36.36.86.58 1.41.58.55 0 1.05-.22 1.41-.59l7-7c.37-.36.59-.86.59-1.41 0-.55-.23-1.06-.59-1.42zM5.5 7C4.67 7 4 6.33 4 5.5S4.67 4 5.5 4 7 4.67 7 5.5 6.33 7 5.5 7z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><span class="screen-reader-text">Tags:</span><a href="https://web-dev-hub.com/tag/computer-science/" rel="tag">Computer Science</a>, <a href="https://web-dev-hub.com/tag/javascript/" rel="tag">Javascript</a>, <a href="https://web-dev-hub.com/tag/technology/" rel="tag">Technology</a>, <a href="https://web-dev-hub.com/tag/tutorial/" rel="tag">Tutorial</a>, <a href="https://web-dev-hub.com/tag/web-development/" rel="tag">Web Development</a></span><span class="comments-link"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M21.99 4c0-1.1-.89-2-1.99-2H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h14l4 4-.01-18z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><a href="https://web-dev-hub.com/2021/04/05/notes-from-javascript-the-good-parts/#respond">Leave a comment<span class="screen-reader-text"> on Notes from JavaScript the Good Parts</span></a></span><span class="edit-link"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04c.39-.39.39-1.02 0-1.41l-2.34-2.34c-.39-.39-1.02-.39-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><a class="post-edit-link" href="https://wordpress.com/post/web-dev-hub.com/579">Edit <span class="screen-reader-text">Notes from JavaScript the Good Parts</span></a></span> </footer><!-- .entry-footer --> | |
</article><!-- #post-${ID} --> | |
<article id="post-578" class="post-578 post type-post status-publish format-standard hentry category-uncategorized tag-javascript tag-programming tag-technology tag-web-design tag-web-development entry"> | |
<header class="entry-header responsive-max-width"> | |
<h2 class="entry-title"><a href="https://web-dev-hub.com/2021/04/03/the-beginners-guide-to-javascript/" rel="bookmark">The Beginner’s Guide To JavaScript</a></h2> </header><!-- .entry-header --> | |
<div class="entry-content"> | |
<h4>Part 1</h4> | |
<figure><img src="https://webdevhubcom.files.wordpress.com/2021/04/781b5-1cg0j-l4zhn7_5g2in-k-ew.png" data-width="1582" data-height="989"></figure> | |
<h3>How to learn effectively</h3> | |
<p><strong>Learning</strong>: The acquisition of skills and the ability to apply them in the future.</p> | |
<p><strong>What makes an Effective learner?</strong></p> | |
<ul> | |
<li>They are active listeners.</li> | |
<li>They are engaged with the material.</li> | |
<li>They are receptive of feedback.</li> | |
<li>They are open to difficulty.</li> | |
</ul> | |
<p><strong>Why do active learning techniques feel difficult?</strong></p> | |
<ul> | |
<li>It feels difficult because you are constantly receiving feedback, and so you are constantly adapting and perfecting the material.</li> | |
</ul> | |
<p><strong>Desirable Difficulty</strong></p> | |
<ul> | |
<li>The skills we wish to obtain is often a difficult one.</li> | |
<li>We want challenging but possible lessons based on current level of skill.</li> | |
</ul> | |
<p><strong>Effective learners space their practice</strong></p> | |
<ul> | |
<li>Consistent effort > cramming => for <strong>durable knowledge</strong></li> | |
</ul> | |
<hr> | |
<h4>Here’s a REPL to practice with:</h4> | |
<p><a href="https://replit.com/@bgoonz/lambda-prep#README.html">https://replit.com/@bgoonz/lambda-prep#README.html</a></p> | |
<hr> | |
<p><a href="https://replit.com/@bgoonz/lambda-prep#README.html">https://replit.com/@bgoonz/lambda-prep#README.html</a></p> | |
<hr> | |
<h3>Hello World</h3> | |
<ul> | |
<li><strong>console.log</strong> : command used to print something onto the screen.</li> | |
<li><strong>syntax</strong> : the exact arrangement of the symbols, characters, and keywords in our code.</li> | |
<li><strong>//</strong> : notation for creating a code comment in JS.</li> | |
<li><strong>code comment</strong> : useful for annotating pieces of code to explain how something works, ignored by computer.</li> | |
</ul> | |
<blockquote><p><strong><em>“Simplicity is prerequisite for reliability.” — Edsger W. Dijkstra</em></strong></p></blockquote> | |
<hr> | |
<h3>The Number Data Type</h3> | |
<p>The <strong>number</strong> data type in JS is used to represent any numerical values, including integers and decimal numbers.</p> | |
<p><strong>Basic Arithmetic Operators</strong></p> | |
<p>Operators are the symbols that perform particular operations.</p> | |
<ul> | |
<li><strong>+</strong> (addition)</li> | |
<li><strong>–</strong> (subtraction)</li> | |
<li><strong>asterisk</strong> (multiplication)</li> | |
<li><strong>/</strong> (division)</li> | |
<li><strong>%</strong> (modulo)</li> | |
</ul> | |
<p>JS evaluates more complex expressions using the general math order of operations aka PEMDAS.</p> | |
<ul> | |
<li><strong>PEMDAS</strong> : Parentheses, Exponents, Multiplication, Division, Modulo, Addition, Subtraction.</li> | |
<li><em>To force a specific order of operation, use the group operator ( ) around a part of the expression.</em></li> | |
</ul> | |
<p><strong>Modulo</strong> : Very useful operation to check divisibility of numbers, check for even & odd, whether a number is prime, and much more! <em>(Discrete Math concept, circular problems can be solved with modulo)</em></p> | |
<ul> | |
<li>Whenever you have a smaller number % a larger number, the answer will just be the initial small number.</li> | |
<li><code>console.log(7 % 10); // => 7;</code></li> | |
</ul> | |
<hr> | |
<h3>The String Data Type</h3> | |
<p>The <strong>string</strong> data type is a primitive data type that used to represent textual data.</p> | |
<ul> | |
<li>can be wrapped by either <strong>single</strong> or <strong>double</strong> quotation marks, <em>best to choose one and stick with it for consistency</em>.</li> | |
<li>If your string contains quotation marks inside, can layer single or double quotation marks to allow it to work.</li> | |
<li><code>"That's a great string"; (valid)</code></li> | |
<li><code>'Shakespeare wrote, "To be or not to be"'; (valid)</code></li> | |
<li><code>'That's a bad string'; (invalid)</code></li> | |
<li>Alt. way to add other quotes within strings is to use template literals.</li> | |
<li><code>`This is a temp'l'ate literal ${function}` // use ${} to invoke functions within.</code></li> | |
<li><strong>.length</strong> : property that can be appended to data to return the length.</li> | |
<li>empty strings have a length of zero.</li> | |
<li><strong>indices</strong> : indexes of data that begin at 0, can call upon index by using the bracket notation [ ].</li> | |
</ul> | |
<p><code>console.log("bootcamp"[0]); // => "b"</code></p> | |
<p><code>console.log("bootcamp"[10]); // => "undefined"</code></p> | |
<p><code>console.log("boots"[1 * 2]); // => "o"</code></p> | |
<p><code>console.log("boots"["boot".length - 1]); // => "t"</code></p> | |
<ul> | |
<li>we can pass expressions through the brackets as well since JS always evaluates expressions first.</li> | |
<li>The index of the last character of a string is always one less than it’s length.</li> | |
<li><strong>indexOf()</strong> : method used to find the first index of a given character within a string.</li> | |
<li><code>console.log("bagel".indexOf("b")); // => 0 console.log("bagel".indexOf("z")); // => -1</code></li> | |
<li>if the character inside the indexOf() search does not exist in the string, the output will be -1.</li> | |
<li>the indexOf() search will return the first instanced index of the the char in the string.</li> | |
<li><strong>concatenate</strong> : word to describe joining strings together into a single string.</li> | |
</ul> | |
<hr> | |
<h3>The Boolean Data Type</h3> | |
<p>The <strong>boolean</strong> data type is the simplest data type since there are only two values: <strong>true</strong> and <strong>false</strong>.</p> | |
<ul> | |
<li><strong>Logical Operators</strong> (B<em>oolean Operators</em>) are used to establish logic in our code.</li> | |
<li><strong>!</strong> (not) : reverses a boolean value.</li> | |
<li><code>console.log(!true); // => false console.log(!!false); // => false</code></li> | |
<li><strong>&&</strong> (and) <strong>Truth Table</strong></li> | |
</ul> | |
<figure><img src="https://webdevhubcom.files.wordpress.com/2021/04/f25af-1aw4icm7-fq7znecbvh3ftw.png" data-width="339" data-height="492"></figure> | |
<ul> | |
<li><strong>Logical Order of Operations</strong> : JS will evaluate !, then &&, then ||.</li> | |
<li><strong>De Morgan’s Law</strong> : Common mistake in boolean logic is incorrectly distributing ! across parentheses.</li> | |
<li><code>!(A || B) === !A && !B; !(A && B) === !A || !B;</code></li> | |
<li>In summary, to correctly distribute ! across parentheses we must also flip the operation within.</li> | |
<li><strong>Short-Circuit Evaluation</strong> : Because JS evalutes from left to right, expressions can “short-circuit”. For example if we have true on the left of an || logical comparison, it will stop evaluating and yield true instead of wasting resources on processing the rest of the statement.</li> | |
<li><code>console.log(true || !false); // => stops after it sees "true ||"</code></li> | |
</ul> | |
<hr> | |
<h3>Comparison Operators</h3> | |
<p>All comparison operators will result in a boolean output.</p> | |
<p><strong>The relative comparators</strong></p> | |
<ul> | |
<li><strong>></strong> (greater than)</li> | |
<li><strong><</strong> (less than)</li> | |
<li><strong>>=</strong> (greater than or equal to)</li> | |
<li><strong><=</strong> (less than or equal to)</li> | |
<li><strong>===</strong> (equal to)</li> | |
<li><strong>!==</strong> (not equal to)</li> | |
</ul> | |
<blockquote><p><em>Fun Fact: “a” < “b” is considered valid JS Code because string comparisons are compared lexicographically (meaning dictionary order), so “a” is less than “b” because it appears earlier!</em></p></blockquote> | |
<blockquote><p><em>If there is ever a standstill comparison of two string lexicographically (i.e. app vs apple) the comparison will deem the shorter string lesser.</em></p></blockquote> | |
<p><strong>Difference between == and ===</strong></p> | |
<ul> | |
<li><strong>===</strong> : Strict Equality, will only return true if the two comparisons are entirely the same.</li> | |
<li><strong>==</strong> : Loose Equality, will return true even if the values are of a different type, due to coercion. (Avoid using this)</li> | |
</ul> | |
<hr> | |
<h3>Variables</h3> | |
<p>Variables are used to store information to be referenced and manipulated in a program.</p> | |
<ul> | |
<li>We initialize a variable by using the <strong>let</strong> keyword and a <strong>=</strong> single equals sign (assignment operator).</li> | |
<li><code>let bootcamp = "Lambda"; console.log(bootcamp); // "Lambda"</code></li> | |
<li>JS variable names can contain any alphanumeric characters, underscores, or dollar signs (cannot being with a number).</li> | |
<li>If you do not declare a value for a variable, undefined is automatically set.</li> | |
<li><code>let bootcamp; console.log(bootcamp); // undefined</code></li> | |
<li>We can change the value of a previously declared variable (let, not const) by re-assigning it another value.</li> | |
<li><strong>let</strong> is the updated version of <strong>var</strong>; there are some differences in terms of hoisting and global/block scope — will be covered later in the course (common interview question!)</li> | |
</ul> | |
<p><strong>Assignment Shorthand</strong></p> | |
<pre><code>let num = 0; | |
num += 10; // same as num = num + 10 | |
num -= 2; // same as num = num - 2 | |
num /= 4; // same as num = num / 4 | |
num *= 7; // same as num = num * 7</code></pre> | |
<ul> | |
<li>In general, any nonsensical arithmetic will result in <strong>NaN</strong> ; usually operations that include undefined.</li> | |
<li><strong>declaration</strong> : process of simply introducing a variable name.</li> | |
<li><strong>initialization</strong> : process of both declaring and assigning a variable on the same line.</li> | |
</ul> | |
<hr> | |
<h3>Functions</h3> | |
<p>A function is a procedure of code that will run when called. Functions are used so that we do not have to rewrite code to do the same thing over and over. (Think of them as ‘subprograms’)</p> | |
<ul> | |
<li><strong>Function Declaration</strong> : Process when we first initially write our function.</li> | |
<li>Includes three things:</li> | |
<li>Name of the function.</li> | |
<li>A list of <em>parameters</em> ()</li> | |
<li>The code to execute {}</li> | |
<li><strong>Function Calls</strong> : We can call upon our function whenever and wherever* we want. (*wherever is only after the initial declaration)</li> | |
<li>JS evaluates code top down, left to right.</li> | |
<li>When we execute a declared function later on in our program we refer to this as <strong>invoking</strong> our function.</li> | |
<li>Every function in JS returns undefined unless otherwise specified.</li> | |
<li>When we hit a <strong>return</strong> statement in a function we immediately exit the function and return to where we called the function.</li> | |
<li>When naming functions in JS always use camelCase and name it something appropriate. > Greate code reads like English and almost explains itself. Think: Elegant, readable, and maintainable!</li> | |
</ul> | |
<hr> | |
<h3>Parameters and Arguments</h3> | |
<ul> | |
<li><strong>Parameters</strong> : Comma seperated variables specified as part of a function’s declaration.</li> | |
<li><strong>Arguments</strong> : Values passed to the function when it is invoked.</li> | |
<li><em>If the number of arguments passed during a function invocation is different than the number of parameters listed, it will still work.</em></li> | |
<li>However, is there are not enough arguments provided for parameters our function will likely yield <strong>Nan</strong>.</li> | |
</ul> | |
<h4>Further resources:</h4> | |
<p><a href="https://replit.com/@bgoonz/lambda-prep#README.html">https://replit.com/@bgoonz/lambda-prep#README.html</a><a href="https://replit.com/@bgoonz/lambda-prep#README.html">https://replit.com/@bgoonz/lambda-prep#README.html</a><a href="https://replit.com/@bgoonz/lambda-prep#README.html">https://replit.com/@bgoonz/lambda-prep#README.html</a><a href="https://replit.com/@bgoonz/lambda-prep#README.html">https://replit.com/@bgoonz/lambda-prep#README.html</a></p> | |
<p><em>More content at <strong><a href="https://plainenglish.io/" target="_blank">plainenglish.io</a></strong></em></p> | |
</div><!-- .entry-content --> | |
<footer class="entry-footer responsive-max-width"> | |
<span class="byline"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><span class="screen-reader-text">Posted by</span><span class="author vcard"><a class="url fn n" href="https://web-dev-hub.com/author/gunerb1/">bgoonz</a></span></span><span class="posted-on"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><defs><path id="a" d="M0 0h24v24H0V0z"></path></defs><clipPath id="b"><use xlink:href="#a" overflow="visible"></use></clipPath><path clip-path="url(#b)" d="M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10 10-4.5 10-10S17.5 2 12 2zm4.2 14.2L11 13V7h1.5v5.2l4.5 2.7-.8 1.3z"></path></svg><a href="https://web-dev-hub.com/2021/04/03/the-beginners-guide-to-javascript/" rel="bookmark"><time class="entry-date published" datetime="2021-04-03T22:25:40-04:00">April 3, 2021</time><time class="updated" datetime="2021-06-11T05:03:27-04:00">June 11, 2021</time></a></span><span class="cat-links"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M10 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2h-8l-2-2z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><span class="screen-reader-text">Posted in</span><a href="https://web-dev-hub.com/category/uncategorized/" rel="category tag">Uncategorized</a></span><span class="tags-links"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M21.41 11.58l-9-9C12.05 2.22 11.55 2 11 2H4c-1.1 0-2 .9-2 2v7c0 .55.22 1.05.59 1.42l9 9c.36.36.86.58 1.41.58.55 0 1.05-.22 1.41-.59l7-7c.37-.36.59-.86.59-1.41 0-.55-.23-1.06-.59-1.42zM5.5 7C4.67 7 4 6.33 4 5.5S4.67 4 5.5 4 7 4.67 7 5.5 6.33 7 5.5 7z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><span class="screen-reader-text">Tags:</span><a href="https://web-dev-hub.com/tag/javascript/" rel="tag">Javascript</a>, <a href="https://web-dev-hub.com/tag/programming/" rel="tag">Programming</a>, <a href="https://web-dev-hub.com/tag/technology/" rel="tag">Technology</a>, <a href="https://web-dev-hub.com/tag/web-design/" rel="tag">Web Design</a>, <a href="https://web-dev-hub.com/tag/web-development/" rel="tag">Web Development</a></span><span class="comments-link"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M21.99 4c0-1.1-.89-2-1.99-2H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h14l4 4-.01-18z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><a href="https://web-dev-hub.com/2021/04/03/the-beginners-guide-to-javascript/#respond">Leave a comment<span class="screen-reader-text"> on The Beginner’s Guide To JavaScript</span></a></span><span class="edit-link"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04c.39-.39.39-1.02 0-1.41l-2.34-2.34c-.39-.39-1.02-.39-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><a class="post-edit-link" href="https://wordpress.com/post/web-dev-hub.com/578">Edit <span class="screen-reader-text">The Beginner’s Guide To JavaScript</span></a></span> </footer><!-- .entry-footer --> | |
</article><!-- #post-${ID} --> | |
<article id="post-577" class="post-577 post type-post status-publish format-standard hentry category-uncategorized tag-css tag-html tag-javascript tag-technology tag-web-development entry"> | |
<header class="entry-header responsive-max-width"> | |
<h2 class="entry-title"><a href="https://web-dev-hub.com/2021/03/28/web-developer-resource-list-part-4/" rel="bookmark">Web Developer Resource List Part 4</a></h2> </header><!-- .entry-header --> | |
<div class="entry-content"> | |
<p>A all encompassing list of tools and resources for web developers</p> | |
<figure><img data-width="1689" data-height="636" src="https://cdn-images-1.medium.com/max/1200/1*QXSlTWm23iJGGW_R4Vslug.png"></figure> | |
<h3>General resources</h3> | |
<ul> | |
<li><a href="http://devdocs.io/" target="_blank">Devdocs.io</a>: Fast, offline, and free documentation browser for developers. Search 100+ docs in one web app: HTML, CSS, JavaScript, PHP, Ruby, Python, Go, C, C++…</li> | |
<li><a href="https://devhints.io/" target="_blank">DevHints</a>: cheatsheets for many web technologies</li> | |
<li><a href="https://carbon.now.sh/?bg=rgba%28171,%20184,%20195,%201%29&t=seti&l=auto&ds=true&wc=true&wa=true&pv=32px&ph=32px&ln=false" target="_blank">Carbon</a>: use this to share images of your code in presentations etc</li> | |
<li><a href="https://badgen.net/" target="_blank">Badgen</a>:</li> | |
<li><a href="https://shields.io/" target="_blank">Shields.io</a>:</li> | |
<li>to your documentation/readmes</li> | |
<li><a href="https://github.com/k88hudson/git-flight-rules" target="_blank">Git Flight Rules</a>: A guide for astronauts (now, programmers using Git) about what to do when things go wrong.</li> | |
<li><a href="https://github.com/luruke/browser-2020" target="_blank">browser-2020</a>: Things you can do with a browser in 2020 ☕️</li> | |
</ul> | |
<h3>📦 Finding and vetting npm packages</h3> | |
<ul> | |
<li><a href="https://www.pikapkg.com/" target="_blank">pika</a>: A searchable catalog of modern “module” packages on npm</li> | |
<li><a href="https://npms.io/" target="_blank">npms</a>: A better and open source search for node packages</li> | |
<li><a href="https://github.com/maticzav/emma-cli" target="_blank">emma</a>: 📦 Terminal assistant to find and install node packages</li> | |
<li><a href="https://github.com/harksys/npmvet" target="_blank">npmvet</a>: A simple CLI tool for vetting npm package versions</li> | |
<li><a href="https://bundlephobia.com/" target="_blank">Bundlephobia</a>: See the “cost” of any npm package</li> | |
<li><a href="https://snyk.io" target="_blank">Snyk</a>: Find any security vulnerabilities for any npm package. Search their database here: <code>https://snyk.io/vuln/npm:{package}</code> e.g. <a href="https://snyk.io/vuln/npm:react" target="_blank">https://snyk.io/vuln/npm:react</a></li> | |
<li><a href="https://runpkg.com/" target="_blank">runpkg</a>: Explore, learn about and perform static analysis on npm packages in the browser</li> | |
</ul> | |
<h3>🎨 CSS</h3> | |
<ul> | |
<li><a href="https://css-tricks.com/snippets/css/a-guide-to-flexbox/" target="_blank">CSS Tricks “Complete Guide to Flexbox”</a></li> | |
<li><a href="https://css-tricks.com/snippets/css/complete-guide-grid/" target="_blank">CSS Tricks “Complete Guide to Grid”</a></li> | |
<li><a href="http://cubic-bezier.com/#.17,.67,.83,.67" target="_blank">Cubic bezier curve creator</a></li> | |
<li><a href="http://matthewlein.com/ceaser/" target="_blank">Ceaser</a>: Cubic bezier curve generator</li> | |
<li><a href="https://csstriggers.com/" target="_blank">CSS Triggers</a>: find out what CSS properties trigger Paint/Layout/Composite renders</li> | |
<li><a href="https://websemantics.uk/tools/responsive-font-calculator/" target="_blank">Fluid-responsive font-size calculator</a>: To scale typography smoothly across viewport widths.</li> | |
<li><a href="http://browserhacks.com/" target="_blank">Browserhacks</a>: Browserhacks is an extensive list of browser specific CSS and JavaScript hacks from all over the interwebs</li> | |
<li><a href="https://codepen.io/shshaw/full/gEiDt" target="_blank">Absolute centering</a>: useful techniques for absolute centering in CSS</li> | |
<li><a href="https://github.com/hankchizljaw/modern-css-reset" target="_blank">modern-css-reset</a>: A bare-bones CSS reset for modern web development</li> | |
<li><a href="https://cssfx.netlify.com/" target="_blank">CSSFX</a>: Beautifully simple click-to-copy CSS effects</li> | |
<li><a href="https://www.shapedivider.app/" target="_blank">Shape Divider App</a></li> | |
</ul> | |
<h3>CSS-in-JS</h3> | |
<ul> | |
<li>CSS-in-JS libraries</li> | |
<li><a href="https://styled-components.com" target="_blank">Styled Components</a>: CSS-in-JS for React</li> | |
<li><a href="http://emotion.sh/" target="_blank">Emotion</a>: CSS-in-JS library</li> | |
<li><a href="https://github.com/callstack/linaria" target="_blank">linaria</a>: Zero-runtime CSS in JS library</li> | |
<li><a href="https://github.com/mrmartineau/design-system-utils" target="_blank">Design System Utils</a>: Design system framework for modern front-end projects (made by me!)</li> | |
<li><a href="https://polished.js.org/" target="_blank">Polished</a>: A lightweight toolset for writing styles in JavaScript</li> | |
<li><a href="https://github.com/brunobertolini/styled-by" target="_blank">styled-by</a>: Simple and powerful lib to handle styled props in your components</li> | |
<li><a href="https://github.com/smooth-code/xstyled" target="_blank">xstyled</a>: Consistent theme based CSS for styled-components 💅</li> | |
<li><a href="https://theme-ui.com" target="_blank">Theme UI</a>: Build consistent, themeable React apps based on constraint-based design principles</li> | |
</ul> | |
<h3>JavaScript</h3> | |
<h3>Useful JS links</h3> | |
<ul> | |
<li><a href="https://stackoverflow.com/a/34842087/91359" target="_blank">JS module import/export syntax</a></li> | |
<li><a href="http://keycode.info/" target="_blank">JavaScript Event KeyCodes</a></li> | |
<li><a href="https://tylermcginnis.com/javascript-visualizer/" target="_blank">JavaScript Visualizer</a></li> | |
<li><a href="https://doesitmutate.xyz/" target="_blank">Does it mutate?</a></li> | |
<li><a href="https://jsperf.com/" target="_blank">jsPerf</a>: JavaScript performance playground</li> | |
<li><a href="https://github.com/mbeaudru/modern-js-cheatsheet" target="_blank">modern-js-cheatsheet</a></li> | |
<li><a href="https://htmldom.dev/" target="_blank">HTML DOM</a>: Common tasks of managing HTML DOM with vanilla JavaScript</li> | |
</ul> | |
<h3>Framework agnostic packages</h3> | |
<h3>General utilities</h3> | |
<ul> | |
<li><a href="https://lodash.com" target="_blank">Lodash</a>: A modern JavaScript utility library delivering modularity, performance & extras.</li> | |
<li><a href="https://github.com/angus-c/just" target="_blank">Just</a>: A library of dependency-free utilities that do just do one thing (like Lodash but smaller)</li> | |
<li>Install each util independently</li> | |
<li>Read the <a href="https://github.com/angus-c/just/blob/master/TRADEOFFS.md" target="_blank">tradeoffs document</a> to see if Lodash is better</li> | |
<li><a href="https://github.com/NickGard/tiny-get" target="_blank">tiny-get</a>: A minimal-weight lodash.get equivalent utility</li> | |
<li><a href="https://www.evt.land/" target="_blank">evt</a>: A type safe replacement for node’s EventEmitter</li> | |
<li><a href="https://github.com/nicbell/liteready" target="_blank">liteready</a>: A lightweight DOM ready.</li> | |
<li><a href="https://github.com/jaredhanson/passport" target="_blank">passport</a>: Simple, unobtrusive authentication for Node.js</li> | |
<li><a href="https://github.com/desandro/get-size" target="_blank">get-size</a>: Get the size of elements</li> | |
<li><a href="https://github.com/appalaszynski/length.js" target="_blank">length.js</a>: Library for length units conversion</li> | |
<li><a href="https://github.com/saschageyer/action-outside" target="_blank">action-outside</a>: Invoke a callback function when clicked or tabbed outside one or multiple DOM elements</li> | |
<li><a href="https://github.com/bfred-it/select-dom" target="_blank">select-dom</a>: Lightweight <code>querySelector</code>/<code>All</code> wrapper that outputs an Array</li> | |
<li><a href="https://github.com/medikoo/memoizee" target="_blank">memoizee</a>: Complete memoize/cache solution for JavaScript</li> | |
<li><a href="https://github.com/alexreardon/memoize-one" target="_blank">memoize-one</a>: A memoization library which only remembers the latest invocation</li> | |
<li><a href="https://github.com/jonschlinkert/kind-of" target="_blank">kind-of</a>: Get the native JavaScript type of a value, fast.</li> | |
<li><a href="https://github.com/felixfbecker/iterare" target="_blank">iterare</a>: Array methods + ES6 Iterators =</li> | |
<li><a href="https://github.com/Rich-Harris/eases-jsnext" target="_blank">eases-jsnext</a>: A grab-bag of modular easing equations</li> | |
<li><a href="https://github.com/paularmstrong/normalizr" target="_blank">normalizr</a>: Normalizes nested JSON according to a schema</li> | |
<li><a href="https://github.com/sindresorhus/lazy-value" target="_blank">lazy-value</a>: Create a lazily evaluated value</li> | |
<li><a href="https://github.com/planttheidea/fast-equals" target="_blank">fast-equals</a>: A blazing fast equality comparison, either shallow or deep</li> | |
<li><a href="https://github.com/planttheidea/fast-copy" target="_blank">fast-copy</a>: A blazing fast deep object copier</li> | |
<li><a href="https://github.com/stipsan/compute-scroll-into-view" target="_blank">compute-scroll-into-view</a>: Utility for calculating what should be scrolled, how it’s scrolled is up to you</li> | |
<li><a href="https://github.com/lukeed/arr" target="_blank">arr</a>: A collection of tiny, highly performant Array.prototype alternatives</li> | |
<li><a href="https://github.com/fuhton/timedstorage" target="_blank">timedstorage</a>: A library for storing and expiring objects in window.localstorage</li> | |
<li><a href="https://github.com/stevemao/left-pad" target="_blank">left-pad</a>: String left pad</li> | |
<li><a href="https://github.com/tiaanduplessis/dont-go" target="_blank">dont-go</a>: A small client-side library with zero dependencies to change the title and/or favicon of the page when it is inactive</li> | |
<li><a href="https://github.com/hybridables/always-done" target="_blank">always-done</a>: Handle completion and errors with elegance! Support for async/await, promises, callbacks, streams and observables. A drop-in replacement for async-done — pass 100% of its tests plus more</li> | |
<li><a href="https://github.com/words" target="_blank">words</a>: Linguistic javascript modules</li> | |
<li><a href="https://github.com/davidtheclark/no-scroll" target="_blank">no-scroll</a>: Disable scrolling on an element that would otherwise scroll</li> | |
<li><a href="https://github.com/catamphetamine/libphonenumber-js" target="_blank">libphonenumber-js</a>: A simpler (and smaller) rewrite of Google Android’s libphonenumber library</li> | |
<li><a href="https://github.com/text-mask/text-mask" target="_blank">text-mask</a>: Input mask for React, Angular, Ember, Vue, & plain JavaScript</li> | |
<li><a href="https://github.com/vtex/msk" target="_blank">msk</a>: Small library to mask strings</li> | |
<li><a href="https://github.com/davidtheclark/focus-trap" target="_blank">focus-trap</a>: Trap focus within a DOM node</li> | |
<li><a href="https://github.com/jamiebuilds/tinykeys" target="_blank">tinykeys</a>: A tiny (~400 B) & modern library for keybindings</li> | |
<li><a href="https://github.com/reasonink/clack" target="_blank">clack</a>: A modern keyboard shortcut library written in Typescript</li> | |
<li><a href="https://github.com/reasonink/clack-react" target="_blank">clack-react</a>: React support for @reasonink/clack</li> | |
<li><a href="https://github.com/ollieglass/js-humanize" target="_blank">js-humanize</a>: Humanize large numbers</li> | |
<li><a href="https://github.com/peterpme/sub-in" target="_blank">sub-in</a>: 🥙 A tiny (115B) find-and-replace utility for strings in Javascript</li> | |
<li><a href="https://github.com/zenozeng/color-hash" target="_blank">color-hash</a>: Generate color based on the given string (using HSL color space and BKDRHash)</li> | |
<li><a href="https://github.com/zeit/title" target="_blank">title</a>: A service for capitalizing your title properly</li> | |
<li><a href="https://github.com/aceakash/string-similarity" target="_blank">string-similarity</a>: Finds degree of similarity between two strings, based on Dice’s Coefficient, which is mostly better than Levenshtein distance</li> | |
<li><a href="https://github.com/ericelliott/cuid" target="_blank">cuid</a>: Collision-resistant ids optimized for horizontal scaling and performance</li> | |
<li><a href="https://github.com/lukeed/obj-str" target="_blank">obj-str</a>: A tiny (96B) library for serializing Object values to Strings. Also serves as a faster & smaller drop-in replacement for the classnames module</li> | |
<li><a href="https://github.com/lukeed/clsx" target="_blank">clsx</a>: A tiny (223B) utility for constructing className strings conditionally. Also serves as a faster & smaller drop-in replacement for the classnames module</li> | |
<li><a href="https://xstate.js.org/docs" target="_blank">xstate</a>: State machines and statecharts for the modern web</li> | |
<li><a href="https://github.com/onury/tasktimer" target="_blank">tasktimer</a>: An accurate timer utility for running periodic tasks on the given interval ticks or dates. (Node and Browser)</li> | |
<li><a href="https://github.com/rough-stuff/rough-notation" target="_blank">rough-notation</a>: Create and animate hand-drawn annotations on a web page</li> | |
</ul> | |
<h3>Async</h3> | |
<ul> | |
<li><a href="https://github.com/axios/axios" target="_blank">axios</a>: Promise based HTTP client for the browser and node.js</li> | |
<li><a href="https://github.com/softonic/axios-retry" target="_blank">axios-retry</a>: Axios plugin that intercepts failed requests and retries them whenever possible</li> | |
<li><a href="https://github.com/developit/redaxios" target="_blank">redaxios</a>: The Axios API, as an 800 byte Fetch wrapper</li> | |
<li><a href="https://github.com/lquixada/cross-fetch" target="_blank">cross-fetch</a>: Universal WHATWG Fetch API for Node, Browsers and React Native</li> | |
<li><a href="https://github.com/asfktz/Awaity.js" target="_blank">awaity</a>: A functional, lightweight alternative to bluebird.js, built with <code>async</code> / <code>await</code> in mind</li> | |
<li><a href="https://github.com/muicss/loadjs" target="_blank">loadjs</a>: A tiny async loader / dependency manager for modern browsers (789 bytes)</li> | |
<li><a href="https://github.com/scopsy/await-to-js" target="_blank">await-to-js</a>: Async await wrapper for easy error handling without try-catch</li> | |
</ul> | |
<h3>Node</h3> | |
<ul> | |
<li><a href="https://www.fastify.io/" target="_blank">Fastify</a>: Fast and low overhead web framework, for Node.js</li> | |
<li><a href="https://expressjs.com" target="_blank">Express</a></li> | |
<li><a href="https://github.com/helmetjs/helmet" target="_blank">helmet</a>: Help secure Express apps with various HTTP headers</li> | |
<li><a href="https://github.com/antongolub/reqresnext" target="_blank">reqresnext</a>: Tiny helper for express middleware testing</li> | |
<li><a href="https://github.com/krakenjs/lusca" target="_blank">lusca</a>: Application security for express apps</li> | |
<li><a href="https://github.com/expressjs/cookie-session" target="_blank">cookie-session</a>: Simple cookie-based session middleware</li> | |
<li><a href="https://github.com/i0natan/nodebestpractices" target="_blank">nodebestpractices</a>: The largest Node.JS best practices list. Curated from the top ranked articles and always updated</li> | |
<li><a href="https://github.com/zeeshanu/dumper.js" target="_blank">dumper.js</a>: A better and pretty variable inspector for your Node.js applications</li> | |
<li><a href="https://github.com/gajus/http-terminator" target="_blank">http-terminator</a>: Gracefully terminates HTTP(S) server</li> | |
<li><a href="https://github.com/uuidjs/uuid" target="_blank">uuid</a>: Generate RFC-compliant UUIDs in JavaScript</li> | |
<li><a href="https://github.com/jshttp/http-errors" target="_blank">http-errors</a>: Create HTTP Errors</li> | |
<li><a href="https://github.com/hapijs/boom" target="_blank">boom</a>: HTTP-friendly error objects</li> | |
<li><a href="https://github.com/denoland/deno" target="_blank">deno</a>: A secure JavaScript and TypeScript runtime</li> | |
<li><a href="https://github.com/micromatch/nanomatch" target="_blank">nanomatch</a>: Fast, minimal glob matcher for node.js. Similar to micromatch, minimatch and multimatch, but without support for extended globs (extglobs), posix brackets or braces, and with complete Bash 4.3 wildcard support: (“*”, “**”, and “?”)</li> | |
<li><a href="https://github.com/sindresorhus/yn" target="_blank">yn</a>: Parse yes/no like values</li> | |
<li><a href="https://github.com/AvianFlu/ncp" target="_blank">ncp</a>: Asynchronous recursive file copying with Node.js</li> | |
</ul> | |
<h4>Logging</h4> | |
<ul> | |
<li><a href="https://github.com/pinojs/pino" target="_blank">pino</a>: 🌲 super fast, all natural json logger 🌲</li> | |
<li><a href="https://github.com/bevry/caterpillar" target="_blank">caterpillar</a>: Caterpillar is the ultimate logging system for Deno, Node.js, and Web Browsers</li> | |
<li><a href="https://github.com/cabinjs/cabin" target="_blank">cabin</a>: Cabin is the best JavaScript and Node.js logging service and logging npm package</li> | |
</ul> | |
<h3>Responsive</h3> | |
<ul> | |
<li><a href="https://github.com/pauldijou/responsive-watch" target="_blank">responsive-watch</a>: Watch some media queries and react when they change</li> | |
<li><a href="https://github.com/robb0wen/tornis" target="_blank">tornis</a>: Tornis helps you watch and respond to changes in your browser’s viewport 🌲</li> | |
<li><a href="https://github.com/ryanve/actual" target="_blank">actual</a>: Determine actual CSS media query breakpoints via JavaScript</li> | |
</ul> | |
<h3>Media and Images</h3> | |
<ul> | |
<li><a href="https://github.com/awcross/images-loaded" target="_blank">images-loaded</a>: Wait for images to load using promises. No dependencies.</li> | |
<li><a href="https://github.com/aFarkas/lazysizes" target="_blank">lazysizes</a>: High performance and SEO friendly lazy loader for images (responsive and normal), iframes and more, that detects any visibility changes triggered through user interaction, CSS or JavaScript without configuration.</li> | |
</ul> | |
<h4>Image services</h4> | |
<ul> | |
<li><a href="https://github.com/lovell/sharp" target="_blank">sharp</a>: High performance Node.js image processing, the fastest module to resize JPEG, PNG, WebP and TIFF images. Uses the libvips library.</li> | |
<li><a href="https://www.imgix.com/" target="_blank">IMGIX</a>: Real-time image processing and image CDN</li> | |
</ul> | |
<h3>Date</h3> | |
<ul> | |
<li><a href="https://date-fns.org/" target="_blank">date-fns</a>: Modern JavaScript date utility library</li> | |
<li><a href="https://github.com/lukeed/tinydate" target="_blank">tinydate</a>: A tiny (337B) reusable date formatter. Extremely fast!</li> | |
<li><a href="https://github.com/aweary/tinytime" target="_blank">tinytime</a>: ⏰ A straightforward date and time formatter in <1kb</li> | |
</ul> | |
<h3>Scrolling</h3> | |
<ul> | |
<li><a href="https://github.com/jonataswalker/scroll-watcher" target="_blank">scroll-watcher</a></li> | |
<li><a href="https://github.com/dollarshaveclub/scrolldir" target="_blank">scrolldir</a>: Leverage Vertical Scroll Direction with CSS</li> | |
</ul> | |
<h3>Carousels</h3> | |
<ul> | |
<li><a href="https://flickity.metafizzy.co/" target="_blank">Flickity</a></li> | |
<li><a href="http://idangero.us/swiper/" target="_blank">Swiper</a></li> | |
</ul> | |
<h3>Animation</h3> | |
<ul> | |
<li><a href="https://github.com/Rich-Harris/ramjet" target="_blank">ramjet</a>: Morph DOM elements from one state to another with smooth animations and transitions</li> | |
<li><a href="https://github.com/juliangarnier/anime" target="_blank">anime</a>: JavaScript Animation Engine</li> | |
<li><a href="https://greensock.com/" target="_blank">GSAP</a>:the standard for JavaScript HTML5 animation | GreenSock</li> | |
<li><a href="https://micku7zu.github.io/vanilla-tilt.js/index.html" target="_blank">Vanilla-tilt.js</a>: A smooth 3D tilt javascript library forked from Tilt.js</li> | |
</ul> | |
<h3>Web workers</h3> | |
<ul> | |
<li><a href="https://github.com/developit/workerize" target="_blank">workerize</a>: Run a module in a Web Worker</li> | |
<li><a href="https://github.com/developit/greenlet" target="_blank">greenlet</a>: Move an async function into its own thread. A simplified single-function version of workerize.</li> | |
</ul> | |
<h3>Immutable</h3> | |
<ul> | |
<li><a href="https://github.com/mweststrate/immer" target="_blank">immer</a>: Create the next immutable state tree by simply modifying the current tree</li> | |
<li><a href="https://github.com/immerjs/use-immer" target="_blank">use-immer</a>: Use immer to drive state with a React hooks</li> | |
<li><a href="https://github.com/planttheidea/unchanged" target="_blank">unchanged</a>: A tiny, fast, unopinionated handler for updating JS objects and arrays immutably</li> | |
<li><a href="https://github.com/rtfeldman/seamless-immutable" target="_blank">seamless-immutable</a>: Immutable data structures for JavaScript which are backwards-compatible with normal JS Arrays and Objectsseamless-immutable`</li> | |
<li><a href="https://github.com/jaredpalmer/mutik" target="_blank">mutik</a>: A tiny (495B) immutable state management library based on Immer</li> | |
</ul> | |
<h3>Typography</h3> | |
<ul> | |
<li><a href="https://github.com/rikschennink/fitty" target="_blank">fitty</a>: Makes text fit perfectly</li> | |
</ul> | |
<h3>Polyfills</h3> | |
<ul> | |
<li><a href="https://github.com/que-etc/resize-observer-polyfill" target="_blank">resize-observer-polyfill</a>:A polyfill for the Resize Observer API</li> | |
</ul> | |
<h3>⚛️ React</h3> | |
<p><a href="https://reactjs.org" target="_blank">reactjs.org</a></p> | |
<ul> | |
<li><a href="https://github.com/facebook/create-react-app" target="_blank">create-react-app</a>: Create React apps with no build configuration</li> | |
<li><a href="https://github.com/timarney/react-app-rewired" target="_blank">react-app-rewired</a>: Override create-react-app webpack configs without ejecting</li> | |
<li><a href="https://github.com/vasanthk/react-bits" target="_blank">react-bits</a>: ✨ React patterns, techniques, tips and tricks ✨</li> | |
</ul> | |
<h3>React-specific libs:</h3> | |
<ul> | |
<li><a href="https://github.com/renatorib/react-powerplug" target="_blank">react-powerplug</a>: Renderless Containers</li> | |
<li><a href="https://github.com/jaredpalmer/formik" target="_blank">formik</a>: Build forms in React, without the tears 😭</li> | |
<li><a href="https://github.com/ReactTraining/react-router" target="_blank">react-router</a>: Declarative routing for React</li> | |
<li><a href="https://reach.tech/router" target="_blank">Reach Router</a></li> | |
<li><a href="https://react-fns.netlify.com/" target="_blank">react-fns</a>: React Components for common Web APIs</li> | |
<li><a href="https://github.com/tajo/react-portal" target="_blank">react-portal</a>: React component for transportation of modals, lightboxes, loading bars… to document.body</li> | |
<li><a href="https://github.com/stereobooster/react-ideal-image" target="_blank">react-ideal-image</a>: 🖼️ An Almost Ideal React Image Component</li> | |
<li><a href="https://github.com/pedronauck/react-adopt" target="_blank">react-adopt</a>: Compose render props components like a pro</li> | |
<li><a href="https://github.com/paypal/downshift" target="_blank">downshift</a></li> | |
<li><a href="https://github.com/jamiebuilds/react-loadable" target="_blank">react-loadable</a>: A higher order component for loading components with promises</li> | |
<li><a href="https://github.com/tajo/react-portal" target="_blank">react-portal</a>: React component for transportation of modals, lightboxes, loading bars… to document.body</li> | |
<li><a href="https://github.com/lingui/js-lingui" target="_blank">js-lingui: 🌍📖</a>: A readable, automated, and optimized (5 kb) internationalization (Intl / i18n) for JavaScript</li> | |
<li><a href="https://github.com/u-wave/react-mq" target="_blank">react-mq</a>: Barebones CSS media query component for React, ~560 bytes</li> | |
<li><a href="https://github.com/ReactTraining/react-media" target="_blank">react-media</a>: CSS media queries for React. This is SSR compatible as well.</li> | |
<li><a href="https://github.com/andrewbranch/merge-props" target="_blank">merge-props</a>: Merges className, style, and event handler props for React elements</li> | |
<li><a href="https://github.com/thearnica/react-uid" target="_blank">react-uid</a>: Render-less container for generating UID for a11y, consistent react key, and any other good reason 🦄</li> | |
<li><a href="https://github.com/lukeed/clsx" target="_blank">clsx</a>: A tiny (229B) utility for constructing <code>className</code> strings conditionally</li> | |
<li><a href="https://www.framer.com/motion/" target="_blank">Framer Motion</a>: An open source React library to power production-ready animations. Design fluid animations for the web, across desktop and mobile</li> | |
<li><a href="https://github.com/dequelabs/react-axe" target="_blank">react-axe</a>: Accessibility auditing for React.js applications</li> | |
<li><a href="https://github.com/geobde/use-click-away" target="_blank">use-click-away</a>: React hook to detect click or touch events outside an element</li> | |
<li><a href="https://github.com/clauderic/react-tiny-virtual-list" target="_blank">react-tiny-virtual-list</a>: A tiny but mighty 3kb list virtualization library, with zero dependencies 💪 Supports variable heights/widths, sticky items, scrolling to index, and more!</li> | |
<li><a href="https://github.com/everweij/react-laag" target="_blank">react-laag</a>: Primitives to build things like tooltips, dropdown menu’s and popovers in React</li> | |
<li><a href="https://github.com/react-dnd/react-dnd" target="_blank">react-dnd</a>: Drag and Drop for React</li> | |
</ul> | |
<h4>React Hooks</h4> | |
<ul> | |
<li><a href="https://github.com/zeit/swr" target="_blank">swr</a>: React Hooks library for remote data fetching</li> | |
<li><a href="https://www.hooks.guide/" target="_blank">Hooks.Guide</a>: Collection of React hooks curated by the community</li> | |
<li><a href="https://usehooks.com/" target="_blank">useHooks</a>: Easy to understand React Hook recipes</li> | |
<li><a href="https://github.com/beautifulinteractions/beautiful-react-hooks" target="_blank">beautiful-react-hooks</a>: 🔥A collection of beautiful and (hopefully) useful React hooks to speed-up your components and hooks development 🔥</li> | |
<li><a href="https://github.com/GoogleChromeLabs/react-adaptive-hooks" target="_blank">react-adaptive-hooks</a>: Deliver experiences best suited to a user’s device and network constraints</li> | |
</ul> | |
<h3>State management</h3> | |
<ul> | |
<li><a href="https://github.com/react-spring/zustand" target="_blank">zustand</a>: 🐻 Bear necessities for state management in React</li> | |
<li><a href="https://github.com/reduxjs/redux" target="_blank">redux</a>: Predictable state container for JavaScript apps</li> | |
<li><a href="https://github.com/reduxjs/reselect" target="_blank">reselect</a>: Selector library for Redux</li> | |
<li><a href="https://github.com/redux-saga/redux-saga" target="_blank">redux-saga</a>: An alternative side effect model for Redux apps</li> | |
<li><a href="https://github.com/afitiskin/redux-saga-routines" target="_blank">redux-saga-routines</a>: Routines for redux-saga</li> | |
<li><a href="https://github.com/reduxjs/redux-thunk" target="_blank">redux-thunk</a>: Thunk middleware for Redux</li> | |
<li><a href="https://github.com/brillout/awesome-redux" target="_blank">awesome-redux</a>: Catalog of Redux Libraries & Learning Material</li> | |
<li><a href="https://github.com/ForsakenHarmony/parket" target="_blank">parket</a>: A library to manage application state, heavily inspired by mobx-state-tree</li> | |
<li><a href="https://github.com/jamiebuilds/unstated" target="_blank">unstated</a>: State so simple, it goes without saying</li> | |
<li><a href="https://github.com/zhujinxuan/mergeState" target="_blank">mergeState</a>: How to Stop Worrying and Use Nested Object/Array in React/Redux States</li> | |
<li><a href="https://github.com/zerobias/effector" target="_blank">effector</a>: The state manager ☄️</li> | |
<li><a href="https://github.com/facebookexperimental/Recoil" target="_blank">Recoil</a>: Recoil is an experimental state management library for React apps. It provides several capabilities that are difficult to achieve with React alone, while being compatible with the newest features of React.</li> | |
</ul> | |
<h3>Server-rendered React</h3> | |
<ul> | |
<li><a href="https://nextjs.org/" target="_blank">Next.js</a> (<a href="https://github.com/zeit/next.js" target="_blank">repo</a>): — Framework for server-rendered or statically-exported React apps</li> | |
<li><a href="https://github.com/zeit/next-plugins" target="_blank">next-plugins</a></li> | |
</ul> | |
<h3>Static site generators</h3> | |
<ul> | |
<li><a href="https://www.gatsbyjs.org/" target="_blank">Gatsby</a>: Blazing fast static site generator for React</li> | |
</ul> | |
<h3>Microservices/Serverless</h3> | |
<ul> | |
<li><a href="https://github.com/zeit/micro" target="_blank">micro</a></li> | |
<li><a href="https://github.com/amio/awesome-micro" target="_blank">awesome-micro</a></li> | |
</ul> | |
<h3>TypeScript</h3> | |
<p><a href="https://www.typescriptlang.org/" target="_blank">typescriptlang.org</a></p> | |
<ul> | |
<li><a href="https://github.com/Microsoft/TypeScript/wiki/What%27s-new-in-TypeScript" target="_blank">What’s new in TypeScript</a>: Microsoft/TypeScript Wiki</li> | |
<li><a href="https://basarat.gitbooks.io/typescript/" target="_blank">TypeScript Deep Dive</a></li> | |
<li><a href="https://blog.mariusschulz.com/series/typescript-evolution" target="_blank">TypeScript Evolution</a></li> | |
<li><a href="https://transform.now.sh/json-to-ts-interface/" target="_blank">JSON to Typescript Interface</a></li> | |
<li><a href="https://github.com/sw-yx/react-typescript-cheatsheet" target="_blank">react-typescript-cheatsheet</a>: a cheatsheet for react users using typescript with react for the first (or nth!) time</li> | |
<li><a href="https://github.com/labs42io/clean-code-typescript" target="_blank">clean-code-typescript</a>: Clean Code concepts adapted for TypeScript</li> | |
</ul> | |
<h3>Command Line, Terminal and shells</h3> | |
<p><a href="https://fishshell.com/" target="_blank">Fish shell</a>: The user-friendly command line shell</p> | |
<ul> | |
<li><a href="https://github.com/mrmartineau/fish" target="_blank">My fish_config</a></li> | |
<li><a href="https://github.com/jorgebucaran/awesome-fish" target="_blank">awesome-fish</a>: A curated list of packages, prompts, and resources for the amazing fish shell</li> | |
<li><a href="https://starship.rs/" target="_blank">Starship</a>: Cross-Shell Prompt</li> | |
<li><a href="https://github.com/IlanCosman/tide" target="_blank">tide</a>: 🌊 A modern prompt manager for the Fish shell</li> | |
</ul> | |
<h3>Creating CLI apps</h3> | |
<ul> | |
<li><a href="https://github.com/infinitered/gluegun" target="_blank">gluegun</a>: A delightful toolkit for building Node-powered CLIs</li> | |
<li><a href="https://github.com/SBoudrias/Inquirer.js" target="_blank">inquirer</a>: A collection of common interactive command line user interfaces</li> | |
<li><a href="https://github.com/tj/commander.js" target="_blank">commander</a>: node.js command-line interfaces made easy</li> | |
<li><a href="https://github.com/lukeed/sade" target="_blank">sade</a>: Sade is a small but powerful tool for building command-line interface (CLI) applications for Node.js that are fast, responsive, and helpful!</li> | |
</ul> | |
<h3>CLI apps</h3> | |
<ul> | |
<li><a href="https://hub.github.com/" target="_blank">hub</a>: hub is an extension to command-line git that helps you do everyday GitHub tasks without ever leaving the terminal</li> | |
<li><a href="https://github.com/zeit/serve" target="_blank">serve</a>: Static file serving and directory listing</li> | |
<li><a href="https://github.com/agarrharr/awesome-cli-apps" target="_blank">awesome-cli-apps</a>: A curated list of command line apps</li> | |
<li><a href="https://github.com/SpaceVim/SpaceVim" target="_blank">SpaceVim</a>: A community-driven modular vim distribution — The ultimate vim configuration</li> | |
</ul> | |
<h3>Tooling</h3> | |
<h3>Code bundlers</h3> | |
<ul> | |
<li><a href="https://github.com/preconstruct/preconstruct" target="_blank">preconstruct</a>: 🎁 Dev and build your code painlessly in monorepos</li> | |
<li><a href="https://webpack.js.org/" target="_blank">Webpack</a>: script/asset bundler</li> | |
<li><a href="https://github.com/mrmartineau/webpack-recipes" target="_blank">Webpack recipes</a></li> | |
<li><a href="https://github.com/nippur72/ifdef-loader" target="_blank">ifdef-loader</a>: Webpack loader for JavaScript/TypeScript conditional compilation</li> | |
<li><a href="https://parceljs.org/" target="_blank">Parcel</a>: Blazing fast, zero configuration web application bundler</li> | |
<li><a href="https://github.com/developit/microbundle" target="_blank">microbundle</a>: Zero-configuration bundler for tiny modules</li> | |
<li><a href="https://rollupjs.org/guide/en" target="_blank">rollup.js</a>: Rollup is a module bundler for JavaScript</li> | |
<li><a href="https://github.com/zeit/ncc" target="_blank">ncc</a>: Node.js Compiler Collection. Simple CLI for compiling a Node.js module into a single file, together with all its dependencies, gcc-style.</li> | |
<li><a href="https://github.com/fastpack/fastpack" target="_blank">fastpack</a>: Pack JS code into a single bundle fast & easy</li> | |
</ul> | |
<h3>Package management and publishing</h3> | |
<ul> | |
<li><a href="https://github.com/sindresorhus/np" target="_blank">np</a>: A better <code>npm publish</code></li> | |
<li><a href="https://github.com/ai/size-limit" target="_blank">size-limit</a>: Prevent JS libraries bloat. If you accidentally add a massive dependency, Size Limit will throw an error</li> | |
<li><a href="https://github.com/siddharthkp/bundlesize" target="_blank">bundlesize</a>: Keep your bundle size in check</li> | |
<li><a href="https://github.com/kentcdodds/nps" target="_blank">nps</a>: All the benefits of npm scripts without the cost of a bloated package.json and limits of json</li> | |
<li><a href="https://dependabot.com/" target="_blank">Dependabot</a>: Dependabot creates pull requests to keep your dependencies secure and up-to-date</li> | |
<li><a href="https://github.com/npm/npm/blob/1fa9169ac9687f0be4156574279a968a48dd2458/doc/misc/npm-config.md" target="_blank">npm-config</a> (docs): More than you probably want to know about npm configuration</li> | |
<li><a href="https://github.com/ds300/patch-package" target="_blank">patch-package</a>: Fix broken node modules with no fuss 📦👌</li> | |
<li><a href="https://github.com/pahen/madge" target="_blank">madge</a>: Create graphs from your CommonJS, AMD or ES6 module dependencies</li> | |
</ul> | |
<h3>Commit hooks</h3> | |
<ul> | |
<li><a href="https://github.com/Arkweid/lefthook" target="_blank">lefthook</a>: Fast and powerful Git hooks manager for any type of projects</li> | |
<li><a href="https://github.com/typicode/husky" target="_blank">husky</a>: Git hooks made easy</li> | |
<li><a href="https://github.com/okonet/lint-staged" target="_blank">lint-staged: 🚫💩</a>: Run linters on git staged files</li> | |
<li><a href="https://github.com/Arkweid/lefthook" target="_blank">lefthook</a>: Fast and powerful Git hooks manager for any type of projects</li> | |
</ul> | |
<h3>Testing</h3> | |
<ul> | |
<li><a href="https://facebook.github.io/jest/" target="_blank">Jest</a>: Delightful JavaScript Testing</li> | |
<li><a href="https://github.com/Raathigesh/majestic" target="_blank">majestic</a>: Zero config UI for Jest</li> | |
<li><a href="https://github.com/mattphillips/jest-chain" target="_blank">jest-chain</a>: Chain Jest matchers together to create one powerful assertion 🃏⛓</li> | |
<li><a href="https://github.com/jest-community/jest-extended" target="_blank">jest-extended</a>: — Additional Jest matchers 🃏💪</li> | |
<li><a href="https://github.com/jest-community/snapshot-diff" target="_blank">snapshot-diff</a>: Diffing snapshot utility for Jest</li> | |
<li><a href="https://github.com/hustcc/jest-date-mock" target="_blank">jest-date-mock</a>: 🌗 Mock <code>Date</code> when run unit test cases with jest. Make tests of Date easier</li> | |
<li><a href="https://cypress.io" target="_blank">Cypress</a>: end-to-end testing</li> | |
<li><a href="https://github.com/kentcdodds/cypress-testing-library" target="_blank">cypress-testing-library</a>: 🐅 Simple and complete custom Cypress commands and utilities that encourage good testing practices</li> | |
<li><a href="https://github.com/avanslaars/cypress-axe" target="_blank">cypress-axe</a>: Custom commands for Cypress to run a11y checks with axe-core</li> | |
<li><a href="https://github.com/bahmutov/start-server-and-test" target="_blank">start-server-and-test</a>: — Starts server, waits for URL, then runs test command; when the tests end, shuts down server</li> | |
<li><a href="https://github.com/kentcdodds/dom-testing-library" target="_blank">dom-testing-library</a>: 🐙 Simple and complete DOM testing utilities that encourage good testing practices</li> | |
<li><a href="https://github.com/testing-library/react-testing-library" target="_blank">react-testing-library 🐐</a>: Simple and complete React DOM testing utilities that encourage good testing practices</li> | |
<li><a href="https://react-testing-examples.com/" target="_blank">react-testing-library</a>: React Testing Examples</li> | |
<li><a href="https://github.com/testing-library/react-hooks-testing-library" target="_blank">react-hooks-testing-library</a>: 🐏 Simple and complete React hooks testing utilities that encourage good testing practices</li> | |
<li><a href="https://github.com/chancejs/chancejs" target="_blank">Chance</a>: Random generator helper for JavaScript</li> | |
<li><a href="https://github.com/Marak/faker.js" target="_blank">faker.js</a>: generate massive amounts of fake data in Node.js and the browser</li> | |
<li><a href="https://github.com/nock/nock" target="_blank">nock</a>: HTTP server mocking and expectations library for Node.js</li> | |
<li><a href="http://stryker-mutator.io/" target="_blank">Stryker Mutator</a></li> | |
<li><a href="https://github.com/tatyshev/given2" target="_blank">given2</a>: Lazy variable evaluation for Jasmine, Mocha, Jest specs, inspired by Ruby and Rspec 💎</li> | |
<li><a href="https://github.com/caderek/benny" target="_blank">benny</a>: A dead simple benchmarking framework for JS/TS libs</li> | |
<li><a href="https://github.com/bestiejs/benchmark.js" target="_blank">benchmark.js</a>: A benchmarking library. As used on <a href="http://jsPerf.com" target="_blank">jsPerf.com</a></li> | |
<li><a href="https://github.com/NoriSte/ui-testing-best-practices" target="_blank">ui-testing-best-practices</a>: The largest UI testing best practices list (lat update: April 2020) (work in progress)</li> | |
</ul> | |
<h3>Code formatting and linting</h3> | |
<ul> | |
<li><a href="https://prettier.io/" target="_blank">Prettier</a></li> | |
<li><a href="https://github.com/nrwl/precise-commits" target="_blank">precise-commits</a>: Painlessly apply Prettier by only formatting lines you have modified anyway!</li> | |
<li><a href="https://github.com/azz/pretty-quick" target="_blank">pretty-quick</a>: Runs Prettier on your changed files</li> | |
<li><a href="https://eslint.org" target="_blank">Eslint</a></li> | |
<li><a href="https://github.com/prettier/eslint-plugin-prettier" target="_blank">eslint-plugin-prettier</a>: ESLint plugin for prettier formatting</li> | |
<li><a href="https://github.com/prettier/eslint-config-prettier" target="_blank">eslint-config-prettier</a>: Turns off all rules that are unnecessary or might conflict with Prettier</li> | |
<li><a href="https://github.com/yannickcr/eslint-plugin-react" target="_blank">eslint-plugin-react</a>: — React specific linting rules for ESLint</li> | |
</ul> | |
<h3>Miscellaneous</h3> | |
<ul> | |
<li><a href="https://github.com/mysticatea/npm-run-all" target="_blank">npm-run-all</a>: A CLI tool to run multiple npm-scripts in parallel or sequential</li> | |
<li><a href="https://github.com/milewski/cross-port-killer" target="_blank">cross-port-killer</a>: Kill the process running on a given TCP port on Windows, Linux and Mac</li> | |
<li><a href="https://github.com/tabrindle/envinfo" target="_blank">envinfo</a>: Generate a report about your development environment for debugging and issue reporting</li> | |
<li><a href="https://github.com/FiloSottile/mkcert" target="_blank">mkcert</a>: A simple zero-config tool to make locally trusted development certificates with any names you’d like</li> | |
</ul> | |
<h3>Progressive Web Apps</h3> | |
<ul> | |
<li><a href="https://developers.google.com/web/tools/workbox/" target="_blank">Workbox</a> & (<a href="https://github.com/GoogleChrome/workbox" target="_blank">repo</a>): JavaScript libraries for Progressive Web Apps</li> | |
</ul> | |
<h3>Code Sandboxes</h3> | |
<ul> | |
<li><a href="https://codesandbox.io/" target="_blank">CodeSandbox</a>: CodeSandbox is perfect for React demo apps</li> | |
<li><a href="http://codepen.io/" target="_blank">Codepen</a>: Codepen is perfect for non-React front-end demos and prototypes</li> | |
<li><a href="http://codeshare.io/" target="_blank">CodeShare</a>: Codeshare is useful for collaborating on a single file if devs are not in the same room</li> | |
<li><a href="https://glitch.com/" target="_blank">Glitch</a></li> | |
</ul> | |
<h3>APIs</h3> | |
<ul> | |
<li><a href="https://www.getpostman.com/" target="_blank">Postman</a>: used to develop, test and monitor APIs</li> | |
<li><a href="http://www.mockapi.io/" target="_blank">MockAPI</a>: create a mock API</li> | |
<li><a href="https://jsonbin.org/" target="_blank">jsonbin</a>: A personal JSON store as a RESTful service</li> | |
<li><a href="http://www.test-cors.org/" target="_blank">test-cors.org</a></li> | |
<li><a href="https://reqres.in/" target="_blank">Reqres</a>: A hosted REST-API ready to respond to your AJAX requests</li> | |
<li><a href="https://miragejs.com/" target="_blank">Mirage JS</a>: An API mocking library for frontend developers</li> | |
<li><a href="https://postwoman.io/" target="_blank">Postwoman</a>: API request builder</li> | |
</ul> | |
<h3>GraphQL</h3> | |
<ul> | |
<li><a href="https://www.graphqlbin.com" target="_blank">GraphQL Playground</a></li> | |
<li><a href="https://www.apollographql.com/" target="_blank">Apollo GraphQL</a>: Apollo Data Graph Platform — unify APIs, microservices, and databases into a data graph that you can query with GraphQL</li> | |
<li><a href="https://www.apollographql.com/docs/react/" target="_blank">Apollo Client (React)</a>: Apollo React GraphQL Docs</li> | |
<li><a href="https://github.com/Saeris/graphql-directives" target="_blank">graphql-directives</a>: 🧭 A collection of custom GraphQL Schema Directives for use with Apollo Server</li> | |
<li><a href="https://github.com/FormidableLabs/urql" target="_blank">urql</a>: The highly customizable and versatile GraphQL client</li> | |
<li><a href="https://github.com/APIs-guru/graphql-lodash" target="_blank">graphql-lodash</a>: 🛠 Data manipulation for GraphQL queries with lodash syntax</li> | |
</ul> | |
<h3>JSON</h3> | |
<ul> | |
<li><a href="https://next.json-generator.com/" target="_blank">JSON generator</a>: generate a lot of custom JSON for your app/site</li> | |
<li><a href="https://jsoneditoronline.org/" target="_blank">JSON Editor Online</a>: view/edit JSON in a better format</li> | |
<li><a href="https://github.com/antonmedv/fx" target="_blank">fx</a>: Command-line tool and terminal JSON viewer 🔥</li> | |
</ul> | |
<h3>HTML</h3> | |
<ul> | |
<li><a href="https://github.com/joshbuchea/HEAD" target="_blank">github.com/joshbuchea/HEAD</a>: the definitive resource for everything that <em>could</em> go in the head of your document</li> | |
<li><a href="https://metatags.io/" target="_blank">MetaTags.io</a>: Preview, Edit and Generate</li> | |
<li><a href="https://www.heymeta.com/" target="_blank">HEY META</a>: Website Meta Tag Check</li> | |
<li><a href="https://richpreview.com/" target="_blank">Rich Link Preview</a></li> | |
</ul> | |
<h3>SVG</h3> | |
<ul> | |
<li><a href="https://svgontheweb.com/" target="_blank">A Practical Guide to SVGs on the web</a></li> | |
<li><a href="https://getwaves.io/" target="_blank">Get Waves</a>: Create SVG waves for your next design</li> | |
<li><a href="https://www.blobmaker.app/" target="_blank">Blobmaker</a>: Make organic SVG shapes for your next design</li> | |
<li><a href="https://github.com/veltman/flubber" target="_blank">flubber</a>: Tools for smoother shape animations</li> | |
<li><a href="http://www.heropatterns.com/" target="_blank">Hero Patterns</a>: Free repeatable SVG background patterns for your web projects</li> | |
</ul> | |
<h3>Icons</h3> | |
<ul> | |
<li><a href="https://iconsvg.xyz/" target="_blank">ICONSVG</a>: Quick customizable SVG icons for your project</li> | |
<li><a href="https://simpleicons.org/" target="_blank">Simple Icons</a></li> | |
<li><a href="https://react-icons.github.io/react-icons/#/" target="_blank">React Icons</a></li> | |
<li><a href="https://evil-icons.io/" target="_blank">Evil Icons</a></li> | |
<li><a href="https://icomoon.io/" target="_blank">Icon Font & SVG Icon Sets ❍ IcoMoon</a></li> | |
<li><a href="https://svgporn.com/" target="_blank">SVG PORN</a></li> | |
<li><a href="https://feathericons.com/" target="_blank">Feather</a>: Simply beautiful open source icons</li> | |
<li><a href="https://github.com/feathericons/react-feather" target="_blank">react-feather</a>: React component for Feather icons</li> | |
<li><a href="https://systemuicons.com/" target="_blank">System UIcons</a></li> | |
</ul> | |
<h3>SVG/Image Media compression</h3> | |
<ul> | |
<li><a href="https://squoosh.app/" target="_blank">Squoosh</a></li> | |
<li><a href="https://jakearchibald.github.io/svgomg/" target="_blank">SVGOMG</a>: SVGO’s Missing GUI</li> | |
</ul> | |
<h3>Conversions and unicode</h3> | |
<ul> | |
<li><a href="https://transform.now.sh/" target="_blank">Transform</a>: All important transforms at one place ⭐️⭐️⭐️ this is so useful</li> | |
<li><a href="https://svgr.now.sh/" target="_blank">SVGR</a>: The SVG to JSX transformer</li> | |
<li><a href="https://svg2jsx.herokuapp.com/" target="_blank">svg2jsx</a></li> | |
<li><a href="https://json-to-js.com/" target="_blank">JSON to JavaScript object literal</a></li> | |
<li><a href="https://unminify.com/" target="_blank">Unminify JS, CSS and HTML Code</a></li> | |
<li><a href="https://encoder.internetwache.org/#tab_uni" target="_blank">Multi-Encoder</a></li> | |
<li><a href="https://r12a.github.io/app-conversion/" target="_blank">Unicode code converter</a></li> | |
</ul> | |
<h3>Features and feature detection</h3> | |
<ul> | |
<li><a href="https://caniuse.com/" target="_blank">Can I Use…</a>: Browser support tables for modern web technologies (HTML5, CSS3, JavaScript etc)</li> | |
<li><a href="http://kangax.github.io/compat-table/es6/" target="_blank">Kangax JavaScript compatibility table</a></li> | |
</ul> | |
<h3>Performance</h3> | |
<ul> | |
<li><a href="https://bundlephobia.com/" target="_blank">Bundlephobia</a>: find the cost of adding a npm package to your bundle</li> | |
</ul> | |
<h3>Performance testing and monitoring</h3> | |
<ul> | |
<li><a href="https://www.webpagetest.org/" target="_blank">WebPageTest</a></li> | |
<li><a href="https://developers.google.com/web/tools/lighthouse/" target="_blank">Lighthouse</a></li> | |
<li><a href="https://calibreapp.com/" target="_blank">Calibre</a></li> | |
<li><a href="https://webspeedtest.cloudinary.com/" target="_blank">Website Speed Test Image Analysis Tool</a> by Cloudinary</li> | |
</ul> | |
<h3>Design</h3> | |
<ul> | |
<li><a href="https://subtract.design/entry/forms" target="_blank">Subtract Guides</a>: Simple Rules for Designing Web & Mobile Forms</li> | |
</ul> | |
<h3>Design Systems and documentation</h3> | |
<ul> | |
<li><a href="https://storybook.js.org/" target="_blank">Storybook</a>: UI dev environment you’ll love to use</li> | |
<li><a href="https://github.com/styleguidist/react-styleguidist" target="_blank">react-styleguidist</a>: — Isolated React component development environment with a living style guide</li> | |
<li><a href="https://docusaurus.io/" target="_blank">Docusaurus</a>: Easy to Maintain Open Source Documentation Websites</li> | |
<li><a href="https://www.docz.site/" target="_blank">Docz</a></li> | |
<li><a href="https://github.com/mrmartineau/design-system-utils" target="_blank">design-system-utils</a>: — Design system framework for modern front-end projects</li> | |
<li><a href="https://docute.org/" target="_blank">Docute</a>: The fastest way to create a documentation site for your project</li> | |
<li><a href="https://github.com/seek-oss/playroom" target="_blank">playroom</a>: Design with JSX, powered by your own component library</li> | |
</ul> | |
<h3>Accessibility (A11y)</h3> | |
<p>Accessibility is an extremely important part of any web project. While the SOW, functional spec or user-stories might not directly mention a11y, it is up to each developer to ensure that best efforts are made to make our websites as accessible as possible.</p> | |
<h3>DevOps</h3> | |
<p><a href="https://httpstatuses.com/" target="_blank">HTTP Status Codes</a></p> | |
<h3>Continuous integration</h3> | |
<ul> | |
<li><a href="https://circleci.com" target="_blank">CircleCI</a>: Paid.</li> | |
<li><a href="https://bitrise.com" target="_blank">Bitrise</a>: Paid. For iOS/Android apps</li> | |
<li><a href="https://travisci.com" target="_blank">Travis CI</a>: Free for open-source</li> | |
</ul> | |
<h3>Docker</h3> | |
<ul> | |
<li><a href="https://github.com/goodwithtech/dockle" target="_blank">dockle</a>: Container Image Linter for Security, Helping build the Best-Practice Docker Image, Easy to start</li> | |
</ul> | |
<h3>Hosting</h3> | |
<ul> | |
<li><a href="https://vercel.com" target="_blank">Vercel</a></li> | |
<li><a href="https://netlify.com" target="_blank">Netlify</a></li> | |
</ul> | |
<h3>Domains</h3> | |
<ul> | |
<li><a href="https://iwantmyname.com/" target="_blank">iwantmyname</a></li> | |
</ul> | |
<h3>Design</h3> | |
<h3>Typography</h3> | |
<ul> | |
<li><a href="http://modularscale.com/" target="_blank">Modular Scale</a></li> | |
<li><a href="https://codepen.io/getflourish/full/vXqewy/" target="_blank">Adaptive Modular Scale</a></li> | |
<li><a href="http://type-scale.com/" target="_blank">Type Scale — A Visual Calculator</a></li> | |
</ul> | |
<h3>IDEs and Text Editors</h3> | |
<h3>VS Code</h3> | |
<ul> | |
<li><a href="https://gist.github.com/mrmartineau/28ef03c53275ea468e470532d6d20449" target="_blank">My VS Code extensions</a></li> | |
<li><a href="https://gist.github.com/mrmartineau/ea3b428124bc1e31cd46dfa55469d781" target="_blank">My preferences</a></li> | |
<li><a href="https://github.com/viatsko/awesome-vscode" target="_blank">awesome-vscode</a>: 🎨 A curated list of delightful VS Code packages and resources</li> | |
</ul> | |
<h3>Programming fonts</h3> | |
<ul> | |
<li><a href="https://www.ibm.com/plex/" target="_blank">IBM Plex Mono</a></li> | |
<li><a href="https://github.com/iaolo/iA-Fonts" target="_blank">iA-Fonts</a></li> | |
<li><a href="http://input.fontbureau.com/" target="_blank">Input: Fonts for Code</a></li> | |
<li><a href="https://github.com/tonsky/FiraCode" target="_blank">FiraCode</a></li> | |
<li><a href="https://github.com/belluzj/fantasque-sans" target="_blank">fantasque-sans</a></li> | |
<li><a href="https://github.com/JetBrains/JetBrainsMono" target="_blank">Jet Brains Mono</a></li> | |
</ul> | |
<h3>Code colour schemes</h3> | |
<ul> | |
<li><a href="https://monokai.pro/" target="_blank">Monokai Pro</a></li> | |
<li><a href="https://marketplace.visualstudio.com/items?itemName=teabyii.ayu" target="_blank">Ayu (Mirage)</a></li> | |
<li><a href="https://draculatheme.com/visual-studio-code/" target="_blank">Dracula</a>: A dark theme for Visual Studio Code and 50+ apps</li> | |
<li><a href="https://marketplace.visualstudio.com/items?itemName=gerane.Theme-OceanicNext" target="_blank">Oceanic Next Theme</a></li> | |
<li><a href="https://github.com/sdras/night-owl-vscode-theme" target="_blank">🌌 Night Owl</a>: A VS Code dark theme for contrast for nighttime coding</li> | |
<li><a href="https://marketplace.visualstudio.com/items?itemName=arcticicestudio.nord-visual-studio-code" target="_blank">Nord</a></li> | |
<li><a href="https://vscodethemes.com/" target="_blank">VSCodeThemes</a></li> | |
<li><a href="https://github.com/mjswensen/themer" target="_blank">themer</a>: 🎨 themer takes a set of colors and generates themes for your apps (editors, terminals, wallpapers, and more)</li> | |
</ul> | |
<h3>Regular expressions</h3> | |
<ul> | |
<li><a href="https://regex101.com/" target="_blank">Regex101</a>: Online regex tester and debugger: PHP, PCRE, Python, Golang and JavaScript</li> | |
</ul> | |
<h3>If you found this guide helpful feel free to checkout my other articles:</h3> | |
<p><a href="https://bryanguner.medium.com/a-list-of-all-of-my-articles-to-link-to-future-posts-1f6f88ebdf5b">https://bryanguner.medium.com/a-list-of-all-of-my-articles-to-link-to-future-posts-1f6f88ebdf5b</a></p> | |
<h3>OR GitHub/gists where I host similar content:</h3> | |
<p><a href="https://bryanguner.medium.com/a-list-of-all-of-my-articles-to-link-to-future-posts-1f6f88ebdf5b">https://bryanguner.medium.com/a-list-of-all-of-my-articles-to-link-to-future-posts-1f6f88ebdf5b</a><a href="https://bryanguner.medium.com/a-list-of-all-of-my-articles-to-link-to-future-posts-1f6f88ebdf5b">https://bryanguner.medium.com/a-list-of-all-of-my-articles-to-link-to-future-posts-1f6f88ebdf5b</a></p> | |
<h3>Or Checkout my personal Resource Site:</h3> | |
<p><a href="https://bryanguner.medium.com/a-list-of-all-of-my-articles-to-link-to-future-posts-1f6f88ebdf5b">https://bryanguner.medium.com/a-list-of-all-of-my-articles-to-link-to-future-posts-1f6f88ebdf5b</a> </p> | |
</div><!-- .entry-content --> | |
<footer class="entry-footer responsive-max-width"> | |
<span class="byline"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><span class="screen-reader-text">Posted by</span><span class="author vcard"><a class="url fn n" href="https://web-dev-hub.com/author/gunerb1/">bgoonz</a></span></span><span class="posted-on"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><defs><path id="a" d="M0 0h24v24H0V0z"></path></defs><clipPath id="b"><use xlink:href="#a" overflow="visible"></use></clipPath><path clip-path="url(#b)" d="M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10 10-4.5 10-10S17.5 2 12 2zm4.2 14.2L11 13V7h1.5v5.2l4.5 2.7-.8 1.3z"></path></svg><a href="https://web-dev-hub.com/2021/03/28/web-developer-resource-list-part-4/" rel="bookmark"><time class="entry-date published updated" datetime="2021-03-28T00:29:52-04:00">March 28, 2021</time></a></span><span class="cat-links"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M10 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2h-8l-2-2z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><span class="screen-reader-text">Posted in</span><a href="https://web-dev-hub.com/category/uncategorized/" rel="category tag">Uncategorized</a></span><span class="tags-links"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M21.41 11.58l-9-9C12.05 2.22 11.55 2 11 2H4c-1.1 0-2 .9-2 2v7c0 .55.22 1.05.59 1.42l9 9c.36.36.86.58 1.41.58.55 0 1.05-.22 1.41-.59l7-7c.37-.36.59-.86.59-1.41 0-.55-.23-1.06-.59-1.42zM5.5 7C4.67 7 4 6.33 4 5.5S4.67 4 5.5 4 7 4.67 7 5.5 6.33 7 5.5 7z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><span class="screen-reader-text">Tags:</span><a href="https://web-dev-hub.com/tag/css/" rel="tag">CSS</a>, <a href="https://web-dev-hub.com/tag/html/" rel="tag">HTML</a>, <a href="https://web-dev-hub.com/tag/javascript/" rel="tag">Javascript</a>, <a href="https://web-dev-hub.com/tag/technology/" rel="tag">Technology</a>, <a href="https://web-dev-hub.com/tag/web-development/" rel="tag">Web Development</a></span><span class="comments-link"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M21.99 4c0-1.1-.89-2-1.99-2H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h14l4 4-.01-18z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><a href="https://web-dev-hub.com/2021/03/28/web-developer-resource-list-part-4/#respond">Leave a comment<span class="screen-reader-text"> on Web Developer Resource List Part 4</span></a></span><span class="edit-link"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04c.39-.39.39-1.02 0-1.41l-2.34-2.34c-.39-.39-1.02-.39-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><a class="post-edit-link" href="https://wordpress.com/post/web-dev-hub.com/577">Edit <span class="screen-reader-text">Web Developer Resource List Part 4</span></a></span> </footer><!-- .entry-footer --> | |
</article><!-- #post-${ID} --> | |
<article id="post-330" class="post-330 post type-post status-publish format-standard hentry category-uncategorized entry"> | |
<header class="entry-header responsive-max-width"> | |
<h2 class="entry-title"><a href="https://web-dev-hub.com/2021/03/23/downloads/" rel="bookmark">Downloads</a></h2> </header><!-- .entry-header --> | |
<div class="entry-content"> | |
<div class="wp-block-file"><a href="https://webdevhubcom.files.wordpress.com/2021/03/bryan-guner-resume-2021-1.pdf">bryan-guner-resume-2021-1</a><a href="https://webdevhubcom.files.wordpress.com/2021/03/bryan-guner-resume-2021-1.pdf" class="wp-block-file__button" download>Resume Download</a></div> | |
<div class="wp-block-file"><a href="https://webdevhubcom.files.wordpress.com/2021/03/bryan-guner-professional-portfolio-2.pptx">bryan-guner-professional-portfolio-2</a><a href="https://webdevhubcom.files.wordpress.com/2021/03/bryan-guner-professional-portfolio-2.pptx" class="wp-block-file__button" download>Portfolio Download</a></div> | |
<div class="wp-block-file"><a href="https://webdevhubcom.files.wordpress.com/2021/03/general-dsp-audio-cover-letter.docx">General CV (outdated…placeholder)</a><a href="https://webdevhubcom.files.wordpress.com/2021/03/general-dsp-audio-cover-letter.docx" class="wp-block-file__button" download>Cover Letter</a></div> | |
<div class="wp-block-file"><a href="https://webdevhubcom.files.wordpress.com/2021/03/sr-project-ii-presentation.pdf">sr-project-ii-presentation</a><a href="https://webdevhubcom.files.wordpress.com/2021/03/sr-project-ii-presentation.pdf" class="wp-block-file__button" download>Dynamic Time Warping Presentation</a></div> | |
<div class="wp-block-file"><a href="https://webdevhubcom.files.wordpress.com/2021/03/final-report-sp2.pdf">final-report-sp2</a><a href="https://webdevhubcom.files.wordpress.com/2021/03/final-report-sp2.pdf" class="wp-block-file__button" download>DTW Effects Triggering Report</a></div> | |
<p></p> | |
</div><!-- .entry-content --> | |
<footer class="entry-footer responsive-max-width"> | |
<span class="byline"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><span class="screen-reader-text">Posted by</span><span class="author vcard"><a class="url fn n" href="https://web-dev-hub.com/author/gunerb1/">bgoonz</a></span></span><span class="posted-on"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><defs><path id="a" d="M0 0h24v24H0V0z"></path></defs><clipPath id="b"><use xlink:href="#a" overflow="visible"></use></clipPath><path clip-path="url(#b)" d="M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10 10-4.5 10-10S17.5 2 12 2zm4.2 14.2L11 13V7h1.5v5.2l4.5 2.7-.8 1.3z"></path></svg><a href="https://web-dev-hub.com/2021/03/23/downloads/" rel="bookmark"><time class="entry-date published updated" datetime="2021-03-23T21:28:39-04:00">March 23, 2021</time></a></span><span class="cat-links"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M10 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2h-8l-2-2z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><span class="screen-reader-text">Posted in</span><a href="https://web-dev-hub.com/category/uncategorized/" rel="category tag">Uncategorized</a></span><span class="comments-link"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M21.99 4c0-1.1-.89-2-1.99-2H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h14l4 4-.01-18z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><a href="https://web-dev-hub.com/2021/03/23/downloads/#respond">Leave a comment<span class="screen-reader-text"> on Downloads</span></a></span><span class="edit-link"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04c.39-.39.39-1.02 0-1.41l-2.34-2.34c-.39-.39-1.02-.39-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><a class="post-edit-link" href="https://wordpress.com/post/web-dev-hub.com/330">Edit <span class="screen-reader-text">Downloads</span></a></span> </footer><!-- .entry-footer --> | |
</article><!-- #post-${ID} --> | |
<article id="post-365" class="post-365 post type-post status-publish format-standard hentry category-uncategorized tag-coding tag-data-structures tag-javascript tag-programming tag-web-development entry"> | |
<header class="entry-header responsive-max-width"> | |
<h2 class="entry-title"><a href="https://web-dev-hub.com/2021/03/23/fundamental-data-structures-in-javascript/" rel="bookmark">Fundamental Data Structures In JavaScript</a></h2> </header><!-- .entry-header --> | |
<div class="entry-content"> | |
Fundamental Data Structures In JavaScript | |
* { | |
font-family: Georgia, Cambria, “Times New Roman”, Times, serif; | |
} | |
html, body { | |
margin: 0; | |
padding: 0; | |
} | |
h1 { | |
font-size: 50px; | |
margin-bottom: 17px; | |
color: #333; | |
} | |
h2 { | |
font-size: 24px; | |
line-height: 1.6; | |
margin: 30px 0 0 0; | |
margin-bottom: 18px; | |
margin-top: 33px; | |
color: #333; | |
} | |
h3 { | |
font-size: 30px; | |
margin: 10px 0 20px 0; | |
color: #333; | |
} | |
header { | |
width: 640px; | |
margin: auto; | |
} | |
section { | |
width: 640px; | |
margin: auto; | |
} | |
section p { | |
margin-bottom: 27px; | |
font-size: 20px; | |
line-height: 1.6; | |
color: #333; | |
} | |
section img { | |
max-width: 640px; | |
} | |
footer { | |
padding: 0 20px; | |
margin: 50px 0; | |
text-align: center; | |
font-size: 12px; | |
} | |
.aspectRatioPlaceholder { | |
max-width: auto !important; | |
max-height: auto !important; | |
} | |
.aspectRatioPlaceholder-fill { | |
padding-bottom: 0 !important; | |
} | |
header, | |
section[data-field=subtitle], | |
section[data-field=description] { | |
display: none; | |
} | |
<article class="h-entry"> | |
<header> | |
<h1 class="p-name">Fundamental Data Structures In JavaScript</h1> | |
</header> | |
<section class="p-summary"> | |
Data structures in JavaScript | |
</section> | |
<section class="e-content"> | |
<section class="section section--body section--first"><div class="section-divider"><hr class="section-divider"></div><div class="section-content"><div class="section-inner sectionLayout--insetColumn"><h4 id="0e6e" class="graf graf--h4 graf--leading graf--kicker"></h4><h3 id="95a6" class="graf graf--h3 graf-after--h4 graf--title">Fundamental Data Structures In JavaScript</h3><h3 id="acd7" class="graf graf--h3 graf-after--h3">Data structures in JavaScript</h3><p id="a3c3" class="graf graf--p graf--hasDropCapModel graf--hasDropCap graf-after--h3"><span class="graf-dropCap">H</span>ere’s a website I created to practice data structures!</p><div id="1cca" class="graf graf--mixtapeEmbed graf-after--p"><a href="https://ds-algo-official-c3dw6uapg-bgoonz.vercel.app/" class="markup--anchor markup--mixtapeEmbed-anchor" title="https://ds-algo-official-c3dw6uapg-bgoonz.vercel.app/"><strong class="markup--strong markup--mixtapeEmbed-strong">directory</strong><br><em class="markup--em markup--mixtapeEmbed-em">Edit description</em>ds-algo-official-c3dw6uapg-bgoonz.vercel.app</a><a href="https://ds-algo-official-c3dw6uapg-bgoonz.vercel.app/" class="js-mixtapeImage mixtapeImage mixtapeImage--empty u-ignoreBlock"></a></div><p id="f838" class="graf graf--p graf--hasDropCapModel graf--hasDropCap graf-after--mixtapeEmbed"><span class="graf-dropCap">H</span>ere’s the repo that the website is built on:</p><div id="6f5f" class="graf graf--mixtapeEmbed graf-after--p"><a href="https://github.com/bgoonz/DS-ALGO-OFFICIAL" class="markup--anchor markup--mixtapeEmbed-anchor" title="https://github.com/bgoonz/DS-ALGO-OFFICIAL"><strong class="markup--strong markup--mixtapeEmbed-strong">bgoonz/DS-ALGO-OFFICIAL</strong><br><em class="markup--em markup--mixtapeEmbed-em">Navigation ####Author:Bryan Guner Big O notation is the language we use for talking about how long an algorithm takes…</em>github.com</a><a href="https://github.com/bgoonz/DS-ALGO-OFFICIAL" class="js-mixtapeImage mixtapeImage u-ignoreBlock" style="background-image:url('https://cdn-images-1.medium.com/fit/c/160/160/0*ZHOIXd9wZmDxwpH8');"></a></div><p id="4d8a" class="graf graf--p graf--hasDropCapModel graf--hasDropCap graf-after--mixtapeEmbed"><span class="graf-dropCap">H</span>ere’s a live code editor where you can mess with any of the examples…</p><figure id="a042" class="graf graf--figure graf--iframe graf-after--p"></figure><h3 id="22a4" class="graf graf--h3 graf-after--figure">Resources (article content below):</h3><h4 id="7e6d" class="graf graf--h4 graf-after--h3">Videos</h4><ul class="postList"><li id="53c4" class="graf graf--li graf-after--h4"><a href="https://www.youtube.com/watch?v=0IAPZzGSbME&list=PLDN4rrl48XKpZkf03iYFl-O29szjTrs_O&index=2&t=0s" class="markup--anchor markup--li-anchor" rel="noopener" target="_blank">Abdul Bari: YouTubeChannel for Algorithms</a></li><li id="ab93" class="graf graf--li graf-after--li"><a href="https://www.youtube.com/watch?v=lxja8wBwN0k&list=PLKKfKV1b9e8ps6dD3QA5KFfHdiWj9cB1s" class="markup--anchor markup--li-anchor" rel="noopener" target="_blank">Data Structures and algorithms</a></li><li id="e614" class="graf graf--li graf-after--li"><a href="https://www.youtube.com/playlist?list=PLmGElG-9wxc9Us6IK6Qy-KHlG_F3IS6Q9" class="markup--anchor markup--li-anchor" rel="noopener" target="_blank">Data Structures and algorithms Course</a></li><li id="3d48" class="graf graf--li graf-after--li"><a href="https://www.khanacademy.org/computing/computer-science/algorithms" class="markup--anchor markup--li-anchor" rel="noopener" target="_blank">Khan Academy</a></li><li id="ac90" class="graf graf--li graf-after--li"><a href="https://www.youtube.com/playlist?list=PL2_aWCzGMAwI3W_JlcBbtYTwiQSsOTa6P" class="markup--anchor markup--li-anchor" rel="noopener" target="_blank">Data structures by mycodeschool</a>Pre-requisite for this lesson is good understanding of pointers in C.</li><li id="9bd9" class="graf graf--li graf-after--li"><a href="https://www.youtube.com/watch?v=HtSuA80QTyo&list=PLUl4u3cNGP61Oq3tWYp6V_F-5jb5L2iHb" class="markup--anchor markup--li-anchor" rel="noopener" target="_blank">MIT 6.006: Intro to Algorithms(2011)</a></li><li id="71f0" class="graf graf--li graf-after--li"><a href="https://www.youtube.com/watch?v=5_5oE5lgrhw&list=PLu0W_9lII9ahIappRPN0MCAgtOu3lQjQi" class="markup--anchor markup--li-anchor" rel="noopener" target="_blank">Data Structures and Algorithms by Codewithharry</a></li></ul><h4 id="66cc" class="graf graf--h4 graf-after--li">Books</h4><ul class="postList"><li id="2eac" class="graf graf--li graf-after--h4"><a href="https://edutechlearners.com/download/Introduction_to_algorithms-3rd%20Edition.pdf" class="markup--anchor markup--li-anchor" rel="noopener" target="_blank">Introduction to Algorithms</a> by Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest, and Clifford Stein</li><li id="3e8d" class="graf graf--li graf-after--li"><a href="http://www.sso.sy/sites/default/files/competitive%20programming%203_1.pdf" class="markup--anchor markup--li-anchor" rel="noopener" target="_blank">Competitive Programming 3</a> by Steven Halim and Felix Halim</li><li id="3aa3" class="graf graf--li graf-after--li"><a href="https://cses.fi/book/book.pdf" class="markup--anchor markup--li-anchor" rel="noopener" target="_blank">Competitive Programmers Hand Book</a> Beginner friendly hand book for competitive programmers.</li><li id="3c02" class="graf graf--li graf-after--li"><a href="https://github.com/Amchuz/My-Data-Structures-and-Algorithms-Resources/raw/master/Books/Data%20Structures%20and%20Algorithms%20-%20Narasimha%20Karumanchi.pdf" class="markup--anchor markup--li-anchor" rel="noopener" target="_blank">Data Structures and Algorithms Made Easy</a> by Narasimha Karumanchi</li><li id="93ec" class="graf graf--li graf-after--li"><a href="https://github.com/Amchuz/My-Data-Structures-and-Algorithms-Resources/raw/master/Books/Learning%20Algorithms%20Through%20Programming%20and%20Puzzle%20Solving.pdf" class="markup--anchor markup--li-anchor" rel="noopener" target="_blank">Learning Algorithms Through Programming and Puzzle Solving</a> by Alexander Kulikov and Pavel Pevzner</li></ul><h4 id="2b85" class="graf graf--h4 graf-after--li">Coding practice</h4><ul class="postList"><li id="824c" class="graf graf--li graf-after--h4"><a href="https://leetcode.com/" class="markup--anchor markup--li-anchor" rel="noopener" target="_blank">LeetCode</a></li><li id="a528" class="graf graf--li graf-after--li"><a href="https://www.interviewbit.com/" class="markup--anchor markup--li-anchor" rel="noopener" target="_blank">InterviewBit</a></li><li id="fa41" class="graf graf--li graf-after--li"><a href="https://codility.com/" class="markup--anchor markup--li-anchor" rel="noopener" target="_blank">Codility</a></li><li id="6c61" class="graf graf--li graf-after--li"><a href="https://www.hackerrank.com/" class="markup--anchor markup--li-anchor" rel="noopener" target="_blank">HackerRank</a></li><li id="dff6" class="graf graf--li graf-after--li"><a href="https://projecteuler.net/" class="markup--anchor markup--li-anchor" rel="noopener" target="_blank">Project Euler</a></li><li id="b2dd" class="graf graf--li graf-after--li"><a href="https://spoj.com/" class="markup--anchor markup--li-anchor" rel="noopener" target="_blank">Spoj</a></li><li id="c8e8" class="graf graf--li graf-after--li"><a href="https://code.google.com/codejam/contests.html" class="markup--anchor markup--li-anchor" rel="noopener" target="_blank">Google Code Jam practice problems</a></li><li id="e8bb" class="graf graf--li graf-after--li"><a href="https://www.hackerearth.com/" class="markup--anchor markup--li-anchor" rel="noopener" target="_blank">HackerEarth</a></li><li id="e803" class="graf graf--li graf-after--li"><a href="https://www.topcoder.com/" class="markup--anchor markup--li-anchor" rel="noopener" target="_blank">Top Coder</a></li><li id="294e" class="graf graf--li graf-after--li"><a href="https://www.codechef.com/" class="markup--anchor markup--li-anchor" rel="noopener" target="_blank">CodeChef</a></li><li id="9c05" class="graf graf--li graf-after--li"><a href="https://www.codewars.com/" class="markup--anchor markup--li-anchor" rel="noopener" target="_blank">Codewars</a></li><li id="356e" class="graf graf--li graf-after--li"><a href="https://codesignal.com/" class="markup--anchor markup--li-anchor" rel="noopener" target="_blank">CodeSignal</a></li><li id="2d20" class="graf graf--li graf-after--li"><a href="http://codekata.com/" class="markup--anchor markup--li-anchor" rel="noopener" target="_blank">CodeKata</a></li><li id="d3bf" class="graf graf--li graf-after--li"><a href="https://www.firecode.io/" class="markup--anchor markup--li-anchor" rel="noopener" target="_blank">Firecode</a></li></ul><h4 id="ae73" class="graf graf--h4 graf-after--li">Courses</h4><ul class="postList"><li id="eac2" class="graf graf--li graf-after--h4"><a href="https://academy.zerotomastery.io/p/master-the-coding-interview-faang-interview-prep" class="markup--anchor markup--li-anchor" rel="noopener" target="_blank">Master the Coding Interview: Big Tech (FAANG) Interviews</a> Course by Andrei and his team.</li><li id="36ca" class="graf graf--li graf-after--li"><a href="https://realpython.com/python-data-structures" class="markup--anchor markup--li-anchor" rel="noopener" target="_blank">Common Python Data Structures</a> Data structures are the fundamental constructs around which you build your programs. Each data structure provides a particular way of organizing data so it can be accessed efficiently, depending on your use case. Python ships with an extensive set of data structures in its standard library.</li><li id="cdc9" class="graf graf--li graf-after--li"><a href="https://www.geeksforgeeks.org/fork-cpp-course-structure" class="markup--anchor markup--li-anchor" rel="noopener" target="_blank">Fork CPP</a> A good course for beginners.</li><li id="6d47" class="graf graf--li graf-after--li"><a href="https://codeforces.com/edu/course/2" class="markup--anchor markup--li-anchor" rel="noopener" target="_blank">EDU</a> Advanced course.</li><li id="8bb5" class="graf graf--li graf-after--li"><a href="https://www.udacity.com/course/c-for-programmers--ud210" class="markup--anchor markup--li-anchor" rel="noopener" target="_blank">C++ For Programmers</a> Learn features and constructs for C++.</li></ul><h4 id="28b7" class="graf graf--h4 graf-after--li">Guides</h4><ul class="postList"><li id="e9e9" class="graf graf--li graf-after--h4"><a href="http://www.geeksforgeeks.org/" class="markup--anchor markup--li-anchor" rel="noopener" target="_blank">GeeksForGeeks — A CS portal for geeks</a></li><li id="a228" class="graf graf--li graf-after--li"><a href="https://www.learneroo.com/subjects/8" class="markup--anchor markup--li-anchor" rel="noopener" target="_blank">Learneroo — Algorithms</a></li><li id="a2f0" class="graf graf--li graf-after--li"><a href="http://www.topcoder.com/tc?d1=tutorials&d2=alg_index&module=Static" class="markup--anchor markup--li-anchor" rel="noopener" target="_blank">Top Coder tutorials</a></li><li id="f3ec" class="graf graf--li graf-after--li"><a href="http://www.infoarena.ro/training-path" class="markup--anchor markup--li-anchor" rel="noopener" target="_blank">Infoarena training path</a> (RO)</li><li id="ec93" class="graf graf--li graf-after--li">Steven & Felix Halim — <a href="https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=118" class="markup--anchor markup--li-anchor" rel="noopener" target="_blank">Increasing the Lower Bound of Programming Contests</a> (UVA Online Judge)</li></ul><h3 id="001c" class="graf graf--h3 graf-after--li"><strong class="markup--strong markup--h3-strong"><em class="markup--em markup--h3-em">space</em></strong></h3><blockquote id="e300" class="graf graf--blockquote graf-after--h3"><em class="markup--em markup--blockquote-em">The space complexity represents the memory consumption of a data structure. As for most of the things in life, you can’t have it all, so it is with the data structures. You will generally need to trade some time for space or the other way around.</em></blockquote><h3 id="a5b0" class="graf graf--h3 graf-after--blockquote"><em class="markup--em markup--h3-em">time</em></h3><blockquote id="5eb8" class="graf graf--blockquote graf-after--h3"><em class="markup--em markup--blockquote-em">The time complexity for a data structure is in general more diverse than its space complexity.</em></blockquote><h3 id="bfc3" class="graf graf--h3 graf-after--blockquote"><em class="markup--em markup--h3-em">Several operations</em></h3><blockquote id="5f9e" class="graf graf--blockquote graf-after--h3"><em class="markup--em markup--blockquote-em">In contrary to algorithms, when you look at the time complexity for data structures you need to express it for several operations that you can do with data structures. It can be adding elements, deleting elements, accessing an element or even searching for an element.</em></blockquote><h3 id="4427" class="graf graf--h3 graf-after--blockquote"><em class="markup--em markup--h3-em">Dependent on data</em></h3><blockquote id="f386" class="graf graf--blockquote graf-after--h3"><em class="markup--em markup--blockquote-em">Something that data structure and algorithms have in common when talking about time complexity is that they are both dealing with data. When you deal with data you become dependent on them and as a result the time complexity is also dependent of the data that you received. To solve this problem we talk about 3 different time complexity.</em></blockquote><ul class="postList"><li id="bc8d" class="graf graf--li graf-after--blockquote"><strong class="markup--strong markup--li-strong">The best-case complexity: when the data looks the best</strong></li><li id="8b06" class="graf graf--li graf-after--li"><strong class="markup--strong markup--li-strong">The worst-case complexity: when the data looks the worst</strong></li><li id="881c" class="graf graf--li graf-after--li"><strong class="markup--strong markup--li-strong">The average-case complexity: when the data looks average</strong></li></ul><h3 id="b65d" class="graf graf--h3 graf-after--li">Big O notation</h3><p id="b7a9" class="graf graf--p graf-after--h3">The complexity is usually expressed with the Big O notation. The wikipedia page about this subject is pretty complex but you can find here a good summary of the different complexity for the most famous data structures and sorting algorithms.</p><h3 id="60f4" class="graf graf--h3 graf-after--p">The Array data structure</h3><figure id="5d48" class="graf graf--figure graf-after--h3"><img class="graf-image" data-width="438" data-height="180" src="https://webdevhubcom.files.wordpress.com/2021/03/86116-0qk3uygeqxamrrflr.gif"></figure><h3 id="59b3" class="graf graf--h3 graf-after--figure">Definition</h3><p id="cf52" class="graf graf--p graf-after--h3">An Array data structure, or simply an Array, is a data structure consisting of a collection of elements (values or variables), each identified by at least one array index or key. The simplest type of data structure is a linear array, also called one-dimensional array. From Wikipedia</p><p id="6985" class="graf graf--p graf-after--p">Arrays are among the oldest and most important data structures and are used by every program. They are also used to implement many other data structures.</p><p id="8957" class="graf graf--p graf-after--p"><em class="markup--em markup--p-em">Complexity</em><br><em class="markup--em markup--p-em">Average</em><br><em class="markup--em markup--p-em">Access Search Insertion Deletion</em></p><p id="ee26" class="graf graf--p graf-after--p">O(1) O(n) O(1) O(n)</p><figure id="bc5e" class="graf graf--figure graf--iframe graf-after--p"></figure><figure id="649e" class="graf graf--figure graf-after--figure"><img class="graf-image" data-width="721" data-height="239" src="https://webdevhubcom.files.wordpress.com/2021/03/b95b2-1-bj2hu-czo2kuzu4x5a53g.png"></figure><p id="9434" class="graf graf--p graf-after--figure">indexvalue0 … this is the first value, stored at zero position</p><ol class="postList"><li id="b953" class="graf graf--li graf-after--p">The index of an array <strong class="markup--strong markup--li-strong">runs in sequence</strong></li></ol><p id="d955" class="graf graf--p graf-after--li">2. This could be useful for storing data that are required to be ordered, such as rankings or queues</p><p id="d54f" class="graf graf--p graf-after--p">3. In JavaScript, array’s value could be mixed; meaning value of each index could be of different data, be it String, Number or even Objects</p><figure id="a342" class="graf graf--figure graf--iframe graf-after--p"></figure><h3 id="7952" class="graf graf--h3 graf-after--figure">2. Objects</h3><p id="b41b" class="graf graf--p graf-after--h3">Think of objects as a logical grouping of a bunch of properties.</p><p id="2c4c" class="graf graf--p graf-after--p">Properties could be some variable that it’s storing or some methods that it’s using.</p><p id="b5b2" class="graf graf--p graf-after--p">I also visualize an object as a table.</p><p id="207d" class="graf graf--p graf-after--p">The main difference is that object’s “index” need not be numbers and is not necessarily sequenced.</p></div><div class="section-inner sectionLayout--outsetColumn"><figure id="c22e" class="graf graf--figure graf--layoutOutsetCenter graf-after--p"><img class="graf-image" data-width="1286" data-height="193" src="https://webdevhubcom.files.wordpress.com/2021/03/c8daa-1kvzkd2zrgea_47igw8hq8g.png"></figure></div><div class="section-inner sectionLayout--insetColumn"><figure id="342b" class="graf graf--figure graf--iframe graf-after--figure"></figure><h3 id="c03a" class="graf graf--h3 graf-after--figure">The Hash Table</h3><figure id="25ee" class="graf graf--figure graf-after--h3"><img class="graf-image" data-width="509" data-height="408" src="https://webdevhubcom.files.wordpress.com/2021/03/bd913-0avbxlafocsv6vsl5.gif"></figure><figure id="0cd2" class="graf graf--figure graf-after--figure"><img class="graf-image" data-width="1024" data-height="768" src="https://cdn-images-1.medium.com/max/800/0*3GJiRoLyEoZ_aIlO"></figure><h3 id="c97f" class="graf graf--h3 graf-after--figure"><em class="markup--em markup--h3-em">Definition</em></h3><blockquote id="136d" class="graf graf--blockquote graf-after--h3"><em class="markup--em markup--blockquote-em">A Hash Table (Hash Map) is a data structure used to implement an associative array, a structure that can map keys to values. A Hash Table uses a hash function to compute an index into an array of buckets or slots, from which the desired value can be found. From Wikipedia</em></blockquote><p id="7014" class="graf graf--p graf-after--blockquote">Hash Tables are considered the more efficient data structure for lookup and for this reason, they are widely used.</p><p id="26e5" class="graf graf--p graf-after--p">Complexity<br>Average<br>Access Search Insertion Deletion</p><ul class="postList"><li id="f63f" class="graf graf--li graf-after--p">O(1) O(1) O(1)</li></ul><blockquote id="6610" class="graf graf--blockquote graf-after--li"><em class="markup--em markup--blockquote-em">The code</em></blockquote><p id="42e7" class="graf graf--p graf-after--blockquote">Note, here I am storing another object for every hash in my Hash Table.</p><figure id="4f27" class="graf graf--figure graf--iframe graf-after--p"></figure><h3 id="2a1e" class="graf graf--h3 graf-after--figure">The Set</h3><h3 id="8369" class="graf graf--h3 graf-after--h3">Sets</h3><p id="dc9b" class="graf graf--p graf-after--h3">Sets are pretty much what it sounds like. It’s the same intuition as Set in Mathematics. I visualize Sets as Venn Diagrams.</p><figure id="7f1f" class="graf graf--figure graf-after--p"><img class="graf-image" data-width="551" data-height="667" src="https://webdevhubcom.files.wordpress.com/2021/03/803cd-0aiqljh9p8baw9tne.png"></figure><figure id="8e72" class="graf graf--figure graf--iframe graf-after--figure"></figure><figure id="4e4d" class="graf graf--figure graf-after--figure"><img class="graf-image" data-width="290" data-height="243" src="https://cdn-images-1.medium.com/max/800/0*gOE33ANZP2ujbjIG"></figure><h3 id="ec47" class="graf graf--h3 graf-after--figure"><em class="markup--em markup--h3-em">Definition</em></h3><blockquote id="a99b" class="graf graf--blockquote graf-after--h3"><em class="markup--em markup--blockquote-em">A Set is an abstract data type that can store certain values, without any particular order, and no repeated values. It is a computer implementation of the mathematical concept of a finite Set. From Wikipedia</em></blockquote><p id="2a4f" class="graf graf--p graf-after--blockquote">The Set data structure is usually used to test whether elements belong to set of values. Rather then only containing elements, Sets are more used to perform operations on multiple values at once with methods such as union, intersect, etc…</p><p id="aded" class="graf graf--p graf-after--p">Complexity<br>Average<br>Access Search Insertion Deletion</p><ul class="postList"><li id="daa6" class="graf graf--li graf-after--p">O(n) O(n) O(n)</li></ul><blockquote id="563a" class="graf graf--blockquote graf-after--li"><em class="markup--em markup--blockquote-em">The code</em></blockquote><figure id="cea8" class="graf graf--figure graf--iframe graf-after--blockquote"></figure><h3 id="007e" class="graf graf--h3 graf-after--figure">The Singly Linked List</h3><figure id="55be" class="graf graf--figure graf-after--h3"><img class="graf-image" data-width="1024" data-height="768" src="https://webdevhubcom.files.wordpress.com/2021/03/5081e-0fls64rv-xq19avca.gif"></figure><h3 id="63b9" class="graf graf--h3 graf-after--figure"><em class="markup--em markup--h3-em">Definition</em></h3><blockquote id="8c39" class="graf graf--blockquote graf-after--h3"><em class="markup--em markup--blockquote-em">A Singly Linked List is a linear collection of data elements, called nodes pointing to the next node by means of pointer. It is a data structure consisting of a group of nodes which together represent a sequence. Under the simplest form, each node is composed of data and a reference (in other words, a link) to the next node in the sequence.</em></blockquote><p id="ce72" class="graf graf--p graf-after--blockquote">Linked Lists are among the simplest and most common data structures because it allows for efficient insertion or removal of elements from any position in the sequence.</p><p id="1516" class="graf graf--p graf-after--p">Complexity<br>Average<br>Access Search Insertion Deletion<br>O(n) O(n) O(1) O(1)</p><blockquote id="fbc3" class="graf graf--blockquote graf-after--p graf--trailing"><em class="markup--em markup--blockquote-em">The code</em></blockquote></div></div></section><section class="section section--body"><div class="section-divider"><hr class="section-divider"></div><div class="section-content"><div class="section-inner sectionLayout--insetColumn"><figure id="09dd" class="graf graf--figure graf--iframe graf--leading"></figure><h3 id="0815" class="graf graf--h3 graf-after--figure">The Doubly Linked List</h3><figure id="a111" class="graf graf--figure graf-after--h3"><img class="graf-image" data-width="730" data-height="201" src="https://webdevhubcom.files.wordpress.com/2021/03/6878a-0tqxir-l_itig3wp-.gif"></figure><h3 id="86b8" class="graf graf--h3 graf-after--figure"><em class="markup--em markup--h3-em">Definition</em></h3><blockquote id="cb5c" class="graf graf--blockquote graf-after--h3"><em class="markup--em markup--blockquote-em">A Doubly Linked List is a linked data structure that consists of a set of sequentially linked records called nodes. Each node contains two fields, called links, that are references to the previous and to the next node in the sequence of nodes. From Wikipedia</em></blockquote><p id="4dfc" class="graf graf--p graf-after--blockquote">Having two node links allow traversal in either direction but adding or removing a node in a doubly linked list requires changing more links than the same operations on a Singly Linked List.</p><p id="9736" class="graf graf--p graf-after--p">Complexity<br>Average<br>Access Search Insertion Deletion<br>O(n) O(n) O(1) O(1)</p><blockquote id="8142" class="graf graf--blockquote graf-after--p"><em class="markup--em markup--blockquote-em">The code</em></blockquote><figure id="892a" class="graf graf--figure graf--iframe graf-after--blockquote"></figure><h3 id="16a2" class="graf graf--h3 graf-after--figure">The Stack</h3></div><div class="section-inner sectionLayout--outsetColumn"><figure id="acb3" class="graf graf--figure graf--layoutOutsetCenter graf-after--h3"><img class="graf-image" data-width="2025" data-height="1136" src="https://webdevhubcom.files.wordpress.com/2021/03/c2742-0qsjyw-lvfo22ecle.gif"></figure></div><div class="section-inner sectionLayout--insetColumn"><h3 id="3dd8" class="graf graf--h3 graf-after--figure"><em class="markup--em markup--h3-em">Definition</em></h3><blockquote id="5ca1" class="graf graf--blockquote graf-after--h3"><em class="markup--em markup--blockquote-em">A Stack is an abstract data type that serves as a collection of elements, with two principal operations: push, which adds an element to the collection, and pop, which removes the most recently added element that was not yet removed. The order in which elements come off a Stack gives rise to its alternative name, LIFO (for last in, first out). From Wikipedia</em></blockquote><p id="e43e" class="graf graf--p graf-after--blockquote">A Stack often has a third method peek which allows to check the last pushed element without popping it.</p><p id="2be7" class="graf graf--p graf-after--p">Complexity<br>Average<br>Access Search Insertion Deletion<br>O(n) O(n) O(1) O(1)</p><blockquote id="7eae" class="graf graf--blockquote graf-after--p"><em class="markup--em markup--blockquote-em">The code</em></blockquote><figure id="16be" class="graf graf--figure graf--iframe graf-after--blockquote"></figure><h3 id="61ea" class="graf graf--h3 graf-after--figure">The Queue</h3><figure id="736d" class="graf graf--figure graf-after--h3"><img class="graf-image" data-width="2025" data-height="1136" src="https://webdevhubcom.files.wordpress.com/2021/03/cea0c-0yvfux5tkp7-v0p7v.gif"></figure><h3 id="777e" class="graf graf--h3 graf-after--figure"><em class="markup--em markup--h3-em">Definition</em></h3><blockquote id="2258" class="graf graf--blockquote graf-after--h3"><em class="markup--em markup--blockquote-em">A Queue is a particular kind of abstract data type or collection in which the entities in the collection are kept in order and the principal operations are the addition of entities to the rear terminal position, known as enqueue, and removal of entities from the front terminal position, known as dequeue. This makes the Queue a First-In-First-Out (FIFO) data structure. In a FIFO data structure, the first element added to the Queue will be the first one to be removed.</em></blockquote><p id="d72e" class="graf graf--p graf-after--blockquote">As for the Stack data structure, a peek operation is often added to the Queue data structure. It returns the value of the front element without dequeuing it.</p><p id="86ee" class="graf graf--p graf-after--p">Complexity<br>Average<br>Access Search Insertion Deletion<br>O(n) O(n) O(1) O(n)</p><blockquote id="d830" class="graf graf--blockquote graf-after--p"><em class="markup--em markup--blockquote-em">The code</em></blockquote><figure id="bc6e" class="graf graf--figure graf--iframe graf-after--blockquote"></figure><h3 id="13ee" class="graf graf--h3 graf-after--figure">The Tree</h3><figure id="8298" class="graf graf--figure graf-after--h3"><img class="graf-image" data-width="450" data-height="378" src="https://cdn-images-1.medium.com/max/800/0*yUiQ-NaPKeLQnN7n"></figure><h3 id="dec9" class="graf graf--h3 graf-after--figure"><em class="markup--em markup--h3-em">Definition</em></h3><blockquote id="5595" class="graf graf--blockquote graf-after--h3"><em class="markup--em markup--blockquote-em">A Tree is a widely used data structure that simulates a hierarchical tree structure, with a root value and subtrees of children with a parent node. A tree data structure can be defined recursively as a collection of nodes (starting at a root node), where each node is a data structure consisting of a value, together with a list of references to nodes (the “children”), with the constraints that no reference is duplicated, and none points to the root node. From Wikipedia</em></blockquote><p id="2c20" class="graf graf--p graf-after--blockquote">Complexity<br>Average<br>Access Search Insertion Deletion<br>O(n) O(n) O(n) O(n)<br>To get a full overview of the time and space complexity of the Tree data structure, have a look to this excellent Big O cheat sheet.</p><figure id="aebb" class="graf graf--figure graf-after--p"><img class="graf-image" data-width="856" data-height="892" src="https://webdevhubcom.files.wordpress.com/2021/03/085ca-1dcdqib6xqbjcrfrz12bwqa.png"></figure><blockquote id="227d" class="graf graf--blockquote graf-after--figure"><em class="markup--em markup--blockquote-em">The code</em></blockquote><figure id="297c" class="graf graf--figure graf--iframe graf-after--blockquote"></figure><h3 id="cf4f" class="graf graf--h3 graf-after--figure">The Graph</h3><figure id="00a8" class="graf graf--figure graf-after--h3"><img class="graf-image" data-width="960" data-height="540" src="https://webdevhubcom.files.wordpress.com/2021/03/f40d4-0q31ml1kjfwlizw3l.gif"></figure><h3 id="315d" class="graf graf--h3 graf-after--figure"><em class="markup--em markup--h3-em">Definition</em></h3><blockquote id="3324" class="graf graf--blockquote graf-after--h3"><em class="markup--em markup--blockquote-em">A Graph data structure consists of a finite (and possibly mutable) set of vertices or nodes or points, together with a set of unordered pairs of these vertices for an undirected Graph or a set of ordered pairs for a directed Graph. These pairs are known as edges, arcs, or lines for an undirected Graph and as arrows, directed edges, directed arcs, or directed lines for a directed Graph. The vertices may be part of the Graph structure, or may be external entities represented by integer indices or references.</em></blockquote><ul class="postList"><li id="f896" class="graf graf--li graf-after--blockquote">A graph is <strong class="markup--strong markup--li-strong">any</strong> collection of nodes and edges.</li><li id="fbda" class="graf graf--li graf-after--li">Much more relaxed in structure than a tree.</li><li id="5281" class="graf graf--li graf-after--li">It doesn’t need to have a root node (not every node needs to be accessible from a single node)</li><li id="0c79" class="graf graf--li graf-after--li">It can have cycles (a group of nodes whose paths begin and end at the same node)</li><li id="4afc" class="graf graf--li graf-after--li">Cycles are not always “isolated”, they can be one part of a larger graph. You can detect them by starting your search on a specific node and finding a path that takes you back to that same node.</li><li id="8f45" class="graf graf--li graf-after--li">Any number of edges may leave a given node</li><li id="51cf" class="graf graf--li graf-after--li">A Path is a sequence of nodes on a graph</li></ul><h3 id="a212" class="graf graf--h3 graf-after--li">Cycle Visual</h3><figure id="d0db" class="graf graf--figure graf-after--h3"><img class="graf-image" data-width="1407" data-height="574" src="https://webdevhubcom.files.wordpress.com/2021/03/47241-1dn1bqcdxdfg4fcvsz6uara.png"></figure><p id="ceb9" class="graf graf--p graf-after--figure">A Graph data structure may also associate to each edge some edge value, such as a symbolic label or a numeric attribute (cost, capacity, length, etc.).</p><p id="4b0c" class="graf graf--p graf-after--p">Representation<br>There are different ways of representing a graph, each of them with its own advantages and disadvantages. Here are the main 2:</p><p id="7553" class="graf graf--p graf-after--p">Adjacency list: For every vertex a list of adjacent vertices is stored. This can be viewed as storing the list of edges. This data structure allows the storage of additional data on the vertices and edges.<br>Adjacency matrix: Data are stored in a two-dimensional matrix, in which the rows represent source vertices and columns represent destination vertices. The data on the edges and vertices must be stored externally.</p><figure id="95c9" class="graf graf--figure graf--iframe graf-after--p"></figure><p id="8850" class="graf graf--p graf-after--figure">Graph</p><blockquote id="b61e" class="graf graf--blockquote graf-after--p graf--trailing"><em class="markup--em markup--blockquote-em">The code</em></blockquote></div></div></section><section class="section section--body section--last"><div class="section-divider"><hr class="section-divider"></div><div class="section-content"><div class="section-inner sectionLayout--insetColumn"><figure id="ed21" class="graf graf--figure graf--iframe graf--leading"></figure><h3 id="30a5" class="graf graf--h3 graf-after--figure">If you found this guide helpful feel free to checkout my GitHub/gists where I host similar content:</h3><div id="1c2f" class="graf graf--mixtapeEmbed graf-after--h3"><a href="https://gist.github.com/bgoonz" class="markup--anchor markup--mixtapeEmbed-anchor" title="https://gist.github.com/bgoonz"><strong class="markup--strong markup--mixtapeEmbed-strong">bgoonz’s gists</strong><br><em class="markup--em markup--mixtapeEmbed-em">Instantly share code, notes, and snippets. Web Developer, Electrical Engineer JavaScript | CSS | Bootstrap | Python |…</em>gist.github.com</a><a href="https://gist.github.com/bgoonz" class="js-mixtapeImage mixtapeImage u-ignoreBlock" style="background-image:url('https://cdn-images-1.medium.com/fit/c/160/160/0*3O67jrqm3EHjTK2H');"></a></div><div id="3585" class="graf graf--mixtapeEmbed graf-after--mixtapeEmbed"><a href="https://github.com/bgoonz" class="markup--anchor markup--mixtapeEmbed-anchor" title="https://github.com/bgoonz"><strong class="markup--strong markup--mixtapeEmbed-strong">bgoonz — Overview</strong><br><em class="markup--em markup--mixtapeEmbed-em">Web Developer, Electrical Engineer JavaScript | CSS | Bootstrap | Python | React | Node.js | Express | Sequelize…</em>github.com</a><a href="https://github.com/bgoonz" class="js-mixtapeImage mixtapeImage u-ignoreBlock" style="background-image:url('https://cdn-images-1.medium.com/fit/c/160/160/0*Udg3rbeFyslZ9dyl');"></a></div><h3 id="cb1a" class="graf graf--h3 graf-after--mixtapeEmbed">Or Checkout my personal Resource Site:</h3><div id="4bce" class="graf graf--mixtapeEmbed graf-after--h3 graf--trailing"><a href="https://web-dev-resource-hub.netlify.app/" class="markup--anchor markup--mixtapeEmbed-anchor" title="https://web-dev-resource-hub.netlify.app/"><strong class="markup--strong markup--mixtapeEmbed-strong">Web-Dev-Resource-Hub</strong><br><em class="markup--em markup--mixtapeEmbed-em">Edit description</em>web-dev-resource-hub.netlify.app</a><a href="https://web-dev-resource-hub.netlify.app/" class="js-mixtapeImage mixtapeImage mixtapeImage--empty u-ignoreBlock"></a></div></div></div></section> | |
</section> | |
<footer><p>By <a href="https://medium.com/@bryanguner" class="p-author h-card">Bryan Guner</a> on <a href="https://medium.com/p/8f9f709c15b4"><time class="dt-published" datetime="2021-03-05T15:46:28.536Z">March 5, 2021</time></a>.</p><p><a href="https://medium.com/@bryanguner/fundamental-data-structures-in-javascript-8f9f709c15b4" class="p-canonical">Canonical link</a></p><p>Exported from <a href="https://medium.com">Medium</a> on March 23, 2021.</p></footer></article> | |
<p></p> | |
</div><!-- .entry-content --> | |
<footer class="entry-footer responsive-max-width"> | |
<span class="byline"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><span class="screen-reader-text">Posted by</span><span class="author vcard"><a class="url fn n" href="https://web-dev-hub.com/author/gunerb1/">bgoonz</a></span></span><span class="posted-on"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><defs><path id="a" d="M0 0h24v24H0V0z"></path></defs><clipPath id="b"><use xlink:href="#a" overflow="visible"></use></clipPath><path clip-path="url(#b)" d="M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10 10-4.5 10-10S17.5 2 12 2zm4.2 14.2L11 13V7h1.5v5.2l4.5 2.7-.8 1.3z"></path></svg><a href="https://web-dev-hub.com/2021/03/23/fundamental-data-structures-in-javascript/" rel="bookmark"><time class="entry-date published" datetime="2021-03-23T15:11:18-04:00">March 23, 2021</time><time class="updated" datetime="2021-03-23T15:11:29-04:00">March 23, 2021</time></a></span><span class="cat-links"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M10 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2h-8l-2-2z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><span class="screen-reader-text">Posted in</span><a href="https://web-dev-hub.com/category/uncategorized/" rel="category tag">Uncategorized</a></span><span class="tags-links"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M21.41 11.58l-9-9C12.05 2.22 11.55 2 11 2H4c-1.1 0-2 .9-2 2v7c0 .55.22 1.05.59 1.42l9 9c.36.36.86.58 1.41.58.55 0 1.05-.22 1.41-.59l7-7c.37-.36.59-.86.59-1.41 0-.55-.23-1.06-.59-1.42zM5.5 7C4.67 7 4 6.33 4 5.5S4.67 4 5.5 4 7 4.67 7 5.5 6.33 7 5.5 7z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><span class="screen-reader-text">Tags:</span><a href="https://web-dev-hub.com/tag/coding/" rel="tag">Coding</a>, <a href="https://web-dev-hub.com/tag/data-structures/" rel="tag">data-Structures</a>, <a href="https://web-dev-hub.com/tag/javascript/" rel="tag">Javascript</a>, <a href="https://web-dev-hub.com/tag/programming/" rel="tag">Programming</a>, <a href="https://web-dev-hub.com/tag/web-development/" rel="tag">Web Development</a></span><span class="comments-link"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M21.99 4c0-1.1-.89-2-1.99-2H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h14l4 4-.01-18z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><a href="https://web-dev-hub.com/2021/03/23/fundamental-data-structures-in-javascript/#respond">Leave a comment<span class="screen-reader-text"> on Fundamental Data Structures In JavaScript</span></a></span><span class="edit-link"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04c.39-.39.39-1.02 0-1.41l-2.34-2.34c-.39-.39-1.02-.39-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><a class="post-edit-link" href="https://wordpress.com/post/web-dev-hub.com/365">Edit <span class="screen-reader-text">Fundamental Data Structures In JavaScript</span></a></span> </footer><!-- .entry-footer --> | |
</article><!-- #post-${ID} --> | |
<article id="post-576" class="post-576 post type-post status-publish format-standard hentry category-uncategorized tag-beginners-guide tag-development tag-javascript tag-technology tag-vscode-extension entry"> | |
<header class="entry-header responsive-max-width"> | |
<h2 class="entry-title"><a href="https://web-dev-hub.com/2021/03/22/vscode-extensions-specifically-for-javascript-development/" rel="bookmark">VSCode Extensions Specifically for JavaScript Development</a></h2> </header><!-- .entry-header --> | |
<div class="entry-content"> | |
<h4><a href="http://medium.com/codex">CODEX</a></h4> | |
<h4>VSCode Extensions that are indispensable in JavaScript development</h4> | |
<h3>Back and Forth</h3> | |
<ul> | |
<li>Adds backwards and forwards buttons to the toolbar in VSCode</li> | |
<li><a href="https://marketplace.visualstudio.com/items?itemName=nick-rudenko.back-n-forth" title="https://marketplace.visualstudio.com/items?itemName=nick-rudenko.back-n-forth" target="_blank">https://marketplace.visualstudio.com/items?itemName=nick-rudenko.back-n-forth</a></li> | |
</ul> | |
<figure><img data-width="796" data-height="616" src="https://cdn-images-1.medium.com/max/800/0*hsbombFMlu6yICjz.gif"></figure> | |
<hr> | |
<h3>Bracket Pair Colorizer 2</h3> | |
<ul> | |
<li>Colors matching brackets so it’s easier to tell which brackets match.</li> | |
<li><a href="https://marketplace.visualstudio.com/items?itemName=CoenraadS.bracket-pair-colorizer-2" title="https://marketplace.visualstudio.com/items?itemName=CoenraadS.bracket-pair-colorizer-2" target="_blank">https://marketplace.visualstudio.com/items?itemName=CoenraadS.bracket-pair-colorizer-2</a></li> | |
</ul> | |
<figure><img data-width="625" data-height="119" src="https://cdn-images-1.medium.com/max/800/0*MT-BCptwnKGYk1Pk.png"></figure> | |
<hr> | |
<h3>Babel Javascript</h3> | |
<ul> | |
<li>A better syntax highlighter for JavaScript code</li> | |
<li><a href="https://marketplace.visualstudio.com/items?itemName=mgmcdermott.vscode-language-babel" title="https://marketplace.visualstudio.com/items?itemName=mgmcdermott.vscode-language-babel" target="_blank">https://marketplace.visualstudio.com/items?itemName=mgmcdermott.vscode-language-babel</a></li> | |
</ul> | |
<figure><img data-width="1440" data-height="1394" src="https://cdn-images-1.medium.com/max/800/0*b5t9hd_8soPq26pq.png"></figure> | |
<hr> | |
<h3>Code Runner</h3> | |
<ul> | |
<li>Puts a “Play” button in your toolbar and let’s you run code files by pressing it.</li> | |
<li><a href="https://marketplace.visualstudio.com/items?itemName=formulahendry.code-runner" title="https://marketplace.visualstudio.com/items?itemName=formulahendry.code-runner" target="_blank">https://marketplace.visualstudio.com/items?itemName=formulahendry.code-runner</a></li> | |
</ul> | |
<h3>Code Runner</h3> | |
<blockquote><p>Run code snippet or code file for multiple languages: <strong>C, C++, Java, JavaScript, PHP, Python, Perl, Perl 6, Ruby, Go, Lua, Groovy, PowerShell, BAT/CMD, BASH/SH, F# Script, F# (.NET Core), C# Script, C# (.NET Core), VBScript, TypeScript, CoffeeScript, Scala, Swift, Julia, Crystal, OCaml Script, R, AppleScript, Elixir, Visual Basic .NET, Clojure, Haxe, Objective-C, Rust, Racket, Scheme, AutoHotkey, AutoIt, Kotlin, Dart, Free Pascal, Haskell, Nim, D, Lisp, Kit, V, SCSS, Sass, CUDA, Less, Fortran</strong>, and custom command</p></blockquote> | |
<h3>Features</h3> | |
<blockquote><p>Run code file of current active Text Editor</p></blockquote> | |
<blockquote><p>Run code file through context menu of file explorer</p></blockquote> | |
<blockquote><p>Run selected code snippet in Text Editor</p></blockquote> | |
<blockquote><p>Run code per Shebang</p></blockquote> | |
<blockquote><p>Run code per filename glob</p></blockquote> | |
<blockquote><p>Run custom command</p></blockquote> | |
<blockquote><p>Stop code running</p></blockquote> | |
<blockquote><p>View output in Output Window</p></blockquote> | |
<blockquote><p>Set default language to run</p></blockquote> | |
<blockquote><p>Select language to run</p></blockquote> | |
<blockquote><p>Support REPL by running code in Integrated Terminal</p></blockquote> | |
<h3>Usages</h3> | |
<h4>To run code:</h4> | |
<ul> | |
<li>use shortcut <code>Ctrl+Alt+N</code></li> | |
<li>or press <code>F1</code> and then select/type <code>Run Code</code>,</li> | |
<li>or right click the Text Editor and then click <code>Run Code</code> in editor context menu</li> | |
<li>or click <code>Run Code</code> button in editor title menu</li> | |
<li>or click <code>Run Code</code> button in context menu of file explorer</li> | |
<li>To stop the running code:</li> | |
<li>use shortcut <code>Ctrl+Alt+M</code></li> | |
<li>or press <code>F1</code> and then select/type <code>Stop Code Run</code></li> | |
<li>or right click the Output Channel and then click <code>Stop Code Run</code> in context menu</li> | |
</ul> | |
<figure><img data-width="1860" data-height="1220" src="https://cdn-images-1.medium.com/max/800/0*_RtB2WiNuXhAJnuJ.gif"></figure> | |
<ul> | |
<li>To select language to run, use shortcut <code>Ctrl+Alt+J</code>, or press <code>F1</code> and then select/type <code>Run By Language</code>, then type or select the language to run: e.g <code>php, javascript, bat, shellscript...</code></li> | |
</ul> | |
<figure><img data-width="1944" data-height="1207" src="https://cdn-images-1.medium.com/max/800/0*lCmaRsgOMINbFJps.gif"></figure> | |
<ul> | |
<li>To run custom command, then use shortcut <code>Ctrl+Alt+K</code>, or press <code>F1</code> and then select/type <code>Run Custom Command</code></li> | |
</ul> | |
<hr> | |
<h3>Color Highlight</h3> | |
<ul> | |
<li>Changes the background color of hex colors in your code to show you what color it actually is</li> | |
<li><a href="https://marketplace.visualstudio.com/items?itemName=naumovs.color-highlight" title="https://marketplace.visualstudio.com/items?itemName=naumovs.color-highlight" target="_blank">https://marketplace.visualstudio.com/items?itemName=naumovs.color-highlight</a></li> | |
</ul> | |
<figure><img data-width="128" data-height="128" src="https://cdn-images-1.medium.com/max/800/0*9K5_QPPvfozmuTWH"></figure> | |
<h3>Git Graph</h3> | |
<ul> | |
<li>Shows you a graphical representation of your git branches and commits</li> | |
<li><a href="https://marketplace.visualstudio.com/items?itemName=mhutchie.git-graph" title="https://marketplace.visualstudio.com/items?itemName=mhutchie.git-graph" target="_blank">https://marketplace.visualstudio.com/items?itemName=mhutchie.git-graph</a></li> | |
</ul> | |
<figure><img data-width="1208" data-height="682" src="https://cdn-images-1.medium.com/max/800/0*eAKBnl6yXJgXZXvZ.gif"></figure> | |
<hr> | |
<h3>GitLens</h3> | |
<ul> | |
<li>Adds tons of cool features to vscode, like viewing commits inline inside the editor</li> | |
<li><a href="https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens" title="https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens" target="_blank">https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens</a></li> | |
</ul> | |
<p>Here are just some of the <strong>features</strong> that GitLens provides,</p> | |
<ul> | |
<li>effortless <a href="https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens#revision-navigation-" title="Jump to Revision Navigation" target="_blank"><strong>revision navigation</strong></a> (backwards and forwards) through the history of a file</li> | |
<li>an unobtrusive <a href="https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens#current-line-blame-" title="Jump to Current Line Blame" target="_blank"><strong>current line blame</strong></a> annotation at the end of the line showing the commit and author who last modified the line, with more detailed blame information accessible on <a href="https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens#hovers-" title="Jump to Hovers" target="_blank"><strong>hover</strong></a></li> | |
<li><a href="https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens#git-code-lens-" title="Jump to Git Code Lens" target="_blank"><strong>authorship code lens</strong></a> showing the most recent commit and number of authors at the top of files and/or on code blocks</li> | |
<li>a <a href="https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens#status-bar-blame-" title="Jump to Status Bar Blame" target="_blank"><strong>status bar blame</strong></a> annotation showing the commit and author who last modified the current line</li> | |
<li>on-demand <strong>file annotations</strong> in the editor gutter, including</li> | |
<li><a href="https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens#gutter-blame-" title="Jump to Gutter Blame" target="_blank"><strong>blame</strong></a> — shows the commit and author who last modified each line of a file</li> | |
<li><a href="https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens#gutter-changes-" title="Jump to Gutter Changes" target="_blank"><strong>changes</strong></a> — highlights any local (unpublished) changes or lines changed by the most recent commit</li> | |
<li><a href="https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens#gutter-heatmap-" title="Jump to Gutter Heatmap" target="_blank"><strong>heatmap</strong></a> — shows how recently lines were changed, relative to all the other changes in the file and to now (hot vs. cold)</li> | |
<li>many rich <strong>Side Bar views</strong></li> | |
<li>a <a href="https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens#commits-view-" title="Jump to the Commits view" target="_blank"><strong><em>Commits</em> view</strong></a> to visualize, explore, and manage Git commits</li> | |
<li>a <a href="https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens#repositories-view-" title="Jump to the Repositories view" target="_blank"><strong><em>Repositories</em> view</strong></a> to visualize, explore, and manage Git repositories</li> | |
<li>a <a href="https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens#file-history-view-" title="Jump to the File History view" target="_blank"><strong><em>File History</em> view</strong></a> to visualize, navigate, and explore the revision history of the current file or just the selected lines of the current file</li> | |
<li>a <a href="https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens#line-history-view-" title="Jump to the Line History view" target="_blank"><strong><em>Line History</em> view</strong></a> to visualize, navigate, and explore the revision history of the selected lines of the current file</li> | |
<li>a <a href="https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens#branches-view-" title="Jump to the Branches view" target="_blank"><strong><em>Branches</em> view</strong></a> to visualize, explore, and manage Git branches</li> | |
<li>a <a href="https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens#remotes-view-" title="Jump to the Remotes view" target="_blank"><strong><em>Remotes</em> view</strong></a> to visualize, explore, and manage Git remotes and remote branches</li> | |
<li>a <a href="https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens#stashes-view-" title="Jump to the Stashes view" target="_blank"><strong><em>Stashes</em> view</strong></a> to visualize, explore, and manage Git stashes</li> | |
<li>a <a href="https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens#tags-view-" title="Jump to the Tags view" target="_blank"><strong><em>Tags</em> view</strong></a> to visualize, explore, and manage Git tags</li> | |
<li>a <a href="https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens#contributors-view-" title="Jump to the Contributors view" target="_blank"><strong><em>Contributors</em> view</strong></a> to visualize, navigate, and explore contributors</li> | |
<li>a <a href="https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens#search--compare-view-" title="Jump to the Search & Compare view" target="_blank"><strong><em>Search & Compare</em> view</strong></a> to search and explore commit histories by message, author, files, id, etc, or visualize comparisons between branches, tags, commits, and more</li> | |
<li>a <a href="https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens#git-command-palette-" title="Jump to the Git Command Palette" target="_blank"><strong>Git Command Palette</strong></a> to provide guided (step-by-step) access to many common Git commands, as well as quick access to</li> | |
<li><a href="https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens#quick-commit-access-" title="Jump to Quick Commit Access" target="_blank">commits</a> — history and search</li> | |
<li><a href="https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens#quick-stash-access-" title="Jump to Quick Stash Access" target="_blank">stashes</a></li> | |
<li><a href="https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens#quick-status-access-" title="Jump to Quick Status Access" target="_blank">status</a> — current branch and working tree status</li> | |
<li>a user-friendly <a href="https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens#interactive-rebase-editor-" title="Jump to the Interactive Rebase Editor" target="_blank"><strong>interactive rebase editor</strong></a> to easily configure an interactive rebase session</li> | |
<li><a href="https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens#terminal-links-" title="Jump to Terminal Links" target="_blank"><strong>terminal links</strong></a> — <code>ctrl+click</code> on autolinks in the integrated terminal to quickly jump to more details for commits, branches, tags, and more</li> | |
<li>rich <a href="https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens#remote-provider-integrations-" title="Jump to Remote Provider Integrations" target="_blank"><strong>remote provider integrations</strong></a> — GitHub, GitLab, Bitbucket, Azure DevOps</li> | |
<li>issue and pull request auto-linking</li> | |
<li>rich hover information provided for linked issues and pull requests (GitHub only)</li> | |
<li>associates pull requests with branches and commits (GitHub only)</li> | |
<li>many <a href="https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens#powerful-commands-" title="Jump to Powerful Commands" target="_blank"><strong>powerful commands</strong></a> for navigating and comparing revisions, and more</li> | |
<li>user-defined <a href="https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens#modes-" title="Jump to Modes" target="_blank"><strong>modes</strong></a> for quickly toggling between sets of settings</li> | |
<li>and so much more 😁</li> | |
</ul> | |
<h3>Features</h3> | |
<h4>Revision Navigation</h4> | |
<figure><img data-width="747" data-height="610" src="https://cdn-images-1.medium.com/max/800/0*ZznZkr2qdB6qT2sX.gif"></figure> | |
<hr> | |
<h3>Markdown All in One</h3> | |
<ul> | |
<li>Everything you need to help you write markdown files in VSCode</li> | |
<li><a href="https://marketplace.visualstudio.com/items?itemName=yzhang.markdown-all-in-one" title="https://marketplace.visualstudio.com/items?itemName=yzhang.markdown-all-in-one" target="_blank">https://marketplace.visualstudio.com/items?itemName=yzhang.markdown-all-in-one</a></li> | |
</ul> | |
<h3>Features</h3> | |
<h3>Keyboard shortcuts</h3> | |
<figure><img data-width="564" data-height="408" src="https://cdn-images-1.medium.com/max/800/0*_usOVMNpDjj4nqKP.gif"></figure> | |
<p>(Typo: multiple words)</p> | |
<figure><img data-width="480" data-height="206" src="https://cdn-images-1.medium.com/max/800/0*Eqbbj4t2090z7JLj.gif"></figure> | |
<p>See full key binding list in the <a href="https://marketplace.visualstudio.com/items?itemName=yzhang.markdown-all-in-one#keyboard-shortcuts-1" target="_blank">keyboard shortcuts</a> section</p> | |
<h3>Table of contents</h3> | |
<figure><img data-width="610" data-height="502" src="https://cdn-images-1.medium.com/max/800/0*T1aP3qXU9HHLvrkZ.png"></figure> | |
<ul> | |
<li>Run command “<strong>Create Table of Contents</strong>” to insert a new table of contents.</li> | |
<li>The TOC is <strong>automatically updated</strong> on file save by default. To disable, please change the <code>toc.updateOnSave</code> option.</li> | |
<li>The <strong>indentation type (tab or spaces)</strong> of TOC can be configured per file. Find the setting in the right bottom corner of VS Code’s status bar.</li> | |
<li><strong><em>Note</em></strong>: Be sure to also check the <code>list.indentationSize</code> option.</li> | |
<li>To make TOC <strong>compatible with GitHub or GitLab</strong>, set option <code>slugifyMode</code> accordingly</li> | |
<li>Three ways to <strong>control which headings are present</strong> in the TOC:</li> | |
<li>Click to expand</li> | |
<li>Easily add/update/remove <strong>section numbering</strong></li> | |
</ul> | |
<figure><img data-width="1536" data-height="676" src="https://cdn-images-1.medium.com/max/800/0*wqtYh9oFLU1GbfLE.gif"></figure> | |
<ul> | |
<li><em>In case you are seeing </em><strong><em>unexpected TOC recognition</em></strong><em>, you can add a </em><code><em><!-- no toc --></em></code><em> comment above the list</em>.</li> | |
</ul> | |
<h3>List editing</h3> | |
<figure><img data-width="428" data-height="180" src="https://cdn-images-1.medium.com/max/800/0*0ipp3m0zajfTJlQR.gif"></figure> | |
<figure><img data-width="428" data-height="180" src="https://cdn-images-1.medium.com/max/800/0*LLQYEmYRbIsx3EkR.gif"></figure> | |
<figure><img data-width="428" data-height="224" src="https://cdn-images-1.medium.com/max/800/0*eoAN8X-cP9iM6l3Y.gif"></figure> | |
<p><strong><em>Note</em></strong>: By default, this extension tries to determine indentation size for different lists according to <a href="https://spec.commonmark.org/0.29/#list-items" target="_blank">CommonMark Spec</a>. If you prefer to use a fixed tab size, please change the <code>list.indentationSize</code> setting.</p> | |
<h3>Print Markdown to HTML</h3> | |
<ul> | |
<li>Commands <code>Markdown: Print current document to HTML</code> and <code>Markdown: Print documents to HTML</code> (batch mode)</li> | |
<li><strong>Compatible</strong> with other installed Markdown plugins (e.g. <a href="https://marketplace.visualstudio.com/items?itemName=bierner.markdown-footnotes" target="_blank">Markdown Footnotes</a>) The exported HTML should look the same as inside VSCode.</li> | |
<li>Use comment <code><!-- title: Your Title --></code> to specify a title of the exported HTML.</li> | |
<li>Plain links to <code>.md</code> files will be converted to <code>.html</code>.</li> | |
<li>It’s recommended to print the exported HTML to PDF with browser (e.g. Chrome) if you want to share your documents with others.</li> | |
</ul> | |
<h3>GitHub Flavored Markdown</h3> | |
<ul> | |
<li>Table formatter</li> | |
</ul> | |
<figure><img data-width="492" data-height="274" src="https://cdn-images-1.medium.com/max/800/0*6yKsV2SWwPFdGHZT.gif"></figure> | |
<ul> | |
<li><strong><em>Note</em></strong>: The key binding is Ctrl + Shift + I on Linux. See <a href="https://code.visualstudio.com/docs/getstarted/keybindings#_keyboard-shortcuts-reference" target="_blank">Visual Studio Code Key Bindings</a>.</li> | |
<li>Task lists</li> | |
</ul> | |
<h3>Math</h3> | |
<figure><img data-width="1088" data-height="226" src="https://cdn-images-1.medium.com/max/800/0*6NkKUCywNSSMsbV2.png"></figure> | |
<p>Please use <a href="https://marketplace.visualstudio.com/items?itemName=goessner.mdmath" target="_blank">Markdown+Math</a> for dedicated math support. Be sure to disable <code>math.enabled</code> option of this extension.</p> | |
<h3>Auto completions</h3> | |
<p>Tip: also support the option <code>completion.root</code></p> | |
<ul> | |
<li>Images/Files (respects option <code>search.exclude</code>)</li> | |
</ul> | |
<figure><img data-width="702" data-height="168" src="https://cdn-images-1.medium.com/max/800/0*0yN3cZ6xsl6c_oP5.png"></figure> | |
<ul> | |
<li>Math functions (including option <code>katex.macros</code>)</li> | |
</ul> | |
<figure><img data-width="308" data-height="337" src="https://cdn-images-1.medium.com/max/800/0*ZYCqFh0MHuE153Ed.png"></figure> | |
<hr> | |
<h3>Mocah Test Explorer</h3> | |
<ul> | |
<li>Lets you run mocha tests in the VSCode sidebar</li> | |
<li><a href="https://marketplace.visualstudio.com/items?itemName=hbenl.vscode-mocha-test-adapter" title="https://marketplace.visualstudio.com/items?itemName=hbenl.vscode-mocha-test-adapter" target="_blank">https://marketplace.visualstudio.com/items?itemName=hbenl.vscode-mocha-test-adapter</a></li> | |
</ul> | |
<h3>Features</h3> | |
<h3>Import command</h3> | |
<figure><img data-width="800" data-height="163" src="https://cdn-images-1.medium.com/max/800/0*1ks3u0MsnG96JUy6.gif"></figure> | |
<pre><code>{<br> "npm-intellisense.importES6": true,<br> "npm-intellisense.importQuotes": "'",<br> "npm-intellisense.importLinebreak": ";\r\n",<br> "npm-intellisense.importDeclarationType": "const",<br>}</code></pre> | |
<h3>Import command (ES5)</h3> | |
<figure><img data-width="960" data-height="432" src="https://cdn-images-1.medium.com/max/800/0*srfRIxEbcL_yxBey.gif"></figure> | |
<pre><code>{<br> "npm-intellisense.importES6": false,<br> "npm-intellisense.importQuotes": "'",<br> "npm-intellisense.importLinebreak": ";\r\n",<br> "npm-intellisense.importDeclarationType": "const",<br>}</code></pre> | |
<hr> | |
<h3>NPM Intellisense</h3> | |
<ul> | |
<li>Autocomlpetes npm module names when you are typing require or import.</li> | |
<li><a href="https://marketplace.visualstudio.com/items?itemName=christian-kohler.npm-intellisense" title="https://marketplace.visualstudio.com/items?itemName=christian-kohler.npm-intellisense" target="_blank">https://marketplace.visualstudio.com/items?itemName=christian-kohler.npm-intellisense</a></li> | |
</ul> | |
<h3>Features</h3> | |
<h3>Import command</h3> | |
<figure><img data-width="800" data-height="163" src="https://cdn-images-1.medium.com/max/800/0*o3KIizXjd5BfnZzR.gif"></figure> | |
<pre><code>{<br> "npm-intellisense.importES6": true,<br> "npm-intellisense.importQuotes": "'",<br> "npm-intellisense.importLinebreak": ";\r\n",<br> "npm-intellisense.importDeclarationType": "const",<br>}</code></pre> | |
<h3>Import command (ES5)</h3> | |
<figure><img data-width="960" data-height="432" src="https://cdn-images-1.medium.com/max/800/0*pCEaJc8pJmJi_dMk.gif"></figure> | |
<pre><code>{<br> "npm-intellisense.importES6": false,<br> "npm-intellisense.importQuotes": "'",<br> "npm-intellisense.importLinebreak": ";\r\n",<br> "npm-intellisense.importDeclarationType": "const",<br>}</code></pre> | |
<h3>Scan devDependencies</h3> | |
<p>Npm intellisense scans only dependencies by default. Set scanDevDependencies to true to enable it for devDependencies too.</p> | |
<pre><code>{<br> "npm-intellisense.scanDevDependencies": true,<br>}</code></pre> | |
<hr> | |
<h3>Path Intellisense</h3> | |
<ul> | |
<li>Auto completes filesystem paths when you are typing them</li> | |
<li><a href="https://marketplace.visualstudio.com/items?itemName=christian-kohler.path-intellisense" title="https://marketplace.visualstudio.com/items?itemName=christian-kohler.path-intellisense" target="_blank">https://marketplace.visualstudio.com/items?itemName=christian-kohler.path-intellisense</a></li> | |
</ul> | |
<h3>Usage</h3> | |
<figure><img data-width="480" data-height="270" src="https://cdn-images-1.medium.com/max/800/0*if44ZSUgw2MDJiFl.gif"></figure> | |
<h3>Commerical Extensions</h3> | |
<h3>Quokka.js</h3> | |
<ul> | |
<li>A paid extension that does amazing things by showing the results of your javascript inline inside the editor window</li> | |
<li><a href="https://marketplace.visualstudio.com/items?itemName=WallabyJs.quokka-vscode" title="https://marketplace.visualstudio.com/items?itemName=WallabyJs.quokka-vscode" target="_blank">https://marketplace.visualstudio.com/items?itemName=WallabyJs.quokka-vscode</a></li> | |
</ul> | |
<h3><a href="https://quokkajs.com/" target="_blank">Quokka.js</a> Visual Studio Code Extension</h3> | |
<p>Quokka.js is a developer productivity tool for rapid JavaScript / TypeScript prototyping. Runtime values are updated and displayed in your IDE next to your code, as you type.</p> | |
<figure><img data-width="800" data-height="500" src="https://cdn-images-1.medium.com/max/800/0*xYo5Z7lROn4tLQu9.gif"></figure> | |
<h3>If you found this guide helpful feel free to checkout my other articles:</h3> | |
<p><a href="https://bryanguner.medium.com/a-list-of-all-of-my-articles-to-link-to-future-posts-1f6f88ebdf5b">https://bryanguner.medium.com/a-list-of-all-of-my-articles-to-link-to-future-posts-1f6f88ebdf5b</a></p> | |
<h3>OR GitHub/gists where I host similar content:</h3> | |
<p><a href="https://bryanguner.medium.com/a-list-of-all-of-my-articles-to-link-to-future-posts-1f6f88ebdf5b">https://bryanguner.medium.com/a-list-of-all-of-my-articles-to-link-to-future-posts-1f6f88ebdf5b</a><a href="https://bryanguner.medium.com/a-list-of-all-of-my-articles-to-link-to-future-posts-1f6f88ebdf5b">https://bryanguner.medium.com/a-list-of-all-of-my-articles-to-link-to-future-posts-1f6f88ebdf5b</a></p> | |
<h3>Or Checkout my personal Resource Site:</h3> | |
<p><a href="https://bryanguner.medium.com/a-list-of-all-of-my-articles-to-link-to-future-posts-1f6f88ebdf5b">https://bryanguner.medium.com/a-list-of-all-of-my-articles-to-link-to-future-posts-1f6f88ebdf5b</a> </p> | |
</div><!-- .entry-content --> | |
<footer class="entry-footer responsive-max-width"> | |
<span class="byline"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><span class="screen-reader-text">Posted by</span><span class="author vcard"><a class="url fn n" href="https://web-dev-hub.com/author/gunerb1/">bgoonz</a></span></span><span class="posted-on"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><defs><path id="a" d="M0 0h24v24H0V0z"></path></defs><clipPath id="b"><use xlink:href="#a" overflow="visible"></use></clipPath><path clip-path="url(#b)" d="M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10 10-4.5 10-10S17.5 2 12 2zm4.2 14.2L11 13V7h1.5v5.2l4.5 2.7-.8 1.3z"></path></svg><a href="https://web-dev-hub.com/2021/03/22/vscode-extensions-specifically-for-javascript-development/" rel="bookmark"><time class="entry-date published updated" datetime="2021-03-22T22:37:45-04:00">March 22, 2021</time></a></span><span class="cat-links"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M10 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2h-8l-2-2z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><span class="screen-reader-text">Posted in</span><a href="https://web-dev-hub.com/category/uncategorized/" rel="category tag">Uncategorized</a></span><span class="tags-links"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M21.41 11.58l-9-9C12.05 2.22 11.55 2 11 2H4c-1.1 0-2 .9-2 2v7c0 .55.22 1.05.59 1.42l9 9c.36.36.86.58 1.41.58.55 0 1.05-.22 1.41-.59l7-7c.37-.36.59-.86.59-1.41 0-.55-.23-1.06-.59-1.42zM5.5 7C4.67 7 4 6.33 4 5.5S4.67 4 5.5 4 7 4.67 7 5.5 6.33 7 5.5 7z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><span class="screen-reader-text">Tags:</span><a href="https://web-dev-hub.com/tag/beginners-guide/" rel="tag">Beginners Guide</a>, <a href="https://web-dev-hub.com/tag/development/" rel="tag">Development</a>, <a href="https://web-dev-hub.com/tag/javascript/" rel="tag">Javascript</a>, <a href="https://web-dev-hub.com/tag/technology/" rel="tag">Technology</a>, <a href="https://web-dev-hub.com/tag/vscode-extension/" rel="tag">Vscode Extension</a></span><span class="comments-link"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M21.99 4c0-1.1-.89-2-1.99-2H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h14l4 4-.01-18z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><a href="https://web-dev-hub.com/2021/03/22/vscode-extensions-specifically-for-javascript-development/#respond">Leave a comment<span class="screen-reader-text"> on VSCode Extensions Specifically for JavaScript Development</span></a></span><span class="edit-link"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04c.39-.39.39-1.02 0-1.41l-2.34-2.34c-.39-.39-1.02-.39-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><a class="post-edit-link" href="https://wordpress.com/post/web-dev-hub.com/576">Edit <span class="screen-reader-text">VSCode Extensions Specifically for JavaScript Development</span></a></span> </footer><!-- .entry-footer --> | |
</article><!-- #post-${ID} --> | |
<article id="post-575" class="post-575 post type-post status-publish format-standard hentry category-uncategorized entry"> | |
<header class="entry-header responsive-max-width"> | |
<h2 class="entry-title"><a href="https://web-dev-hub.com/2021/03/22/a-list-of-all-of-my-articles-to-link-to-future-posts/" rel="bookmark">A list of all of my articles to link to future posts</a></h2> </header><!-- .entry-header --> | |
<div class="entry-content"> | |
<p>You should probably skip this one… seriously it’s just for internal use!</p> | |
<p><a href="https://bryanguner.medium.com/">https://bryanguner.medium.com/</a><a href="https://bryanguner.medium.com/">https://bryanguner.medium.com/</a><a href="https://bryanguner.medium.com/">https://bryanguner.medium.com/</a><a href="https://bryanguner.medium.com/">https://bryanguner.medium.com/</a><a href="https://bryanguner.medium.com/">https://bryanguner.medium.com/</a><a href="https://bryanguner.medium.com/">https://bryanguner.medium.com/</a><a href="https://bryanguner.medium.com/">https://bryanguner.medium.com/</a><a href="https://bryanguner.medium.com/">https://bryanguner.medium.com/</a><a href="https://bryanguner.medium.com/">https://bryanguner.medium.com/</a><a href="https://bryanguner.medium.com/">https://bryanguner.medium.com/</a><a href="https://bryanguner.medium.com/">https://bryanguner.medium.com/</a><a href="https://bryanguner.medium.com/">https://bryanguner.medium.com/</a><a href="https://bryanguner.medium.com/">https://bryanguner.medium.com/</a><a href="https://bryanguner.medium.com/">https://bryanguner.medium.com/</a><a href="https://bryanguner.medium.com/">https://bryanguner.medium.com/</a><a href="https://bryanguner.medium.com/">https://bryanguner.medium.com/</a><a href="https://bryanguner.medium.com/">https://bryanguner.medium.com/</a><a href="https://bryanguner.medium.com/">https://bryanguner.medium.com/</a><a href="https://bryanguner.medium.com/">https://bryanguner.medium.com/</a><a href="https://bryanguner.medium.com/">https://bryanguner.medium.com/</a><a href="https://bryanguner.medium.com/">https://bryanguner.medium.com/</a><a href="https://bryanguner.medium.com/">https://bryanguner.medium.com/</a><a href="https://bryanguner.medium.com/">https://bryanguner.medium.com/</a><a href="https://bryanguner.medium.com/">https://bryanguner.medium.com/</a><a href="https://bryanguner.medium.com/">https://bryanguner.medium.com/</a><a href="https://bryanguner.medium.com/">https://bryanguner.medium.com/</a><a href="https://bryanguner.medium.com/">https://bryanguner.medium.com/</a><a href="https://bryanguner.medium.com/">https://bryanguner.medium.com/</a><a href="https://bryanguner.medium.com/">https://bryanguner.medium.com/</a><a href="https://bryanguner.medium.com/">https://bryanguner.medium.com/</a><a href="https://bryanguner.medium.com/">https://bryanguner.medium.com/</a><a href="https://bryanguner.medium.com/">https://bryanguner.medium.com/</a><a href="https://bryanguner.medium.com/">https://bryanguner.medium.com/</a><a href="https://bryanguner.medium.com/">https://bryanguner.medium.com/</a><a href="https://bryanguner.medium.com/">https://bryanguner.medium.com/</a><a href="https://bryanguner.medium.com/">https://bryanguner.medium.com/</a><a href="https://bryanguner.medium.com/">https://bryanguner.medium.com/</a><a href="https://bryanguner.medium.com/">https://bryanguner.medium.com/</a> </p> | |
</div><!-- .entry-content --> | |
<footer class="entry-footer responsive-max-width"> | |
<span class="byline"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><span class="screen-reader-text">Posted by</span><span class="author vcard"><a class="url fn n" href="https://web-dev-hub.com/author/gunerb1/">bgoonz</a></span></span><span class="posted-on"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><defs><path id="a" d="M0 0h24v24H0V0z"></path></defs><clipPath id="b"><use xlink:href="#a" overflow="visible"></use></clipPath><path clip-path="url(#b)" d="M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10 10-4.5 10-10S17.5 2 12 2zm4.2 14.2L11 13V7h1.5v5.2l4.5 2.7-.8 1.3z"></path></svg><a href="https://web-dev-hub.com/2021/03/22/a-list-of-all-of-my-articles-to-link-to-future-posts/" rel="bookmark"><time class="entry-date published updated" datetime="2021-03-22T18:45:03-04:00">March 22, 2021</time></a></span><span class="cat-links"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M10 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2h-8l-2-2z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><span class="screen-reader-text">Posted in</span><a href="https://web-dev-hub.com/category/uncategorized/" rel="category tag">Uncategorized</a></span><span class="comments-link"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M21.99 4c0-1.1-.89-2-1.99-2H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h14l4 4-.01-18z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><a href="https://web-dev-hub.com/2021/03/22/a-list-of-all-of-my-articles-to-link-to-future-posts/#respond">Leave a comment<span class="screen-reader-text"> on A list of all of my articles to link to future posts</span></a></span><span class="edit-link"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04c.39-.39.39-1.02 0-1.41l-2.34-2.34c-.39-.39-1.02-.39-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><a class="post-edit-link" href="https://wordpress.com/post/web-dev-hub.com/575">Edit <span class="screen-reader-text">A list of all of my articles to link to future posts</span></a></span> </footer><!-- .entry-footer --> | |
</article><!-- #post-${ID} --> | |
<article id="post-574" class="post-574 post type-post status-publish format-standard hentry category-uncategorized tag-computer-engineering tag-javascript tag-resources tag-software-development tag-technology entry"> | |
<header class="entry-header responsive-max-width"> | |
<h2 class="entry-title"><a href="https://web-dev-hub.com/2021/03/21/web-development-resources-part-3/" rel="bookmark">Web Development Resources Part 3</a></h2> </header><!-- .entry-header --> | |
<div class="entry-content"> | |
<p>I’m the psychological equivalent of a physical hoarder only instead of empty soda cans and dead racoons it’s lists of links and resources.</p> | |
<h3>Here’s parts one and two:</h3> | |
<p><a href="https://javascript.plainenglish.io/my-take-on-awesome-javascript-243255451e74">https://javascript.plainenglish.io/my-take-on-awesome-javascript-243255451e74</a><a href="https://javascript.plainenglish.io/my-take-on-awesome-javascript-243255451e74">https://javascript.plainenglish.io/my-take-on-awesome-javascript-243255451e74</a></p> | |
<hr> | |
<figure><img data-width="300" data-height="300" src="https://cdn-images-1.medium.com/max/600/0*7Taf8gWWh5YjoM-s.png"></figure> | |
<h3>Performance</h3> | |
<ul> | |
<li><a href="https://developers.google.com/web/fundamentals/performance/webpack/" target="_blank">https://developers.google.com/web/fundamentals/performance/webpack/</a></li> | |
<li><a href="https://iamakulov.com/notes/resize-scroll/" target="_blank">https://iamakulov.com/notes/resize-scroll/</a></li> | |
<li><a href="https://iamakulov.com/notes/optimize-images-webpack/" target="_blank">https://iamakulov.com/notes/optimize-images-webpack/</a></li> | |
<li><a href="https://developers.google.com/web/fundamentals/performance/webpack/decrease-frontend-size" target="_blank">https://developers.google.com/web/fundamentals/performance/webpack/decrease-frontend-size</a></li> | |
<li><a href="https://code.facebook.com/posts/557147474482256" target="_blank">https://code.facebook.com/posts/557147474482256</a></li> | |
<li><a href="http://www.phpied.com/rendering-repaint-reflowrelayout-restyle" target="_blank">www.phpied.com/rendering-repaint-reflowrelayout-restyle</a></li> | |
<li><a href="https://blogs.windows.com/msedgedev/2017/03/08/scrolling-on-the-web/" target="_blank">https://blogs.windows.com/msedgedev/2017/03/08/scrolling-on-the-web/</a></li> | |
<li><a href="https://developers.google.com/web/fundamentals/performance/lazy-loading-guidance/images-and-video/" target="_blank">https://developers.google.com/web/fundamentals/performance/lazy-loading-guidance/images-and-video/</a></li> | |
</ul> | |
<figure><img data-width="700" data-height="1047" src="https://cdn-images-1.medium.com/max/800/0*-D07MORsmwK-pHOZ.jpg"></figure> | |
<h3>Case studies</h3> | |
<ul> | |
<li><a href="https://github.com/andrew--r/frontend-case-studies" target="_blank">https://github.com/andrew–r/frontend-case-studies</a></li> | |
<li><a href="http://iamakulov.com/notes/walmart/" target="_blank">http://iamakulov.com/notes/walmart/</a></li> | |
</ul> | |
<h3>Interviews</h3> | |
<ul> | |
<li><a href="https://performancejs.com/post/hde6d32/The-Best-Frontend-JavaScript-Interview-Questions-%28Written-by-a-Frontend-Engineer%29" target="_blank">https://performancejs.com/post/hde6d32/The-Best-Frontend-JavaScript-Interview-Questions-(Written-by-a-Frontend-Engineer)</a></li> | |
<li><a href="https://github.com/nishant8BITS/123-Essential-JavaScript-Interview-Question" target="_blank">https://github.com/nishant8BITS/123-Essential-JavaScript-Interview-Question</a></li> | |
<li><a href="https://github.com/yangshun/tech-interview-handbook" target="_blank">https://github.com/yangshun/tech-interview-handbook</a></li> | |
<li><a href="https://github.com/IgnaciodeNuevo/frontend-development-interviews#questions-to-know-the-company-better" target="_blank">https://github.com/IgnaciodeNuevo/frontend-development-interviews#questions-to-know-the-company-better</a></li> | |
<li><a href="http://www.creativebloq.com/features/12-common-javascript-questions-answered" target="_blank">http://www.creativebloq.com/features/12-common-javascript-questions-answered</a></li> | |
<li><a href="http://www.thatjsdude.com/interview/js1.html" target="_blank">http://www.thatjsdude.com/interview/js1.html</a></li> | |
<li><a href="http://www.thatjsdude.com/interview/js2.html" target="_blank">http://www.thatjsdude.com/interview/js2.html</a></li> | |
<li><a href="http://www.thatjsdude.com/interview/dom.html" target="_blank">http://www.thatjsdude.com/interview/dom.html</a></li> | |
<li><a href="https://github.com/khan4019/front-end-Interview-Questions" target="_blank">https://github.com/khan4019/front-end-Interview-Questions</a></li> | |
<li><a href="https://github.com/h5bp/Front-end-Developer-Interview-Questions" target="_blank">https://github.com/h5bp/Front-end-Developer-Interview-Questions</a></li> | |
</ul> | |
<h3>Web</h3> | |
<ul> | |
<li><a href="https://howdns.works/" target="_blank">https://howdns.works/</a></li> | |
<li><a href="https://howhttps.works/" target="_blank">https://howhttps.works</a></li> | |
</ul> | |
<h3>Architecture</h3> | |
<ul> | |
<li><a href="https://medium.com/@cramforce/designing-very-large-javascript-applications-6e013a3291a3" target="_blank">https://medium.com/@cramforce/designing-very-large-javascript-applications-6e013a3291a3</a></li> | |
<li><a href="https://www.toptal.com/javascript/comprehensive-guide-javascript-design-patterns" target="_blank">https://www.toptal.com/javascript/comprehensive-guide-javascript-design-patterns</a></li> | |
<li><a href="https://addyosmani.com/resources/essentialjsdesignpatterns/book/" target="_blank">https://addyosmani.com/resources/essentialjsdesignpatterns/book/</a></li> | |
</ul> | |
<h3>Accessibility</h3> | |
<ul> | |
<li><a href="https://developers.google.com/web/fundamentals/accessibility/how-to-review" target="_blank">https://developers.google.com/web/fundamentals/accessibility/how-to-review</a></li> | |
</ul> | |
<h3>Node</h3> | |
<ul> | |
<li><a href="https://www.toptal.com/javascript/a-guide-to-npm-the-node-package-manager" target="_blank">https://www.toptal.com/javascript/a-guide-to-npm-the-node-package-manager</a></li> | |
</ul> | |
<h3>JS</h3> | |
<ul> | |
<li><a href="https://blog.mgechev.com/2018/01/29/javascript-decorators-aop-autobind-memoization/" target="_blank">https://blog.mgechev.com/2018/01/29/javascript-decorators-aop-autobind-memoization/</a></li> | |
<li><a href="https://developers.google.com/web/fundamentals/primers/async-functions" target="_blank">https://developers.google.com/web/fundamentals/primers/async-functions</a></li> | |
<li><a href="https://developers.google.com/web/fundamentals/primers/promises" target="_blank">https://developers.google.com/web/fundamentals/primers/promises</a></li> | |
<li><a href="https://www.toptal.com/javascript/asynchronous-javascript-async-await-tutorial" target="_blank">https://www.toptal.com/javascript/asynchronous-javascript-async-await-tutorial</a></li> | |
<li><a href="https://www.toptal.com/software/definitive-guide-to-datetime-manipulation" target="_blank">https://www.toptal.com/software/definitive-guide-to-datetime-manipulation</a></li> | |
<li><a href="https://www.toptal.com/javascript/javascript-es6-cheat-sheet" target="_blank">https://www.toptal.com/javascript/javascript-es6-cheat-sheet</a></li> | |
<li><a href="https://www.safaribooksonline.com/library/view/es6-in-motion/10000MNLV201701/" target="_blank">https://www.safaribooksonline.com/library/view/es6-in-motion/10000MNLV201701/</a></li> | |
</ul> | |
<h3>CSS</h3> | |
<ul> | |
<li><a href="https://www.smashingmagazine.com/2018/05/print-stylesheets-in-2018/" target="_blank">https://www.smashingmagazine.com/2018/05/print-stylesheets-in-2018/</a></li> | |
</ul> | |
<h3>If you found this guide helpful feel free to checkout my GitHub/gists where I host similar content:</h3> | |
<p><a href="https://javascript.plainenglish.io/my-take-on-awesome-javascript-243255451e74">https://javascript.plainenglish.io/my-take-on-awesome-javascript-243255451e74</a><a href="https://javascript.plainenglish.io/my-take-on-awesome-javascript-243255451e74">https://javascript.plainenglish.io/my-take-on-awesome-javascript-243255451e74</a></p> | |
<h3>Or Checkout my personal Resource Site:</h3> | |
<p><a href="https://javascript.plainenglish.io/my-take-on-awesome-javascript-243255451e74">https://javascript.plainenglish.io/my-take-on-awesome-javascript-243255451e74</a> </p> | |
</div><!-- .entry-content --> | |
<footer class="entry-footer responsive-max-width"> | |
<span class="byline"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><span class="screen-reader-text">Posted by</span><span class="author vcard"><a class="url fn n" href="https://web-dev-hub.com/author/gunerb1/">bgoonz</a></span></span><span class="posted-on"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><defs><path id="a" d="M0 0h24v24H0V0z"></path></defs><clipPath id="b"><use xlink:href="#a" overflow="visible"></use></clipPath><path clip-path="url(#b)" d="M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10 10-4.5 10-10S17.5 2 12 2zm4.2 14.2L11 13V7h1.5v5.2l4.5 2.7-.8 1.3z"></path></svg><a href="https://web-dev-hub.com/2021/03/21/web-development-resources-part-3/" rel="bookmark"><time class="entry-date published updated" datetime="2021-03-21T15:41:52-04:00">March 21, 2021</time></a></span><span class="cat-links"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M10 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2h-8l-2-2z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><span class="screen-reader-text">Posted in</span><a href="https://web-dev-hub.com/category/uncategorized/" rel="category tag">Uncategorized</a></span><span class="tags-links"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M21.41 11.58l-9-9C12.05 2.22 11.55 2 11 2H4c-1.1 0-2 .9-2 2v7c0 .55.22 1.05.59 1.42l9 9c.36.36.86.58 1.41.58.55 0 1.05-.22 1.41-.59l7-7c.37-.36.59-.86.59-1.41 0-.55-.23-1.06-.59-1.42zM5.5 7C4.67 7 4 6.33 4 5.5S4.67 4 5.5 4 7 4.67 7 5.5 6.33 7 5.5 7z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><span class="screen-reader-text">Tags:</span><a href="https://web-dev-hub.com/tag/computer-engineering/" rel="tag">Computer Engineering</a>, <a href="https://web-dev-hub.com/tag/javascript/" rel="tag">Javascript</a>, <a href="https://web-dev-hub.com/tag/resources/" rel="tag">Resources</a>, <a href="https://web-dev-hub.com/tag/software-development/" rel="tag">Software Development</a>, <a href="https://web-dev-hub.com/tag/technology/" rel="tag">Technology</a></span><span class="comments-link"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M21.99 4c0-1.1-.89-2-1.99-2H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h14l4 4-.01-18z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><a href="https://web-dev-hub.com/2021/03/21/web-development-resources-part-3/#respond">Leave a comment<span class="screen-reader-text"> on Web Development Resources Part 3</span></a></span><span class="edit-link"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04c.39-.39.39-1.02 0-1.41l-2.34-2.34c-.39-.39-1.02-.39-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><a class="post-edit-link" href="https://wordpress.com/post/web-dev-hub.com/574">Edit <span class="screen-reader-text">Web Development Resources Part 3</span></a></span> </footer><!-- .entry-footer --> | |
</article><!-- #post-${ID} --> | |
<article id="post-573" class="post-573 post type-post status-publish format-standard hentry category-uncategorized tag-computer-science tag-guides-and-tutorials tag-interview tag-skills tag-technology entry"> | |
<header class="entry-header responsive-max-width"> | |
<h2 class="entry-title"><a href="https://web-dev-hub.com/2021/03/21/web-development-interview-part-3%f0%9f%92%bb/" rel="bookmark">Web Development Interview Part 3💻</a></h2> </header><!-- .entry-header --> | |
<div class="entry-content"> | |
<h4><a href="http://medium.com/codex">CODEX</a></h4> | |
<h4><strong>This installment is going to be the least technically demanding thus far however these questions are a more realistic reflection on what a junior developer could be asked by a company with reasonable hiring practices…</strong></h4> | |
<figure><img data-width="991" data-height="594" src="https://cdn-images-1.medium.com/max/800/1*dTDrkYZJYhASUP2TTknAgA.png"></figure> | |
<blockquote><p><strong>… Speaking of which … stay tuned till the end of the article or skip down to it for a list of web development companies with reportedly fair hiring practices!</strong></p></blockquote> | |
<h4>Here’s parts one and two; they’re both much more technical in nature than this one!</h4> | |
<p><a class="m-story" href="https://medium.com/star-gazers/the-web-developers-technical-interview-e347d7db3822" target="_blank" data-width="750" data-border="1" data-collapsed="">View at Medium.com</a><a class="m-story" href="https://medium.com/star-gazers/the-web-developers-technical-interview-e347d7db3822" target="_blank" data-width="750" data-border="1" data-collapsed="">View at Medium.com</a></p> | |
<hr> | |
<h3>👋🏻 Behavioral & Cultural Interview Questions</h3> | |
<blockquote><p><em>Software engineer interviewers ask behavioral/cultural questions to evaluate interviewee’s soft skills, and also to decide whether the candidate is a cultural fit. Make sure you’ve prepared great answers to these interview questions.</em></p></blockquote> | |
<blockquote><p><strong><em>⚫</em></strong>Tell me about yourself</p></blockquote> | |
<blockquote><p><strong><em>⚫====></em></strong>“Tell me about yourself” is one of the most common and important interview questions. However, it can be daunting, as it’s one you need to get right. After all, not only is it your first impression on the interviewer, but you also need to be simultaneously professional and authentic when answering it.</p></blockquote> | |
<blockquote><p><strong><em>⚫</em></strong>So how can you give a good answer without oversharing? To help you structure your answer, we’ll give you a rough guideline: start with a short introduction, talk about the present, recount the past, and mention your future goals.</p></blockquote> | |
<figure><img data-width="940" data-height="626" src="https://cdn-images-1.medium.com/max/800/0*E6ldmJAPG95McXVB"></figure> | |
<hr> | |
<h3>What are some side projects you’re currently working on?</h3> | |
<p><em>Current Experience</em></p> | |
<blockquote><p><strong><em>⚫</em></strong><em>Outline the role you’re currently in, your responsibilities, and your achievements (without reciting your resume)</em></p></blockquote> | |
<blockquote><p><strong><em>⚫</em></strong><em>Highlight what you’re most passionate about (i.e. working with PMs to perfect product specs, discussing with colleagues about different tech stacks, helping others excel in their jobs and career)</em></p></blockquote> | |
<blockquote><p><strong><em>⚫</em></strong><em>Recount one or two job-related projects and/or situations that map onto the job you’re applying to (i.e. collaborating with designers, working with legacy code, implementing best-practices, introducing new tech stacks, mentoring your colleagues)</em></p></blockquote> | |
<h3>Past Experience</h3> | |
<blockquote><p><strong>Now it’s time to highlight your skills a little:</strong></p></blockquote> | |
<blockquote><p><strong><em>⚫</em></strong>Selectively highlight one high-impact (preferably quantifiable) project you were involved with for each job</p></blockquote> | |
<blockquote><p><strong><em>⚫</em></strong>Highlight the hard and soft skills you learned from your past working experiences</p></blockquote> | |
<blockquote><p><strong><em>⚫</em></strong>Emphasize the initiatives you took to improve the company’s work flow (i.e. propose new flow to streamline sprints) or your own skillsets (i.e. engaging in hackathon with colleagues or friends)</p></blockquote> | |
<h3>Future Expectations</h3> | |
<blockquote><p><strong><em>⚫</em></strong>Convey what you hope to achieve and learn from the new job</p></blockquote> | |
<blockquote><p><strong><em>⚫</em></strong>Detail products, projects, features, or initiatives you can imagine yourself help kick off and lead in the company</p></blockquote> | |
<blockquote><p><strong><em>⚫</em></strong>Tell me what a productive day at work looks like to you</p></blockquote> | |
<blockquote><p><strong><em>⚫</em></strong>This question may not appear in every interview, but when they do, it’s important for you to highlight your organizational and prioritization skills. When hiring managers ask this question, they want to know:</p></blockquote> | |
<blockquote><p><strong><em>⚫</em></strong>Whether you’re a proactive communicator and a good planner of your time</p></blockquote> | |
<h3>How you strike a balance between multiple ongoing projects</h3> | |
<p><span>D</span><strong><em>escribe one or two instances where you had several projects running simultaneously and how you managed to prioritize different tasks, make progress, meet milestones, and work on iterations based on feedback.</em></strong></p> | |
<blockquote><p><strong><em>⚫</em></strong>How you deliver quality work with limited time</p></blockquote> | |
<blockquote><p><strong><em>⚫</em></strong>When there’s limited time and multiple projects going on, you may not be able to give 100% to the projects at hand. Let the interviewers know:</p></blockquote> | |
<blockquote><p><strong><em>⚫</em></strong>How you decide which tasks should be prioritized</p></blockquote> | |
<blockquote><p><strong><em>⚫</em></strong>How you negotiate deadlines and milestones with stakeholders</p></blockquote> | |
<blockquote><p><strong><em>⚫</em></strong>How you ensure all projects will be delivered with acceptable quality</p></blockquote> | |
<blockquote><p><strong><em>⚫</em></strong>At what milestones you believe it’s ok to deliver something “less than perfect”</p></blockquote> | |
<blockquote><p><strong><em>⚫</em></strong>How you decide when to go back and improve the “minimum viable projects” delivered earlier in the project’s timeline</p></blockquote> | |
<h3>Professional Skills</h3> | |
<blockquote><p><strong><em>⚫</em></strong>Will you excel in this job? Are you passionate about this job? It’s time to show how. For the first question, highlight some of your professional abilities:</p></blockquote> | |
<blockquote><p><strong><em>⚫</em></strong>Industry experience</p></blockquote> | |
<blockquote><p><strong><em>⚫</em></strong>Technical skills</p></blockquote> | |
<blockquote><p><strong><em>⚫</em></strong>Soft skills</p></blockquote> | |
<blockquote><p><strong><em>⚫</em></strong>Key accomplishments</p></blockquote> | |
<h4>For the second question, showcase your excitement for the job. Hiring managers want to see your excitement for these reasons:</h4> | |
<blockquote><p><strong><em>⚫1></em></strong>Excitement will fuel your performance</p></blockquote> | |
<blockquote><p><strong><em>⚫2></em></strong>Passion will confirm that you’re interested in this job</p></blockquote> | |
<blockquote><p><strong><em>⚫</em></strong>Eagerness will help you get through challenges at work</p></blockquote> | |
<blockquote><p><strong><em>⚫</em></strong>Company culture and shared values</p></blockquote> | |
<blockquote><p><strong><em>⚫</em></strong>Do you know the company’s culture and will you be a good fit? Here are some culture-related points you could cover in your answer:</p></blockquote> | |
<blockquote><p><strong><em>⚫</em></strong>You’re attracted to the company’s general reputation</p></blockquote> | |
<blockquote><p><strong><em>⚫</em></strong>You’re inspired by a specific leader in the company</p></blockquote> | |
<blockquote><p><strong><em>⚫</em></strong>You’re passionate about the company’s products and services</p></blockquote> | |
<blockquote><p><strong><em>⚫</em></strong>You’re onboard with the company’s initiatives (community engagement, public endorsements, etc.)</p></blockquote> | |
<blockquote><p><strong><em>⚫</em></strong>You admire the company’s culture. Here are some specific examples:</p></blockquote> | |
<hr> | |
<h3>Commitment to the company</h3> | |
<blockquote><p><strong><em>⚫Are you passionate about the company and will you stay committed to this company? If the interviewer already asked you “Where do you see yourself in 5 years?” then you don’t have to stress too much about showing your long-term commitment when answering this question. However, if you haven’t had the opportunity to show your commitment to the company, the most organic way to show your commitment is to talk about your long term plans in the company. Here are some things you can talk about:</em></strong></p></blockquote> | |
<blockquote><p><strong><em>⚫</em></strong>Projects you want to start</p></blockquote> | |
<blockquote><p><strong><em>⚫</em></strong>Potential directions you think the company can go in</p></blockquote> | |
<blockquote><p><strong><em>⚫</em></strong>The different products/teams you want to contribute to</p></blockquote> | |
<blockquote><p><strong><em>⚫</em></strong>Processes you’d like to participate in improving</p></blockquote> | |
<h3>Why should we hire you?</h3> | |
<blockquote><p><strong><em>⚫</em></strong>Ultimately, every single question interviewers ask you is related to this overarching question: “Why should we hire you?” Interviewers want to know, as confidently as possible, that you will be a good hire. Therefore, your answer should confirm that you’ll be a good hire.</p></blockquote> | |
<blockquote><p><strong><em>⚫</em></strong>Unlike the more specific questions we’ve outlined above, this question is a generic question that requires a concise but powerful answer. Think about this as your elevator pitch — you should be able to sell yourself to the interview within a matter of minutes.</p></blockquote> | |
<blockquote><p><strong><em>⚫</em></strong>To come up with your elevator pitch, you’ll need to do some planning and consolidation.</p></blockquote> | |
<blockquote><p><strong><em>⚫</em></strong>Here are some guiding questions for you to kickoff your brainstorming sessions:</p></blockquote> | |
<blockquote><p><strong><em>⚫</em></strong>What are the most important qualifications for this position from the company’s perspective?</p></blockquote> | |
<blockquote><p><strong><em>⚫</em></strong>What are my strong suits and how do they set me apart from others?</p></blockquote> | |
<blockquote><p><strong><em>⚫</em></strong>What are my most monumental accomplishments?</p></blockquote> | |
<blockquote><p><strong><em>⚫</em></strong>Why are you the best person for this job?</p></blockquote> | |
<blockquote><p><strong><em>⚫</em></strong>Consolidate and practice your pitch</p></blockquote> | |
<blockquote><p><strong><em>⚫</em></strong>Combine your answers in prose form to make sure each point flows to the next smoothly</p></blockquote> | |
<blockquote><p><strong><em>⚫</em></strong>Check to make sure your answer sets you apart from other candidates</p></blockquote> | |
<blockquote><p><strong><em>⚫!!!!!!!</em></strong>Practice, practice, and practice, but DO NOT TRY TO MEMORIZE YOUR PITCH!!!!!!!!!</p></blockquote> | |
<h3>📝 Interview Etiquette & Other Tips</h3> | |
<p>Nailing an interview takes more than just knowing how to answer common interview questions. You’ll also need to prepare questions of your own, think about salary, and get your communications right. Here’s how.</p> | |
<h4>Questions to ask in an interview</h4> | |
<p>⮕As the job seeker, it’s normal to feel like you’re being interrogated during interviews. However, at its core, an interview is a conversation, and should be a two-way interaction. As the interviewee, you need to stay engaged and ask thoughtful questions.</p> | |
<p>⮕By asking questions, you’re expressing your genuine curiosity towards the company. This helps companies know that you’re serious about them. Additionally, it also helps you evaluate whether the job and/or the company is really what you’re looking for.</p> | |
<p>⮕There are fantastic resources out there with more than a dozen questions you can ask interviewers. Here, we’ll provide a few that we think are essential to help you gain deeper understandings about the role, company, and your future within the company:</p> | |
<p>⮕The job and cross-team communication</p> | |
<p>⮕The company’s values and working culture</p> | |
<p>⮕What are some shared qualities and characteristics among your employees?</p> | |
<p>⮕What’s your favorite part about working at the company?</p> | |
<p>⮕What’s your least favorite part about working at the company?</p> | |
<p>Professional growth opportunities</p> | |
<p>⮕Are there multiple product/service teams in the company? Can engineers apply to join a different team? What does the process look like?</p> | |
<p>⮕Are there professional development courses and training available?</p> | |
<p>⮕Do senior engineers and engineering leads usually get promoted from within the company?</p> | |
<h3>Closing questions and next steps</h3> | |
<blockquote><p><strong><em>⚫</em></strong>Is there anything unclear or concerning about my background that I can help clarify?</p></blockquote> | |
<blockquote><p><strong><em>⚫</em></strong>What are the next steps in the interview process?</p></blockquote> | |
<blockquote><p><strong><em>⚫</em></strong>Is there anything else I can provide you with that would be helpful?</p></blockquote> | |
<blockquote><p><strong><em>⚫</em></strong>How to answer salary expectations?</p></blockquote> | |
<blockquote><p><strong><em>⚫</em></strong>“What are you salary expectations?” can be a daunting question. If talking about money wasn’t uncomfortable enough already, most job seekers worry that proposing the “wrong number” would cost them the job — or land them a job offer with a disappointing salary. Not great.</p></blockquote> | |
<hr> | |
<h3>Follow up ?????</h3> | |
<blockquote><p><strong><em>⚫</em></strong>Depending on how many rounds of interviews you’ve gone through, you may feel differently about how close you are to getting the job. The closer you get to the end of the hiring process, the more likely it is for you to start feeling anxious due to higher expectations. As a result, you may be eager to follow up with the hiring manager regarding your interview results. With that said, there’s a fine line between showing your eager attitude and coming off as desperate.</p></blockquote> | |
<blockquote><p><strong><em>⚫</em></strong>Before we get to the types of follow up emails you should send out, make sure to ask the hiring manager about when you can expect to hear back from them about next steps. This information will help you decide when it’s appropriate to follow up down the line.</p></blockquote> | |
<blockquote><p><strong><em>⚫</em></strong>There are four types of follow up emails you should send at different times after the interview: Thank you email, checking-in email, second follow up email, final follow up email.</p></blockquote> | |
<h4>Thank you email</h4> | |
<p><strong>A thank you email should be sent out on the same day of the interview or one day after your interview. The main purpose of this email is to show your excitement and appreciation. This email should be short and sweet and should include:</strong></p> | |
<h4>A thank you note for their time</h4> | |
<p>⮕<strong>A brief mention of the specific job you interviewed for</strong></p> | |
<p>⮕<strong>A brief note of what you found most impressive about the company</strong></p> | |
<p>⮕<strong>One or two things you learned about the organization</strong></p> | |
<p>⮕<strong>One sentence about how you’re excited you are to contribute in a specific way</strong></p> | |
<figure><img data-width="640" data-height="439" src="https://cdn-images-1.medium.com/max/800/0*tZNLWVUGmj2tJK3j.jpg"></figure> | |
<hr> | |
<h3><strong><em>Technical interview :</em></strong></h3> | |
<h4>⮕<strong><em>questions examine a candidate’s thought processes and assess what approaches they adopt to solve problems. The most common end-to-end software development questions are listed below.</em></strong></h4> | |
<h3>Here’s the repo that I use to practice my technical chops for interviews:</h3> | |
<p><a class="m-story" href="https://medium.com/star-gazers/the-web-developers-technical-interview-e347d7db3822" target="_blank" data-width="750" data-border="1" data-collapsed="">View at Medium.com</a></p> | |
<h3>1. Development</h3> | |
<blockquote><p><strong><em>⚫Describe the process you used for a recent project, from requirements to delivery. Does your team prefer using Agile or Waterfall? Any pros and cons?</em></strong></p></blockquote> | |
<blockquote><p><strong><em>⚫ In answering this question, you need to show your planning, process, and communication/collaboration skills. Think in advance about a suitable project where your contributions cover all these bases.</em></strong></p></blockquote> | |
<blockquote><p><strong><em>⚫If you can, it’s best to choose to describe an Agile project you worked on, as organizations whether they use a Waterfall or Agile methodology, are keen to work with developers experienced in Agile.</em></strong></p></blockquote> | |
<blockquote><p><strong><em>⚫ Ideally, share a project in which you worked with a bigger team.</em></strong></p></blockquote> | |
<blockquote><p><strong><em>⚫ Outline the components of the project and what role you played.</em></strong></p></blockquote> | |
<blockquote><p><strong><em>⚫ Highlight any interactions with other teams and the process for handover and collaboration.</em></strong></p></blockquote> | |
<blockquote><p><strong><em>⚫Highlight any interactions with other teams and the process for handover and collaboration.</em></strong></p></blockquote> | |
<h3>2. Based on your experience in this project, specify your favorite and least favorite part of this type of collaboration.</h3> | |
<p><span>R</span><strong><em>emember to keep positive because the interviewers are always looking for constructive answers.</em></strong></p> | |
<blockquote><p><strong><em>⚫You can specify cutting edge collaboration tools and techniques and/or methodologies that you already know the company employs in their own workflows.</em></strong></p></blockquote> | |
<blockquote><p><strong><em>⚫For the least favorite parts, don’t just list the downsides and failures, but also mention what you’ve learned from it and how you would improve.</em></strong></p></blockquote> | |
<blockquote><p><strong><em>⚫ Ensure that you come across humbled from the failures, not exasperated and that you know better than everyone else — even if you truly feel this way! Explain how you tried to positively encourage your team to correct the course rather than staying silent and going with a consensus majority.</em></strong></p></blockquote> | |
<h3><strong><em>3. Based on the project, what programming languages / tools / services did you use? And why did you choose them?</em></strong></h3> | |
<blockquote><p><strong><em>⚫ Questions like this are designed to allow you to showcase your way of thinking. The interviewer is looking to hear your ability to make choices based on rational decisions — so make sure that you show that you can do this!</em></strong></p></blockquote> | |
<blockquote><p><strong><em>To begin with, give an example of a project in which you had the most ownership or you had the greatest sense of achievement/efficiency/effectiveness from the toolchain used.</em></strong></p></blockquote> | |
<blockquote><p><strong><em>⚫ Next, describe the goal of the project, and briefly go through your responsibilities when it came to the toolchain decision-making process. Within Agile work practices, it’s usually a team effort to decide the best programming languages/tools/services are the best fit for the project, within customer requirements. Outline the consultation process you went through with both the customer and your team to arrive at the best solutions.</em></strong></p></blockquote> | |
<h3>4. Describe the biggest toolchain-related challenge you encountered in the project:</h3> | |
<blockquote><p><strong><em>⚫Outline the situation, the goal you expected, and the reason why there was a challenge.</em></strong></p></blockquote> | |
<blockquote><p><strong><em>⚫Share the toolchain you used when you encountered the problem, then other technologies and tools you applied to help solve it, if applicable. Ensure to note whether there was a full tool pivot or you managed to build onto an existing library (or something similar) to achieve the end goal.</em></strong></p></blockquote> | |
<blockquote><p><strong><em>⚫Remember: the most important thing is not what you ultimately used, but how many options you referred to during the process, and which metrics you adopted to decide which tech to go for. Remember to share the pros and cons of your decision, and if, looking back now, whether you would do it differently.</em></strong></p></blockquote> | |
<h3>5. How would you design this system for scale?</h3> | |
<blockquote><p><strong><em>⚫First of all, the interviewer would like to know the traffic level we’re expecting: 1,000, 100,000, or 10 million users per second? Think about the data expectations for each system user, database connections (blocking/nonblocking actions), downtime specifics, and cloud considerations (if any).</em></strong></p></blockquote> | |
<blockquote><p><strong><em>⚫List the potential problems that might occur when trying to scale. Different traffic levels may have different problems, so make sure you think this through, and decide the priorities of the problems that you should solve. Many codebases are not built for scale, so note code changes that might need to occur, rather than just infrastructure expectations.</em></strong></p></blockquote> | |
<blockquote><p><strong><em>⚫Different traffic levels may have different system architectures. List the options you think best fit your scenario and explain why you choose them. Many apps utilize a stripped-back product (which can be achieved through system architecture) when high traffic levels affect systems, rather than crashing the product completely or users experiencing unacceptable wait times.</em></strong></p></blockquote> | |
<h3>6. Testing: What is your process to test a code when developing a software or application? How do you decide the scope of your test case?</h3> | |
<blockquote><p><strong><em>⚫First, do your groundwork to ensure that you thoroughly understand the different testing types. Do you know your unit testing from your regression testing from your user acceptance testing? If you need to brush up, check out this great resource.</em></strong></p></blockquote> | |
<blockquote><p><strong><em>⚫Once you’ve got that on lock, it’s time to share a project that you’ve tested thoroughly before.</em></strong></p></blockquote> | |
<blockquote><p><strong><em>⚫Remember to separate the project into different sections. Each section should apply the testing type that fits its characteristics. Describe the goals of different testing types, and also introduce the library/service you used for the test. (For bonus points: explain the pros and cons of the library/service and whether it was your decision to choose that particular suite.)</em></strong></p></blockquote> | |
<blockquote><p><strong><em>⚫It makes sense at this point to include documentation (and particularly inline documentation) you use that helps clarify functions/issues so that testing goes smoothly.</em></strong></p></blockquote> | |
<blockquote><p><strong><em>⚫You may also mention a project you were involved in where testing was not well conducted and how you would — or did — go about fixing the issues.</em></strong></p></blockquote> | |
<h3>Monitoring</h3> | |
<h3>7. What kind of tools / services do you use for logging? What kind of data will you log? And what’s the next step when you get the log?</h3> | |
<blockquote><p><strong><em>⚫Time for some details! When answering this question, give an example of a project that you’ve monitored before.</em></strong></p></blockquote> | |
<blockquote><p><strong><em>⚫Explain what information you logged and what questions it answered.</em></strong></p></blockquote> | |
<blockquote><p><strong><em>⚫Please do not just describe the data format but also give the reason why you decided to extract this data.</em></strong></p></blockquote> | |
<blockquote><p><strong><em>⚫Describe the reporting process and any associated tools used.</em></strong></p></blockquote> | |
<blockquote><p><strong><em>⚫Some questions to think about to help you structure your answer, and nail your response:</em></strong></p></blockquote> | |
<hr> | |
<h3>What to avoid</h3> | |
<blockquote><p><strong><em>⚫</em></strong>Complaining about having to handle the problem</p></blockquote> | |
<blockquote><p><strong><em>⚫</em></strong>Showing how annoyed you were at the problem</p></blockquote> | |
<blockquote><p><strong><em>⚫</em></strong>Pointing fingers at others for the problem</p></blockquote> | |
<blockquote><p><strong><em>⚫</em></strong>Talking ill of your bosses or coworkers</p></blockquote> | |
<blockquote><p><strong><em>⚫</em>Keep in mind that your interviewer is not only trying to get a glimpse of your past, but to gain an understanding of how you might react to challenges should they hire you. Therefore, when you’re choosing your scenario, try to pick one that may be applicable in your new work setting as well.</strong></p></blockquote> | |
<hr> | |
<h3>NOW; Here’s some for you guys to answer in the comments!</h3> | |
<h4>8. Which logging services have you researched and used before?</h4> | |
<h4>9. Why did you choose or look into each particular logging service?</h4> | |
<h4>10. Was your decision because of the scale, the features, or the size of the community?</h4> | |
<h4>11. In what scenarios did you check these logs? Was it scheduled daily/weekly/monthly or as an on-demand activity?</h4> | |
<h4>12. What information would the data be transformed into? Was it for development, business, or customer decision-making?</h4> | |
<h4>13. What information would the data be transformed into? Was it for development, business, or customer decision-making?</h4> | |
<hr> | |
<p><a href="https://gist.github.com/bgoonz/15a638abb3b4026abc8e5ca05f8d90f1">https://gist.github.com/bgoonz/15a638abb3b4026abc8e5ca05f8d90f1</a></p> | |
<h3>If you found this guide helpful feel free to checkout my GitHub/gists where I host similar content:</h3> | |
<p><a class="m-story" href="https://medium.com/star-gazers/the-web-developers-technical-interview-e347d7db3822" target="_blank" data-width="750" data-border="1" data-collapsed="">View at Medium.com</a><a class="m-story" href="https://medium.com/star-gazers/the-web-developers-technical-interview-e347d7db3822" target="_blank" data-width="750" data-border="1" data-collapsed="">View at Medium.com</a></p> | |
<h3>Or Checkout my personal Resource Site:</h3> | |
<p><a class="m-story" href="https://medium.com/star-gazers/the-web-developers-technical-interview-e347d7db3822" target="_blank" data-width="750" data-border="1" data-collapsed="">View at Medium.com</a> </p> | |
</div><!-- .entry-content --> | |
<footer class="entry-footer responsive-max-width"> | |
<span class="byline"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><span class="screen-reader-text">Posted by</span><span class="author vcard"><a class="url fn n" href="https://web-dev-hub.com/author/gunerb1/">bgoonz</a></span></span><span class="posted-on"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><defs><path id="a" d="M0 0h24v24H0V0z"></path></defs><clipPath id="b"><use xlink:href="#a" overflow="visible"></use></clipPath><path clip-path="url(#b)" d="M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10 10-4.5 10-10S17.5 2 12 2zm4.2 14.2L11 13V7h1.5v5.2l4.5 2.7-.8 1.3z"></path></svg><a href="https://web-dev-hub.com/2021/03/21/web-development-interview-part-3%f0%9f%92%bb/" rel="bookmark"><time class="entry-date published updated" datetime="2021-03-21T14:53:19-04:00">March 21, 2021</time></a></span><span class="cat-links"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M10 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2h-8l-2-2z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><span class="screen-reader-text">Posted in</span><a href="https://web-dev-hub.com/category/uncategorized/" rel="category tag">Uncategorized</a></span><span class="tags-links"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M21.41 11.58l-9-9C12.05 2.22 11.55 2 11 2H4c-1.1 0-2 .9-2 2v7c0 .55.22 1.05.59 1.42l9 9c.36.36.86.58 1.41.58.55 0 1.05-.22 1.41-.59l7-7c.37-.36.59-.86.59-1.41 0-.55-.23-1.06-.59-1.42zM5.5 7C4.67 7 4 6.33 4 5.5S4.67 4 5.5 4 7 4.67 7 5.5 6.33 7 5.5 7z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><span class="screen-reader-text">Tags:</span><a href="https://web-dev-hub.com/tag/computer-science/" rel="tag">Computer Science</a>, <a href="https://web-dev-hub.com/tag/guides-and-tutorials/" rel="tag">Guides And Tutorials</a>, <a href="https://web-dev-hub.com/tag/interview/" rel="tag">Interview</a>, <a href="https://web-dev-hub.com/tag/skills/" rel="tag">Skills</a>, <a href="https://web-dev-hub.com/tag/technology/" rel="tag">Technology</a></span><span class="comments-link"><svg class="svg-icon" width="16" height="16" aria-hidden="true" role="img" focusable="false" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M21.99 4c0-1.1-.89-2-1.99-2H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h14l4 4-.01-18z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg><a href="https://web-dev-hub.com/2021/03/21/web-development-interview-part-3%f0%9f%92%bb/#respond">Leave a comment<span class="screen-reader-text"> on Web Devel |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment