Using IIFE in JavaScript and creating your own Each function

aaron feingold
4 min readMar 5, 2021

--

Rubik_Tesselation

Ever run npm test on fresh line of code, and see you terminal jam up on some newly written loop like for(let i = 0; i <…etc…etc)? You quit, then your fan starts getting very loud. Yet you notice your MacBook doesn’t even feel very hot. So, you check your activity monitor, and the number one highest CPU usage is kernal_task. Maybe you quickly close a bunch of running apps, like Spotify and Slack and Zoom, and the fan subsides; or instead, your cursor does that color palette spin. So does that really fix the problem?

My advice here is: stop, have a sip of coffee and solve a Rubik’s cube.

What’s happening here is basically the kernal_task is looking out for the CPU. It is going to make the CPU inaccessible by raising the fan speed. It’s a neat little trick when you think about it. It wards off predators.

When you’ve solved you Rubik cube, the computer should be chill again. Now try closing a bunch of apps. You probably have endless windows of infinite tabs re-rendering youTube tutorials, StackOverflow, docs, Medium, etc in Chrome. Quit those distractions.

Now, it is apparent that the time to fix that if statement logic has come.

Here, I’m going to discuss building your own each function as the beginning for a functional library in JavaScript while making use of an Immediately Invoked Function. Tests were done with Mocha and Chai running npm test; although, problem statements are given here, using these tools is pretty cool; Visual Studio Code has a fun debug console.

There are great docs and tons of articles on these topics already. Seemingly endless. So if you are unfamiliar with these terms, begin googling.

The point of this exercise is to understand what is happening under the hood of these very important functions, libraries like lodash, and this blog post will lend my approach to observing their implementation using pseudocode. I’m not going to be doing an in depth discussion of passing callbacks, the module pattern or JS non-enforcement of arity

Solving for Each

fi.each(collection, callback)Iterates over a collection of elements, passing each element in turn to a callback function. Each invocation of callback is called with three arguments: (element, index, collection). If collection is a JavaScript object, callback's arguments will be (value, key, collection). Returns the original collection for chaining.

Within the test file we are given this:

const unmodifiedTestArr = [1, 2, 3, 4]const unmodifiedTestObj = {one: 1, two: 2, three: 3, four: 4}describe('each', function () {const alert = chai.spy();const testArr = [1, 2, 3, 4]const testObj = Object.assign({}, unmodifiedTestObj)const spy = chai.spy(x => true)it('calls alert with each element passed', function () {fi.each(testArr, alert)expect(alert).to.have.been.called.exactly(testArr.length)})it('calls alert properly on object values', function () {fi.each(testObj, spy)const objValues = Object.values(testObj)objValues.forEach((val) => { expect(spy).to.have.been.called.with(val) })})it('returns the original collection', function () {const result = fi.each(testObj, spy)expect(testObj === result).to.equal(true)expect(objectsEqual(testObj, result)).to.equal(true)})})

Its ok if that’s a lot to take in with this screen view. My goal is to break down these test to better understand what is being passed into my code, and the expectations of the app’s behavior.

Basically, first we are testing an array, and secondly we are testing an object; at all indices of the array we run an alert; each key of the hash run a spy on the value; then stopping; we want the original collection returned unchanged. If you’ve used the Array.prototype.forEach() many times now, this sound routine is ordinary. However, in contemplation of what a pure function is, breaking it down to its purest routines can help to remodel.

##PSEUDOCODE APPROACH

each, as in forEach, is a function that takes in some data and a callback, which I like to call an action because to me that means doing work, and returns the original data, for chaining.first, we'll need to evaluate what kind of data type we are dealing with here. if its an array, we can slice it and assign to a variable; or even do a spread operator to make a copy. however, if its an object, we are dealing with key value pairs--we want the values. luckily there is a built-in way to do this I've researched, so we don't have to build that test out ourselves, although we could. ultimately, it too returns an array. how very convenient. next, now that our data is sanitized for processing, it is good to go and iterate on. we are going to apply that action to every element, doing the work, whatever it may be. We make use of the index, the copied collection and the callback for the entire length of data.finally, return the original test data unscathed. what are some errors or side-effects though? Will have to test again.

With this working idea, I build my IIFE. I intend to do a map and reduce function as well, but not explain here in this article (successive ones). Consider how we wrap the library in the expression:

const fi = (function() {  return {
each: function() {
return "Each"
},

map: function () {
return "Map"
},

reduce: function(){
return "Reduce"
}
}
})();
###example callconsole.log(fi.each())
//=> Hello

Now to build out this each method, I read into the docs on the basics like Object.assign(), which led to Object.values(), and so forth. I also use built in methods like Array.isArray(), and Array.prototype.slice(). These little tricks save a lot of time.

Here’s my completed version with the example calls, forthcoming functions, commas, and comments removed:

Hope this blog helped contribute a lens on these topics as you continue to work with JavaScript. Experimenting with the foundational lessons unveils many layers of abstraction that are often overlooked.

--

--

aaron feingold
0 Followers

web developer making apps for people with appetite