Posts

Learn JavaScript again

Jun 8, 2019 | 6 minutes read

Tags: javascript

It is time to learn JavaScript again for me as I just started in a Chingu team project last week. Our team decided that we’ll make something that is inspired by the Momentum browser extension. Now, on to the part where I write down what I learned this week.

I am happy that our team decided to use native JavaScript for this project, although I don’t mind if some of my teammates would use a library to build a feature. As the whole point of Chingu anyway is for people to learn and collaborate. I am even happier that I now have to worry less about the hoisting issue that put me off JavaScript before. That is all thanks to the let and const keywords. YAY!

When you declare a variable using the let keyword, it keeps the variable’s scope to where it was declared, unlike var where it hoists it up to the global or function scope. Using let or const makes block scope real in JavaScript. Quirks that happened to me before with the var keyword can now be avoided:

function Test(){
    for (var index = 0; index < 3; index++) {
        
        for (var index = 0; index < 3; index++) {
            
            console.log(`Inner loop ${index}`);          
        }

        console.log(`Outer loop ${index}`);
    }
};
Old JavaScript making me cringe…

Back then, JavaScript does not have block scope, it has function scope. If you come from a language that is block scoped, the behavior above is confusing. JavaScript’s little goblins take all those variable declarations and puts them at the top – either global, or at the start of a function. What really happened above was there was only one index variable in the Test function, even though you intended to have two. What made me mad with JavaScript before, is why didn’t it complain about the same variable names if it would put them all up there anyway?! It printed 3 once because that is the value of index when the inner loop finished. Because of this behavior, you might be unaware that you created an infinite loop when you have nested for loops – it sure caught me before. Compare that to the code below:

function TestTwo(){
    for (let index = 0; index < 3; index++) {
        
        for (let index = 0; index < 3; index++) {
            
            console.log(`Inner loop ${index}`);          
        }

        console.log(`Outer loop ${index}`);
    }
};
Block scope as it should be

Using the let keyword allows you to write code that executes the way you think it should. On the other hand, the const keyword is much like let, but the variable cannot be reassigned, I think this feels correct because that is what a constant should be. Note to self – use const for variables that most likely will not be reassigned (functions, etc) and use let for those variables that you know will be.

The arrow function is another lovely addition for me. Since arrow functions do not have their own this, it will use the this of whatever function or object it was declared in. That change is important if you want to write in an Object Oriented style in my opinion.

Instead of using an old hack like below, where you save the value of this to another variable to have access to it later:

function Library() {
    var me = this;
    me.books = 0;
    
    setInterval(function addBook() {
        
        me.books++;
    }, 1000);
}

You can write code like the one below:

function Library() {
    this.books = 0;

    setInterval(() => {

        this.books++;
    }, 1000);
}

To me, that feels more object oriented, and you don’t have to write a little hack to achieve it. You also save typing some characters with arrow functions, and when you are writing function expressions, callback functions after an ajax call, etc. those saved characters all add up. Note, There are two rules from an excellent post about arrow functions that I agree with:

In ES6, this hacks mostly go away if you follow these rules:

  • Use non-arrow functions for methods that will be called using the object.method() syntax. Those are the functions that will receive a meaningful this value from their caller.
  • Use arrow functions for everything else.

String interpolation is one of those parts that I dread about old JavaScript. I’m sure any person that wrote some JavaScript before needed to write code like the one below:

'Why on earth ' + (is + JS + string + interpolation) + ' like this ' + (junk + here) + '.'

This much awaited change is what this language needed. Now you can write strings like this:

function add(){
    let a = 1;
    let b = 2;
    let total = a + b;
    
    console.log(`${total} is the result of adding ${a} and ${b}.`);
}

Note that there are other uses for this template literals as they are called in JavaScript, just the one above is already a big win though.

I had an issue with the pomodoro timer that I was building for our team project, I only need to pass something by reference to persist changes to its value. I asked in Chingu’s chatroom and one of my colleagues said “Yes! Pass by reference is in JS when you pass objects, but not primitive types”. My colleague gave a blog post to support his statement – which is why we should always take whatever we read online with a few cups of rice.

I knew before that JS does not have this in the language, and I was thrilled to test if this exists now. Below is a quick test code in a browser’s console:

Sadly, we can see in that image that there is still no pass by reference in JavaScript – I hope I’m wrong though or that this feature gets added later. The first arrow above points to where the passed argument is assigned to a new and different object. The second arrow points to the call to this function with object a passed to it, and the third arrow points to where the content of object a is printed out after passing it to the function. We can see here that outside the function’s scope, the changes to object a does not persist. That proves to me that even for objects, JavaScript still passes by value.

I think the confusion happens when it comes to reference types because when these are passed to functions, by default a copy of the reference – a pointer – is created (in JavaScript and C# anyway). Since changes to the value of an item (object properties for instance) that a reference points to will be visible to all other pointers, this could be confusing, as it may seem that changes to the object inside the function persists outside of it.