Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
259 lines (169 sloc) 14 KB


Starter Files + Completed solutions for the JavaScript 30 Day Challenge.

Grab the course at

My lessons learned

Day 01 - JavaScript Drum Kit

  • Good little refresher on the classList property that returns a DOMTokenList object

  • Why would Wes create an array from the NodeList, when NodeList has a forEach Function?


    Seems like the forEach Function on a nodeList is not implemented by older browsers:

    “Although NodeList is not an Array, it is possible to iterate on it using forEach(). Several older browsers have not implemented this method yet. You can also convert it to an Array using Array.from.”

Day 02 - JS + CSS Clock

In addition I gave the hands different sizes. I added also the fraction of minutes to the hour hand (“hours + (minutes / 60)”), so it moves slowly to the next hour, instead of jumping a full hour when the minute hand goes from 59 to 0.

  • transform-origin: 100% moves the origin all the way to the right on the x-axis
  • transition-timing-function lets you choose the way a transformation is happening (e.g.: ease-in or ease-out). In the chrome dev tools you can choose a transformation and change it using the handle bars

Day 03 - Playing with CSS Variables and JS

  • Playing with CSS Variables and JSdocument.documentElement returns the root element of the document
  • The dataset property contains the values of all the “data-” attributes of an element
  • Refresher on CSS variables. It’s possible to use fallback values if a variable is not defined

Day 04 - Array Cardio 1

Day 05 - Flex Panels

Day 06 - Ajax Typeahead

Use a regexp to filter an array like so:

