Day 89: Never to Good For Review

Stack Overflow and blog articles make me grateful for access to internet yet again! I covered two ways to perform an array reversal in C and continued to study how modules in Node.js are structured. I found answers on one quirk that (imo) was poorly explained in the book I am reading. Once I saw a diagram and a great answer it made everything a whole lot clearer. What a time to be alive. Answers to your questions so easily accessible from anywhere in the world and at any time of day. WILD!

TLDR;

Okay, so here are the highlights of what I did:

  • I read through an article on how to reverse an array. The article demonstrated how to tackle the problem using the iterative (looping) method and the recursive method. It was interesting to view both. I saw what I was doing wrong immediately and realized I had failed because I was being lazy and trying to skip steps. Live and learn. It’s working now.
  • Read through the docs for module wrappers in Node.js. It didn’t make sense how exports were structured until I found an answer on Stack Overflow that answered the question perfectly. The CommonJS system is odd and outside of the convenience/abstraction benefit of the exports binding I don’t get why it’s there. Anyways, I am moving on from chapter 10 of “Eloquent JavaScript” by Marijn Haverbeke. Although, my knowledge is not perfect I have built a solid base for when I revisit the topic. For now I need to move on.

Notes on exports vs. module.exports in Node.js

const ordinal = require("ordinal");
const {days, months} = require("date-names");

exports.formatDate = function(date, format) {
  return format.replace(/YYYY|M(MMM)?|Do?|dddd/g, tag => {
    if (tag == "YYYY") return date.getFullYear();
    if (tag == "M") return date.getMonth();
    if (tag == "MMMM") return months[date.getMonth()];
    if (tag == "D") return date.getDate();
    if (tag == "Do") return ordinal(date.getDate());
    if (tag == "dddd") return days[date.getDay()];
  });
};

We can define require, in its most minimal form, like this:

require.cache = Object.create(null);

function require(name) {
  if (!(name in require.cache)) {
    let code = readFile(name);
    let module = {exports: {}};
    require.cache[name] = module;
    let wrapper = Function("require, exports, module", code);
    wrapper(require, module.exports, module);
  }
  return require.cache[name].exports;
}

In this code, readFile is a made-up function that reads a file and returns its contents as a string. Standard JavaScript provides no such functionality—but different JavaScript environments, such as the browser and Node.js, provide their own ways of accessing files. The example just pretends that readFile exists.

To avoid loading the same module multiple times, require keeps a store (cache) of already loaded modules. When called, it first checks if the requested module has been loaded and, if not, loads it. This involves reading the module’s code, wrapping it in a function, and calling it.

The interface of the ordinal package we saw before is not an object but a function. Here is how that happens. A quirk of the CommonJS modules is that, though the module system will create an empty interface object for you (bound to exports), it is in reality just a convenience binding. exports by default points to the empty object bound to module.exports. Additionally, whatever is bound to module.exports is what actually gets returned from the module’s wrapper function (a.k.a. what other modules can actually access). This means we can add properties to the module.exports object while abstracting with just exports. However, when we want to export something other than an object we would replace the default object with any value by overwriting module.exports. We would not overwrite exports as this would have no effect on what gets returned by the wrapper function and accessed by other modules. The exports binding is only good for setting object property values as it conveniently points to the module.exports object (I think…). So re-writing module.exports is done by many modules to export a single value instead of an interface object.


Goal For Round 6 of the #100DaysofCode Challenge

This is my sixth round of the “#100daysofcode” challenge. I will be continuing my work from round five into round six. I am currently working through the book “Cracking the Coding Interview” by Gayle Laakmann McDowell. My goal is to become more familiar with algorithms and data structures. This goal was derived from my goal to better understand operating systems and key programs that I use in the terminal regularly e.g. Git. This goal was in term derived from my desire to better understand the fundamental tools used for coding outside of popular GUIs. This in turn was derived from my desire to be a better back-end developer.

I have no idea if my path is correct but I am walking down this road anyways. Worst case scenario I learn a whole bunch of stuff that will help me out on my own personal projects.