..

Javascript notes

Here are some concepts that I always forget whenever I start a js project.

Arrow function

I thought arrow function is just a new way of writing a function, but there’s this tricky this concept in javascript. I guess I don’t have to worry about this because it’s part of the old days of javascript, but I still see this a lot in code.

A method in an object can access an object property using this. In this example, we can access pets property of printSomething object inside the addHello function using this.pets. But the anonymous, function inside addHello function cannot access this.name.

// Prints hello undefined
const printSomething = {
    name: 'John Smith',
    pets: ['dog', 'cat', 'monkey'],

    addHello() {
        this.pets.forEach(
            function (pet) {
            console.log(`Hello ${this.name}, your pet is ${pet}`)
        }
        )
    }
}

printSomething.addHello()

We usually have to “bind” them.

// Need to call bind to work
const printSomething = {
    name: 'John Smith',
    pets: ['dog', 'cat', 'monkey'],

    addHello() {
        this.pets.forEach(
            function (pet) {
            console.log(`Hello ${this.name}, your pet is ${pet}`)
        }.bind(this)
        )
    }
}

printSomething.addHello()

With arrow functions, we don’t have to bind them because the this is determined by the scope of the parent function. No matter how many parent the inner function has! Even if the the anonymous function is inside the addHello() function, it can still recognize the properties of printSomething, because the anonymous function is inside printSomething.

//No need to call bind because arrow function inside loop()
const printSomething = {
    name: 'John Smith',
    pets: ['dog', 'cat', 'monkey'],

    addHello() {
        this.pets.forEach((pet) => {
            console.log(`Hello ${this.name}, your pet is ${pet}`)
        }
        )
    }
}

printSomething.addHello()

P.S: we can remove return from an arrow function, if it’s only one line

const sum = (a, b) => a + b

Closure

Speaking of arrow functions where the scope of their ‘this’ is lexical scoping, let’s review lexical scoping. I like this definition from stackoverflow:

Lexical Scoping defines how variable names are resolved in nested functions: inner functions contain the scope of parent functions even if the parent function has returned. [https://stackoverflow.com/questions/1047454/what-is-lexical-scope]

It says that even if the function has returned, inner functions still know about the parent functions.

Let’s see this example from mozilla:

function makeAdder(x) {
  return function (y) {
    return x + y;
  };
}

const add5 = makeAdder(5);

console.log(add5(2)); // 7

The function makeAdder is returning a function that accepts argument y. add5 forms a closure that takes in makeAdder that would always have 5 as an argument for y. Because of closure, it makes it possible for a function to have “private” variables.

Callback function

A function passed as an argument to another function that is called to complete an action. I usually see callback functions when for example, you make a network call and have this callback functions to do something after that network call.

Here’s an example callback, listContents is a callback pass inside fs.readdir function.

const listContents = (err, files) => {
  console.log('running callback')
  if (err) {
    console.error(err)
  } else {
    for (const name of files) {
      console.log(name)
    }
  }
}

const srcDir = process.argv[2]
fs.readdir(srcDir, listContents)