Friday, 29 December 2023
Understanding Rest & Spread operator in Javascript
Closures in Javascript
Background
Closures in Javascript
It's important to note that it is not just a function but a combination of function + referenced to its lexical environment.
Let's take a simple example:
(() => {
var name = "Aniket";
const displayName = () => {
console.log(name);
}
displayName();
})()
The (()=>{})() is a self-executing function. Inside it, you can see an anonymous function defined using the arrow operator. Inside this function, we have defined a variable called name and again an anonymous function called displayName which prints the name variable in the console.
What is interesting to note here is that even though the variable name is local to the outermost anonymous function we can still access it inside the displayName method, this is possible due to closures. When we created an anonymous function & assigned it to the displayName const variable it actually created a closure that comprised of the function itself + the reference to the lexical environment which includes the name variable defined in the outer scope.
NOTE: Nested functions have access to variables declared in their outer scope.
Understanding scopes
Here check variable even though was defined inside the if block has become a global scoped variable (Unlike other languages like Java where it would have created a local scoped variable).
- let - defines a variable local to the scope
- const - defines a constant variable again local to the scope.
Interesting examples
Now let's see some interesting examples before we wind this up.
See the below examples & predict the output
const myName = ["Aniket", "Abhijit", "Awantika"];
for(var i; i<myName.length;i++)
{
setTimeout(function(){
console.log('Name: ' + myName[i] + 'at index:' + i);
},3000)
}
The output is
It prints undefined as Name & index as 3 all the three times the loop executes. Let's try to understand why this happened: When we pass a custom function inside setTimeout it creates a closure of the function bundled with the captured environment from the out functions scope. Three closures are created by the loop but each shares the same lexical environment which has the variable "i" with changing values. This is because the "i" variable is defined as var and has a global scope. The value of "i" in the passed function is determined when it is actually executed after the timeout completes (when it comes from the event loop). Since the loop has already been completed by the time these closures from the event loop are executed "i" points to 3 and there is no such index in that array as the size is 3 and the index range from 0 to 2. Hence it prints "i" as 3 and the name as "undefined" three times - one for each closure created in the loop.
You can fix this by using a wrapper function to be passed inside setTimeout API argument which will create its own closure with the actual local value of "i" and pass it to the event table instead of just the original closure which is pointing to global scoped "I". Eg see below where I have given two ways one using function keyword and one using anonymous function
Or you could simply change var to let in the for loop which will create a block-scoped variable instead of a global scope and changes will still work fine.
Related Links
Saturday, 16 May 2020
How to add code Syntax highlighting to your blogger blog?
Background
If you own a technical blog or a website you generally need to add code to illustrate your examples. In such cases highlighting the code becomes essential. You would have seen the code syntax highlighting in this blog itself.In this post, I will show you how you can achieve this.
How to add code Syntax highlighting to your blogger blog?
For code syntax highlighting we will use SyntaxHighlighter. I will specifically tell you how to add this to your blogger blog.- Open your blogger blog dashboard
- Go to Theme
- Click on 3 dots beside "My theme" and click on "Edit HTML"
- In the panel which opens and shows some HTML code search and go to the line with </head> tag. This is where your head tag ends. We need to add some include CSS and js files here along with some custom javascript.
- Inside the head tag (Just before </head> add following code)
<!-- Syntax Highlighter START --> <link href="http://alexgorbatchev.com/pub/sh/current/styles/shCore.css" rel="stylesheet" type="text/css"></link> <link href="http://alexgorbatchev.com/pub/sh/current/styles/shThemeDefault.css" rel="stylesheet" type="text/css"></link> <script src="http://alexgorbatchev.com/pub/sh/current/scripts/shCore.js" type="text/javascript"> <script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushAS3.js' type='text/javascript'/> <script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushBash.js' type='text/javascript'/> <script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushColdFusion.js' type='text/javascript'/> <script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushCSharp.js' type='text/javascript'/> <script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushCpp.js' type='text/javascript'/> <script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushCss.js' type='text/javascript'/> <script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushDelphi.js' type='text/javascript'/> <script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushDiff.js' type='text/javascript'/> <script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushErlang.js' type='text/javascript'/> <script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushGroovy.js' type='text/javascript'/> <script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushJScript.js' type='text/javascript'/> <script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushJava.js' type='text/javascript'/> <script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushJavaFX.js' type='text/javascript'/> <script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushPerl.js' type='text/javascript'/> <script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushPhp.js' type='text/javascript'/> <script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushPlain.js' type='text/javascript'/> <script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushPowerShell.js' type='text/javascript'/> <script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushPython.js' type='text/javascript'/> <script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushRuby.js' type='text/javascript'/> <script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushScala.js' type='text/javascript'/> <script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushSql.js' type='text/javascript'/> <script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushVb.js' type='text/javascript'/> <script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushXml.js' type='text/javascript'/> <script language='javascript' type='text/javascript'> SyntaxHighlighter.config.bloggerMode = true; SyntaxHighlighter.all(); </script>
- Once done save the file and reload blog.
- Now if you want any highlighting you can use the corresponding class in <pre> tag. Eg for Java you can do
<pre class="brush:java">This will be highlighted</pre>
- Instead of Java you can have other languages as well. Choices are: cpp, c, c++, c#, c-sharp, csharp, css, delphi, pascal, java, js, jscript, javascript, php, py, python, rb, ruby, rails, ror, sql, vb, vb.net, xml, html, xhtml, xslt. You can see the latest list of supported languages.
- You can only add js files for brushes you need (See optimization below)
Optimizations
This is the good part! We would not call ourselves programmers if we did not have an optimization part :)- You can see above there are a bunch of js files added in the head tag. You might not need all and each page load with load these external JS code which can slow loading if your blog. So Add only those JS files which you need. In fact, if you see the screenshot above I have used just the Java brush JS. I just use the same for all types of codes.
- If you do not want the code highlighting to work for your homepage (Just for the the posts you write), you can add all above code inside the following tags:
<b:if cond='data:blog.pageType == "item"'> </b:if>
- Lastly, you would have also noticed the link base path for JS and CSS files are different in my code that what I originally provided. That's because I have used the CDN path(https://cdnjs.com/libraries/SyntaxHighlighter). This is done primarily for 2 things:
- First, it allows highlighting to work even on https. By default with the above code loading your blog site with https protocol will not show highlighting. That's because your include scripts are HTTP and not supported for https.
- Secondly, if the HTTP links are down you are screwed. CDN caches the scripts and cs files. So you can always rely on it (rely is is a strong word but it's better than those HTTP links :) )
Configuration
- Another thing you might have noticed is the change of theme file I have used. The original set of code I proposed uses a default theme shThemeDefault.css but I have changed this to use shThemeEmacs.css. You can use whichever theme you like - Just include the corresponding theme CSS file (and remove the default one). Some of the available themes are: shThemeRDark, shThemeMidnight, shThemeMDUltra, shThemeFadeToGrey, shThemeEmacs, shThemeEclipse, shThemeDjango, shThemeDefault, shCoreRDark, shCoreMidnight, shCoreMDUltra, shCoreFadeToGrey, shCoreEmacs, shCoreEclipse, shCoreDjango, shCoreDefault
- I already mentioned you should only include and use the JS files corresponding to language brushed you intent to use. This will reduce your page load time. You can also use the "b:if" tag I mentioned above so that these scripts load for your blog posts.
You can already see this blog using all of these customizations. Feel free to comment if you need any help. Thanks.
Related Links
Sunday, 24 February 2019
How to write Mocha and Chai unit tests for your Node.js app?
Background
Sample Node.js App
- mkdir mochatest
- cd mochatest
- npm install mocha chai --save-dev
var addition = function(a,b) {
return a + b;
}
var subtraction = function(a,b) {
return a - b;
}
module.exports = {
add: addition,
subtract: subtraction
}
- add
- subtract
How to write Mocha and Chai unit tests for your Node.js app?
const assert = require('chai').assert;
const index = require("../index");
describe("Index Tests", function(){
describe("Addition", function(){
it("Addition functionality test", function() {
let result = index.add(4,5);
assert.equal(result,9);
});
it("Addition return type test", function() {
let result = index.add(4,5);
assert.typeOf(result,'number');
});
});
describe("Subtraction", function(){
it("Subtraction functionality test", function() {
let result = index.subtract(5,4);
assert.equal(result,1);
});
it("Subtraction return type test", function() {
let result = index.subtract(5,4);
assert.typeOf(result,'number');
});
});
});
- add
- subtract
- equal
- typeof
Finally, let's plug this in the npm system. package.json already has test script as follows -
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
change this to
"scripts": {
"test": "mocha"
},
and you can simply run following command to execute tests -
- npm run test
Related Links
Tuesday, 16 October 2018
Lerna Tutorial - Managing Monorepos with Lerna
Background
- Single lint, build, test and release process.
- Easy to coordinate changes across modules.
- A single place to report issues.
- Easier to set up a development environment.
- Tests across modules are run together which finds bugs that touch multiple modules easier.
Lerna Tutorial - Managing Monorepos with Lerna
- npm install --global lerna
- lerna -v
- mkdir lerna-demo
- cd lerna-demo
- lerna init
It does following things -
- Creates packages folder. All packages go under this.
- Creates package.json at the root. This defines global dependencies. It has the dependency on lerna by default.
- Creates lerna.json at the root. This identifies lerna repo root.
- cd packages
Package - AdditionModule
- mkdir AdditionModule
- cd AdditionModule
- npm init -y
module.exports.add = function(x,y){
return x + y;
}
Save the file. This basically exposes add method to any other package that would have a dependency on this. Your 1st package is done. Let's create one more package for subtraction.
Package - SubtractionModule
Run similar commands inside packages folder -- mkdir SubtractionModule
- cd SubtractionModule
- npm init -y
module.exports.subtract = function(x,y){
return x - y;
}
Package - Calc
- mkdir Calc
- cd Calc
- npm init -y
var add = require('AdditionModule');
var subtract = require('SubtractionModule');
var sum = add.add(2,3);
var diff = subtract.subtract(3,2);
console.log("Sum: " + sum + " Diff: " + diff);
"dependencies": {
"AdditionModule": "1.0.0",
"SubtractionModule": "1.0.0"
},
{
"name": "Calc",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"AdditionModule": "1.0.0",
"SubtractionModule": "1.0.0"
},
}
- lerna bootstrap
Now you can simply run calc index.js as follows -
- node packages/Calc/index.js
The important thing was the linking part that lerna does for you so that you do not have to worry about it.
For complete details on all available commands see - https://github.com/lerna/lerna
Related Links
- What is the purpose of Node.js module.exports and how do you use it?(OSFG)
- https://github.com/lerna/lerna
Friday, 2 February 2018
Simulating environment variables in NodeJs using dotenv package
Background
Simulating environment variables in NodeJs using dotenv package
- npm install dotenv
Now that we have package installed let's see how we can simulate an environment variable. For this simply create a file name .env in the same directory and add the environment variable you expect to read in code in it. For this demo I will use 3 environment variables -
- ENVIRONMENT=local
- USERNAME=athakur
- PASSWORD=athakur
'use strict';
const dotenv = require('dotenv');
dotenv.config();
const env = process.env.ENVIRONMENT
const username = process.env.USERNAME
const password = process.env.PASSWORD
console.log("Env : " + env);
console.log("Username : " + username);
console.log("Password : " + password);
- node test.js
Env : local
Username : athakur
Password : athakur
NOTE : .env file would be hidden in Ubuntu since Ubuntu hides all files that start with a dot (.). You can just press Ctrl + H to view hidden files or do a "ls -la" in console. More details -
Related Links
- How to install Node and npm to run node.js programs in Linux(OSFG)
- How to show hidden files and folder in Ubuntu(OSFG)
- https://www.npmjs.com/package/dotenv
Saturday, 11 November 2017
Understanding Promises in javascript
Background
Understanding Promises in javascript
- Fulfilled : Asynchronous operation corresponding to this promise is completed successfully.
- Rejected : Asynchronous operation corresponding to this promise has failed. Promise will have the reason why it failed.
- Pending : The asynchronous operation is still pending and is neither in fulfilled or rejected state.
- Settled : This is a generic state. Asynchronous operation is complete and can be in - Fulfilled or Rejected state.
var testPromise = new Promise(function(resolve, reject){
//your test operation - can be async
let testSuccess = true; // can be false depending on if your test async operation failed
if(testSuccess) {
resolve("success");
}
else {
reject("failure");
}
});
testPromise.then(function(successResult){
console.log("Test promise succeded with result : " + successResult);
}).catch(function(failureResult){
console.log("Test promise failed with result : " + failureResult);
This prints output : Test promise succeded with result : success
- First we created a new promise with constructor new Promise()
- constructor takes an argument as function that basically defines what operation needs to be performed as part of that promise
- This function takes two callbacks -
- resolve()
- reject()
- You will call resolve() when your operation is successful and will call reject when it fails. resolve() will essentially put the promise in Fulfilled state where as reject will put it in Rejected state ww saw above.
- Depending on result of our operation (can be asynchronous) we will call resolve() or reject()
- Once promise object is created we can call it using then() method of promise object. then() method will be called when promise is fulfilled and catch() method will be called when it is rejected/failed.
- You can toggle the value of testSuccess boolean and see for yourself.
- Each then() and catch() take an argument which is nothing but variable passed by resolve() and reject() which in this case is success or failure
var test1 = new Promise(function(resolve,reject){
resolve('test1');
});
var test2 = new Promise(function(resolve,reject){
resolve('test2');
});
var test3 = new Promise(function(resolve,reject){
resolve('test3');
});
test1.then(function(test1Result){
console.log('completed : ' + test1Result);
return test2;
}).then(function(test2Result){
console.log('completed : ' + test2Result);
return test3;
}).then(function(test3Result){
console.log('completed : ' + test3Result);
});
Only difference here is in each then function we are returning next promise and calling then on it so that it is run sequentially.
Alternatively you can also do -
var test1Func = function() {
return test1;
};
var test2Func = function() {
return test2;
};
var test3Func = function() {
return test1;
};
test1Func().then(function(test1Result){
console.log('completed : ' + test1Result);
return test2Func();
}).then(function(test2Result){
console.log('completed : ' + test2Result);
return test3Func();
}).then(function(test3Result){
console.log('completed : ' + test3Result);
});
Promise.all([test1Func(),test2Func(),test3Func()]).then(function(){
console.log('All tests finished');
});
And this will output - All tests finished
Similarly if you want to do something if any one of the promise is complete you can do -
Promise.race([test1Func(),test2Func(),test3Func()]).then(function(){
console.log('All tests finished');
});
and this will output - One of the tests finished
To sum it up promise looks like below -
Related Links
Sunday, 18 December 2016
Greasemonkey script to dim white background webpages in Firefox
Background
- Greasemonkey script to block Game of Thrones spoilers
- Greasemonkey script to replay Youtube videos once they finish
Bright white pages strain your eyes. I love dark black/grey themes and they dont strain your eyes as well. So was looking out for an addon to do this.
Chrome has a beautiful addon called -
Unfortunately there is no such good plugin available on Firefox. Hence this script. You can configure RGB to the background color you wish to have. The script will be executed when your DOM(Document object model) is loaded.
Greasemonkey script to dim white background webpages in Firefox
It has sort of greyish background.
NOTE : This is not a script originally written by me. I have just modified it to suit my needs. Feel free to edit it and use as per your requirements.
Related Links
Saturday, 11 June 2016
Greasemonkey script to replay Youtube videos once they finish
Background
Setup
Related Links
Sunday, 29 May 2016
Greasemonkey script to block Game of Thrones spoilers
Background
Greasemonkey script to block Game of Thrones spoilers
// ==UserScript==
// @name Spoiler Killer
// @include http://*.facebook.com/*
// @include https://*.facebook.com/*
// @require http://code.jquery.com/jquery-1.7.1.min.js
// @require https://gist.github.com/raw/2625891/waitForKeyElements.js
// @grant none
// @version 1
// @namespace http://opensourceforgeeks.blogspot.in/
// @description Blacken facebook posts possibly containing Game of Thrones spoilers.
// copied from https://gist.github.com/vshivam/94d18c5d652217a449a5b785cbda1073
// ==/UserScript==
(function(){
var terms = ['spoiler', 'game of thrones', 'hodor', 'jon snow', 'khaleesi', 'stark', 'dothraki'];
function actionFunction(node){
var content = node.html();
content = content.toLowerCase();
$.each(terms, function(index, term){
if(content.indexOf(term) > -1){
var overlay = $('<div />' ).css({
position: "absolute",
width: "100%",
height: "100%",
left: 0,
top: 0,
zIndex: 1000000,
background: "#000000",
});
(function(overlay, node){
overlay.appendTo(node.css("position", "relative"));
$(node).on("mouseenter", function(){
overlay.hide();
});
$(node).on("mouseleave", function(){
overlay.show();
});
})(overlay, node);
}
});
}
waitForKeyElements("div.userContentWrapper", actionFunction);
})();
Script essentially blackens the posts that contain spoiler words. Feel free to add/remove words as you choose suitable. Make sure that the script is running on the site you intend it to be. You can test that from Greasemonkey icon near URL bar. See following screenshot for details -
Related Links
Tuesday, 10 May 2016
Hide variable from console access - Javascript Closures and self executing functions
Background
<script>
var counter = 0;
function increment() {
counter++;
console.log('After increment counter : ' + counter);
}
function decrement() {
counter--;
console.log(' After decrement counter : ' + counter);
}
</script>
- In above code counter is a global variable.
- In a web page global variables belong to window object. So you can also access it using window.counter.
- Global variables can be accessed/changed by all scripts in a page.
- A local variable can only be used inside the function where it is defined. It is hidden from other functions and other scripting code.
- Global and local variables with the same name are different variables. Modifying one, does not modify the other.
- Variables created without the keyword var, are always global, even if they are created inside a function.
Javascript closure
<script>
var increment, decrement, printCounter;
(function () {
var counter = 0;
increment = function() {
counter++;
console.log('After increment counter : ' + counter);
};
decrement = function() {
counter--;
console.log(' After decrement counter : ' + counter);
};
printCounter = function() {
console.log('counter : ' + counter);
};
})();
</script>
(function(){
//Bunch of code...
})();
It's called self executing function. It is executed only once when page loads.
So A closure is a function having access to the parent scope, even after the parent function has closed.
var increment = (function () {
var counter = 0;
return function () {return counter += 1;}
})();
increment();
increment();
increment();
// the counter is now 3
Related Links
Sunday, 15 November 2015
Create your own chrome plugin example demo
Background
Getting Started
- First and foremost what you need is a file called manifest.json. This file essentially tell chrome browser details about your plugin like it's name, it's version, what permission it needs and the actual code files.
For our demo this file looks something like below -
{
"manifest_version": 2,
"name": "Open Source For Geeks Chrome Test Plugin",
"description": "This extension will just show current active Tab URL",
"version": "1.0",
"browser_action": {
"default_icon": "icon.png",
"default_popup": "popup.html"
},
"permissions": [
"activeTab"
]
}
Contents of manifest.json file are basically json with plugin details. As you must have notices by now it references two essential resources -
- icon.png
- popup.html
- Go ahead and put icon.png and create a file called popup.html is the same directory - "chrome_plugin".
If you do not have the icon you can use the one above. It's 20*20 pixels icon.
- Next edit popup.html with following contents -
<!doctype html> <html> <head> <title>OSFG Chrome Demo Plugin</title> <script src="popup.js"></script> </head> <body> <h1>Current Site URL : </h1> <br/> <div id="currentTabUrl"></div> </body> </html>
Again a simple HTML file but note it asks to load a popup.js javascript file.
- Go ahead create a file called popup.js and add following contents to it -
function getCurrentActiveTabUrl(callback) {
var tabQueryInfo = {
active: true,
currentWindow: true
};
chrome.tabs.query(tabQueryInfo, function(tabs) {
var currentTab = tabs[0];
var url = currentTab.url;]
console.log(url);
console.assert(typeof url == 'string', 'currentTab.url should be a string');
callback(url);
});
}
function renderOutput(outputText) {
document.getElementById('currentTabUrl').innerHTML = "<a href='" + outputText + "'>" + outputText + "</a>";
}
document.addEventListener('DOMContentLoaded', function() {
getCurrentActiveTabUrl(function(url) {
renderOutput(url);
});
});
Take some time to see the javascript code above. It essentially reads the current active TAB url and shows it in the popup in an anchor tag. And there you go your first chrome plugin is all set to be deployed.
NOTE : Most of the chrome APIs are asynchronous. So you cannot do something like -
var currTabUrl;
chrome.tabs.query(queryInfo, function(tabs) {
currTabUrl= tabs[0].url;
});
alert(currTabUrl); // Will show "undefined" as chrome.tabs.query is async.
Deploying your chrome plugin
- Go to chrome://extensions/ URL is your chrome browser. Here you should see list of existing chrome extensions you are using.
- Make sure "Developer Mode" check box is selected.
- Now click on "Load Unpacked Extension" and select the folder you have plugin in - "chrome_plugin" directory is this case.
- Now open any tab. You should see the plugin with icon you had put in the directory just besides Omnibox. Go to any URL and then click on the plugin icon.
You can download this sample chrome plugin code from here.
Appending custom methods to chrome right click Menu
{
"manifest_version": 2,
"name": "Chrome Test Plugin",
"description": "This extension will just show current active Tab URL",
"version": "1.0",
"background": {
"scripts": ["background.js"]
},
"browser_action": {
"default_icon": "icon.png",
"default_popup": "popup.html"
},
"permissions": [
"activeTab",
"contextMenus"
]
}
- There is a new permission added called contextMenus. This basically lets you operator om chrome context menus.
- There is a new key added called background that basically tells chrome about background processes. You can specify scripts or page here.
function searchgooglemaps(info)
{
var searchstring = info.selectionText;
chrome.tabs.create({url: "http://maps.google.com/maps?q=" + searchstring})
}
chrome.contextMenus.create({title: "Search Google Maps", contexts:["selection"], onclick: searchgooglemaps});
And you are done. Reload the extension.
When you click on "Search Google Maps" you should see a new Tab opening with google maps and a search location of your desired selected String.
Related Links




































