JS Functional OOP and reduce

At the end, we make a class that calculates factorials and series (d=1) just to explain the OOP and reduce.

OOP intro with JS

So as a developer, we interact and make use of Object Oriented practices a lot. It's either we are instantiating an object of a class, calling a method of a class or other things like that. The best explanation of OOP I've seen is that from Steve Jobs where he described it saying

Objects are like people. They’re living, breathing things that have knowledge inside them about how to do things and have memory inside them so they can remember things. And rather than interacting with them at a very low level, you interact with them at a very high level of abstraction, like we’re doing right here. Here’s an example: If I’m your laundry object, you can give me your dirty clothes and send me a message that says, “Can you get my clothes laundered, please.” I happen to know where the best laundry place in San Francisco is. And I speak English, and I have dollars in my pockets. So I go out and hail a taxicab and tell the driver to take me to this place in San Francisco. I go get your clothes laundered, I jump back in the cab, I get back here. I give you your clean clothes and say, “Here are your clean clothes.” You have no idea how I did that. You have no knowledge of the laundry place. Maybe you speak French, and you can’t even hail a taxi. You can’t pay for one, you don’t have dollars in your pocket. Yet I knew how to do all of that. And you didn’t have to know any of it. All that complexity was hidden inside of me, and we were able to interact at a very high level of abstraction. That’s what objects are. They encapsulate complexity, and the interfaces to that complexity are high level.

That's a really nice intro to OOP, and you can find the rest of his explanation here.

OOP JS

Thats enough with the stories, let's get digging. We've seen how objects and classes relate. A class can be simply seen as a blue print with which you create objects. That simple. So say an object created like this

let man = {
    name: 'John',
    age: 14,
    speak: function(){
    console.log(`My name is ${name} and I'm ${age} years old`)
    }
}

Hooray, we just made a man, xD. Well, say we want to make a world of men, we have to repeat this syntax making over 7 billion of that statement. Thats such a pain. This is where classes come handy. We simply make a blueprint with

class Human {
     constructor(name, age){
     this.name = name
     this.age = age
     }
    speak(){
        console.log(`My name is ${this.name} and I'm ${this.age} years old`)
    }
}

Now we can make new objects and use them simply by saying

const joe = new Human('Joe', 14)
joe.speak()
// My name is Joe and I'm 14 years old

Hey, I know all these. Ok, sorry just an intro, let's move to functional OOP

Functional OOP

So long before classes came to JS with the ES6, OOP was achieved with functions. In fact, classes are just a fancy way of using these functional approach. Should I show you, check the typeof the human class I created above

console.log(Human instanceof Function)
// true

So, how do we make classes with functions, simple:

function Human(name, age) {
    this.name = name
    this.age = age
    this.speak = function(){
        console.log(this.name)
    }
}
const Joe = new Human('Joe', 14)

Now, that function is called a constructor function. Let's move to prototypes

Functional prototypes

So, we made a method inside Human constructor, but that means we make the method for all instances of that class. This is repetition and waste of memory. Instead we can make methods that come with the class and only instantiated when called. This can be done with prototypes. Anyways, before we go there, let's learn about Object.create(). So, this function simply makes an object but fallsback to the parent object for properties not defined in its initialization.

// Parent object
const Laptop = {
    os: 'any',
    charges: true,
    leastPrice: 4000
}
// Child object
const Apple = Object.create(Laptop)
Apple.os = 'MacOs'
Apple.leastPrice = 7000
console.log(Apple.os)
// MacOs
console.log(Apple.charges)
// true

So what happened? The Apple object is an object that has its own properties but when asked for a property that it doesn't have, it checks its parent object. Now let's talk about the prototypes

const PC = function(name, os){
    this.name = name
    this.os = os
}
PC.prototype.Alexa = function(){
    console.log(`My name is alexa, on ${this.name} laptop and have an Os of ${this.os}`)
}
const Mac = new PC('apple', 'MacOs')
Mac.Alexa()
// My name is alexa, on apple laptop and have an Os of MacOs

Now you might think do all classes have prototypes. Yh, you're right. You can check the array prototypes list by logging it console.log(Array.prototype) which is why all arrays you create have methods like slice, splice, reduce which we're talking about next

The reduce method of arrays

So what is reduce? It's just a fancy array function that takes a total (initiated to zero by default at first) and a current value and you can perform any action to it. Note, reduce doesn't mutate your array, just returns a value. So a basic example is summing up an array of number

nums = [3, 5, 7, 9]
function fn(total, current) {
    return total + current
}
// so this functions takes the previous total giving to it
// by reduce and increments it returns it as the new total
sum = nums.reduce(fn, 0)
// reduce calls the function we want to use on each 
// element in the arr, initiates a value of 0 as total
console.log(sum)
// logs 24 as the answer

Finally, lets wrap it together and make the factorial and series class we said

First initiate the class

const arr = function(i) {
    if(!(this instanceof arr)){
        return new arr(i)
    }
}

Whoah, what have you done there? Chill, we just made sure that if you didn't remember to use the new keyword to instantiate an object, we helped you add the new to it. Next, we make an array from the value you pass to the array from 1 to that value

const arr = function(i) {
    if(!(this instanceof arr)){
        return new arr(i)
    }
    this.numArr = Array.from(Array(i).keys()).map(e=>e+1)
}

So what happens? The Array makes an array from 1 to the value i you pass to it. The map is to make the array start from 1 and not 0. Next is to create the factorial and series function using the reduce and prototypes we discussed.

arr.prototype.factorial = function(){
    return this.numArr.reduce((total, current) => total * current, 1)
}

arr.prototype.series = (function(){
    return this.numArr.reduce((total, current) => total + current)
})

So we used the reduce to instantiate a total of 1 at first and hence multiply the total by the current value and return the result as the new total. Similar is done with the sum function. Finally we use the class and its prototype methods.

console.log(arr(5).factorial())
// 120
console.log(arr(5).series())
// 15

Ooops, we've gone over the classes and the reduce function. Sorry it's a very lengthy one. Thanks for reading and its a first hashnode blog :) So let me know if there's any error or anything unclear. It'll be so nice hearing the reviews. Bye for now, from xpan!