JavaScript – this keyword usage and binding

JavaScript is very elastic and popular language, but many things may be “strange” if we used soemthing else before. One of important things is that we create a lot of functions, callbacks and everything is asynchronous (if we don’t change this). Other important matter is “this” keyword – may be very unintuitive if we try to use it in similar way to other languages. But this keyword is very powerful and we can simplify our code using this keyword. See few examples in this post.

Very simple situation – we can use loop inside loop to get or modify data objects. In “standard” case, we have to create reference to instance to use our parent in child – it’s jumping scope and the simplest method to “fix” some “issues”:

myFunction () {
    let instance = this

    this.categories.forEach(function (category) {
        category.subcategories.forEach(function (element) {
            let name = instance.name + ' - ' + element.name
        })
    })
}

But… we have not to do this. We can use this and bind to function – it will overwrite local this by our binding value:

myFunction () {
    this.categories.forEach(function (category) {
        category.subcategories.forEach(function (element) {
            let name = instance.name + ' - ' + this.name
        }.bind(this))
    }.bind(this))
}

Will bind always better? Not – with many sub-callbacks, code will be mess. With jumping scope we can create only one top-level variable and use it in any sub-levels.
There is also additional information – what are this in different cases? Go back to first code:

myFunction () {
    let instance = this
    console.log(this) // it will be [object Window]
    this.categories.forEach(function (category) {
        console.log(this) // it will be current category
        category.subcategories.forEach(function (element) {
            console.log(this) // it will be current subcategory
            let name = instance.name + ' - ' + element.name
        })
    })
}

But… it’s on global function, not in methods from object:

var ourObject = {}
ourObject.ourFunction = function () {
  console.log(this) // it will be ref to ourObject, not window!
}

Another ways to change this scope is to use call() or apply() methods, similar to bind:

var categories = [{
    id: 1
    title: 'MTB'
},{
    id: 6
    title: 'Road Bike'
},{
    id: 8
    title: 'Gravel'
}];


for (var i = 0; i < categories.length; i++) {
  (function () {
    console.log(this.id + ' - ' + this.title)
  }).call(categories[i]) // inside this will be current categories[i]
}