JavaScript Concepts to Make Your Head Spin: Closures, Currying, and More 🤪
Udit Kumar / February 08, 2022
5 min read • ––– views
Hold onto your hats, folks, because we're about to go on a wild ride through the land of JavaScript. During this journey, we'll cover all the important concepts you need to know to be a JavaScript master.
So, let's get started ✨!
JavaScript prototypes and prototypal inheritance
JavaScript is a prototype-based language. This means that objects in JavaScript have a hidden internal property called [[Prototype]] (as opposed to classes, which don't). This [[Prototype]] property is either null or references another object. That object is called the prototype.
When you try to access a property on an object, and if the object doesn't have that property, JavaScript will look at the object's [[Prototype]]. If the [[Prototype]] also doesn't have the property, then JavaScript will look at the [[Prototype]] of the [[Prototype]], and so on. This is called prototypal inheritance.
Let's see this in action:
jsconst person = {
  isHuman: false,
  printIntroduction: function () {
    console.log(`My name is ${this.name}. Am I human? ${this.isHuman}`);
  }
};
const me = Object.create(person);
me.name = 'Udit'; // "name" is a property set on "me", but not on "person"
me.printIntroduction();
// expected output: "My name is Udit. Am I human? false"
In the above example, me is an object created from the person object using Object.create().
me doesn't have its own isHuman property, but since objects inherit properties from their prototypes, me.isHuman will return the isHuman property found on person.
JavaScript closures
A closure is the combination of a function and the lexical environment within which that function was declared. This environment consists of any local variables that were in-scope at the time the closure was created.
In short, a closure gives you access to an outer function's scope from an inner function. In JavaScript, closures are created every time a function is created, at function creation time.
Let's see this in action:
jsfunction makeAdder(x) {
  // parameter `x` is an inner variable
  // inner function `add()` uses `x`, so
  // it has a "closure" over it
  function add(y) {
    return y + x;
  }
  return add;
}
// `plusOne` gets a reference to the inner `add(..)`
// function with `x` preset to `1`
const plusOne = makeAdder(1);
// `plusTen` gets a reference to the inner `add(..)`
// function with `x` preset to `10`
const plusTen = makeAdder(10);
plusOne(3); // 4  <-- 1 + 3
plusOne(41); // 42 <-- 1 + 41
plusTen(13); // 23 <-- 10 + 13
In the above example, plusOne and plusTen are both closures. They share the same function body definition, but store different lexical environments. In plusOne, x is 1, and in plusTen, x is 10.
JavaScript this
The this keyword refers to the object it belongs to.
It has different values depending on where it is used:
- In a method, 
thisrefers to the owner object (here method means a function that is a property of an object). - Alone, 
thisrefers to the global object. - In a function, 
thisrefers to the global object. - In a function, in strict mode, 
thisisundefined. - In an event, 
thisrefers to the element that received the event. - Methods like 
call(), andapply()can referthisto any object which is passed as an argument. 
Let's see this in action:
jsconst person = {
  name: 'Udit',
  weight: 70,
  info: function () {
    console.log(`${this.name} weighs ${this.weight} kg.`);
  }
};
person.info(); // "Udit weighs 70 kg."
In the above example, this refers to the person object that "owns" the info() method.
JavaScript Currying
Currying is a technique of evaluating function with multiple arguments, into sequence of functions with single argument.
A curried function takes multiple arguments one at a time and returns a new function that takes the next argument until all arguments are passed.
Let's see this in action:
jsfunction curry(fn) {
  return function curried(...args) {
    if (args.length >= fn.length) {
      return fn.apply(this, args);
    } else {
      return function (...args2) {
        return curried.apply(this, args.concat(args2));
      };
    }
  };
}
function sum(a, b, c) {
  return a + b + c;
}
const curriedSum = curry(sum);
console.log(curriedSum(1, 2, 3)); // 6, still callable normally
console.log(curriedSum(1)(2, 3)); // 6, currying of 1st arg
console.log(curriedSum(1)(2)(3)); // 6, full currying
In the above example, curry() is a higher-order function that takes a function as an argument and returns a new function. The new function is a curried version of the original function.
Conclusion
Learning JavaScript is a never-ending journey. There are so many concepts to learn and so many things to explore. I hope this blog post helped you understand some of the most important concepts in JavaScript.
That's it for this blog post. I hope you enjoyed it. If you have any questions, feel free to reach out to me on Twitter or LinkedIn. I'd love to hear from you!