In mid-July 2022 I did a leveling and performance review exercise with my manager at work (which resulted in a raise / promotion for me 🤑). One of the objectives I set was to improve my understanding of JavaScript, which I use everyday at work. Technically we use Vue for our frontend applications, but we believe the underlying language is more appropriate than the framework it sits on top of. The process of the exercise spanned several weeks and so I came accross Beginner JavaScript by Wes Bos. And he put the entirety of the course in written form for FREE on his website. I decided a cadence of one lesson per-work day would work well for me and while "beginner" isn't my category I was confident I would learn something in almost every lesson, or at least a reminder. And to keep myself accountable I decided to make a Twitter thread of the takeaway from each lesson. You can find that thread here:
Did you know that @wesbos has a written version of his Beginner JavaScript course on his website? I'm gonna try to do a lesson a day and tweet something I learned!
— Andy Pickle (@pickleat) July 1, 2022
Additionally, we started a book club reading Eloquent Javascript, but I'll write about that later.
I Learned if you have a script tag that imports an external JS file you can't put any JS inside that tag and expect it to run. Example:
<script src="./some.js">
console.log("Hey ma!"); // Won't print
</script>
"Kebab case" variables are not valid JavaScript Never realized this! Lesson Link
ESLint and Prettier. These are magic. ESLint: tells you why your code is not up to standard. This can be frustrating, but it helpful on projects to have a clear guidelines. Prettier: fixes syntax issues to keep code looking right. Lesson Link
Symbol
is a type in JS, that allows for unique identifiers for Objects. But I'm struggling to try to use it... I can add Symbols as keys, and get a list of keys, but I can't access the value with that Symbol. I need to learn more here.
Lesson Link
TIL that 0.1 + 0.2 = 0.30000000004 in most programming languages 🤯.
Also that NaN
is typeof
number.
Lesson Link
I feel good about my understanding here, always good to refresh though. I remember it being hard to understand why you would group things at first, but a person as an "Object" is a good example. Lesson Link
TIL: You cannot have a const of undefined
unless you explicitly set it as such. Because a const
variable must be initialized with a value.
const cantBeUndefined;
// Uncaught SyntaxError: Missing initializer in const declaration
const canBeUndefinted = undefined;
// Works!
"===
always checks that the value AND type are exactly the same." -Wes Bos (emphasis added).
I remember getting tripped up by single, double, and triple = when I first started. Glad for the refresher here.
Lesson Link
There are many built-in functions in JS. Some handle tedious work for us and return values (parsing numbers), others perform actions (scrollTo scrolls a user to a certain place) and don't return anything. Lesson Link
Variables inside functions are temporary and after the function is run they are "garbage collected" (i.e. deleted from memory). If you want to use a value returned from a function, you need to save it in a new variable. Lesson Link
TIL: The difference between parameters and arguments. Parameters are in the function declaration, and arguments are passed when the function is called. But let's be real, they are used interchangeably. Lesson Link
TIL Methods are functions that live inside of objects! Code Example:
const person = {
name: "Andy",
sayHi() { console.log(`Hi ${this.name}!`)},
}
sayHi()
is a method!
Lesson Link
Console.table()
is a Dream come true. HOW HAVE I NEVER KNOWN ABOUT THIS?!
Console.count()
will also be super useful.
There are also way more ways to add breakpoints in the console than I knew about!
Lesson Link
All I can say is that scoping is hard. Lesson Link
Most of this is pretty straightforward, but I found this quote helpful: "Only function declaration types of functions are hoisted, not function expressions (when you put a function in a variable)." Little gotcha there. Lesson Link
Closures are functions that return a function. Those functions can then be run independently from then on and keep their data. Closures are useful if you need to do something more than once (like perhaps keep the score of two games going). Lesson Link
Window
: Global, everything for your browser lives in here.
Navigator
: Browser specific, permissions, and your device.
Document
: All your HTML lives in here. This is your entry point to interacting with JavaScript.
Lesson Link
It is interesting that querySelectorAll()
will select all the elements on the page no matter how deeply nested they are. So child elements with parents of the same type will be returned as separate items in the NodeList
Lesson Link
"...the difference between elements and nodes. Nodes can be anything, but an actual element is something that is wrapped in a tag."
I learned about the insertAdjacentText()
method!
Lesson Link
Didn't learn anything specifically "new", but nice reminder of how to toggle classes on and off, and add event listeners to run functions. Lesson Link
TIL working with custom data-attributes on an element you use element.dataset
to get access to its attributes.
Example
<div class="name" data-name="Andy">Div</div>
I would use document.querySelector(".name").dataset.name
to get access to "Andy" in data-name
attribute.
Lesson Link
Good reminders of the basics like document.createElement()
, and element.appendChild()
, but also some new ones I don't recall using like element.cloneNode()
and document.insertAdjacentElement()
Lesson Link
I've never used document.createRange()
and/or createContextualFragment()
. I'd imagine many frameworks use these under the hood (or similar) to limit DOM re-rendering. Very cool!
Lesson Link
The difference between element.children
vs element.childNodes
.
<div class="andy">Hi, my name is <em>Andy Pickle</em>. I like coffee, music and watches</div>
const andy = document.querySelector('.andy');
console.log(andy.children);
console.log(andy.childNodes);
andy.children
will show an HTMLCollection with only the <em>
in it. Whereas andy.childNodes
will show a NodeList with text, <em>
, and more text.
Essentially .childNodes
gives you everything inside what you've selected and .children
only gives you HTML elements inside your selection.
Lesson Link
Challenge: take a blank JS file and edit an HTML file with it. But write all JavaScript out BEFORE looking at the results. My solutions had several errors, but I got there in the end. It was good to review insertAdjacentHTML()
.
(paraphrasing Wes here) The three steps for event listeners:
Other learnings:
// Adding a listener
element.addEventListener('click', function() {
console.log('clicked');
})
// Attempting to remove it
element.removeEventListener('click', function() {
console.log('clicked');
}) // Doesn't work
This doesn't work because even though the function
is exactly the same, the listener needs to be a reference to a named function. If we ever want to remove a listener we need to declare its callback function with a name.
event.pressure
works on touchscreen devices!
The difference between event.target
and event.currentTarget
is currentTarget
is the specific element clicked, and target
can be an event that has been bubbled up by a child element.
<script>
function whoFiredTheEvent(event) {
if(event.target === event.currentTarget){
console.log("Button Fired it")
}
if(event.target !== event.currentTarget){
console.log("Child Span Fired it")
}
}
const buttons = document.querySelectorAll('button');
buttons.forEach((button) => {
button.addEventListener('click', whoFiredTheEvent)
})
</script>
<body>
<button class="no-bubbles">
No Bubbles
</button>
<button class="bubbles">
Bubbles <span>Up</span>
</button>
</body>
In the example above if you click on "Up" you will see that the currentTarget
is <span>Up</span>
but the function whoFiredTheEvent
is still called because it bubbles up.
If you don't want an event to bubble up you can use event.stopPropagation()
.
You can also make sure to capture events in global way by using the third parameter to your eventListener. Like so:
window.addEventListener('click', (event) => {
console.log('in the capture phase');
event.stopPropagation();
},
{ capture: true }
)
If the above code was added to the previous example then we would never make it to the whoFiredTheEvent()
function because the capture phase occurs before the bubbling phase. This could be helpful if you need to check for something BEFORE adding / removing a certain listener. But probably not on "click".
event.preventDefault()
allows you to override the default behavior of a particular element. Links should take you somewhere, but adding event.preventDefault()
allows you to do something first, or perhaps ask a second question. Its main usecase is on forms and buttons in my experience.
Lesson Link