Find me on medium
While I was looking over some objects in JavaScript the other day I realized that choosing what to learn is an effective way to take big leaps in the learning process. In todays world working smart is the way to go if you were to be doing something for the money. That is because value is the money maker. The more value something is to someone, the chances of that person paying for it increases dramatically.
When I look back into my beginning stages I was thankful for learning the forEach
, map
, filter
and reduce
very early on in my career, because I started seeing them everywhere. I didn't know it at the time but learning them first was the smart thing to do. And I don't mean just looking at some documentation on how to use them. I read books that dove deep into those topics.
There's a difference between learning something like reduce
as opposed to something like map
. If I were to be asked which one I'd like to learn first and which one I'd push aside for later. I would choose reduce
to get going with because mastering reduce
will already help me become familiar with filter
and map
at the same time since it can do both of them in the same function block:
function filterInStrings(fn, arr) {
return arr.filter((item) => {
return typeof item === 'string'
})
}
function mapToUppercase(fn, arr) {
return arr.map((item) => item.toUpperCase())
}
// Achieves what filterInStrings and mapToUppercase does in one function block
function reduce(reducer, arr) {
return arr.reduce((acc, item) => {
if (typeof item === 'string') {
return acc.concat(item.toUpperCase())
}
return acc
})
}
This post will go over 10 JavaScript and NodeJS Tips that Knock Away Multiple Concepts with One Stone Each
Request object (hint: window.fetch
)
Ever used the window.fetch api in JavaScript when developing web applications? This popular function has two golden objects that I recommend learning as soon as possible.
The issue I see right now is that articles don't really go over these objects when they talk about the fetch api. Surely some will say read the response data by accessing the body
property as well as the headers, but even knowing different data types of the response data can go a long way. The Request and Response object is wrapped in every request you make.
When you learn the Request interface you are actually hitting plenty of birds with one stone because when you venture out and get your hands dirty with third party tools available to the JavaScript community you will realize that this interface is purposely mimicked as a way to simplify (and unify) all application development that work with the http request/response pipeline.
For example I use Gatsby Functions and the arguments they pass in to each function includes the request object which is the same as the object from the http module in nodejs.
Another example is Web Workers in JavaScript. Workers are a hot feature in modern web applications which also uses the fetch
api, where the Request
object appears again.
Response object (hint: window.fetch
)
Just like the Request object, the Response object is just as (if not then more) important than the Request object because this contains the most sensitive part of your application--the response data.
Once you get familiar with the Request and Response interface, you will have an easier time understanding documentations to third party tools.
For example, modern frameworks like GatsbyJS (again) mimic this structure in Gatsby Functions. ExpressJS is all about working with the Request and Response objects which is used by famous companies like Yahoo, Amazon, LinkedIn, The New York Times, The Home Depot, AT&T, Meetup, The Wall Street Journal, Docker, and many more (Source: stackshare).
I use AWS Lambda functions through the @aws-sdk/client-lambda SDK and see similar Request/Response objects with the same body
, headers
, statusCode
properties when setting the InvocationType
to "RequestResponse"
I also use Netlify Functions and the object you must return from each handler is the same shape you see from a Response
with a statusCode that you must know to ensure the consumer handles it accordingly.
Curry functions
Curry functions in JavaScript are functions that take one or more arguments at a time and returns a new function that expects the next (or remaining) arguments. It is a transformation of functions that returns new functions until all of the arguments are (expected to be) completed.
If you're a beginner in programming this might sound very odd. You'd most likely be asking yourself why anyone would ever return functions by giving functions. This is a different concept in the real world. If we want apples we don't want to have to give apples to get apples back. Why not just give the function and get what we need right away?
The benefits that currying provides is what makes libraries like lodash so powerful. You can create a function that has some behavior predefined, then reuse it as a transformation for upcoming values (hint: even functions are treated as values in JavaScript). lodash-fp makes use of this pattern throughout all of their code and helps you work with a whole new programming paradigm.
Understanding currying is understanding function composition. When you spend lots of your time coming up with elegant ways to compose functions together you are already working with advanced concepts in one shot like lexical scoping, closures, higher order functions (the next section), execution contexts, passing this
around correctly (if dependent), maintaining references, etc.
Here's what I mean:
function curry(f) {
const z = {}
return function one(x, ...args) {
return function two(y) {
return f.call(one, x, y, z, ...args)
}
}
}
Here is all the things happening in this code snippet as the result of performing currying:
- Higher order function
- Lexical scoping
- Closures
- Maintaining references
- Partial application
- Maintaining
this
(if you intend to) - Hiding implementation details
- Share the same object to all future functions to work with
A good example that makes great use of this technique is the createStore function from the redux library. (Hint: There are comments in that snippet that describe some neat behavior as the function is curried)
Higher order functions
We previously talked about the benefits of curry functions. We also barely mentioned higher order functions.
By learning currying, you also learn working hands on with higher order functions, another big concept in JavaScript to make a big leap into your learning process.
When you learn higher order functions, you're also learning:
- How to work with and how to visualize closures
- How to create partial application functions
- How variables get memorized (which might help you understand memoization
Almost every JavaScript library out there works with higher order functions. It's what you can do with higher order functions that matters most. If you can understand higher order functions, you're already on a good start to understanding how to do advanced techniques like transducers in JavaScript.
Stdout/Stdio/Stderr
Learning/working with stdout
, stderr
and stdio
is probably a must if you like to develop applications on NodeJS (and even for web applications). This was something I didn't pay attention to much until later on in my development career.
Little did I know that I was working with stdout
in almost every single file.
Understanding stdout
, stderr
and stdio
and how it was being used in applications all of a sudden made a lot of concepts in magical frameworks "click" in my head when I first started focusing onto it awhile back.
Awhile back I was also planning to learn how the native child_process
module in NodeJS works, but I kept pushing it aside. When I finally decided to get my hands dirty with it, I realized that stdout
already knocked away the mysterious I had with the module. Then it was easy for me to get into tools like Ink.
Promises (in conjunction with the callback concept)
Mastering promises and callbacks will improve your ability to work with asynchronous code. Callbacks and promises are also everywhere.
This should be one of the first things to master if you are a beginner. Your ability to debug also improves when dealing with complex code, like this annoying tricky code snippet that is presented commonly at interviews:
const arr = [10, 12, 15, 21]
for (var i = 0; i < arr.length; i++) {
setTimeout(function () {
console.log('The index of this number is: ' + i)
}, 3000)
}
Thinking virtually
There's no doubt about it: thinking in virtual data structures is the way to go for modern application development. This is a concept popularized in React that inspired libraries like virtual-dom to provide more ways to write performant code for web apps.
When you start understanding the benefits and how working with virtual data structures is preferred over working directly with the DOM, you are already half way into understanding the modern techniques that power many of todays web applications. Some examples of such techniques are rehydration and server components.
Heck, thinking in virtual structures will even help your speed and ability to work directly with AST structures. Ultimately your brain is just exercising so much on just plain objects.
Traversing/Playing with the DOM
Traversing the DOM correctly (in terms of correctly visiting children/parents in the expected order) will help prepare you understand several things:
How to work with ASTs (when you're comfortable working with ASTs you're pretty much comfortable working with creating your own babel plugins and/or working programmatically with tools like TypeScript)
How to understand ASTs
Tree traversal (You automatically understand traversing trees and how to collect results in a predictable manner). Don't be too scared about scary words like "depth first search" or "binary search", just think of what you do in the DOM when you traverse a DOM's descendants or ascendants. When you're new and someone tells you to start understanding tree traversal for interviews, you might feel overwhelmed because you don't even know where to start. Just start with the DOM. Don't overthink it too much.
How modern tools like mdx work beneath the surface.
Spreading things
You can learn a few very important concepts when you spend a lot of your time spreading things like so:
function merge(obj1, obj2) {
return { ...obj, ...obj2 }
}
By trial and error you will eventually come across errors where you wonder:
- Why some objects aren't spreading and instead cause errors (Hint:
{ ...options.bar }
what if options.bar is not an object?) - Why some arrays aren't spreading and instead cause errors (Hint:
[...options.bar]
what if options.bar is not an array?) - Why
undefined
"spreads" into objects andnull
doesn't - How to "make" an object "spreadable" (Hint: The iterable protocol, in other words work with the
[Symbol.iterator]
). This will will help you understand all of the above concepts
It's worth noting here that you might also want to understand that the alternative way of merging objects (Object.assign
) silently causes side effects:
const fruits = ['apple', 'banana']
const data = {
carrots: [],
get myFruits() {
fruits.pop()
return fruits
},
onion: 2,
}
const mergedData = Object.assign(data, {
beverages: ['pepsi'],
})
Result (myFruits
changed):
{ "carrots": [], "myFruits": ["apple"], "onion": 2, "beverages": ["pepsi"] }
Blob
Blobs are everywhere. They can be found in window.fetch
, serialized into urls for img
and video
, uploading files, returned as a data type for some responses, etc.
Get familiar with working with Blob
. This is the object that is used for online media sharing (such as images and videos), streaming, distributing files across networks, storing log files and updating them, file recovery, data storage (for analytical applications for example), as well as IoT (Internet of Things) applications.
Conclusion
And that concludes the end of this post! I hope you have found valuable information here and look out for more from me in the future!
Find me on medium
Top comments (0)