Category Archives: Uncategorized
Open for Extension (closed to modification) example (open close)
JS extends example
ref – https://dev.to/carstenbehrens/solid-open-closed-principle-in-javascript-2a1g
1 2 3 4 5 6 7 |
class DecimalToBinary { // Some other helper functions … dec2bin(number) { return parseInt(number, 10).toString(2); } } |
Let’s literally use extends to use existing functionality to create our own.
First there is an existing NumberConverter where we check if a number is really a number. And given a number, and to from base, it will parse it into the proper number. This object, while very useful, is vague, and open to a wide range of use.
1 2 3 4 5 6 7 8 9 10 11 |
class NumberConverter { isNumber(number) { // Just an example of a helper function return true; } convertBase(number, fromBase, toBase) { // A naive implementation without error checking etc. return parseInt(number, fromBase).toString(toBase); } } |
Let’s EXTEND functionality of that NumberConverter. We specifically want to change decimal to binary.
The decimal number has a base 10 so we enter 10 for the from base.. Then put 2 as the to base because binaries are base 2. Thus would then parse the int from a base 10 decimal to a base 2 binary. Thus, we extended the functionality of our NumberConverter so that it specifically converts decimal to binary.
1 2 3 4 5 6 7 8 9 10 |
class DecimalToBinary extends NumberConverter { isDecimalNumber(number) { // Just an example of a helper function, not actual implementation return true; } dec2bin(number) { return this.convertBase(number, 10, 2); } } |
Open Closed JS example (Announce)
JS array object example
Say we have an announce function that takes data as a parameter and then accesses the items property from it. Assuming that its an array, we use a forEach to loop over it and display
1 2 3 4 5 |
function announce(collection) { collection.items.forEach(function(element) { console.log(element); }); } |
The parameter with the property items referencing an array
1 2 3 4 5 6 |
var favoriteCities = { items: ["Copenhagen", "Kampala", "Montevideo"], description: "My favorite cities around the world:", }; announce(favoriteCities); |
But there’s a problem. What if favoriteCities all of a sudden changed to an object like so:
1 2 3 4 5 6 7 8 9 |
var favoriteCities = { items: { "Denmark": "Copenhagen", "Uganda": "Kampala", "Uraguay": "Montevideo" }, description: "My favorite cities around the world:", }; |
Yikes! Now our announce function won’t work anymore because its expecting an array, instead of an object.
The reason is that the announce function knows too much about how favoriteCities was implemented and expects it to have an items property that is an array.
A better solution is to use polymorphism and to let each collection object decide for itself how its items should be iterated over and logged.
We implement announce where we call a log function on the injected object.
1 2 3 |
function announce(collection) { collection.logItems(); } |
This way, logItems will always log the respective data. Because when we update favoriteCities to an array, we’ll also update logItems.
In this final snippet, we provide favoriteCities with a logItems method that implements how to log its items. As far as announce is concerned, it can deal with any collection object so long as it has a description property and a logItems method. This is the OCP in action — the announce function is extensible because it can handle any collection that guarantees these two properties but it is also closed to modification because we don’t have to change the source code in announce to change its available behaviors.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
var favoriteCities = { items: { "Denmark": "Copenhagen", "Uganda": "Kampala", "Uraguay": "Montevideo" }, description: "My favorite cities around the world:", logItems: function() { Object.keys(this.items).forEach(function(key) { console.log(this.items[key]); }, this); }, }; |
Open Closed JS example (Monster)
Monster Open-Close Principle
ref – https://medium.com/@severinperez/maintainable-code-and-the-open-closed-principle-b088c737262
The chief benefit of the OCP is maintainability. If you adhere to the OCP you can greatly decrease future maintenance costs. The opposite applies as well — when you don’t adhere to the OCP, future maintenance costs will be greater. Consider how the coupling of two entities affects their respective maintainability. The more a given entity knows about how another one is implemented, the more we can say that they are coupled. Therefore, if one of the two entities is changed, then the other must be changed too. Here is a simple example:
We create a MonsterManager that takes in an array of monsters and locations. It then calls rampageAll on it and has all the monsters rampaging through all the locations.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
// Monster Types and Manager var MonsterManager = { init: function(monsters, locations) { this.monsters = monsters; this.locations = locations; }, getRandomLocation: function() { function getRandomInt(max) { return Math.floor(Math.random() * Math.floor(max)); } return this.locations[getRandomInt(this.locations.length)]; }, |
But in order execute the Monster’s abilities, we must first check the monster. Then execute whatever special functionality it has. In order to do this, we check for the prototype of the Monster.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
rampageAll: function() { this.monsters.forEach(function(monster) { var location = this.getRandomLocation(); if (Object.getPrototypeOf(monster) == Kaiju) { console.log( "The " + monster.type + " " + monster.name + " is rampaging through " + location + "!" ); } else if (Object.getPrototypeOf(monster) == GreatOldOne) { console.log( "The " + monster.type + " " + monster.name + " has awaken from its slumber in " + location + "!" ); } }, this); } }; |
Now we create literal objects in order for instances of the monsters to be created
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
var Kaiju = { init: function(name) { this.name = name; this.type = "Kaiju"; return this; } }; var GreatOldOne = { init: function(name) { this.name = name; this.type = "Great Old One"; return this; } }; |
Create the monsters and locations
1 2 3 4 5 6 7 8 9 10 11 12 |
// Rampage! var monsters = []; var locations = ["Athens", "Budapest", "New York", "Santiago", "Tokyo"]; var rodan = Object.create(Kaiju).init("Rodan"); monsters.push(rodan); var gzxtyos = Object.create(GreatOldOne).init("Gzxtyos"); monsters.push(gzxtyos); var myMonsterManager = Object.create(MonsterManager); myMonsterManager.init(monsters, locations); |
Then start rampaging!
1 2 3 4 |
myMonsterManager.rampageAll(); // Logs: (with variable city names) // The Kaiju Rodan is rampaging through Santiago! // The Great Old One Gzxtyos has awaken from its slumber in Athens! |
In this snippet we use the OLOO pattern to define a MonsterManager prototype object and two types of monster prototypes, Kaiju and GreatOldOne. After initializing some monsters and an array of locations, we then initialize a new MonsterManager called myMonsterManager and call its rampageAll method, unleashing our monsters on those unlucky cities the randomLocation method happens to choose (sorry!) Can you spot any problems in this code related to OCP adherence?
Take a look at the rampageAll method — right now it iterates over each monster and checks whether they are of type Kaiju or GreatOldOne and then logs an appropriate message. What happens when this monster-filled world surfaces some new and terrible type of monster? In order for the program to work we would have to add another branch of conditional logic to the rampageAll method. In other words, we would have to modify the source code and therefore break the OCP. Doing so would not be a big deal with just one more monster type, but what about 10 new types? Or 20? Or 1,000? (Apparently this poor world is filled with monsters!) In order to extend the behavior of our MonsterManager (that is, let it deal with more types of monsters) we are going to have to think about how we deal with individual monster types.
Ultimately, the MonsterManager probably shouldn’t care about how each different monster rampages, so long as it has the ability to rampage in some fashion. Implementing our program this way would allow us to abstract away the rampage functionality to each individual monster. In other words, we can extend the functionality of the rampageAll method without changing the source code of MonsterManager. This use of abstraction is often described as a sort of contract — the objects being used promise to implement some piece of functionality and the object using them promises not to care how they do it. In this case, each monster promises to have a rampage function and MonsterManager promises to let them handle the details.
The correct approach
1 2 3 4 5 6 |
function ImplementationError(message) { this.name="Implementation Error"; this.message = message; } ImplementationError.prototype = new Error(); |
We connect its prototype to a new Error object
In order to inherit from JS’s Error object
Let’s first create a literal object
it sets the interface for all components to follow
we declare that we have an init property and rampage init
This means that all components who conform to this will need to implement these two functions
1 2 3 4 |
var MonsterInterface = { init: null, rampage: null, } |
Bladmaster is an object that has __proto__ pointing to MonsterInterface
We want this to act as a prototype object
1 |
var Bladmaster = Object.create(MonsterInterface); |
we then conform to our Monster Interface and implement:
init
rampage
1 2 3 4 5 6 7 8 9 10 |
Bladmaster.init = function(name) { this.name = name || "This Bladmaster"; this.type = "Bladmaster"; this.ability = "Cyclone Spinning Blade"; return this; } Bladmaster.rampage = function(location) { console.log(this.name + ' executed ' + this.ability + ' at ' + location); } |
Now we have Bladmaster prototype ready. We can create many instances of the Kaiju Monster
Let’s create a small group
we create an instance where the instance’s __proto__ point to to Bladmaster.
this enables us to inherit Bladmaster propeties
1 2 3 |
const katara = Object.create(Bladmaster); const meerak = Object.create(Bladmaster); const samuro = Object.create(Bladmaster); |
But wait a minute, we need to make sure Bladmaster REALLY conforms to MonterInterface. Not just take their word for it.
prototypeObject is our Bladmaster
interfaceObject is MonsterInterface
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
function createWithInterfaceValidation(prototypeObject, interfaceObject) { // so for every key in our MonterInterface: init, rampage // index 0: key is init // index 1: key is rampage Object.keys(interfaceObject).forEach(function(key) { // if init DOES NOT exist as a property for Kaiju // OR // if init IS NOT A function console.log('key is: ', key); console.log('function is: ', prototypeObject[key]); if (prototypeObject[key] === null || typeof prototypeObject[key] !== "function") { // then we throw an error throw new ImplementationError( "Required method " + key + " has not been implemented." ); } }); // init and function MUST BE functions // IFF then we will use it as a prototype to create an object return Object.create(prototypeObject); } |
So we validate our Bladmaster according to MonsterInterface
1 2 3 4 5 6 7 8 9 10 |
const monsters = []; let Gorn = createWithInterfaceValidation(Bladmaster, MonsterInterface); monsters.push(Gorn.init("Gorn")); let Samuro = createWithInterfaceValidation(Bladmaster, MonsterInterface); monsters.push(Samuro.init("Samuro")); let Tonak = createWithInterfaceValidation(Bladmaster, MonsterInterface); monsters.push(Tonak.init("Tonak")); |
Now that we have our monsters, we need to create a Monster Manager
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
var MonsterManager = { init: function(monsters, locations) { this.monsters = monsters; this.locations = locations; }, getRandomLocation: function() { function getRandomInt(max) { return Math.floor(Math.random() * Math.floor(max)); } return this.locations[getRandomInt(this.locations.length)]; }, rampageAll: function() { this.monsters.forEach(function(monster) { var location = this.getRandomLocation(); monster.rampage(location); }, this); } }; |
We then create our locations and then add in both monsters and locations.
MonsterManager then proceeds to call rampageAll.
1 2 3 |
var locations = ["Athens", "Budapest", "New York", "Santiago", "Tokyo"]; MonsterManager.init(monsters, locations); MonsterManager.rampageAll(); |
MonsterManager’s rampageAll’s implementation will proceed to have each monster execute their abilities upon the city:
1 2 3 4 5 6 7 |
rampageAll: function() { this.monsters.forEach(function(monster) { var location = this.getRandomLocation(); monster.rampage(location); }, this); } |
JS design patterns
https://addyosmani.com/resources/essentialjsdesignpatterns/book/
Protected: Scania Backend Documentation
Protected: access token vs refresh tokens
Protected: Apply Theme in React (part 4) – Routing in React using React-Router-Dom
Enumerable properties in Javascript
ref – https://www.geeksforgeeks.org/what-does-enumerable-property-mean-in-javascript/
An enumerable property in JavaScript means that a property can be viewed if it is iterated using the for…in loop or Object.keys() method. All the properties which are created by simple assignment or property initializer are enumerable by default.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<script> // Creating a student object const student = { registration: '12342', name: 'Sandeep', age: 27, marks: 98 }; // prints all the keys in student object for (const key in student) { console.log(key); } </script> |
output:
registration
name
age
marks
Since all the properties are initialized by property initializer, they all have enumerable set to true by default. To explicitly change the internal enumerable attribute of a property, the Object.defineProperty() method is used. Also, to check whether a property is enumerable or not, we use the function propertyIsEnumerable(). It returns true if the property is enumerable or false otherwise.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
<script> // Creating a student object const student = { registration: '12342', name: 'Sandeep', age: 27, }; // This sets the enumerable attribute // of marks property to false Object.defineProperty(student, 'marks', { value: 98, configurable: true, writable: false, enumerable: false, }); // To print whether enumerable or not console.log(student.propertyIsEnumerable('registration')); console.log(student.propertyIsEnumerable('name')); console.log(student.propertyIsEnumerable('age')); console.log(student.propertyIsEnumerable('marks')); </script> |
output:
true
true
true
false
Properties that are created using the defineProperty() method have enumerable flag set to false. When the same above code is run using a for loop, the “marks” property is not visible.
1 2 3 4 5 6 |
// This will not print the property // Who's enumerable property is set to false for (const key in student){ console.log(key) } |
Output:
registration
name
age
Function in React called twice
ref – https://stackoverflow.com/questions/50819162/why-is-my-function-being-called-twice-in-react
When you create a project using create-react-app, it puts the App component inside React.StrictMode tags.
1 2 3 |
<React.StrictMode> <App /> </React.StrictMode> |
Document says:
Strict mode can’t automatically detect side effects for you, but it can help you spot them by making them a little more deterministic. This is done by intentionally double-invoking the following methods:
Class component constructor method
The render method
setState updater functions (the first argument)
The static getDerivedStateFromProps lifecycle
The shouldComponentUpdate method
It is expected that setState updaters will run twice in strict mode in development.
This helps ensure the code doesn’t rely on them running a single time.
If your setState updaters are pure functions (as they should be) then this shouldn’t affect the logic of your application.
If you do not want this effect, do this:
1 2 3 4 |
<> <App /> <MyPureComponent /> </>, |