function findMatches(wordToMatch, cities) {
  const regex = new RegExp(wordToMatch, 'gi');
  return cities.filter(place => {
    return || place.state.match(regex);

Day 07 - Array Cardio Day 2

  • Use curly braces in a console.log statement to see the whole object
console.log({ isAdult });
  • Use splice to cut out an element of an array on a specific index
arr.splice(index, 1);

Day 08 - Fun with HTML5 canvas

  • Learned a whole lot about the HTML5 canvas and how to draw lines
  • Destructuring an array can help you to reduce lines of codes, when you do assignments. It just makes things more compact:
[lastX, lastY] = [e.offsetX, e.offsetY];
  • There is a mouseout event. Never used that one before ;)

Day 09 - Dev Tools Domination

  • %s to interpolate a string console.log('This is a %s string', '💩');
  • %c to add styling console.log('%c This one is styled', 'font-size: 20px; background-color: green');
  • There is log, warn, error and assert. Assert use you use for example like this console.assert(typeof 'abc' === 'number', 'This is wrong');
  • console.clear() might come in handy sometime
  • Use console.dir(p); to be able to drill down on an element and see all it's properties
  • Group statement together like so'my group');
console.log('First log statement');
console.log('Second log statement');
console.log('Third log statement');
console.groupEnd('my group');

Day 10 - Hold Shift and Check Checkboxes

Day 11 - Custom Video Player

Day 12 - Key Sequence Detection

  • Didn't learn anything JavaScript related, but first time I've heard about the Konami Code
  • Cornify

Day 13 - Slide in on scroll

  • Window.scrollY: The read-only scrollY property of the Window interface returns the number of pixels that the document is currently scrolled vertically.
  • Window.innerHeight: Height (in pixels) of the browser window viewport including, if rendered, the horizontal scrollbar.
  • HTMLElement.offsetTop: The HTMLElement.offsetTop read-only property returns the distance of the current element relative to the top of the offsetParent node.
  • I also like this little debounce function:
function debounce(func, wait = 20, immediate = true) {
      var timeout;
      return function () {
        var context = this, args = arguments;
        var later = function () {
          timeout = null;
          if (!immediate) func.apply(context, args);
        var callNow = immediate && !timeout;
        timeout = setTimeout(later, wait);
        if (callNow) func.apply(context, args);

Day 14 - JavaScript References VS copying

There are a bunch of different ways to copy an array:

  • arr2 = arr1.slice() Slice is usually used to cut out a part of an existing array and return a new array. If there are no arguments, the whole array will be returned as a new array.
  • arr2 = [].concat(arr1) Create a new array and concat the old array into it.
  • arr2 = Array.from(arr1) Array.from returns a new array from an existing one. It can take any array-like or iterable object as an argument.
  • arr2 = [...arr1] ES6 spread operator. Very clean and short syntax. Create a new array and spreads the contents of the old array.

Cloning an object is done with Object.assign person2 = Object.assign({}, person, { sex: 'male' }); It takes 3 arguments: A new object, the object to clone, and an object with properties that need to be overwritten.

Careful: All the functions only make a shallow copy which is one level deep. For deep copies you should use lodash or something similar.

However there is a poor man's solution for a deep copy p2 = JSON.parse(JSON.stringify(p)); It makes a string out of an object and immediately parses it into a new object. Be careful when using this and check if it's performant enough.

Day 15 - Local Storage

  • Use preventDefault to prevent the default action of an event, like submitting a form when clicking the submit button
  • Element.matches()
  • To fully clear an array you can just set it's length to 0

Day 16 - Mouse Move Shadow

Day 17 - Sort without Articles

  • If you need to sort something with modified data, you can easily do that within the sort function as you are not changing the elements of the array itself.

For example

function strip(bandName) {
  return bandName.replace(/^(a |the |an )/i, '').trim();

const sortedBands = bands.sort((a, b) => (strip(a) > strip(b) ? 1 : -1));

Day 18 - Adding Up Times with Reduce

  • Chose a slightly different way than Wes. Didn't learn anything new, but it was a good thing to repeat the usage of reduce.

Day 19 - Webcam Fun

  • Access the media devices like this navigator.mediaDevices.getUserMedia({ video: true, audio: false })
  • Set the video element source to the localMediaStream video.src = window.URL.createObjectURL(localMediaStream); The localMediaStream is being returned from getUserMedia above.
  • createObjectURL
  • And a whole lot more, about how you can work the the webcam video, the canvas object and manipulate pixels. This session is worth revisiting once to fully understand all the details.

Day 20 - Speech Detection

  • The native speech recognition is a lot of fun. It doesn't need much for code than for example Annyang
  • Turn on the interimResults to see how words get corrected. This way you already see the results, before they are final.

Day 21 - Geolocation

This one I didn't complete as I didn't want to install XCode. I've learned about the watchPosition function in the Geolocation.

Day 22 - Follow Along Link Highlighter

Day 23 - Speech Synthesis

Day 24 - Sticky Nav

  • Compare the offsetTop of the navigation bar with the scollY of the window. If the scrollY is bigger than the offsetTop then set a class on the body. Add CSS to change the navigation position to fixed when that class is applied to the body. To compensate for the element that has been taken out of the layout (because of the position fixed), add the height of that element to a padding in the body. Like this you can avoid any page jank.

Day 25 - Event capture, Propagation and Bubbling

  • This was very useful, quick refresher
  • Event capture happens when an event happens. The browser goes into the DOM and figures out what element has been clicked. It stores all the elements while travelling down into the DOM. Later it fires event on all those elements, starting with the one that has been clicked and then going up the capturing chain. The going up part is called bubbling.
  • Bubbling can be prevented by calling stopPropagation() on the event.
  • Running a function "going down" can be achieved by a third argument in the addEventListener function. It's an options object and it the flag "capture" is set to true the callback will fire on the capturing phase.
  • If you set "once" in the options object, the event listener will unbind itself after running. It will only run once.

Day 26 - Stripe Follow Along Nav

  • Little reminder that an arrow function can help you out when you have a this-aware function that you want to run as a callback (here in a setTimeout)
  • I understood the concept of the follow along navigation. It would take a bit of time to build it without help. The important thing is to keep in mind to subtract the position of the navigation, to position the elements correctly. Would be worth to build something like that from scratch and without help once.

Day 27 - Click and Drag

  • pageX:

    Being based on the edge of the document as it is, this property takes into account any horizontal scrolling of the page. For example, if the page is scrolled such that 200 pixels of the left side of the document are scrolled out of view, and the mouse is clicked 100 pixels inward from the left edge of the view, the value returned by pageX will be 300

  • offsetLeft

    The HTMLElement.offsetLeft read-only property returns the number of pixels that the upper left corner of the current element is offset to the left within the HTMLElement.offsetParent node.

  • scrollLeft

    The Element.scrollLeft property gets or sets the number of pixels that an element's content is scrolled to the left.

Day 28 - Video Speed Controller

  • offsetHeight: The HTMLElement.offsetHeight read-only property is the height of the element including vertical padding and borders, as an integer.

Day 29 - Count Down Timer

  • A form that has name attribute can be directly accessed via a property on the document `document.myFormName.addEventListener...``
  • There is a reset function of the event of a from.
  • You can set the title of a tab by using document.title

Day 30 - Whack A Mole

  • Event.isTrusted The isTrusted read-only property of the Event interface is a boolean that is true when the event was generated by a user action, and false when the event was created or modified by a script or dispatched via dispatchEvent.

Final Thoughts

This was one of the most fun courses I completed in a long time. It was very good to get back to the basics and play around with vanilla javascript, even though this is not what I use on a daily basis. It still helped to clarify a lot of concepts and each day I was able to learn something new. I mostly enjoyed the data-tutorials, like the cardio array ones, but of course it was also fun to play around with the canvas object and things that are a bit more visual. I can really recommend this course to every one, Wes is a fantastic teacher and his enthusiasm is infectious.