Merge pull request #6 from 30-seconds/disintegration-tools
Integration-tools cleanup
This commit is contained in:
13
.travis.yml
13
.travis.yml
@ -1,13 +0,0 @@
|
||||
language: node_js
|
||||
cache:
|
||||
directories:
|
||||
- node_modules
|
||||
node_js:
|
||||
- lts/*
|
||||
before_install:
|
||||
- git fetch --depth=10000
|
||||
script:
|
||||
- npm run extractor
|
||||
after_success:
|
||||
- chmod +x .travis/push.sh
|
||||
- .travis/push.sh
|
||||
@ -1,35 +0,0 @@
|
||||
#!/bin/bash
|
||||
setup_git() {
|
||||
git config --global user.email "30secondsofcode@gmail.com"
|
||||
git config --global user.name "30secondsofcode"
|
||||
}
|
||||
|
||||
commit_website_files() {
|
||||
if [ $TRAVIS_EVENT_TYPE != "pull_request" ]; then
|
||||
if [ $TRAVIS_BRANCH == "master" ]; then
|
||||
echo "Committing to master branch..."
|
||||
git checkout master
|
||||
git add *
|
||||
if [ $TRAVIS_EVENT_TYPE == "cron" ]; then
|
||||
git commit --message "Travis build: $TRAVIS_BUILD_NUMBER [cron]"
|
||||
elif [ $TRAVIS_EVENT_TYPE == "api" ]; then
|
||||
git commit --message "Travis build: $TRAVIS_BUILD_NUMBER [custom]"
|
||||
else
|
||||
git commit --message "Travis build: $TRAVIS_BUILD_NUMBER"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
upload_files() {
|
||||
if [ $TRAVIS_EVENT_TYPE != "pull_request" ]; then
|
||||
if [ $TRAVIS_BRANCH == "master" ]; then
|
||||
echo "Pushing to master branch..."
|
||||
git push --quiet "https://${GH_TOKEN}@github.com/30-seconds/30-seconds-blog.git" master > /dev/null 2>&1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
setup_git
|
||||
commit_website_files
|
||||
upload_files
|
||||
@ -1,328 +0,0 @@
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"id": "10-vs-code-extensions-for-js-developers",
|
||||
"type": "snippetListing",
|
||||
"title": "10 must-have VS Code extensions for JavaScript developers",
|
||||
"attributes": {
|
||||
"text": "Developers will most likely argue for the rest of eternity about the most productive code editor and the best extensions. Here are my personal extension preferences for VS Code as a JavaScript developer:\n\n1. ESLint\n[ESLint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) turns the popular JavaScrpt linter into an extension of VS Code. It automatically reads your linting configuration, identifies problems and even fixes them for you, if you want.\n\n2. GitLens\n[GitLens](https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens) is a very powerful collaboration tool for VS Code. It provides many useful tools for git such as blame, code authorship, activity heatmaps, recent changes, file history and even commit search.\n \n3. Debugger for Chrome\n[Debugger for Chrome](https://marketplace.visualstudio.com/items?itemName=msjsdiag.debugger-for-chrome) allows you to debug your JavaScript code in Chrome or Chromium. Breakpoints, call stack inspection and stepping inside a function are only some of its features.\n\n4. Bracket Pair Colorizer 2\n[Bracket Pair Colorizer 2](https://marketplace.visualstudio.com/items?itemName=CoenraadS.bracket-pair-colorizer-2) makes reading code faster as it makes matching brackets the same color. This extension for VS Code improves upon its predecessor by providing improved performance.\n\n5. Bookmarks\n[Bookmarks](https://marketplace.visualstudio.com/items?itemName=alefragnani.Bookmarks) is one of those extensions that will significantly reduce your time jumping between different files, as it allows you to save important positions and navigate back to them easily and quickly.\n\n6. TODO Highlight\n[TODO Highlight](https://marketplace.visualstudio.com/items?itemName=wayou.vscode-todo-highlight) simplifies tracking leftover tasks by allowing you to list all of your TODO annotations, as well as adding a handy background highlight to them to make them pop out immediately. \n\n7. Live Server\n[Live Server](https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer) gives you an easy way to serve web pages from VS Code, making previewing and debugging a lot easier. One of the core features is the live reload support that many developers are used to.\n\n8. REST Client\n[REST Client](https://marketplace.visualstudio.com/items?itemName=humao.rest-client) allows you to send HTTP requests and view the responses directly in VS Code. This extension supports a wide range of formats and authorization and should work with most setups.\n\n9. One Dark Pro\n[One Dark Pro](https://marketplace.visualstudio.com/items?itemName=zhuangtongfa.Material-theme) is one of the most popular VS Code themes and with very good reason. It provides a clean theme with a nice palette that has great contrast and is very comfortable to use on a daily basis.\n \n10. Fira Code\n[Fira Code](https://github.com/tonsky/FiraCode) is not a traditional VS Code extension and might take a couple more steps to set up, but it's a superb programming font with ligatures that will help you scan code faster once you get used to it.\n\n**Image credit:** [Fotis Fotopoulos](https://unsplash.com/@ffstop?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/code?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)\n",
|
||||
"tags": [
|
||||
"devtools",
|
||||
"vscode"
|
||||
]
|
||||
},
|
||||
"meta": {
|
||||
"hash": "2dd00656f3a19b08dd10877431101751009c00b0658dc5d3acab61e11fea21e3"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "4-seo-tips-for-developers",
|
||||
"type": "snippetListing",
|
||||
"title": "4 SEO tips for developers",
|
||||
"attributes": {
|
||||
"text": "SEO is becoming increasingly relevant as the internet keeps growing. While most web developers usually have little experience with SEO, it is not particularly difficult to handle some of the basics. Here are my top SEO tips for web developers:\n\n1. Craft user-friendly URLs and map the appropriately\nFirst and foremost, start at the very beginning, which is your URL slugs. For URL slugs the rule is that you want them to be human-readable, with words separated by dashes and with no random letters or digits added. Secondly, it's a good idea to make sure that parts of your URLs match to a logical structure in your website (e.g. `/blog/posts/awesome-list-of-seo-tips`). Finally, take the time to build a sitemap and redirect any broken or old URLs to new ones. This will help reduce 404 pages.\n\n2. Use structured data to help Google understand your pages\nStructured data is what Google uses to power its featured snippets, those little cards that appear at the top of certain searches. It's a good idea to set up structured data for your pages, which will help you rank higher in search results and possibly even land a featured snippet every once in a while. Just make sure to find the appropriate structured data type and include it in your page and you should be good to go.\n\n3. Set up Google Analytics and Google Search Console\nThis is hardly a new tip, but I think it deserves a spot on the list, as both of these tools are extremely important. Google Analytics allows you to track user behavior and gather data that can help you identify problems and opportunities, while Google Search Console is helpful for figuring out what users are searching for before landing on your website.\n\n4. Keep an eye on your markup, performance and accessibility\nLast but not least, something that is probably already on your list, is optimizing your code. This includes everything from writing semantic markup and keeping requests to a minimum to optimizing for all device types, making your website accessible and ensuring fast load times. Keep in mind that websites have many moving parts that evolve and change over time, so it's a good idea to audit your website often with a tool like Lighthouse.\n\n**Image credit:** [timJ](https://unsplash.com/@the_roaming_platypus?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/code?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)\n",
|
||||
"tags": [
|
||||
"seo",
|
||||
"webdev"
|
||||
]
|
||||
},
|
||||
"meta": {
|
||||
"hash": "ebc2337246ca7925e763034b8f5718f6276afd9252856cad56eff5f6d6ba25f1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "6-javascript-regexp-tricks",
|
||||
"type": "snippetListing",
|
||||
"title": "6 JavaScript Regular Expression features you can use today",
|
||||
"attributes": {
|
||||
"text": "Regular expressions, while very powerful, are notoriously hard to master. Here are 6 useful features that can help you start using them in your JavaScript projects:\n\n**Capturing groups**\n\nCapturing groups allow you to get specific parts of the matched string, simply by wrapping part of the regular expression in parentheses `(...)`:\n\n```js\nconst str = 'JavaScript is a programming language';\n/(JavaScript) is a (.*)/.exec(str);\n/*\n [\n 0: 'JavaScript is a programming language',\n 1: 'JavaScript',\n 2: 'programming language'\n ]\n*/\n```\n\n**Non-capturing groups**\n\nNon-capturing groups are used for matching something without capturing it, like an either/or matching group that you do not really need. They are defined similarly to capturing groups, but prefixed with `?:`:\n\n```js\nconst str = 'JavaScript is a programming language';\n/(?:JavaScript|Python) is a (.+)/.exec(str);\n/*\n [\n 0: 'JavaScript is a programming language',\n 1: 'programming language'\n ]\n*/\n```\n\n**Named capturing groups**\n\nNamed capturing groups allow you to name a capturing group, by prefixing it with `<name>`:\n\n```js\nconst str = 'JavaScript is a programming language';\n/(?<subject>.+) is a (?<description>.+)/.exec(str);\n/*\n [\n 0: 'JavaScript is a programming language',\n 1: 'JavaScript',\n 2: 'programming language',\n groups: {\n subject: 'JavaScript,\n description: 'programming language'\n }\n ]\n*/\n```\n\n**Capturing group backreferences**\n\nBackreferences help you write shorter regular expressions, by repeating an existing capturing group, using `\\1`, `\\2` etc. Similarly, you can also repeat named capturing groups using `\\k<name>`:\n\n```js\nconst str = 'JavaScript is a programming language - an awesome programming language JavaScript is';\n/(.+) is a (?<description>.+) - an awesome \\k<description> \\1 is/.exec(str);\n/*\n [\n 0: 'JavaScript is a programming language - an awesome programming language JavaScript is',\n 1: 'JavaScript',\n 2: 'programming language',\n groups: {\n subject: 'JavaScript,\n description: 'programming language'\n }\n ]\n*/\n```\n\n**Lookaheads**\n\nLookaheads allow you to check if something is followed by a certain pattern, without actually matching it. You can create positive lookaheads using `?=` and negative lookaheads using `?!`:\n\n```js\nconst str = 'JavaScript is not the same as Java and you should remember that';\n/Java(?=Script)(.*)/.exec(str);\n/*\n [\n 0: 'JavaScript is not the same as Java and you should remember that',\n 1: 'Script is not the same as Java and you should remember that'\n ]\n*/\n\n/Java(?!Script)(.*)/.exec(str);\n/*\n [\n 0: 'Java and you should remember that',\n 1: ' and you should remember that'\n ]\n*/\n```\n\n**Unicode characters**\n\nFinally, you can match unicode characters, using `/p{...}` and the `/u` flag. Examples include, but are not limited to `{Emoji}`, `{Math_Symbols}` and `{Script=Greek}`:\n\n```js\nconst str = 'Greek looks like this: γεια';\n/\\p{Script=Greek}+/u.exec(str);\n/*\n [\n 0: 'γεια'\n ]\n*/\n```\n\n**Image credit:** [Kace Rodriguez](https://unsplash.com/@kace?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/code?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)\n",
|
||||
"tags": [
|
||||
"javascript",
|
||||
"string",
|
||||
"regexp"
|
||||
]
|
||||
},
|
||||
"meta": {
|
||||
"hash": "2e6e5d06cb22bf4dfed8489172861f9361129f1fb83cf503d4817b332ae459bf"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "7-chrome-extensions-for-web-developers",
|
||||
"type": "snippetListing",
|
||||
"title": "7 essential Chrome extensions for web developers",
|
||||
"attributes": {
|
||||
"text": "Google Chrome's developer tools are nothing short of amazing, but there are a few missing tools that can increase your productivity even further. Here are my personal favorite extensions that I use everyday:\n\n1. CSS Peeper\n[CSS Peeper](https://chrome.google.com/webstore/detail/css-peeper/mbnbehikldjhnfehhnaidhjhoofhpehk?hl=en) is an all-in-one tool for CSS inspection that allows you to quickly peek at the styles, fonts, color palettes and assets of any website you want.\n\n2. React Developer Tools\n[React Developer Tools](https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi?hl=en) is the de facto extension when working with React, providing all the necessary inspection tools for your React applications.\n\n3. LastPass\n[LastPass](https://chrome.google.com/webstore/detail/lastpass-free-password-ma/hdokiejnpimakedhajhdlcegeplioahd?hl=en) keeps your accounts and API keys secure, by providing a free password manager complete with password generation and password-protected notes.\n\n4. uBlock Origin\n[uBlock Origin](https://chrome.google.com/webstore/detail/ublock-origin/cjpalhdlnbpafiamejdnhcphjbkeiagm?hl=en) is a simple yet effective ad blocker extension that you can just install and forget about, as it keeps your browsing experience ad-free.\n\n5. VisBug\n[VisBug](https://chrome.google.com/webstore/detail/visbug/cdockenadnadldjbbgcallicgledbeoc?hl=en) allows you to tweak website designs on the fly, using very intuitive controls and tools, without having to delve into any code at all.\n\n6. JSON Viewer\n[JSON Viewer](https://chrome.google.com/webstore/detail/json-viewer/gbmdgpbipfallnflgajpaliibnhdgobh?hl=en) provides some much needed syntax highlighting and style customization to JSON responses, which are nowadays very commonplace in most web APIs.\n\n7. EditThisCookie\n[EditThisCookie](https://chrome.google.com/webstore/detail/editthiscookie/fngmhnnpilhplaeedifhccceomclgfbg?hl=en) is a powerful cookie manager extension, that allows you to add, delete, edit and even export and import cookies quickly and efficiently.\n\n**Image credit:** [Fotis Fotopoulos](https://unsplash.com/@ffstop?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/code?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)\n",
|
||||
"tags": [
|
||||
"devtools",
|
||||
"webdev"
|
||||
]
|
||||
},
|
||||
"meta": {
|
||||
"hash": "298a153b85f60c81a96e98bc3823ef580492060a06c65ef17e5c49430a6cfc59"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "8-tips-for-remote-work",
|
||||
"type": "snippetListing",
|
||||
"title": "8 tips for working from home",
|
||||
"attributes": {
|
||||
"text": "Working from home (also known as remote work) seems like a great alternative to going to the office every morning, but it comes with its own set of challenges that you need to overcome in order to stay healthy and productive. Here are my tips for achieving just that:\n\n1. Set up your work environment\nWorking from home has its perks, but nothing beats a well-designed office space where everything is set up with only one purpose in mind: working. Figure out your home office, experiment with different settings and understand what works best for you as soon as possible. An ideal working space is comfortable, quiet and has the right equipment for you.\n\n2. Establish ground rules\nMost likely you are not living alone, so you have to establish some ground rules with your roomate or significant other. It's up to you to drive the point home that during working hours you are, for the most part, not home. Sure, you can answer the door if you expect a delivery, but that's pretty much as far as you can go. People should not bother you during working hours, unless absolutely necessary, as small distractions pile up fast.\n\n3. Inform others of your availability\nIt's important to let people know that you are online and working or that you are taking a short break for lunch. Remember that you are still part of a team that requires coordination and others probably depend on your work to some extent. Remember to update your status as necessary to make collaboration easier.\n\n4. Socialize with coworkers\nWorking from home can lead to feelings of loneliness, disconnect, isolation which can quickly spin out of control and lead to depression. Communicate with people on your team as if you were in the same room. A healthy amount of communication will help you feel more like you are all working together rather than each one on their own.\n\n5. Be your best professional self\nNobody might be watching you at home, so you can theoretically slack off as much as you like in your pajamas, but that's not very professional. Try to dress appropriately in case you join a video call and behave professionaly, so no inappropriate websites or hours upon hours of checking social media. Ask yourself if someone in a shared office space would do whatever it is you are doing and, if the answer is no, stop doing it.\n\n6. Plan your daily and weekly tasks\nHaving a coherent working plan helps you organize your time and prioritize important tasks above trivial ones. It also helps to put things into perspective and have a general idea of what other people on the team are working on. Plan ahead of time together with your team and keep each other posted on the progress of each task. Short term plans help you get through the day, long term plans help everyone meet their deadlines.\n\n7. Use the right collaboration tools\nWorking from home has its own challenges and issues, so try to find the right tools for the job. Slack, Skype, Zoom, Hangouts are great for communication. Design tools such as Figma or Sketch cloud help you communicate designs quickly and effectively. GitHub is the perfect tool for code collaboration and VS Code has an extension (Live Share) for sharing your code editors. Communicate with your team, figure out your needs and pick tools that work for you.\n\n8. Maintain regular hours\nIt's as easy to forget about breaks as it is to start working late. Try to set a schedule that sits well with your team and stick to it. If you would work 9 to 5 in a regular office environment, do the same at home. Take regular breaks, do not forget to sign off when put in your daily hours and come back tomorrow. After all, it's business as usual.\n\n**Image credit:** [Goran Ivos](https://unsplash.com/@goran_ivos?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/code?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)\n",
|
||||
"tags": [
|
||||
"programming",
|
||||
"jobs",
|
||||
"webdev"
|
||||
]
|
||||
},
|
||||
"meta": {
|
||||
"hash": "5e48e683f0ef6ae3ae5ea9600b62919041bab9d2e9e00a12a1a8ad78c89542d4"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "breaking-react",
|
||||
"type": "snippetListing",
|
||||
"title": "Breaking React - a common pattern to avoid",
|
||||
"attributes": {
|
||||
"text": "I am by no means an expert React engineer, but I have a couple years of experience under my belt. While React is an extremely powerful library for building user interfaces, it is also quite fragile at places. A very common bug I have encountered is caused by direct DOM manipulation in combination with React. This is not exactly an anti-pattern, but under the right circumstances it can break your entire React application and might be hard to debug. \n\nHere's [a minimal example](https://codepen.io/chalarangelo/pen/jOEojVJ?editors=0010) of how one can reproduce this bug, before we dive into explaining the problem and how to fix it:\n\n```jsx\nconst destroyElement = () => \n document.getElementById('app').removeChild(document.getElementById('my-div'));\n\nconst App = () => {\n const [elementShown, updateElement] = React.useState(true);\n \n return (\n <div id='app'>\n <button onClick={() => destroyElement()}>\n Delete element via querySelector\n </button>\n <button onClick={() => updateElement(!elementShown)}>\n Update element and state\n </button>\n { elementShown ? <div id=\"my-div\">I am the element</div> : null }\n </div>\n );\n};\n\nReactDOM.render(<App />, document.getElementById('root'));\n```\n\nThis looks like a pretty simple React application, with a container, two buttons and a state variable. However, it will crash if you click the button that calls `destroyElement()` and then click the other button. _Why?_ you might ask. The issue here might not be immediately obvious, but if you look at your browser console you will notice the following exception:\n\n```\nUncaught DOMException: Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node.\n```\n\nThis might still be cryptic, so let me explain what is going on. React uses its own representation of the DOM, called a virtual DOM, in order to figure out what to render. Usually, the virtual DOM will match the current DOM structure and React will process changes in props and state, updating the virtual DOM and then sending the necessary changes to the real DOM. \n\nHowever, in this case React's virtual DOM and the real DOM are different, because of `destroyElement()` removing the `#my-div` element. As a result, when React tries to update the real DOM with the changes from the virtual DOM, the `#my-div` element cannot be removed as it doesn't exist anymore. This results in the above exception being thrown and your application breaking.\n\nThis example is short and easy to resolve, by refactoring `destroyElement()` to be part of the `App` component and interact with its state, yet it showcases how fragile React can be under circumstances. Having a shared codebase, with many developers working on different things, can lead to issues like this being introduced and tracking them down can be rather tricky, which is why you might want to be very careful when directly manipulating the DOM when you use React.\n\n**Image credit:** [Julia Joppien](https://unsplash.com/@vitreous_macula?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/code?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)\n",
|
||||
"tags": [
|
||||
"react",
|
||||
"debugging"
|
||||
]
|
||||
},
|
||||
"meta": {
|
||||
"hash": "633fa8b4636401636d8bcf368f6967b96f50b65be845c9dd923a49e897fba771"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "code-anatomy-performant-python",
|
||||
"type": "snippetListing",
|
||||
"title": "Code Anatomy - Writing high performance Python code",
|
||||
"attributes": {
|
||||
"text": "Writing short and efficient Python code is not always easy or straightforward. However, it's often that we see a piece of code and we don't realize the thought process behind the way it was written. We will be taking a look at the [difference](/python/s/difference) snippet, which returns the difference between two iterables, in order to understand its structure.\n\nBased on the description of the snippet's functionality, we can naively write it like this:\n\n```py\ndef difference(a, b):\n return [item for item in a if item not in b]\n```\n\nThe above implementation may work well enough, but doesn't account for duplicates in `b`, making the code take more time than necessary in cases with many duplicates in the second list. To solve this issue, we can make use of the `set()` method, which will only keep the unique values in the list:\n\n```py\ndef difference(a, b):\n return [item for item in a if item not in set(b)]\n```\n\nThis version, while it seems like an improvement, may actually be slower than the previous one. If you look closely, you will see that `set()` is called for every `item` in `a` causing the result of `set(b)` to be evaluated every time. Here's an example where we wrap `set()` with another method to better showcase the problem:\n\n```py\ndef difference(a, b):\n return [item for item in a if item not in make_set(b)]\n\ndef make_set(itr):\n print('Making set...')\n return set(itr)\n\nprint(difference([1, 2, 3], [1, 2, 4]))\n# Making set...\n# Making set...\n# Making set...\n# [3]\n```\n\nThe solution to this issue is to call `set()` once before the list comprehension and store the result to speed up the process:\n\n```py\ndef difference(a, b):\n _b = set(b)\n return [item for item in a if item not in _b]\n```\n\nAnother option worth mentioning when analyzing performance for this snippet is the use of a list comprehension versus using something like `filter()` and `list()`. Implementing the same code using the latter option would result in something like this:\n\n```py\ndef difference(a, b):\n _b = set(b)\n return list(filter(lambda item: item not in _b, a))\n```\n\nUsing `timeit` to analyze the performance of the last two code examples, it's pretty clear that using list comprehension can be up to ten times faster than the alternative, as it's a native language feature that works very similar to a simple `for` loop without the overhead of the extra function calls. This explains why we prefer it, apart from readability.\n\nThis pretty much applies to most mathematical list operation snippets, such as [difference](/python/s/difference), [symmetric_difference](/python/s/symmetric-difference) and [intersection](/python/s/intersection).\n\n**Image credit:** [Kalen Emsley](https://unsplash.com/@kalenemsley?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/code?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)\n",
|
||||
"tags": [
|
||||
"python",
|
||||
"list",
|
||||
"performance"
|
||||
]
|
||||
},
|
||||
"meta": {
|
||||
"hash": "40d3da7677547b9f7a7e8dd25fa0217658ecccabc9f794a8b2da416b60a122a0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "copy-text-to-clipboard-with-javascript",
|
||||
"type": "snippetListing",
|
||||
"title": "How can I copy text to clipboard with JavaScript?",
|
||||
"attributes": {
|
||||
"text": "**Core functionality**\n\nA very common need when building websites is the ability to copy text to clipboard with a single button click. Javascript can easily do this in five short steps:hout the user selecting it or hitting the appropriate key combination on their keyboard. Javascript can easily do this in five short steps:\n\n1. Create a` <textarea>` element to be appended to the document. Set its value to the string that we want to copy to the clipboard.\n2. Append said `<textarea>` element to the current HTML document.\n3. Use `HTMLInputElement.select()` to select the contents of the `<textarea>` element.\n4. Use `Document.execCommand('copy')` to copy the contents of the `<textarea>` to the clipboard.\n5. Remove the `<textarea>` element from the document.\n\nThe simplest version of this method looks something like this:\n\n```js\nconst copyToClipboard = str => {\n const el = document.createElement('textarea');\n el.value = str;\n document.body.appendChild(el);\n el.select();\n document.execCommand('copy');\n document.body.removeChild(el);\n};\n```\n\nBear in mind that this method will not work everywhere, but only as a result of a user action (e.g. inside a `click` event listener), due to the way `Document.execCommand()` works.\n\n**Hide the appended element**\n\nThe above method, while functional, might have some issues such as flashing when appending and removing the `<textarea>`, a problem that is even more apparent when considering accessibility. A major improvement to this method comes from adding some CSS to make the element invisible and restrict editing by users:\n\n```js\nconst copyToClipboard = str => {\n const el = document.createElement('textarea');\n el.value = str;\n el.setAttribute('readonly', '');\n el.style.position = 'absolute';\n el.style.left = '-9999px';\n document.body.appendChild(el);\n el.select();\n document.execCommand('copy');\n document.body.removeChild(el);\n};\n```\n\n**Save and restore the original document's selection**\n\nThe final consideration before wrapping this up is respecting the user's previous interaction with the website, like having already selected some content. Luckily, we can now use some modern Javascript methods and properties like `DocumentOrShadowRoot.getSelection()`, `Selection.rangeCount`, `Selection.getRangeAt()`, `Selection.removeAllRanges()` and `Selection.addRange()` to save and restore the original document selection. You can find the final code with these improvements implemented in the [copyToClipboard snippet](/js/s/copy-to-clipboard/).\n\n**Image credit:** [Kaitlyn Baker](https://unsplash.com/@kaitlynbaker?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/code?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)\n",
|
||||
"tags": [
|
||||
"javascript",
|
||||
"browser"
|
||||
]
|
||||
},
|
||||
"meta": {
|
||||
"hash": "9a5b35e84ff9b2b86e943e3a30d1f34cef1272fdf712a85d637d53c7fbd40cc5"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "css-variables",
|
||||
"type": "snippetListing",
|
||||
"title": "What are CSS variables and where can I use them?",
|
||||
"attributes": {
|
||||
"text": "CSS variables (officially called CSS custom properties) behave much like variables in other languages, allowing you to define named variables that contain specific values to be reused within the CSS document. They are defined using the custom property notation, which always start with two dashes (e.g. `--my-color: black;`) and are accessed using the `var()` function (e.g. `color: var(--my-color);`). Custom properties are exceptionally useful for sharing styles between different elements and components (e.g. vertical rhythm, typography variables, color palettes etc.).\n\nOne of the most common examples of CSS variable usage is theming and dark mode, where CSS variables are used to create a shared palette across the whole website, then easily swap it out for a different one by applying a class to a common ancestor (e.g. the `<body>` element or a top-level container). This example helps demonstrate global variables defined in the `:root` element and cascading, as the top-level ancestor inherits values from the `:root` element:\n\n```css\n/* Global variables are defined in the :root element. */\n:root {\n --bg-color: #fff;\n --main-color: #000;\n --secondary-color: #222;\n}\n/* Elements inherit variables from their parents. */\nbody {\n background-color: var(--bg-color);\n color: var(--main-color);\n}\nsmall {\n color: var(--secondary-color);\n}\n/* Elements can define their own values and variables, overriding inherited ones.*/\nbody.dark {\n --bg-color: #080808;\n --main-color: #fff;\n --secondary-color: #ccc;\n}\n```\n\nAnother rather useful example is defining shared customized styles for certain variants of an element, allowing the customization of whole trees of components without having to repeat styles over and over. This example demonstrates cascading even better than the previous one and also introduces the idea of sharing styles between different elements:\n\n```css\n.btn {\n --bg-color: #002299;\n --text-color: #fff;\n --highlight-color: #669900;\n\n background-color: var(--bg-color);\n color: var(--text-color);\n}\n/* --highlight-color is also available to the children of .btn */\n.btn .highlight {\n color: var(--highlight-color);\n}\n/* .btn.danger .highlight will use the --highlight-color defined in .btn-danger */\n.btn-danger {\n --bg-color: #dd4a68;\n --text-color: #000;\n --highlight-color: #990055;\n}\n```\n\nFinally, keep in mind the following useful tips for working with CSS variables:\n\n- You can define fallback values, by providing a second argument to the `var()` function (e.g. `var(--text-color, black);` will default to `black` if `--text-color` is not defined).\n- CSS variables are case sensitive, so mind your capitalization. They can also be inlined in HTML like any other style (e.g. `<div style=\"--text-color: red\">`).\n- You can nest `var()` calls, using another variable as fallback (e.g. `var(--main-color, var(--other-color))`), pass them to other functions such as `calc()` or even assign one variable to another (e.g. `--text-color: var(--main-color);`).\n\n**Image credit:** [Pankaj Patel](https://unsplash.com/@pankajpatel?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/code?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)\n",
|
||||
"tags": [
|
||||
"css",
|
||||
"visual",
|
||||
"layout"
|
||||
]
|
||||
},
|
||||
"meta": {
|
||||
"hash": "f4cc0d29901e6a9fd75b94396db60740431bde26adc6342455f22eaf212350c8"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "flexbox-cheatsheet",
|
||||
"type": "snippetListing",
|
||||
"title": "Flexbox Cheat Sheet",
|
||||
"attributes": {
|
||||
"text": "**Container**\n\n- `display: flex` or `display: inline-flex`: creates a flex context (or an inline flex context) for direct children of this element\n- `flex-direction` determines the main and cross axis for the container, valid values are:\n - `row` (default): horizontal, in the direction of writing (left to right for English)\n - `row-reverse`: horizontal, in the opposite direction of writing (right to left for English)\n - `column`: vertical, top to bottom\n - `column-reverse`: vertical, bottom to top\n- `flex-wrap` determines if flex items will try to fit in one line, valid values are:\n - `nowrap` (default): all flex items will be on one line\n - `wrap`: flex items will wrap onto multiple lines, top to bottom\n - `wrap-reverse`: flex items will wrap onto multiple lines, bottom to top\n- `flex-flow`: shorthand combining `flex-direction` and `flex-wrap`\n - Formal syntax: `flex-flow: <'flex-direction'> || <'flex-wrap'>`\n- `justify-content` defines the alignment along the main axis, valid values are:\n - `flex-start` (default): pack flex items from the start\n - `flex-end`: pack flex items from the end\n - `start`: pack items from the start\n - `end`: pack items from the end\n - `left`: pack items from the left\n - `right`: pack items from the right\n - `center`: pack items around the center\n - `space-around`: distribute items evenly with equal space around them\n - `space-between`: distribute items evenly with equal space between them\n - `space-evenly`: distribute items evenly, ensuring equal space between any two items\n - `stretch`: distribute items evenly, stretching auto-sized items to fit the container\n- `align-items` defines the alignment along the cross axis, valid values are:\n - `flex-start` (default): pack flex items from the start\n - `flex-end`: pack flex items from the end\n - `start`: pack items from the start\n - `end`: pack items from the end\n - `center`: pack items around the center\n - `baseline`: align items based on their baselines\n - `stretch`: stretch items to fill the container\n- `align-content` defines the alignment of extra space along the cross axis, valid values are:\n - `flex-start` (default): pack flex items from the start\n - `flex-end`: pack flex items from the end\n - `start`: pack items from the start\n - `end`: pack items from the end\n - `center`: pack items around the center\n - `space-around`: distribute items evenly with equal space around them\n - `space-between`: distribute items evenly with equal space between them\n - `space-evenly`: distribute items evenly, ensuring equal space between any two items\n - `stretch`: distribute items evenly, stretching auto-sized items to fit the container\n\n\n\n**Items**\n\n- `flex-grow` determines how much the item can grow if necessary\n - Accepts a single positive number (unitless), default value is `0`\n - Specifies how much of the remaining space in the flex container should be assigned to the item\n - The remaining space is the size of the flex container minus the size of all flex items' sizes together\n - If all items have the same `flex-grow`, all items will receive an equal share of the remaining space\n - If not all items have the same `flex-grow`, the remaining space is distributed according to the ratio defined by these values\n- `flex-shrink` determines how much the items can shrink if necessary\n - Accepts a single positive number (unitless), default value is `1`\n - If the size of all flex items is larger than the flex container, items shrink to fit according to `flex-shrink`\n- `flex-basis` determines the initial size of a flex item before the remaining space is distributed\n - Can use any valid `width` value, intrinsic size values, `auto` (default) or `content`\n - `auto` means \"look at my `width` or `height` property\", whereas `content` is used for automatic sizing\n- `flex`: shorthand combining `flex-grow`, `flex-shrink` and `flex-basis`\n - Formal syntax: `flex: none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]`\n- `align-self` allows the item to override the default `align-items` specified by the container\n - Valid values are the same as those of the `align-items` property in the container\n- `order` determines the ordering of the item\n - Accepts an integer value\n - Items in a container are sorted by ascending `order` value and then by their source code order\n - Might cause accessibility issues if used incorrectly\n\n**Image credit:** [Markus Spiske](https://unsplash.com/@markusspiske?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/code?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)\n",
|
||||
"tags": [
|
||||
"css",
|
||||
"layout",
|
||||
"flexbox",
|
||||
"cheatsheet"
|
||||
]
|
||||
},
|
||||
"meta": {
|
||||
"hash": "fbb0468c7c8ad791d31faed987a824b72ee754e37a00c7eb077e7d9593b3293f"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "javascript-deep-freeze-object",
|
||||
"type": "snippetListing",
|
||||
"title": "How can I deep freeze an object in JavaScript?",
|
||||
"attributes": {
|
||||
"text": "Objects in JavaScript are mutable, regardless if you define them as `const` variables or not. In fact, using `const` when defining an object only prevents the variable from being reassigned. However, you can reassign the properties of a `const` object or array, like this:\n\n```js\nconst myObj = { a: 10, b: 20, c: 30 };\nmyObj.a = 12; // { a: 12, b: 20, c: 30 };\n\nconst myArr = [15, 25, 35];\nmyArr[1] = 28; // [15, 28, 35];\n```\n\nTo make an object immutable, we can utilize `Object.freeze()`, which will prevent the addition of new properties and prevent deletion and changes to existing properties to some extent. However, while `Object.freeze()` provides somewhat of a solution, it only mitigates the problem to the next nesting level, as in reality it performs a shallow freeze. This means that properties that are objects or arrays can still be mutated:\n\n```js\nconst myObj = {\n a: 1,\n b: 'hello',\n c: [0, 1, 2],\n d: { e: 1, f: 2 }\n};\nObject.freeze(myObj);\n\nmyObj.a = 10;\nmyObj.b = 'hi';\nmyObj.c[1] = 4;\nmyObj.d.e = 0;\n/*\nmyObj = {\n a: 1,\n b: 'hello',\n c: [0, 4, 2],\n d: { e: 0, f: 2 }\n}\n*/\n```\n\nAs you can see, `Object.freeze()` is a step in the right direction, but only shallow freezes the object. To solve the issue we can use recursion, checking if each property is itself an object and, if `Object.isFrozen()` is `false`, apply `Object.freeze()` to it:\n\n```js\nconst myObj = {\n a: 1,\n b: 'hello',\n c: [0, 1, 2],\n d: { e: 1, f: 2 }\n};\n\nconst deepFreeze = obj => {\n Object.keys(obj).forEach(prop => {\n if (obj[prop] === 'object' && !Object.isFrozen(obj[prop])) deepFreeze(v[prop]);\n });\n return Object.freeze(obj);\n};\ndeepFreeze(myObj);\n\nmyObj.a = 10;\nmyObj.b = 'hi';\nmyObj.c[1] = 4;\nmyObj.d.e = 0;\n\n/*\nmyObj = {\n a: 1,\n b: 'hello',\n c: [0, 1, 2],\n d: { e: 1, f: 2 }\n}\n*/\n```\n\nIn the above example, we apply the techniques we described previously to ensure that the given object is deeply frozen. You can view the complete code, along with more examples in the [deepFreeze](/js/s/deep-freeze) snippet.\n\n**Image credit:** [Aaron Burden](https://unsplash.com/@aaronburden?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/code?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)\n",
|
||||
"tags": [
|
||||
"javascript",
|
||||
"object"
|
||||
]
|
||||
},
|
||||
"meta": {
|
||||
"hash": "499c16b65845aa9dd2e4758e11051975db1d3e1ddc7a38e5ce3cb6e7073f7d06"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "javascript-for-in-for-of-foreach",
|
||||
"type": "snippetListing",
|
||||
"title": "What is the difference between JavaScript's for...in, for...of and forEach?",
|
||||
"attributes": {
|
||||
"text": "`for...in` is used to iterate over all enumerable properties of an object, including inherited enumerable properties. \nThis iteration statement can be used with arrays strings or plain objects, but not with `Map` or `Set` objects.\n\n```js\nfor (let prop in ['a', 'b', 'c']) \n console.log(prop); // 0, 1, 2 (array indexes)\n\nfor (let prop in 'str') \n console.log(prop); // 0, 1, 2 (string indexes)\n\nfor (let prop in {a: 1, b: 2, c: 3}) \n console.log(prop); // a, b, c (object property names)\n\nfor (let prop in new Set(['a', 'b', 'a', 'd'])) \n console.log(prop); // undefined (no enumerable properties)\n```\n\n`for...of` is used to iterate over iterable objects, iterating over their values instead of their properties.\nThis iteration statement can be used with arrays, strings, `Map` or `Set` objects, but not with plain objects.\n\n```js\nfor (let val of ['a', 'b', 'c']) \n console.log(val); // a, b, c (array values)\n\nfor (let val of 'str') \n console.log(val); // s, t, r (string characters)\n\nfor (let val of {a: 1, b: 2, c: 3}) \n console.log(prop); // TypeError (not iterable)\n\nfor (let val of new Set(['a', 'b', 'a', 'd'])) \n console.log(val); // a, b, d (Set values)\n```\n\nFinally, `forEach()` is a method of the `Array` prototype, which allows you to iterate over the elements of an array.\nWhile `forEach()` only iterates over arrays, it can access both the value and the index of each element while iterating.\n\n```js\n['a', 'b', 'c'].forEach(\n val => console.log(val) // a, b, c (array values)\n);\n\n['a', 'b', 'c'].forEach(\n (val, i) => console.log(i) // 0, 1, 2 (array indexes)\n);\n```\n\n**Image credit:** [Tim Stief](https://unsplash.com/@timstief?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/code?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)\n",
|
||||
"tags": [
|
||||
"javascript",
|
||||
"array",
|
||||
"object",
|
||||
"iterator"
|
||||
]
|
||||
},
|
||||
"meta": {
|
||||
"hash": "af1563c13c9cfc4f3ca9ab6c06c0e23579f134f0a4c37220e95d75eb785f943b"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "javascript-iterators",
|
||||
"type": "snippetListing",
|
||||
"title": "What are JavaScript Iterators and where can I use them?",
|
||||
"attributes": {
|
||||
"text": "JavaScript iterators were introduced in ES6 and they are used to loop over a sequence of values, usually some sort of collection. By definition, an iterator must implement a `next()` function, that returns an object in the form of `{ value, done }` where `value` is the next value in the iteration sequence and `done` is a boolean determining if the sequence has already been consumed.\n\nA very simple iterator with practical use in a real-world project could be as follows:\n\n```js\nclass LinkedList {\n constructor(data) {\n this.data = data;\n }\n\n firstItem() {\n return this.data.find(i => i.head);\n }\n\n findById(id) {\n return this.data.find(i => i.id === id);\n }\n\n [Symbol.iterator]() {\n let item = {next: this.firstItem().id};\n return {\n next: () => {\n item = this.findById(item.next);\n if(item) {\n return {value: item.value, done: false};\n }\n return {value: undefined, done: true};\n }\n };\n }\n}\n\nconst myList = new LinkedList([\n {id: 'a10', value: 'First', next: 'a13', head: true },\n {id: 'a11', value: 'Last', next: null, head: false },\n {id: 'a12', value: 'Third', next: 'a11', head: false },\n {id: 'a13', value: 'Second', next: 'a12', head: false }\n]);\n\nfor(let item of myList) {\n console.log(item); // 'First', 'Second', 'Third', 'Last'\n}\n```\n\nIn the above example, we implement a `LinkedList` data structure, that internally uses a `data` array where each item has a `value`, alongside some implementation-specific properties used to determine its position in the sequence. Objects constructed from this class are not iterable by default, so we define an iterator via the use of `Symbol.iterator` and set it up so that the returned sequence is in order based on the internal implementation of the class, while the returned items only return their `value`. \n\nOn a related note, iterators are just functions, meaning they can be called like any other function (e.g. to delegate the iteration to an existing iterator), while also not being restricted to the `Symbol.iterator` name, allowing us to define multiple iterators for the same object. Here's an example of these concepts at play:\n\n```js\nclass SpecialList {\n constructor(data) {\n this.data = data;\n }\n\n [Symbol.iterator]() {\n return this.data[Symbol.iterator]();\n }\n\n values() {\n return this.data\n .filter(i => i.complete)\n .map(i => i.value)\n [Symbol.iterator]();\n }\n}\n\nconst myList = new SpecialList([\n {complete: true, value: 'Lorem ipsum'},\n {complete: true, value: 'dolor sit amet'},\n {complete: false},\n {complete: true, value: 'adipiscing elit'}\n]);\n\nfor(let item of myList) {\n console.log(item); // The exact data passed to the SpecialList constructor above\n}\n\nfor(let item of myList.values()) {\n console.log(item); // 'Lorem ipsum', 'dolor sit amet', 'adipiscing elit'\n}\n```\n\nIn this example, we use the native array iterator of the `data` object to make our `SpecialList` iterable, returning the exact values of the `data` array. Meanwhile, we also define a `values` method, which is an iterator itself, using `Array.prototype.filter()` and `Array.prototype.map()` on the `data` array, then finally returning the `Symbol.iterator` of the result, allowing iteration only over non-empty objects in the sequence and returning just the `value` for each one.\n\n\n**Image credit:** [Daniele Levis Pelusi](https://unsplash.com/@yogidan2012?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/code?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)\n",
|
||||
"tags": [
|
||||
"javascript",
|
||||
"array",
|
||||
"object",
|
||||
"iterator"
|
||||
]
|
||||
},
|
||||
"meta": {
|
||||
"hash": "0b63d58f3ecd1d4dc6d3007629ce4e4a570dc15c09f09edcff6ef6a31a04bfc2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "javascript-memoization",
|
||||
"type": "snippetListing",
|
||||
"title": "Where and how can I use memoization in JavaScript?",
|
||||
"attributes": {
|
||||
"text": "Memoization is a commonly used technique that you can use to speed up your code significantly. It uses a cache to store results, so that subsequent calls of time-consuming functions do not perform the same work another time. Based on this definition, we can easily extract some criteria that can help us decide when to use memoization in our code:\n\n- Memoization should be mainly used to speed up slow-performing, costly or time-consuming function calls\n- Memoization speeds up subsequent calls, so it is best used when you anticipate multiple calls of the same function under the same circumstances\n- Memoization stores results in memory, therefore it should be avoided when the same function is called multiple times under very different circumstances\n\nA simple, object-oriented example of implementing memoization could be as follows:\n\n```js\nclass MyObject {\n constructor(data) {\n this.data = data;\n this.data[this.data.length - 2] = { value: 'Non-empty' };\n }\n\n firstNonEmptyItem() {\n return this.data.find(v => !!v.value);\n }\n\n firstNonEmptyItemMemo() {\n if (!this.firstNonEmpty)\n this.firstNonEmpty = this.data.find(v => !!v.value);\n return this.firstNonEmpty;\n }\n}\n\nconst myObject = new MyObject(Array(2000).fill({ value: null }));\n\nfor (let i = 0; i < 100; i ++)\n myObject.firstNonEmptyItem(); // ~4000ms\nfor (let i = 0; i < 100; i ++)\n myObject.firstNonEmptyItemMemo(); // ~70ms\n```\n\nThe above example showcases a way to implement memoization inside a class, however it makes the assumptions that the `data` structure will not be altered over the lifecycle of the object and that this is the only expensive function call we will make, so it cannot be reused. It also doesn't account for arguments being passed to the function, which would alter the result. A functional approach that would work with any given function and also account for arguments can be found in the form of the [memoize snippet](/js/s/memoize/), which uses a `Map` to store different values. \n\nWe still recommend using that snippet as the primary way to memoize a function, however JavaScript's [Proxy object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy) provides an interesting alternative via the use of the `handler.apply()` trap, which can be used for this purpose as follows:\n\n```js\nconst memoize = fn => new Proxy(fn, {\n cache: new Map(),\n apply (target, thisArg, argsList) {\n let cacheKey = argsList.toString();\n if(!this.cache.has(cacheKey))\n this.cache.set(cacheKey, target.apply(thisArg, argsList));\n return this.cache.get(cacheKey);\n }\n});\n\nconst fibonacci = n => (n <= 1 ? 1 : fibonacci(n - 1) + fibonacci(n - 2));\nconst memoizedFibonacci = memoize(fibonacci);\n\nfor (let i = 0; i < 100; i ++)\n fibonacci(30); // ~5000ms\nfor (let i = 0; i < 100; i ++)\n memoizedFibonacci(30); // ~50ms\n```\n\n\n**Image credit:** [Mark Tegethoff](https://unsplash.com/@tegethoff?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/code?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)\n",
|
||||
"tags": [
|
||||
"javascript",
|
||||
"function",
|
||||
"memoization"
|
||||
]
|
||||
},
|
||||
"meta": {
|
||||
"hash": "35d0c102613d534ddb5aa96ef34da058c6fb29daac4d16ccdcee095007a45131"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "javascript-modify-url-without-reload",
|
||||
"type": "snippetListing",
|
||||
"title": "How do I use JavaScript to modify the URL without reloading the page?",
|
||||
"attributes": {
|
||||
"text": "**Using the History API**\n\nThe HTML5 [History API](https://developer.mozilla.org/en-US/docs/Web/API/History_API) is definitely the way to go for modern websites, as it accomplishes the task at hand, while also providing additional functionality. You can use either `history.pushState()` or `history.replaceState()` to modify the URL in the browser, depending on your needs:\n\n```js\n// Current URL: https://my-website.com/page_a\nconst nextURL = 'https://my-website.com/page_b';\nconst nextTitle = 'My new page title';\nconst nextState = { additionalInformation: 'Updated the URL with JS' };\n\n// This will create a new entry in the browser's history, without reloading\nwindow.history.pushState(nextState, nextTitle, nextURL);\n\n// This will replace the current entry in the browser's history, without reloading\nwindow.history.replaceState(nextState, nextTitle, nextURL);\n```\n\nThe arguments for both methods are the same, allowing you to pass a customized serializable `state` object as the first argument, a customized `title` (although most browsers will ignore this parameter) and the `URL` you want to add/replace in the browser's history. Bear in mind that the History API only allows same-origin URLs, so you cannot navigate to an entirely different website.\n\n**Using the Location API**\n\nThe older [Location API](https://developer.mozilla.org/en-US/docs/Web/API/Location) is not the best tool for the job, as it reloads the page, however it still allows you to modify the current URL and might be useful when working with legacy browsers. You can modify the URL, using either `window.location.href`, `location.assign()` or `location.replace()`:\n\n```js\n// Current URL: https://my-website.com/page_a\nconst nextURL = 'https://my-website.com/page_b';\n\n// This will create a new entry in the browser's history, reloading afterwards\nwindow.location.href = nextURL;\n\n// This will replace the current entry in the browser's history, reloading afterwards\nwindow.location.assign(nextURL);\n\n// This will replace the current entry in the browser's history, reloading afterwards\nwindow.location.replace(nextURL);\n```\n\nAs you can see, all three options will cause a page reload, which can be undesirable. Additionally, you can only set the URL, without any additional arguments, unlike using the History API. Finally, the Location API doesn't restrict you to same-origin URLs, which can be the cause of security issues if you are not careful.\n\n**Image credit:** [Alexander Andrews](https://unsplash.com/@alex_andrews?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/code?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)\n",
|
||||
"tags": [
|
||||
"javascript",
|
||||
"browser"
|
||||
]
|
||||
},
|
||||
"meta": {
|
||||
"hash": "a6ee4f4b0f3aaad0e2e9fbd131c95cb78a31d1428472d328d4869d90ebe8b20e"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "javascript-shallow-deep-clone",
|
||||
"type": "snippetListing",
|
||||
"title": "How do I clone an object in JavaScript?",
|
||||
"attributes": {
|
||||
"text": "JavaScript's primitive data types, such as numbers, strings, null, undefined and booleans are immutable, meaning their value cannot change once created. However, objects and arrays are mutable, allowing their value to be altered after creation. What this means in practice is that primitives are passed by value, whereas objects and arrays are passed by reference. Consider the following example:\n\n```js\nlet str = 'Hello';\nlet copy = str;\ncopy = 'Hi';\n// str = 'Hello', copy = 'Hi'\n\nlet obj = { a: 1, b: 2 };\nlet objCopy = obj;\nobjCopy.b = 4;\n// obj = { a: 1, b: 4}, objCopy = { a: 1, b: 4 }\n```\n\nWhat happens in the of `obj` is that the object is passed by reference to `objCopy`, therefore changing the value of one of the variables also affects the other one. `objCopy` is effectively an alias referencing the same object. We can remedy this issue by cloning the object, using a variety of techniques such as the spread operator (`...`) or `Object.assign()` with an empty object:\n\n```js\nlet obj = { a: 1, b: 2};\nlet clone = { ...obj };\nclone.b = 4;\n// obj = { a: 1, b: 2}, clone = { a: 1, b: 4 }\n\nlet otherClone = Object.assign({}, obj);\notherClone.b = 6;\nclone.b = 4;\n// obj = { a: 1, b: 2}, otherClone = { a: 1, b: 6 }\n```\n\nBoth of these solutions showcase an example of shallow cloning, as they will work for the outer (shallow) object, but fail if we have nested (deep) objects which will ultimately be passed by reference. As usual, there are a few approaches to this problem, the simpler of which is using `JSON.stringify()` and `JSON.parse()` to deal with the situation:\n\n```js\nlet obj = { a: 1, b: { c: 2 } };\nlet clone = JSON.parseJSON.stringify(obj));\nclone.b.c = 4;\n// obj = { a: 1, b: { c: 2 }}, clone = { a: 1, b: { c: 4 } }\n```\n\nWhile the above example works, it has to serialize and deserialize the whole object, which can significantly impact the performance of your code, so it might not be appropriate for larger objects or in projects where performance is important.\n\nAlternatively, you can use a recursive function that deep clones an object and is a lot faster, such as the one in the [deepClone snippet](/js/s/deep-clone). Similarly, if you want a ready-to-use shallow cloning function, you can find one in the [shallowClone snippet](/js/s/shallow-clone).\n\n**Image credit:** [Joshua Ang](https://unsplash.com/@jangus231?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/code?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)\n",
|
||||
"tags": [
|
||||
"javascript",
|
||||
"object"
|
||||
]
|
||||
},
|
||||
"meta": {
|
||||
"hash": "5de8f6afdd97123712222e40e8a2864ca5fe9c02db7d3787205f4e6196627c99"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "javascript-singleton-proxy",
|
||||
"type": "snippetListing",
|
||||
"title": "How can I implement a singleton in JavaScript?",
|
||||
"attributes": {
|
||||
"text": "A singleton is an object-oriented software design pattern which ensures a given class is only ever instantiated once and can be quite useful in many different situations, such as creating global objects and components shared across an application. While JavaScript supports object-oriented programming, it doesn't seem to provide many simple options to implement this pattern. \n\nThe most flexible, albeit somewhat advanced, approach involves using the [Proxy object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy). The Proxy object is used to define so-called traps, methods that allow the definition of custom behavior for certain operations such as property lookup, assignment etc. The singleton pattern dictates that the given class can only have one instance, which means that the most useful trap is `handler.construct()`, the trap for the `new` operator. \n\nAs the `handler` is itself an object, we can use it to store the unique instance of the class we want, if it has been instantiated, while also providing a trap for the `new` operator via `handler.construct()`. In doing so, we can create an object that can be easily reused for any class we want to convert into a singleton, while also allowing us to provide additional traps for any other operations we might want to customize. \n\nHere's the most basic version of a function that takes a `class` and converts it into a singleton, based on the above explanation:\n\n```js\nconst singletonify = (className) => {\n return new Proxy(className.prototype.constructor, {\n instance: null,\n construct: (target, argumentsList) => {\n if (!this.instance)\n this.instance = new target(...argumentsList);\n return this.instance;\n }\n });\n}\n```\n\nAnd here is a simple practical example to better understand what it does:\n\n```js\nclass MyClass {\n constructor(msg) {\n this.msg = msg;\n }\n\n printMsg() {\n console.log(this.msg);\n }\n}\n\nMySingletonClass = singletonify(MyClass);\n\nconst myObj = new MySingletonClass('first');\nmyObj.printMsg(); // 'first'\nconst myObj2 = new MySingletonClass('second');\nmyObj2.printMsg(); // 'first'\n```\n\nIn the above example, you can see that the second time `MySingletonClass` is instantiated, nothing happens, due to the fact that an instance already exists, so it is returned instead of a new object being created. While this is the minimum implementation of a `singletonify` function, it can easily be extended to modify the behavior even further or even use some of the data passed to the constructor in subsequent calls to update the `instance` it holds.\n\n\n**Image credit:** [David Watkis](https://unsplash.com/@david_watkis?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)\n",
|
||||
"tags": [
|
||||
"javascript",
|
||||
"object",
|
||||
"function",
|
||||
"pattern"
|
||||
]
|
||||
},
|
||||
"meta": {
|
||||
"hash": "c0fdcc7dd89958154b42f98bbf9d2d954b4ddf3135cf8c80e1441729c31911fd"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "javascript-swap-two-variables",
|
||||
"type": "snippetListing",
|
||||
"title": "How can I swap two variables in JavaScript?",
|
||||
"attributes": {
|
||||
"text": "In the past, swapping the values of two variables in JavaScript required an intermediate variable to store one of the values while swapping, which would result in something similar to this:\n\n```js\nlet a = 10;\nlet b = 20;\n\nlet tmp;\ntmp = a;\na = b;\nb = tmp;\n```\n\nWhile this approach still works, there are more elegant and less verbose options available to us nowadays. For example, JavaScript ES6 introduced destructuring assignments, allowing individual array items to be assigned to variables in a single statement. Here's what that looks like:\n\n```js\nconst [x, y] = [1, 2];\n```\n\nDestructuring assignments are extremely useful in a handful of situations, including swapping two variables. To accomplish this, we can create an array from the two variables, then use a destructuring assignment to reassign them to each other:\n\n```js\nlet a = 10;\nlet b = 20;\n\n[a , b] = [b, a];\n```\n\n**Image credit:** [roman manukyan](https://unsplash.com/@romanukyan?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/code?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)\n",
|
||||
"tags": [
|
||||
"javascript",
|
||||
"array",
|
||||
"variables"
|
||||
]
|
||||
},
|
||||
"meta": {
|
||||
"hash": "a4c0efa45613af0c281f3e7f855b79de353f7668f88af0e5ddd20635deb03386"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "regexp-cheatsheet",
|
||||
"type": "snippetListing",
|
||||
"title": "Regular Expressions Cheat Sheet",
|
||||
"attributes": {
|
||||
"text": "**Anchors**\n\n- `^`: start of the string or the start of a line in a multiline pattern\n- `$`: end of the string or the end of a line in a multiline pattern\n- `\\b`: word boundary\n- `\\B`: not word boundary (opposite of `\\b`)\n\nNote: Anchors are non-quantifiable (i.e. cannot be followed by a quantifier).\n\n**Character sequences**\n\n- `.`: any character except line breaks\n- `\\w`: any word character\n- `\\W`: any non-word character (opposite of `\\w`)\n- `\\s`: any whitespace character\n- `\\S`: any non-whitespace character (opposite of `\\s`)\n- `\\d`: any digit character\n- `\\D`: any non-digit character (opposite of `\\d`)\n- `[abc]`: a single character in the given set (here `a`, `b` or `c`)\n- `[^abc]`: a single character not in the given set (opposite of `[abc]`)\n- `[a-z]`: a single character in the given range (here between `a` and `z` inclusive)\n- `[^a-z]`: a single character not in the given range (opposite of `[a-z]`)\n- `[a-zA-Z]`: a single character in either of the given ranges\n\nNote: Use `\\` to escape special characters (e.g. `\\`, `/`, `[`, `]`, `(`, `)`, `{`, `}` etc.).\n\n**Quantifiers**\n\n- `a?`: zero or one of `a` (equal to `a{0,1}`)\n- `a*`: zero or more of `a` (equal to `a{0,}`)\n- `a+`: one or more of `a` (equal to `a{1,}`)\n- `a{3}`: exactly 3 of `a`\n- `a{3,}`: 3 or more of `a`\n- `a{3,5}`: between 3 and 5 of `a` (inclusive)\n\nNote: `a` is any valid quantifiable expression.\n\n**Groups**\n\n- `(ab)`: match and capture everything enclosed (here exactly `ab`)\n- `(a|b)`: match and capture either one character (here `a` or `b`)\n- `(?:ab)`: match everything enclosed, without capturing\n\n**Flags**\n\n- `g`: Global\n- `m`: Multiline\n- `i`: Case insensitive\n- `u`: Unicode\n\nNote that this cheatsheet is meant only as a starting point and is by no means a complete guide to all the features and nuances of regular expressions. You can also read [6 JavaScript Regular Expression features you can use today](/blog/s/6-javascript-regexp-tricks) for a deeper dive into some more advanced features.\n\n**Image credit:** [Todd Quackenbush](https://unsplash.com/@toddquackenbush?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/code?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)\n",
|
||||
"tags": [
|
||||
"javascript",
|
||||
"string",
|
||||
"regexp",
|
||||
"cheatsheet"
|
||||
]
|
||||
},
|
||||
"meta": {
|
||||
"hash": "b101a1baa164ded445484e1d09414ba53ee16a399c20f9611b4b0c2bcdb43ee0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "testing-stateful-ui-components",
|
||||
"type": "snippetListing",
|
||||
"title": "An approach to testing stateful React components",
|
||||
"attributes": {
|
||||
"text": "Some time ago, I was tasked with writing tests for a handful of React components, an otherwise mundane and uninspiring task, that somehow ended with a \"Eureka!\" moment for me. The specifics of the project and its components are of little importanc, however the key detail is that I was working with stateful React components that are used daily by a large team and, as such, are refactored and updated quite often.\n\nMy initial approach consisted of writing some simple tests, such as checking if the component is rendered properly and if certain events fire appropriately. In doing so, I was comparing state directly with the result I was expecting, having the component's code right next to my assertions. Of course, this isn't bad by anyone's standards, but for a codebase with many moving parts, it is not the greatest idea. Let me show you an example why:\n\n```js\ncontext('the component is initialized in a collapsed state', function() {\n let wrapper;\n beforeEach(function(){\n wrapper = mount(<StatefulComponent />);\n });\n\n it('component state.expanded is false', function() {\n expect(wrapper.state('expanded')).to.be.false;\n });\n});\n```\n\nIn this test, we check if the component's state has `expanded` equal to `false`. Our test will pass, as long as this simple condition is true. It's a very simple test that should be easy to understand even for someone completely unfamiliar with the codebase.\n\nHowever, over time the component's implementation might change. What happens if `expanded` in our state ends up meaning something different? Or worse yet, if it isn't reflected the same way in the interface?\n\nEnter my \"Eureka!\" moment:\n\n> The application's UI should always be considered the result of combining the component's props and state.\n\nThe above statement implies that a component's state can be considered a black box while testings, an abstraction layer that should not be accessed unless absolutely necessary. So, instead of the test presented above, we should be doing something more like this:\n\n```js\ncontext('the component is initialized in a collapsed state', function() {\n let wrapper;\n beforeEach(function(){\n wrapper = mount(<StatefulComponent />);\n });\n\n it('component does not have the expanded class', function() {\n expect(wrapper.find('div').hasClass('expanded')).to.be.false;\n });\n});\n```\n\nOur test is still easy to read and understand, but it's a better test in general. \n\nBy directly checking the DOM instead of the component's state, we provide information about the component's output to future code authors, instead of asking them to keep the existing implementation intact. It seems like a better way to document the component and it's easier to track future changes should someone refactor the UI in such a way that the DOM representation of the component is altered.\n\n**Image credit:** [Evan Clark](https://unsplash.com/@evanrclark?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)\n",
|
||||
"tags": [
|
||||
"react",
|
||||
"testing"
|
||||
]
|
||||
},
|
||||
"meta": {
|
||||
"hash": "8a68806114f98a5da74a0785b6ccb29ed19398f9d1ecfb48ee8a6e195b6f322a"
|
||||
}
|
||||
}
|
||||
],
|
||||
"meta": {
|
||||
"specification": "http://jsonapi.org/format/",
|
||||
"type": "snippetListingArray",
|
||||
"language": {
|
||||
"short": "",
|
||||
"long": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,529 +0,0 @@
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"id": "10-vs-code-extensions-for-js-developers",
|
||||
"title": "10 must-have VS Code extensions for JavaScript developers",
|
||||
"type": "blog.list",
|
||||
"attributes": {
|
||||
"fileName": "10-vs-code-extensions-for-js-developers.md",
|
||||
"cover": "blog_images/10-vs-code-extensions-for-js-developers.jpg",
|
||||
"excerpt": "VS Code is steadily gaining popularity among developers. Here are 10 essential extensions for JavaScript developers that aim to increase your productivity.",
|
||||
"authors": [
|
||||
"chalarangelo"
|
||||
],
|
||||
"text": "Developers will most likely argue for the rest of eternity about the most productive code editor and the best extensions. Here are my personal extension preferences for VS Code as a JavaScript developer:\n\n1. ESLint\n[ESLint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) turns the popular JavaScrpt linter into an extension of VS Code. It automatically reads your linting configuration, identifies problems and even fixes them for you, if you want.\n\n2. GitLens\n[GitLens](https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens) is a very powerful collaboration tool for VS Code. It provides many useful tools for git such as blame, code authorship, activity heatmaps, recent changes, file history and even commit search.\n \n3. Debugger for Chrome\n[Debugger for Chrome](https://marketplace.visualstudio.com/items?itemName=msjsdiag.debugger-for-chrome) allows you to debug your JavaScript code in Chrome or Chromium. Breakpoints, call stack inspection and stepping inside a function are only some of its features.\n\n4. Bracket Pair Colorizer 2\n[Bracket Pair Colorizer 2](https://marketplace.visualstudio.com/items?itemName=CoenraadS.bracket-pair-colorizer-2) makes reading code faster as it makes matching brackets the same color. This extension for VS Code improves upon its predecessor by providing improved performance.\n\n5. Bookmarks\n[Bookmarks](https://marketplace.visualstudio.com/items?itemName=alefragnani.Bookmarks) is one of those extensions that will significantly reduce your time jumping between different files, as it allows you to save important positions and navigate back to them easily and quickly.\n\n6. TODO Highlight\n[TODO Highlight](https://marketplace.visualstudio.com/items?itemName=wayou.vscode-todo-highlight) simplifies tracking leftover tasks by allowing you to list all of your TODO annotations, as well as adding a handy background highlight to them to make them pop out immediately. \n\n7. Live Server\n[Live Server](https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer) gives you an easy way to serve web pages from VS Code, making previewing and debugging a lot easier. One of the core features is the live reload support that many developers are used to.\n\n8. REST Client\n[REST Client](https://marketplace.visualstudio.com/items?itemName=humao.rest-client) allows you to send HTTP requests and view the responses directly in VS Code. This extension supports a wide range of formats and authorization and should work with most setups.\n\n9. One Dark Pro\n[One Dark Pro](https://marketplace.visualstudio.com/items?itemName=zhuangtongfa.Material-theme) is one of the most popular VS Code themes and with very good reason. It provides a clean theme with a nice palette that has great contrast and is very comfortable to use on a daily basis.\n \n10. Fira Code\n[Fira Code](https://github.com/tonsky/FiraCode) is not a traditional VS Code extension and might take a couple more steps to set up, but it's a superb programming font with ligatures that will help you scan code faster once you get used to it.\n\n**Image credit:** [Fotis Fotopoulos](https://unsplash.com/@ffstop?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/code?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)\n",
|
||||
"tags": [
|
||||
"devtools",
|
||||
"vscode"
|
||||
]
|
||||
},
|
||||
"meta": {
|
||||
"hash": "2dd00656f3a19b08dd10877431101751009c00b0658dc5d3acab61e11fea21e3",
|
||||
"firstSeen": "1577090516",
|
||||
"lastUpdated": "1579272458",
|
||||
"updateCount": 6,
|
||||
"authorCount": 2
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "4-seo-tips-for-developers",
|
||||
"title": "4 SEO tips for developers",
|
||||
"type": "blog.list",
|
||||
"attributes": {
|
||||
"fileName": "4-seo-tips-for-developers.md",
|
||||
"cover": "blog_images/4-seo-tips-for-developers.jpg",
|
||||
"excerpt": "As time goes by, SEO is becoming increasingly relevant, but most web developers seem to have little experience with it. Here are 4 actionable SEO tips you can implement today.",
|
||||
"authors": [
|
||||
"chalarangelo"
|
||||
],
|
||||
"text": "SEO is becoming increasingly relevant as the internet keeps growing. While most web developers usually have little experience with SEO, it is not particularly difficult to handle some of the basics. Here are my top SEO tips for web developers:\n\n1. Craft user-friendly URLs and map the appropriately\nFirst and foremost, start at the very beginning, which is your URL slugs. For URL slugs the rule is that you want them to be human-readable, with words separated by dashes and with no random letters or digits added. Secondly, it's a good idea to make sure that parts of your URLs match to a logical structure in your website (e.g. `/blog/posts/awesome-list-of-seo-tips`). Finally, take the time to build a sitemap and redirect any broken or old URLs to new ones. This will help reduce 404 pages.\n\n2. Use structured data to help Google understand your pages\nStructured data is what Google uses to power its featured snippets, those little cards that appear at the top of certain searches. It's a good idea to set up structured data for your pages, which will help you rank higher in search results and possibly even land a featured snippet every once in a while. Just make sure to find the appropriate structured data type and include it in your page and you should be good to go.\n\n3. Set up Google Analytics and Google Search Console\nThis is hardly a new tip, but I think it deserves a spot on the list, as both of these tools are extremely important. Google Analytics allows you to track user behavior and gather data that can help you identify problems and opportunities, while Google Search Console is helpful for figuring out what users are searching for before landing on your website.\n\n4. Keep an eye on your markup, performance and accessibility\nLast but not least, something that is probably already on your list, is optimizing your code. This includes everything from writing semantic markup and keeping requests to a minimum to optimizing for all device types, making your website accessible and ensuring fast load times. Keep in mind that websites have many moving parts that evolve and change over time, so it's a good idea to audit your website often with a tool like Lighthouse.\n\n**Image credit:** [timJ](https://unsplash.com/@the_roaming_platypus?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/code?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)\n",
|
||||
"tags": [
|
||||
"seo",
|
||||
"webdev"
|
||||
]
|
||||
},
|
||||
"meta": {
|
||||
"hash": "ebc2337246ca7925e763034b8f5718f6276afd9252856cad56eff5f6d6ba25f1",
|
||||
"firstSeen": "1579265475",
|
||||
"lastUpdated": "1579271771",
|
||||
"updateCount": 3,
|
||||
"authorCount": 2
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "6-javascript-regexp-tricks",
|
||||
"title": "6 JavaScript Regular Expression features you can use today",
|
||||
"type": "blog.story",
|
||||
"attributes": {
|
||||
"fileName": "6-javascript-regexp-tricks.md",
|
||||
"cover": "blog_images/6-javascript-regexp-tricks.jpg",
|
||||
"excerpt": "Regular expressions, while very powerful, are notoriously hard to master. Start using them in your JavaScript code by understanding these 6 features.",
|
||||
"authors": [
|
||||
"chalarangelo"
|
||||
],
|
||||
"text": "Regular expressions, while very powerful, are notoriously hard to master. Here are 6 useful features that can help you start using them in your JavaScript projects:\n\n**Capturing groups**\n\nCapturing groups allow you to get specific parts of the matched string, simply by wrapping part of the regular expression in parentheses `(...)`:\n\n```js\nconst str = 'JavaScript is a programming language';\n/(JavaScript) is a (.*)/.exec(str);\n/*\n [\n 0: 'JavaScript is a programming language',\n 1: 'JavaScript',\n 2: 'programming language'\n ]\n*/\n```\n\n**Non-capturing groups**\n\nNon-capturing groups are used for matching something without capturing it, like an either/or matching group that you do not really need. They are defined similarly to capturing groups, but prefixed with `?:`:\n\n```js\nconst str = 'JavaScript is a programming language';\n/(?:JavaScript|Python) is a (.+)/.exec(str);\n/*\n [\n 0: 'JavaScript is a programming language',\n 1: 'programming language'\n ]\n*/\n```\n\n**Named capturing groups**\n\nNamed capturing groups allow you to name a capturing group, by prefixing it with `<name>`:\n\n```js\nconst str = 'JavaScript is a programming language';\n/(?<subject>.+) is a (?<description>.+)/.exec(str);\n/*\n [\n 0: 'JavaScript is a programming language',\n 1: 'JavaScript',\n 2: 'programming language',\n groups: {\n subject: 'JavaScript,\n description: 'programming language'\n }\n ]\n*/\n```\n\n**Capturing group backreferences**\n\nBackreferences help you write shorter regular expressions, by repeating an existing capturing group, using `\\1`, `\\2` etc. Similarly, you can also repeat named capturing groups using `\\k<name>`:\n\n```js\nconst str = 'JavaScript is a programming language - an awesome programming language JavaScript is';\n/(.+) is a (?<description>.+) - an awesome \\k<description> \\1 is/.exec(str);\n/*\n [\n 0: 'JavaScript is a programming language - an awesome programming language JavaScript is',\n 1: 'JavaScript',\n 2: 'programming language',\n groups: {\n subject: 'JavaScript,\n description: 'programming language'\n }\n ]\n*/\n```\n\n**Lookaheads**\n\nLookaheads allow you to check if something is followed by a certain pattern, without actually matching it. You can create positive lookaheads using `?=` and negative lookaheads using `?!`:\n\n```js\nconst str = 'JavaScript is not the same as Java and you should remember that';\n/Java(?=Script)(.*)/.exec(str);\n/*\n [\n 0: 'JavaScript is not the same as Java and you should remember that',\n 1: 'Script is not the same as Java and you should remember that'\n ]\n*/\n\n/Java(?!Script)(.*)/.exec(str);\n/*\n [\n 0: 'Java and you should remember that',\n 1: ' and you should remember that'\n ]\n*/\n```\n\n**Unicode characters**\n\nFinally, you can match unicode characters, using `/p{...}` and the `/u` flag. Examples include, but are not limited to `{Emoji}`, `{Math_Symbols}` and `{Script=Greek}`:\n\n```js\nconst str = 'Greek looks like this: γεια';\n/\\p{Script=Greek}+/u.exec(str);\n/*\n [\n 0: 'γεια'\n ]\n*/\n```\n\n**Image credit:** [Kace Rodriguez](https://unsplash.com/@kace?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/code?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)\n",
|
||||
"tags": [
|
||||
"javascript",
|
||||
"string",
|
||||
"regexp"
|
||||
]
|
||||
},
|
||||
"meta": {
|
||||
"hash": "2e6e5d06cb22bf4dfed8489172861f9361129f1fb83cf503d4817b332ae459bf",
|
||||
"firstSeen": "1586949890",
|
||||
"lastUpdated": "1586949890",
|
||||
"updateCount": 2,
|
||||
"authorCount": 2
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "7-chrome-extensions-for-web-developers",
|
||||
"title": "7 essential Chrome extensions for web developers",
|
||||
"type": "blog.list",
|
||||
"attributes": {
|
||||
"fileName": "7-chrome-extensions-for-web-developers.md",
|
||||
"cover": "blog_images/10-vs-code-extensions-for-js-developers.jpg",
|
||||
"excerpt": "Google Chrome's developer tools are nothing short of amazing. Here are 7 must-have extensions you can add to increase your productivity even further.",
|
||||
"authors": [
|
||||
"chalarangelo"
|
||||
],
|
||||
"text": "Google Chrome's developer tools are nothing short of amazing, but there are a few missing tools that can increase your productivity even further. Here are my personal favorite extensions that I use everyday:\n\n1. CSS Peeper\n[CSS Peeper](https://chrome.google.com/webstore/detail/css-peeper/mbnbehikldjhnfehhnaidhjhoofhpehk?hl=en) is an all-in-one tool for CSS inspection that allows you to quickly peek at the styles, fonts, color palettes and assets of any website you want.\n\n2. React Developer Tools\n[React Developer Tools](https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi?hl=en) is the de facto extension when working with React, providing all the necessary inspection tools for your React applications.\n\n3. LastPass\n[LastPass](https://chrome.google.com/webstore/detail/lastpass-free-password-ma/hdokiejnpimakedhajhdlcegeplioahd?hl=en) keeps your accounts and API keys secure, by providing a free password manager complete with password generation and password-protected notes.\n\n4. uBlock Origin\n[uBlock Origin](https://chrome.google.com/webstore/detail/ublock-origin/cjpalhdlnbpafiamejdnhcphjbkeiagm?hl=en) is a simple yet effective ad blocker extension that you can just install and forget about, as it keeps your browsing experience ad-free.\n\n5. VisBug\n[VisBug](https://chrome.google.com/webstore/detail/visbug/cdockenadnadldjbbgcallicgledbeoc?hl=en) allows you to tweak website designs on the fly, using very intuitive controls and tools, without having to delve into any code at all.\n\n6. JSON Viewer\n[JSON Viewer](https://chrome.google.com/webstore/detail/json-viewer/gbmdgpbipfallnflgajpaliibnhdgobh?hl=en) provides some much needed syntax highlighting and style customization to JSON responses, which are nowadays very commonplace in most web APIs.\n\n7. EditThisCookie\n[EditThisCookie](https://chrome.google.com/webstore/detail/editthiscookie/fngmhnnpilhplaeedifhccceomclgfbg?hl=en) is a powerful cookie manager extension, that allows you to add, delete, edit and even export and import cookies quickly and efficiently.\n\n**Image credit:** [Fotis Fotopoulos](https://unsplash.com/@ffstop?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/code?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)\n",
|
||||
"tags": [
|
||||
"devtools",
|
||||
"webdev"
|
||||
]
|
||||
},
|
||||
"meta": {
|
||||
"hash": "298a153b85f60c81a96e98bc3823ef580492060a06c65ef17e5c49430a6cfc59",
|
||||
"firstSeen": "1584527851",
|
||||
"lastUpdated": "1584527851",
|
||||
"updateCount": 2,
|
||||
"authorCount": 2
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "8-tips-for-remote-work",
|
||||
"title": "8 tips for working from home",
|
||||
"type": "blog.list",
|
||||
"attributes": {
|
||||
"fileName": "8-tips-for-remote-work.md",
|
||||
"cover": "blog_images/8-tips-for-remote-work.jpg",
|
||||
"excerpt": "Working from home seems like a great alternative to going to the office, but there are challenges that come with it that you need to overcome...",
|
||||
"authors": [
|
||||
"chalarangelo"
|
||||
],
|
||||
"text": "Working from home (also known as remote work) seems like a great alternative to going to the office every morning, but it comes with its own set of challenges that you need to overcome in order to stay healthy and productive. Here are my tips for achieving just that:\n\n1. Set up your work environment\nWorking from home has its perks, but nothing beats a well-designed office space where everything is set up with only one purpose in mind: working. Figure out your home office, experiment with different settings and understand what works best for you as soon as possible. An ideal working space is comfortable, quiet and has the right equipment for you.\n\n2. Establish ground rules\nMost likely you are not living alone, so you have to establish some ground rules with your roomate or significant other. It's up to you to drive the point home that during working hours you are, for the most part, not home. Sure, you can answer the door if you expect a delivery, but that's pretty much as far as you can go. People should not bother you during working hours, unless absolutely necessary, as small distractions pile up fast.\n\n3. Inform others of your availability\nIt's important to let people know that you are online and working or that you are taking a short break for lunch. Remember that you are still part of a team that requires coordination and others probably depend on your work to some extent. Remember to update your status as necessary to make collaboration easier.\n\n4. Socialize with coworkers\nWorking from home can lead to feelings of loneliness, disconnect, isolation which can quickly spin out of control and lead to depression. Communicate with people on your team as if you were in the same room. A healthy amount of communication will help you feel more like you are all working together rather than each one on their own.\n\n5. Be your best professional self\nNobody might be watching you at home, so you can theoretically slack off as much as you like in your pajamas, but that's not very professional. Try to dress appropriately in case you join a video call and behave professionaly, so no inappropriate websites or hours upon hours of checking social media. Ask yourself if someone in a shared office space would do whatever it is you are doing and, if the answer is no, stop doing it.\n\n6. Plan your daily and weekly tasks\nHaving a coherent working plan helps you organize your time and prioritize important tasks above trivial ones. It also helps to put things into perspective and have a general idea of what other people on the team are working on. Plan ahead of time together with your team and keep each other posted on the progress of each task. Short term plans help you get through the day, long term plans help everyone meet their deadlines.\n\n7. Use the right collaboration tools\nWorking from home has its own challenges and issues, so try to find the right tools for the job. Slack, Skype, Zoom, Hangouts are great for communication. Design tools such as Figma or Sketch cloud help you communicate designs quickly and effectively. GitHub is the perfect tool for code collaboration and VS Code has an extension (Live Share) for sharing your code editors. Communicate with your team, figure out your needs and pick tools that work for you.\n\n8. Maintain regular hours\nIt's as easy to forget about breaks as it is to start working late. Try to set a schedule that sits well with your team and stick to it. If you would work 9 to 5 in a regular office environment, do the same at home. Take regular breaks, do not forget to sign off when put in your daily hours and come back tomorrow. After all, it's business as usual.\n\n**Image credit:** [Goran Ivos](https://unsplash.com/@goran_ivos?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/code?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)\n",
|
||||
"tags": [
|
||||
"programming",
|
||||
"jobs",
|
||||
"webdev"
|
||||
]
|
||||
},
|
||||
"meta": {
|
||||
"hash": "5e48e683f0ef6ae3ae5ea9600b62919041bab9d2e9e00a12a1a8ad78c89542d4",
|
||||
"firstSeen": "1584044081",
|
||||
"lastUpdated": "1584044081",
|
||||
"updateCount": 2,
|
||||
"authorCount": 2
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "breaking-react",
|
||||
"title": "Breaking React - a common pattern to avoid",
|
||||
"type": "blog.story",
|
||||
"attributes": {
|
||||
"fileName": "breaking-react.md",
|
||||
"cover": "blog_images/breaking-react.jpg",
|
||||
"excerpt": "As powerful as React is, it is also quite fragile at places. Did you know that just a few lines are more than enough to break your entire React application?",
|
||||
"authors": [
|
||||
"chalarangelo"
|
||||
],
|
||||
"text": "I am by no means an expert React engineer, but I have a couple years of experience under my belt. While React is an extremely powerful library for building user interfaces, it is also quite fragile at places. A very common bug I have encountered is caused by direct DOM manipulation in combination with React. This is not exactly an anti-pattern, but under the right circumstances it can break your entire React application and might be hard to debug. \n\nHere's [a minimal example](https://codepen.io/chalarangelo/pen/jOEojVJ?editors=0010) of how one can reproduce this bug, before we dive into explaining the problem and how to fix it:\n\n```jsx\nconst destroyElement = () => \n document.getElementById('app').removeChild(document.getElementById('my-div'));\n\nconst App = () => {\n const [elementShown, updateElement] = React.useState(true);\n \n return (\n <div id='app'>\n <button onClick={() => destroyElement()}>\n Delete element via querySelector\n </button>\n <button onClick={() => updateElement(!elementShown)}>\n Update element and state\n </button>\n { elementShown ? <div id=\"my-div\">I am the element</div> : null }\n </div>\n );\n};\n\nReactDOM.render(<App />, document.getElementById('root'));\n```\n\nThis looks like a pretty simple React application, with a container, two buttons and a state variable. However, it will crash if you click the button that calls `destroyElement()` and then click the other button. _Why?_ you might ask. The issue here might not be immediately obvious, but if you look at your browser console you will notice the following exception:\n\n```\nUncaught DOMException: Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node.\n```\n\nThis might still be cryptic, so let me explain what is going on. React uses its own representation of the DOM, called a virtual DOM, in order to figure out what to render. Usually, the virtual DOM will match the current DOM structure and React will process changes in props and state, updating the virtual DOM and then sending the necessary changes to the real DOM. \n\nHowever, in this case React's virtual DOM and the real DOM are different, because of `destroyElement()` removing the `#my-div` element. As a result, when React tries to update the real DOM with the changes from the virtual DOM, the `#my-div` element cannot be removed as it doesn't exist anymore. This results in the above exception being thrown and your application breaking.\n\nThis example is short and easy to resolve, by refactoring `destroyElement()` to be part of the `App` component and interact with its state, yet it showcases how fragile React can be under circumstances. Having a shared codebase, with many developers working on different things, can lead to issues like this being introduced and tracking them down can be rather tricky, which is why you might want to be very careful when directly manipulating the DOM when you use React.\n\n**Image credit:** [Julia Joppien](https://unsplash.com/@vitreous_macula?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/code?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)\n",
|
||||
"tags": [
|
||||
"react",
|
||||
"debugging"
|
||||
]
|
||||
},
|
||||
"meta": {
|
||||
"hash": "633fa8b4636401636d8bcf368f6967b96f50b65be845c9dd923a49e897fba771",
|
||||
"firstSeen": "1580380519",
|
||||
"lastUpdated": "1580380519",
|
||||
"updateCount": 2,
|
||||
"authorCount": 2
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "code-anatomy-performant-python",
|
||||
"title": "Code Anatomy - Writing high performance Python code",
|
||||
"type": "blog.story",
|
||||
"attributes": {
|
||||
"fileName": "code-anatomy-performant-python.md",
|
||||
"cover": "blog_images/code-anatomy-performant-python.jpg",
|
||||
"excerpt": "Writing short, efficient Python code is not always straightforward. Read how we optimize our list snippets to increase performance using a couple of simple tricks.",
|
||||
"authors": [
|
||||
"maciv",
|
||||
"chalarangelo"
|
||||
],
|
||||
"text": "Writing short and efficient Python code is not always easy or straightforward. However, it's often that we see a piece of code and we don't realize the thought process behind the way it was written. We will be taking a look at the [difference](/python/s/difference) snippet, which returns the difference between two iterables, in order to understand its structure.\n\nBased on the description of the snippet's functionality, we can naively write it like this:\n\n```py\ndef difference(a, b):\n return [item for item in a if item not in b]\n```\n\nThe above implementation may work well enough, but doesn't account for duplicates in `b`, making the code take more time than necessary in cases with many duplicates in the second list. To solve this issue, we can make use of the `set()` method, which will only keep the unique values in the list:\n\n```py\ndef difference(a, b):\n return [item for item in a if item not in set(b)]\n```\n\nThis version, while it seems like an improvement, may actually be slower than the previous one. If you look closely, you will see that `set()` is called for every `item` in `a` causing the result of `set(b)` to be evaluated every time. Here's an example where we wrap `set()` with another method to better showcase the problem:\n\n```py\ndef difference(a, b):\n return [item for item in a if item not in make_set(b)]\n\ndef make_set(itr):\n print('Making set...')\n return set(itr)\n\nprint(difference([1, 2, 3], [1, 2, 4]))\n# Making set...\n# Making set...\n# Making set...\n# [3]\n```\n\nThe solution to this issue is to call `set()` once before the list comprehension and store the result to speed up the process:\n\n```py\ndef difference(a, b):\n _b = set(b)\n return [item for item in a if item not in _b]\n```\n\nAnother option worth mentioning when analyzing performance for this snippet is the use of a list comprehension versus using something like `filter()` and `list()`. Implementing the same code using the latter option would result in something like this:\n\n```py\ndef difference(a, b):\n _b = set(b)\n return list(filter(lambda item: item not in _b, a))\n```\n\nUsing `timeit` to analyze the performance of the last two code examples, it's pretty clear that using list comprehension can be up to ten times faster than the alternative, as it's a native language feature that works very similar to a simple `for` loop without the overhead of the extra function calls. This explains why we prefer it, apart from readability.\n\nThis pretty much applies to most mathematical list operation snippets, such as [difference](/python/s/difference), [symmetric_difference](/python/s/symmetric-difference) and [intersection](/python/s/intersection).\n\n**Image credit:** [Kalen Emsley](https://unsplash.com/@kalenemsley?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/code?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)\n",
|
||||
"tags": [
|
||||
"python",
|
||||
"list",
|
||||
"performance"
|
||||
]
|
||||
},
|
||||
"meta": {
|
||||
"hash": "40d3da7677547b9f7a7e8dd25fa0217658ecccabc9f794a8b2da416b60a122a0",
|
||||
"firstSeen": "1584269405",
|
||||
"lastUpdated": "1584269405",
|
||||
"updateCount": 2,
|
||||
"authorCount": 2
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "copy-text-to-clipboard-with-javascript",
|
||||
"title": "How can I copy text to clipboard with JavaScript?",
|
||||
"type": "blog.question",
|
||||
"attributes": {
|
||||
"fileName": "copy-text-to-clipboard-with-javascript.md",
|
||||
"cover": "blog_images/copy-text-to-clipboard-with-javascript.jpg",
|
||||
"excerpt": "Learn how to programmatically copy text to clipboard with a few lines of JavaScript and level up your web development skills.",
|
||||
"authors": [
|
||||
"chalarangelo"
|
||||
],
|
||||
"text": "**Core functionality**\n\nA very common need when building websites is the ability to copy text to clipboard with a single button click. Javascript can easily do this in five short steps:hout the user selecting it or hitting the appropriate key combination on their keyboard. Javascript can easily do this in five short steps:\n\n1. Create a` <textarea>` element to be appended to the document. Set its value to the string that we want to copy to the clipboard.\n2. Append said `<textarea>` element to the current HTML document.\n3. Use `HTMLInputElement.select()` to select the contents of the `<textarea>` element.\n4. Use `Document.execCommand('copy')` to copy the contents of the `<textarea>` to the clipboard.\n5. Remove the `<textarea>` element from the document.\n\nThe simplest version of this method looks something like this:\n\n```js\nconst copyToClipboard = str => {\n const el = document.createElement('textarea');\n el.value = str;\n document.body.appendChild(el);\n el.select();\n document.execCommand('copy');\n document.body.removeChild(el);\n};\n```\n\nBear in mind that this method will not work everywhere, but only as a result of a user action (e.g. inside a `click` event listener), due to the way `Document.execCommand()` works.\n\n**Hide the appended element**\n\nThe above method, while functional, might have some issues such as flashing when appending and removing the `<textarea>`, a problem that is even more apparent when considering accessibility. A major improvement to this method comes from adding some CSS to make the element invisible and restrict editing by users:\n\n```js\nconst copyToClipboard = str => {\n const el = document.createElement('textarea');\n el.value = str;\n el.setAttribute('readonly', '');\n el.style.position = 'absolute';\n el.style.left = '-9999px';\n document.body.appendChild(el);\n el.select();\n document.execCommand('copy');\n document.body.removeChild(el);\n};\n```\n\n**Save and restore the original document's selection**\n\nThe final consideration before wrapping this up is respecting the user's previous interaction with the website, like having already selected some content. Luckily, we can now use some modern Javascript methods and properties like `DocumentOrShadowRoot.getSelection()`, `Selection.rangeCount`, `Selection.getRangeAt()`, `Selection.removeAllRanges()` and `Selection.addRange()` to save and restore the original document selection. You can find the final code with these improvements implemented in the [copyToClipboard snippet](/js/s/copy-to-clipboard/).\n\n**Image credit:** [Kaitlyn Baker](https://unsplash.com/@kaitlynbaker?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/code?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)\n",
|
||||
"tags": [
|
||||
"javascript",
|
||||
"browser"
|
||||
]
|
||||
},
|
||||
"meta": {
|
||||
"hash": "9a5b35e84ff9b2b86e943e3a30d1f34cef1272fdf712a85d637d53c7fbd40cc5",
|
||||
"firstSeen": "1579513283",
|
||||
"lastUpdated": "1579513283",
|
||||
"updateCount": 2,
|
||||
"authorCount": 2
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "css-variables",
|
||||
"title": "What are CSS variables and where can I use them?",
|
||||
"type": "blog.question",
|
||||
"attributes": {
|
||||
"fileName": "css-variables.md",
|
||||
"cover": "blog_images/css-variables.jpg",
|
||||
"excerpt": "Learn how CSS custom properties (CSS variables) work and what you can use them for in your code and designs.",
|
||||
"authors": [
|
||||
"chalarangelo"
|
||||
],
|
||||
"text": "CSS variables (officially called CSS custom properties) behave much like variables in other languages, allowing you to define named variables that contain specific values to be reused within the CSS document. They are defined using the custom property notation, which always start with two dashes (e.g. `--my-color: black;`) and are accessed using the `var()` function (e.g. `color: var(--my-color);`). Custom properties are exceptionally useful for sharing styles between different elements and components (e.g. vertical rhythm, typography variables, color palettes etc.).\n\nOne of the most common examples of CSS variable usage is theming and dark mode, where CSS variables are used to create a shared palette across the whole website, then easily swap it out for a different one by applying a class to a common ancestor (e.g. the `<body>` element or a top-level container). This example helps demonstrate global variables defined in the `:root` element and cascading, as the top-level ancestor inherits values from the `:root` element:\n\n```css\n/* Global variables are defined in the :root element. */\n:root {\n --bg-color: #fff;\n --main-color: #000;\n --secondary-color: #222;\n}\n/* Elements inherit variables from their parents. */\nbody {\n background-color: var(--bg-color);\n color: var(--main-color);\n}\nsmall {\n color: var(--secondary-color);\n}\n/* Elements can define their own values and variables, overriding inherited ones.*/\nbody.dark {\n --bg-color: #080808;\n --main-color: #fff;\n --secondary-color: #ccc;\n}\n```\n\nAnother rather useful example is defining shared customized styles for certain variants of an element, allowing the customization of whole trees of components without having to repeat styles over and over. This example demonstrates cascading even better than the previous one and also introduces the idea of sharing styles between different elements:\n\n```css\n.btn {\n --bg-color: #002299;\n --text-color: #fff;\n --highlight-color: #669900;\n\n background-color: var(--bg-color);\n color: var(--text-color);\n}\n/* --highlight-color is also available to the children of .btn */\n.btn .highlight {\n color: var(--highlight-color);\n}\n/* .btn.danger .highlight will use the --highlight-color defined in .btn-danger */\n.btn-danger {\n --bg-color: #dd4a68;\n --text-color: #000;\n --highlight-color: #990055;\n}\n```\n\nFinally, keep in mind the following useful tips for working with CSS variables:\n\n- You can define fallback values, by providing a second argument to the `var()` function (e.g. `var(--text-color, black);` will default to `black` if `--text-color` is not defined).\n- CSS variables are case sensitive, so mind your capitalization. They can also be inlined in HTML like any other style (e.g. `<div style=\"--text-color: red\">`).\n- You can nest `var()` calls, using another variable as fallback (e.g. `var(--main-color, var(--other-color))`), pass them to other functions such as `calc()` or even assign one variable to another (e.g. `--text-color: var(--main-color);`).\n\n**Image credit:** [Pankaj Patel](https://unsplash.com/@pankajpatel?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/code?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)\n",
|
||||
"tags": [
|
||||
"css",
|
||||
"visual",
|
||||
"layout"
|
||||
]
|
||||
},
|
||||
"meta": {
|
||||
"hash": "f4cc0d29901e6a9fd75b94396db60740431bde26adc6342455f22eaf212350c8",
|
||||
"firstSeen": "1583775570",
|
||||
"lastUpdated": "1583775570",
|
||||
"updateCount": 2,
|
||||
"authorCount": 2
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "flexbox-cheatsheet",
|
||||
"title": "Flexbox Cheat Sheet",
|
||||
"type": "blog.cheatsheet",
|
||||
"attributes": {
|
||||
"fileName": "flexbox-cheatsheet.md",
|
||||
"cover": "blog_images/flexbox.jpg",
|
||||
"excerpt": "Flexbox allows you to create fluid layouts easily. If you find yourself constantly looking up the syntax or how it work, this handy cheatsheet is all you need.",
|
||||
"authors": [
|
||||
"chalarangelo"
|
||||
],
|
||||
"text": "**Container**\n\n- `display: flex` or `display: inline-flex`: creates a flex context (or an inline flex context) for direct children of this element\n- `flex-direction` determines the main and cross axis for the container, valid values are:\n - `row` (default): horizontal, in the direction of writing (left to right for English)\n - `row-reverse`: horizontal, in the opposite direction of writing (right to left for English)\n - `column`: vertical, top to bottom\n - `column-reverse`: vertical, bottom to top\n- `flex-wrap` determines if flex items will try to fit in one line, valid values are:\n - `nowrap` (default): all flex items will be on one line\n - `wrap`: flex items will wrap onto multiple lines, top to bottom\n - `wrap-reverse`: flex items will wrap onto multiple lines, bottom to top\n- `flex-flow`: shorthand combining `flex-direction` and `flex-wrap`\n - Formal syntax: `flex-flow: <'flex-direction'> || <'flex-wrap'>`\n- `justify-content` defines the alignment along the main axis, valid values are:\n - `flex-start` (default): pack flex items from the start\n - `flex-end`: pack flex items from the end\n - `start`: pack items from the start\n - `end`: pack items from the end\n - `left`: pack items from the left\n - `right`: pack items from the right\n - `center`: pack items around the center\n - `space-around`: distribute items evenly with equal space around them\n - `space-between`: distribute items evenly with equal space between them\n - `space-evenly`: distribute items evenly, ensuring equal space between any two items\n - `stretch`: distribute items evenly, stretching auto-sized items to fit the container\n- `align-items` defines the alignment along the cross axis, valid values are:\n - `flex-start` (default): pack flex items from the start\n - `flex-end`: pack flex items from the end\n - `start`: pack items from the start\n - `end`: pack items from the end\n - `center`: pack items around the center\n - `baseline`: align items based on their baselines\n - `stretch`: stretch items to fill the container\n- `align-content` defines the alignment of extra space along the cross axis, valid values are:\n - `flex-start` (default): pack flex items from the start\n - `flex-end`: pack flex items from the end\n - `start`: pack items from the start\n - `end`: pack items from the end\n - `center`: pack items around the center\n - `space-around`: distribute items evenly with equal space around them\n - `space-between`: distribute items evenly with equal space between them\n - `space-evenly`: distribute items evenly, ensuring equal space between any two items\n - `stretch`: distribute items evenly, stretching auto-sized items to fit the container\n\n\n\n**Items**\n\n- `flex-grow` determines how much the item can grow if necessary\n - Accepts a single positive number (unitless), default value is `0`\n - Specifies how much of the remaining space in the flex container should be assigned to the item\n - The remaining space is the size of the flex container minus the size of all flex items' sizes together\n - If all items have the same `flex-grow`, all items will receive an equal share of the remaining space\n - If not all items have the same `flex-grow`, the remaining space is distributed according to the ratio defined by these values\n- `flex-shrink` determines how much the items can shrink if necessary\n - Accepts a single positive number (unitless), default value is `1`\n - If the size of all flex items is larger than the flex container, items shrink to fit according to `flex-shrink`\n- `flex-basis` determines the initial size of a flex item before the remaining space is distributed\n - Can use any valid `width` value, intrinsic size values, `auto` (default) or `content`\n - `auto` means \"look at my `width` or `height` property\", whereas `content` is used for automatic sizing\n- `flex`: shorthand combining `flex-grow`, `flex-shrink` and `flex-basis`\n - Formal syntax: `flex: none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]`\n- `align-self` allows the item to override the default `align-items` specified by the container\n - Valid values are the same as those of the `align-items` property in the container\n- `order` determines the ordering of the item\n - Accepts an integer value\n - Items in a container are sorted by ascending `order` value and then by their source code order\n - Might cause accessibility issues if used incorrectly\n\n**Image credit:** [Markus Spiske](https://unsplash.com/@markusspiske?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/code?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)\n",
|
||||
"tags": [
|
||||
"css",
|
||||
"layout",
|
||||
"flexbox",
|
||||
"cheatsheet"
|
||||
]
|
||||
},
|
||||
"meta": {
|
||||
"hash": "fbb0468c7c8ad791d31faed987a824b72ee754e37a00c7eb077e7d9593b3293f",
|
||||
"firstSeen": "1588368109",
|
||||
"lastUpdated": "1588368109",
|
||||
"updateCount": 2,
|
||||
"authorCount": 2
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "javascript-deep-freeze-object",
|
||||
"title": "How can I deep freeze an object in JavaScript?",
|
||||
"type": "blog.question",
|
||||
"attributes": {
|
||||
"fileName": "javascript-deep-freeze-object.md",
|
||||
"cover": "blog_images/javascript-deep-freeze-object.jpg",
|
||||
"excerpt": "Learn how mutability works in JavaScript, its applications to objects and how you can properly freeze them to make them constant.",
|
||||
"authors": [
|
||||
"chalarangelo"
|
||||
],
|
||||
"text": "Objects in JavaScript are mutable, regardless if you define them as `const` variables or not. In fact, using `const` when defining an object only prevents the variable from being reassigned. However, you can reassign the properties of a `const` object or array, like this:\n\n```js\nconst myObj = { a: 10, b: 20, c: 30 };\nmyObj.a = 12; // { a: 12, b: 20, c: 30 };\n\nconst myArr = [15, 25, 35];\nmyArr[1] = 28; // [15, 28, 35];\n```\n\nTo make an object immutable, we can utilize `Object.freeze()`, which will prevent the addition of new properties and prevent deletion and changes to existing properties to some extent. However, while `Object.freeze()` provides somewhat of a solution, it only mitigates the problem to the next nesting level, as in reality it performs a shallow freeze. This means that properties that are objects or arrays can still be mutated:\n\n```js\nconst myObj = {\n a: 1,\n b: 'hello',\n c: [0, 1, 2],\n d: { e: 1, f: 2 }\n};\nObject.freeze(myObj);\n\nmyObj.a = 10;\nmyObj.b = 'hi';\nmyObj.c[1] = 4;\nmyObj.d.e = 0;\n/*\nmyObj = {\n a: 1,\n b: 'hello',\n c: [0, 4, 2],\n d: { e: 0, f: 2 }\n}\n*/\n```\n\nAs you can see, `Object.freeze()` is a step in the right direction, but only shallow freezes the object. To solve the issue we can use recursion, checking if each property is itself an object and, if `Object.isFrozen()` is `false`, apply `Object.freeze()` to it:\n\n```js\nconst myObj = {\n a: 1,\n b: 'hello',\n c: [0, 1, 2],\n d: { e: 1, f: 2 }\n};\n\nconst deepFreeze = obj => {\n Object.keys(obj).forEach(prop => {\n if (obj[prop] === 'object' && !Object.isFrozen(obj[prop])) deepFreeze(v[prop]);\n });\n return Object.freeze(obj);\n};\ndeepFreeze(myObj);\n\nmyObj.a = 10;\nmyObj.b = 'hi';\nmyObj.c[1] = 4;\nmyObj.d.e = 0;\n\n/*\nmyObj = {\n a: 1,\n b: 'hello',\n c: [0, 1, 2],\n d: { e: 1, f: 2 }\n}\n*/\n```\n\nIn the above example, we apply the techniques we described previously to ensure that the given object is deeply frozen. You can view the complete code, along with more examples in the [deepFreeze](/js/s/deep-freeze) snippet.\n\n**Image credit:** [Aaron Burden](https://unsplash.com/@aaronburden?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/code?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)\n",
|
||||
"tags": [
|
||||
"javascript",
|
||||
"object"
|
||||
]
|
||||
},
|
||||
"meta": {
|
||||
"hash": "499c16b65845aa9dd2e4758e11051975db1d3e1ddc7a38e5ce3cb6e7073f7d06",
|
||||
"firstSeen": "1584454530",
|
||||
"lastUpdated": "1584454530",
|
||||
"updateCount": 2,
|
||||
"authorCount": 2
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "javascript-for-in-for-of-foreach",
|
||||
"title": "What is the difference between JavaScript's for...in, for...of and forEach?",
|
||||
"type": "blog.question",
|
||||
"attributes": {
|
||||
"fileName": "javascript-for-in-for-of-foreach.md",
|
||||
"cover": "blog_images/javascript-for-in-for-of-foreach.jpg",
|
||||
"excerpt": "Learn the differences between the three most commonly used iteration methods offered by JavaScript, which often confuse beginners and veterans alike.",
|
||||
"authors": [
|
||||
"chalarangelo"
|
||||
],
|
||||
"text": "`for...in` is used to iterate over all enumerable properties of an object, including inherited enumerable properties. \nThis iteration statement can be used with arrays strings or plain objects, but not with `Map` or `Set` objects.\n\n```js\nfor (let prop in ['a', 'b', 'c']) \n console.log(prop); // 0, 1, 2 (array indexes)\n\nfor (let prop in 'str') \n console.log(prop); // 0, 1, 2 (string indexes)\n\nfor (let prop in {a: 1, b: 2, c: 3}) \n console.log(prop); // a, b, c (object property names)\n\nfor (let prop in new Set(['a', 'b', 'a', 'd'])) \n console.log(prop); // undefined (no enumerable properties)\n```\n\n`for...of` is used to iterate over iterable objects, iterating over their values instead of their properties.\nThis iteration statement can be used with arrays, strings, `Map` or `Set` objects, but not with plain objects.\n\n```js\nfor (let val of ['a', 'b', 'c']) \n console.log(val); // a, b, c (array values)\n\nfor (let val of 'str') \n console.log(val); // s, t, r (string characters)\n\nfor (let val of {a: 1, b: 2, c: 3}) \n console.log(prop); // TypeError (not iterable)\n\nfor (let val of new Set(['a', 'b', 'a', 'd'])) \n console.log(val); // a, b, d (Set values)\n```\n\nFinally, `forEach()` is a method of the `Array` prototype, which allows you to iterate over the elements of an array.\nWhile `forEach()` only iterates over arrays, it can access both the value and the index of each element while iterating.\n\n```js\n['a', 'b', 'c'].forEach(\n val => console.log(val) // a, b, c (array values)\n);\n\n['a', 'b', 'c'].forEach(\n (val, i) => console.log(i) // 0, 1, 2 (array indexes)\n);\n```\n\n**Image credit:** [Tim Stief](https://unsplash.com/@timstief?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/code?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)\n",
|
||||
"tags": [
|
||||
"javascript",
|
||||
"array",
|
||||
"object",
|
||||
"iterator"
|
||||
]
|
||||
},
|
||||
"meta": {
|
||||
"hash": "af1563c13c9cfc4f3ca9ab6c06c0e23579f134f0a4c37220e95d75eb785f943b",
|
||||
"firstSeen": "1579507951",
|
||||
"lastUpdated": "1580888902",
|
||||
"updateCount": 4,
|
||||
"authorCount": 2
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "javascript-iterators",
|
||||
"title": "What are JavaScript Iterators and where can I use them?",
|
||||
"type": "blog.question",
|
||||
"attributes": {
|
||||
"fileName": "javascript-iterators.md",
|
||||
"cover": "blog_images/javascript-iterators.jpg",
|
||||
"excerpt": "Learn how the new JavaScript ES6 Iterators work and how you can use them to level up your programming projects by understanding these short code examples.",
|
||||
"authors": [
|
||||
"chalarangelo"
|
||||
],
|
||||
"text": "JavaScript iterators were introduced in ES6 and they are used to loop over a sequence of values, usually some sort of collection. By definition, an iterator must implement a `next()` function, that returns an object in the form of `{ value, done }` where `value` is the next value in the iteration sequence and `done` is a boolean determining if the sequence has already been consumed.\n\nA very simple iterator with practical use in a real-world project could be as follows:\n\n```js\nclass LinkedList {\n constructor(data) {\n this.data = data;\n }\n\n firstItem() {\n return this.data.find(i => i.head);\n }\n\n findById(id) {\n return this.data.find(i => i.id === id);\n }\n\n [Symbol.iterator]() {\n let item = {next: this.firstItem().id};\n return {\n next: () => {\n item = this.findById(item.next);\n if(item) {\n return {value: item.value, done: false};\n }\n return {value: undefined, done: true};\n }\n };\n }\n}\n\nconst myList = new LinkedList([\n {id: 'a10', value: 'First', next: 'a13', head: true },\n {id: 'a11', value: 'Last', next: null, head: false },\n {id: 'a12', value: 'Third', next: 'a11', head: false },\n {id: 'a13', value: 'Second', next: 'a12', head: false }\n]);\n\nfor(let item of myList) {\n console.log(item); // 'First', 'Second', 'Third', 'Last'\n}\n```\n\nIn the above example, we implement a `LinkedList` data structure, that internally uses a `data` array where each item has a `value`, alongside some implementation-specific properties used to determine its position in the sequence. Objects constructed from this class are not iterable by default, so we define an iterator via the use of `Symbol.iterator` and set it up so that the returned sequence is in order based on the internal implementation of the class, while the returned items only return their `value`. \n\nOn a related note, iterators are just functions, meaning they can be called like any other function (e.g. to delegate the iteration to an existing iterator), while also not being restricted to the `Symbol.iterator` name, allowing us to define multiple iterators for the same object. Here's an example of these concepts at play:\n\n```js\nclass SpecialList {\n constructor(data) {\n this.data = data;\n }\n\n [Symbol.iterator]() {\n return this.data[Symbol.iterator]();\n }\n\n values() {\n return this.data\n .filter(i => i.complete)\n .map(i => i.value)\n [Symbol.iterator]();\n }\n}\n\nconst myList = new SpecialList([\n {complete: true, value: 'Lorem ipsum'},\n {complete: true, value: 'dolor sit amet'},\n {complete: false},\n {complete: true, value: 'adipiscing elit'}\n]);\n\nfor(let item of myList) {\n console.log(item); // The exact data passed to the SpecialList constructor above\n}\n\nfor(let item of myList.values()) {\n console.log(item); // 'Lorem ipsum', 'dolor sit amet', 'adipiscing elit'\n}\n```\n\nIn this example, we use the native array iterator of the `data` object to make our `SpecialList` iterable, returning the exact values of the `data` array. Meanwhile, we also define a `values` method, which is an iterator itself, using `Array.prototype.filter()` and `Array.prototype.map()` on the `data` array, then finally returning the `Symbol.iterator` of the result, allowing iteration only over non-empty objects in the sequence and returning just the `value` for each one.\n\n\n**Image credit:** [Daniele Levis Pelusi](https://unsplash.com/@yogidan2012?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/code?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)\n",
|
||||
"tags": [
|
||||
"javascript",
|
||||
"array",
|
||||
"object",
|
||||
"iterator"
|
||||
]
|
||||
},
|
||||
"meta": {
|
||||
"hash": "0b63d58f3ecd1d4dc6d3007629ce4e4a570dc15c09f09edcff6ef6a31a04bfc2",
|
||||
"firstSeen": "1581851360",
|
||||
"lastUpdated": "1581851360",
|
||||
"updateCount": 2,
|
||||
"authorCount": 2
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "javascript-memoization",
|
||||
"title": "Where and how can I use memoization in JavaScript?",
|
||||
"type": "blog.question",
|
||||
"attributes": {
|
||||
"fileName": "javascript-memoization.md",
|
||||
"cover": "blog_images/javascript-memoization.jpg",
|
||||
"excerpt": "Learn different ways to memoize function calls in JavaScript as well as when to use memoization to get the best performance results.",
|
||||
"authors": [
|
||||
"chalarangelo"
|
||||
],
|
||||
"text": "Memoization is a commonly used technique that you can use to speed up your code significantly. It uses a cache to store results, so that subsequent calls of time-consuming functions do not perform the same work another time. Based on this definition, we can easily extract some criteria that can help us decide when to use memoization in our code:\n\n- Memoization should be mainly used to speed up slow-performing, costly or time-consuming function calls\n- Memoization speeds up subsequent calls, so it is best used when you anticipate multiple calls of the same function under the same circumstances\n- Memoization stores results in memory, therefore it should be avoided when the same function is called multiple times under very different circumstances\n\nA simple, object-oriented example of implementing memoization could be as follows:\n\n```js\nclass MyObject {\n constructor(data) {\n this.data = data;\n this.data[this.data.length - 2] = { value: 'Non-empty' };\n }\n\n firstNonEmptyItem() {\n return this.data.find(v => !!v.value);\n }\n\n firstNonEmptyItemMemo() {\n if (!this.firstNonEmpty)\n this.firstNonEmpty = this.data.find(v => !!v.value);\n return this.firstNonEmpty;\n }\n}\n\nconst myObject = new MyObject(Array(2000).fill({ value: null }));\n\nfor (let i = 0; i < 100; i ++)\n myObject.firstNonEmptyItem(); // ~4000ms\nfor (let i = 0; i < 100; i ++)\n myObject.firstNonEmptyItemMemo(); // ~70ms\n```\n\nThe above example showcases a way to implement memoization inside a class, however it makes the assumptions that the `data` structure will not be altered over the lifecycle of the object and that this is the only expensive function call we will make, so it cannot be reused. It also doesn't account for arguments being passed to the function, which would alter the result. A functional approach that would work with any given function and also account for arguments can be found in the form of the [memoize snippet](/js/s/memoize/), which uses a `Map` to store different values. \n\nWe still recommend using that snippet as the primary way to memoize a function, however JavaScript's [Proxy object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy) provides an interesting alternative via the use of the `handler.apply()` trap, which can be used for this purpose as follows:\n\n```js\nconst memoize = fn => new Proxy(fn, {\n cache: new Map(),\n apply (target, thisArg, argsList) {\n let cacheKey = argsList.toString();\n if(!this.cache.has(cacheKey))\n this.cache.set(cacheKey, target.apply(thisArg, argsList));\n return this.cache.get(cacheKey);\n }\n});\n\nconst fibonacci = n => (n <= 1 ? 1 : fibonacci(n - 1) + fibonacci(n - 2));\nconst memoizedFibonacci = memoize(fibonacci);\n\nfor (let i = 0; i < 100; i ++)\n fibonacci(30); // ~5000ms\nfor (let i = 0; i < 100; i ++)\n memoizedFibonacci(30); // ~50ms\n```\n\n\n**Image credit:** [Mark Tegethoff](https://unsplash.com/@tegethoff?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/code?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)\n",
|
||||
"tags": [
|
||||
"javascript",
|
||||
"function",
|
||||
"memoization"
|
||||
]
|
||||
},
|
||||
"meta": {
|
||||
"hash": "35d0c102613d534ddb5aa96ef34da058c6fb29daac4d16ccdcee095007a45131",
|
||||
"firstSeen": "1582813405",
|
||||
"lastUpdated": "1582813405",
|
||||
"updateCount": 2,
|
||||
"authorCount": 2
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "javascript-modify-url-without-reload",
|
||||
"title": "How do I use JavaScript to modify the URL without reloading the page?",
|
||||
"type": "blog.question",
|
||||
"attributes": {
|
||||
"fileName": "javascript-modify-url-without-reload.md",
|
||||
"cover": "blog_images/javascript-modify-url-without-reload.jpg",
|
||||
"excerpt": "Learn all of the options JavaScript provides for modifying the URL of the current page in the browser without reloading the page.",
|
||||
"authors": [
|
||||
"chalarangelo"
|
||||
],
|
||||
"text": "**Using the History API**\n\nThe HTML5 [History API](https://developer.mozilla.org/en-US/docs/Web/API/History_API) is definitely the way to go for modern websites, as it accomplishes the task at hand, while also providing additional functionality. You can use either `history.pushState()` or `history.replaceState()` to modify the URL in the browser, depending on your needs:\n\n```js\n// Current URL: https://my-website.com/page_a\nconst nextURL = 'https://my-website.com/page_b';\nconst nextTitle = 'My new page title';\nconst nextState = { additionalInformation: 'Updated the URL with JS' };\n\n// This will create a new entry in the browser's history, without reloading\nwindow.history.pushState(nextState, nextTitle, nextURL);\n\n// This will replace the current entry in the browser's history, without reloading\nwindow.history.replaceState(nextState, nextTitle, nextURL);\n```\n\nThe arguments for both methods are the same, allowing you to pass a customized serializable `state` object as the first argument, a customized `title` (although most browsers will ignore this parameter) and the `URL` you want to add/replace in the browser's history. Bear in mind that the History API only allows same-origin URLs, so you cannot navigate to an entirely different website.\n\n**Using the Location API**\n\nThe older [Location API](https://developer.mozilla.org/en-US/docs/Web/API/Location) is not the best tool for the job, as it reloads the page, however it still allows you to modify the current URL and might be useful when working with legacy browsers. You can modify the URL, using either `window.location.href`, `location.assign()` or `location.replace()`:\n\n```js\n// Current URL: https://my-website.com/page_a\nconst nextURL = 'https://my-website.com/page_b';\n\n// This will create a new entry in the browser's history, reloading afterwards\nwindow.location.href = nextURL;\n\n// This will replace the current entry in the browser's history, reloading afterwards\nwindow.location.assign(nextURL);\n\n// This will replace the current entry in the browser's history, reloading afterwards\nwindow.location.replace(nextURL);\n```\n\nAs you can see, all three options will cause a page reload, which can be undesirable. Additionally, you can only set the URL, without any additional arguments, unlike using the History API. Finally, the Location API doesn't restrict you to same-origin URLs, which can be the cause of security issues if you are not careful.\n\n**Image credit:** [Alexander Andrews](https://unsplash.com/@alex_andrews?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/code?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)\n",
|
||||
"tags": [
|
||||
"javascript",
|
||||
"browser"
|
||||
]
|
||||
},
|
||||
"meta": {
|
||||
"hash": "a6ee4f4b0f3aaad0e2e9fbd131c95cb78a31d1428472d328d4869d90ebe8b20e",
|
||||
"firstSeen": "1585309707",
|
||||
"lastUpdated": "1585323436",
|
||||
"updateCount": 4,
|
||||
"authorCount": 2
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "javascript-shallow-deep-clone",
|
||||
"title": "How do I clone an object in JavaScript?",
|
||||
"type": "blog.question",
|
||||
"attributes": {
|
||||
"fileName": "javascript-shallow-deep-clone.md",
|
||||
"cover": "blog_images/javascript-shallow-deep-clone.jpg",
|
||||
"excerpt": "Learn how JavaScript handles mutable data, such as objects and arrays, and understand how shallow cloning and deep cloning work.",
|
||||
"authors": [
|
||||
"chalarangelo"
|
||||
],
|
||||
"text": "JavaScript's primitive data types, such as numbers, strings, null, undefined and booleans are immutable, meaning their value cannot change once created. However, objects and arrays are mutable, allowing their value to be altered after creation. What this means in practice is that primitives are passed by value, whereas objects and arrays are passed by reference. Consider the following example:\n\n```js\nlet str = 'Hello';\nlet copy = str;\ncopy = 'Hi';\n// str = 'Hello', copy = 'Hi'\n\nlet obj = { a: 1, b: 2 };\nlet objCopy = obj;\nobjCopy.b = 4;\n// obj = { a: 1, b: 4}, objCopy = { a: 1, b: 4 }\n```\n\nWhat happens in the of `obj` is that the object is passed by reference to `objCopy`, therefore changing the value of one of the variables also affects the other one. `objCopy` is effectively an alias referencing the same object. We can remedy this issue by cloning the object, using a variety of techniques such as the spread operator (`...`) or `Object.assign()` with an empty object:\n\n```js\nlet obj = { a: 1, b: 2};\nlet clone = { ...obj };\nclone.b = 4;\n// obj = { a: 1, b: 2}, clone = { a: 1, b: 4 }\n\nlet otherClone = Object.assign({}, obj);\notherClone.b = 6;\nclone.b = 4;\n// obj = { a: 1, b: 2}, otherClone = { a: 1, b: 6 }\n```\n\nBoth of these solutions showcase an example of shallow cloning, as they will work for the outer (shallow) object, but fail if we have nested (deep) objects which will ultimately be passed by reference. As usual, there are a few approaches to this problem, the simpler of which is using `JSON.stringify()` and `JSON.parse()` to deal with the situation:\n\n```js\nlet obj = { a: 1, b: { c: 2 } };\nlet clone = JSON.parseJSON.stringify(obj));\nclone.b.c = 4;\n// obj = { a: 1, b: { c: 2 }}, clone = { a: 1, b: { c: 4 } }\n```\n\nWhile the above example works, it has to serialize and deserialize the whole object, which can significantly impact the performance of your code, so it might not be appropriate for larger objects or in projects where performance is important.\n\nAlternatively, you can use a recursive function that deep clones an object and is a lot faster, such as the one in the [deepClone snippet](/js/s/deep-clone). Similarly, if you want a ready-to-use shallow cloning function, you can find one in the [shallowClone snippet](/js/s/shallow-clone).\n\n**Image credit:** [Joshua Ang](https://unsplash.com/@jangus231?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/code?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)\n",
|
||||
"tags": [
|
||||
"javascript",
|
||||
"object"
|
||||
]
|
||||
},
|
||||
"meta": {
|
||||
"hash": "5de8f6afdd97123712222e40e8a2864ca5fe9c02db7d3787205f4e6196627c99",
|
||||
"firstSeen": "1586870396",
|
||||
"lastUpdated": "1586870396",
|
||||
"updateCount": 2,
|
||||
"authorCount": 2
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "javascript-singleton-proxy",
|
||||
"title": "How can I implement a singleton in JavaScript?",
|
||||
"type": "blog.question",
|
||||
"attributes": {
|
||||
"fileName": "javascript-singleton-proxy.md",
|
||||
"cover": "blog_images/javascript-singleton-proxy.jpg",
|
||||
"excerpt": "Learn how to implement a singleton, a commonly used software design pattern, in JavaScript using the Proxy object.",
|
||||
"authors": [
|
||||
"chalarangelo"
|
||||
],
|
||||
"text": "A singleton is an object-oriented software design pattern which ensures a given class is only ever instantiated once and can be quite useful in many different situations, such as creating global objects and components shared across an application. While JavaScript supports object-oriented programming, it doesn't seem to provide many simple options to implement this pattern. \n\nThe most flexible, albeit somewhat advanced, approach involves using the [Proxy object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy). The Proxy object is used to define so-called traps, methods that allow the definition of custom behavior for certain operations such as property lookup, assignment etc. The singleton pattern dictates that the given class can only have one instance, which means that the most useful trap is `handler.construct()`, the trap for the `new` operator. \n\nAs the `handler` is itself an object, we can use it to store the unique instance of the class we want, if it has been instantiated, while also providing a trap for the `new` operator via `handler.construct()`. In doing so, we can create an object that can be easily reused for any class we want to convert into a singleton, while also allowing us to provide additional traps for any other operations we might want to customize. \n\nHere's the most basic version of a function that takes a `class` and converts it into a singleton, based on the above explanation:\n\n```js\nconst singletonify = (className) => {\n return new Proxy(className.prototype.constructor, {\n instance: null,\n construct: (target, argumentsList) => {\n if (!this.instance)\n this.instance = new target(...argumentsList);\n return this.instance;\n }\n });\n}\n```\n\nAnd here is a simple practical example to better understand what it does:\n\n```js\nclass MyClass {\n constructor(msg) {\n this.msg = msg;\n }\n\n printMsg() {\n console.log(this.msg);\n }\n}\n\nMySingletonClass = singletonify(MyClass);\n\nconst myObj = new MySingletonClass('first');\nmyObj.printMsg(); // 'first'\nconst myObj2 = new MySingletonClass('second');\nmyObj2.printMsg(); // 'first'\n```\n\nIn the above example, you can see that the second time `MySingletonClass` is instantiated, nothing happens, due to the fact that an instance already exists, so it is returned instead of a new object being created. While this is the minimum implementation of a `singletonify` function, it can easily be extended to modify the behavior even further or even use some of the data passed to the constructor in subsequent calls to update the `instance` it holds.\n\n\n**Image credit:** [David Watkis](https://unsplash.com/@david_watkis?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)\n",
|
||||
"tags": [
|
||||
"javascript",
|
||||
"object",
|
||||
"function",
|
||||
"pattern"
|
||||
]
|
||||
},
|
||||
"meta": {
|
||||
"hash": "c0fdcc7dd89958154b42f98bbf9d2d954b4ddf3135cf8c80e1441729c31911fd",
|
||||
"firstSeen": "1582639323",
|
||||
"lastUpdated": "1582639323",
|
||||
"updateCount": 2,
|
||||
"authorCount": 2
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "javascript-swap-two-variables",
|
||||
"title": "How can I swap two variables in JavaScript?",
|
||||
"type": "blog.question",
|
||||
"attributes": {
|
||||
"fileName": "javascript-swap-two-variables.md",
|
||||
"cover": "blog_images/javascript-swap-two-variables.jpg",
|
||||
"excerpt": "Learn how to swap the values of two variables in JavaScript using a single line of ES6 code.",
|
||||
"authors": [
|
||||
"chalarangelo"
|
||||
],
|
||||
"text": "In the past, swapping the values of two variables in JavaScript required an intermediate variable to store one of the values while swapping, which would result in something similar to this:\n\n```js\nlet a = 10;\nlet b = 20;\n\nlet tmp;\ntmp = a;\na = b;\nb = tmp;\n```\n\nWhile this approach still works, there are more elegant and less verbose options available to us nowadays. For example, JavaScript ES6 introduced destructuring assignments, allowing individual array items to be assigned to variables in a single statement. Here's what that looks like:\n\n```js\nconst [x, y] = [1, 2];\n```\n\nDestructuring assignments are extremely useful in a handful of situations, including swapping two variables. To accomplish this, we can create an array from the two variables, then use a destructuring assignment to reassign them to each other:\n\n```js\nlet a = 10;\nlet b = 20;\n\n[a , b] = [b, a];\n```\n\n**Image credit:** [roman manukyan](https://unsplash.com/@romanukyan?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/code?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)\n",
|
||||
"tags": [
|
||||
"javascript",
|
||||
"array",
|
||||
"variables"
|
||||
]
|
||||
},
|
||||
"meta": {
|
||||
"hash": "a4c0efa45613af0c281f3e7f855b79de353f7668f88af0e5ddd20635deb03386",
|
||||
"firstSeen": "1587985971",
|
||||
"lastUpdated": "1587985971",
|
||||
"updateCount": 2,
|
||||
"authorCount": 2
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "regexp-cheatsheet",
|
||||
"title": "Regular Expressions Cheat Sheet",
|
||||
"type": "blog.cheatsheet",
|
||||
"attributes": {
|
||||
"fileName": "regexp-cheatsheet.md",
|
||||
"cover": "blog_images/cheatsheet1.jpg",
|
||||
"excerpt": "Regular expressions are a very useful tool in a variety of situations. Save this cheatsheet for any time you need to look up their syntax and speed up your development.",
|
||||
"authors": [
|
||||
"chalarangelo"
|
||||
],
|
||||
"text": "**Anchors**\n\n- `^`: start of the string or the start of a line in a multiline pattern\n- `$`: end of the string or the end of a line in a multiline pattern\n- `\\b`: word boundary\n- `\\B`: not word boundary (opposite of `\\b`)\n\nNote: Anchors are non-quantifiable (i.e. cannot be followed by a quantifier).\n\n**Character sequences**\n\n- `.`: any character except line breaks\n- `\\w`: any word character\n- `\\W`: any non-word character (opposite of `\\w`)\n- `\\s`: any whitespace character\n- `\\S`: any non-whitespace character (opposite of `\\s`)\n- `\\d`: any digit character\n- `\\D`: any non-digit character (opposite of `\\d`)\n- `[abc]`: a single character in the given set (here `a`, `b` or `c`)\n- `[^abc]`: a single character not in the given set (opposite of `[abc]`)\n- `[a-z]`: a single character in the given range (here between `a` and `z` inclusive)\n- `[^a-z]`: a single character not in the given range (opposite of `[a-z]`)\n- `[a-zA-Z]`: a single character in either of the given ranges\n\nNote: Use `\\` to escape special characters (e.g. `\\`, `/`, `[`, `]`, `(`, `)`, `{`, `}` etc.).\n\n**Quantifiers**\n\n- `a?`: zero or one of `a` (equal to `a{0,1}`)\n- `a*`: zero or more of `a` (equal to `a{0,}`)\n- `a+`: one or more of `a` (equal to `a{1,}`)\n- `a{3}`: exactly 3 of `a`\n- `a{3,}`: 3 or more of `a`\n- `a{3,5}`: between 3 and 5 of `a` (inclusive)\n\nNote: `a` is any valid quantifiable expression.\n\n**Groups**\n\n- `(ab)`: match and capture everything enclosed (here exactly `ab`)\n- `(a|b)`: match and capture either one character (here `a` or `b`)\n- `(?:ab)`: match everything enclosed, without capturing\n\n**Flags**\n\n- `g`: Global\n- `m`: Multiline\n- `i`: Case insensitive\n- `u`: Unicode\n\nNote that this cheatsheet is meant only as a starting point and is by no means a complete guide to all the features and nuances of regular expressions. You can also read [6 JavaScript Regular Expression features you can use today](/blog/s/6-javascript-regexp-tricks) for a deeper dive into some more advanced features.\n\n**Image credit:** [Todd Quackenbush](https://unsplash.com/@toddquackenbush?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/code?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)\n",
|
||||
"tags": [
|
||||
"javascript",
|
||||
"string",
|
||||
"regexp",
|
||||
"cheatsheet"
|
||||
]
|
||||
},
|
||||
"meta": {
|
||||
"hash": "b101a1baa164ded445484e1d09414ba53ee16a399c20f9611b4b0c2bcdb43ee0",
|
||||
"firstSeen": "1588336747",
|
||||
"lastUpdated": "1588368109",
|
||||
"updateCount": 3,
|
||||
"authorCount": 2
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "testing-stateful-ui-components",
|
||||
"title": "An approach to testing stateful React components",
|
||||
"type": "blog.story",
|
||||
"attributes": {
|
||||
"fileName": "testing-stateful-ui-components.md",
|
||||
"cover": "blog_images/testing-stateful-ui-components.jpg",
|
||||
"excerpt": "Testing stateful React components is by no means a difficult task, but did you know there is an elegant solution that doesn't involve testing state directly?",
|
||||
"authors": [
|
||||
"chalarangelo"
|
||||
],
|
||||
"text": "Some time ago, I was tasked with writing tests for a handful of React components, an otherwise mundane and uninspiring task, that somehow ended with a \"Eureka!\" moment for me. The specifics of the project and its components are of little importanc, however the key detail is that I was working with stateful React components that are used daily by a large team and, as such, are refactored and updated quite often.\n\nMy initial approach consisted of writing some simple tests, such as checking if the component is rendered properly and if certain events fire appropriately. In doing so, I was comparing state directly with the result I was expecting, having the component's code right next to my assertions. Of course, this isn't bad by anyone's standards, but for a codebase with many moving parts, it is not the greatest idea. Let me show you an example why:\n\n```js\ncontext('the component is initialized in a collapsed state', function() {\n let wrapper;\n beforeEach(function(){\n wrapper = mount(<StatefulComponent />);\n });\n\n it('component state.expanded is false', function() {\n expect(wrapper.state('expanded')).to.be.false;\n });\n});\n```\n\nIn this test, we check if the component's state has `expanded` equal to `false`. Our test will pass, as long as this simple condition is true. It's a very simple test that should be easy to understand even for someone completely unfamiliar with the codebase.\n\nHowever, over time the component's implementation might change. What happens if `expanded` in our state ends up meaning something different? Or worse yet, if it isn't reflected the same way in the interface?\n\nEnter my \"Eureka!\" moment:\n\n> The application's UI should always be considered the result of combining the component's props and state.\n\nThe above statement implies that a component's state can be considered a black box while testings, an abstraction layer that should not be accessed unless absolutely necessary. So, instead of the test presented above, we should be doing something more like this:\n\n```js\ncontext('the component is initialized in a collapsed state', function() {\n let wrapper;\n beforeEach(function(){\n wrapper = mount(<StatefulComponent />);\n });\n\n it('component does not have the expanded class', function() {\n expect(wrapper.find('div').hasClass('expanded')).to.be.false;\n });\n});\n```\n\nOur test is still easy to read and understand, but it's a better test in general. \n\nBy directly checking the DOM instead of the component's state, we provide information about the component's output to future code authors, instead of asking them to keep the existing implementation intact. It seems like a better way to document the component and it's easier to track future changes should someone refactor the UI in such a way that the DOM representation of the component is altered.\n\n**Image credit:** [Evan Clark](https://unsplash.com/@evanrclark?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)\n",
|
||||
"tags": [
|
||||
"react",
|
||||
"testing"
|
||||
]
|
||||
},
|
||||
"meta": {
|
||||
"hash": "8a68806114f98a5da74a0785b6ccb29ed19398f9d1ecfb48ee8a6e195b6f322a",
|
||||
"firstSeen": "1579161498",
|
||||
"lastUpdated": "1579265244",
|
||||
"updateCount": 3,
|
||||
"authorCount": 2
|
||||
}
|
||||
}
|
||||
],
|
||||
"meta": {
|
||||
"specification": "http://jsonapi.org/format/",
|
||||
"type": "snippetArray",
|
||||
"language": {
|
||||
"short": "",
|
||||
"long": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,8 +0,0 @@
|
||||
module.exports = {
|
||||
"name": "30-seconds-blog",
|
||||
"description": "The official 30-seconds blog",
|
||||
"repositoryUrl": "https://github.com/30-seconds/30-seconds-blog",
|
||||
"snippetPath": "blog_posts",
|
||||
"snippetDataPath": "blog_data",
|
||||
"parser": "_30blogParser",
|
||||
};
|
||||
2243
package-lock.json
generated
2243
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
23
package.json
23
package.json
@ -1,23 +0,0 @@
|
||||
{
|
||||
"name": "30-seconds-blog",
|
||||
"version": "1.0.0",
|
||||
"description": "The official 30-seconds blog",
|
||||
"main": "config.js",
|
||||
"scripts": {
|
||||
"extractor": "extract-snippet-data config.js"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/30-seconds/30-seconds-blog"
|
||||
},
|
||||
"author": "30-seconds",
|
||||
"license": "CC0-1.0",
|
||||
"bugs": {
|
||||
"url": "https://github.com/30-seconds/30-seconds-blog/issues"
|
||||
},
|
||||
"homepage": "https://www.30secondsofcode.org",
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"@30-seconds/integration-tools": "^1.3.2"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user