Removing JavaScript’s “this” keyword makes it a better language. Here’s why.

Removing JavaScript’s “this” keyword makes it a better language. Here’s why.

this is of course the source of much confusion in JavaScript. The reason being that this depends on how the function was invoked, not where the function was defined.

JavaScript without this looks like a better functional programming language.

this losing context

Methods are functions that are stored in objects. In order for a function to know on which object to work, this is used. this represents the function’s context.

this loses context in many situations. It loses context inside nested functions, it loses context in callbacks.

Let’s take the case of a timer object. The timer objects waits for the previous call to finish before making a new call. It implements the recursive setTimeout pattern. In the next example, in nested functions and callbacks, this loses context:

class Timer {
 constructor(callback, interval){
    this.callback = callback;
    this.interval = interval;
    this.timerId = 0;
  }
  
 executeAndStartTimer(){
   this.callback().then(function startNewTimer(){
       this.timerId =  
       setTimeout(this.executeAndStartTimer, this.interval);
   });
 }
    
 start(){
   if(this.timerId === 0){
     this.executeAndStartTimer();
   }
 }
 stop(){
   if(this.timerId !== 0){
     clearTimeout(this.timerId);
     this.timerId = 0;
   }
 }
}
const timer = new Timer(getTodos, 2000);
timer.start();
function getTodos(){
  console.log("call");
  return fetch("https://jsonplaceholder.typicode.com/todos");
}

this loses context when the method is used as an event handler.

Let’s take the case of a React component that builds a search query. In both methods, used as event handlers, this loses context:

class SearchForm extends React.Component {
  handleChange(event) {
    const newQuery = Object.freeze({ text: event.target.value });
    this.setState(newQuery);
  }
  search() {
    const newQuery = Object.freeze({ text: this.state.text });
    if (this.props.onSearch) this.props.onSearch(newQuery);
  }
  render() {
    return (
      <form>
      <input onChange={this.handleChange} value={this.state.text} />
      <button onClick={this.search} type="button">Search</button>
      </form>
    );
  }
}

There are many solutions for these issues : the bind() method, the that/self pattern, the arrow function.

For more on how to fix this related issue issues, take a look at What to do when “this” loses context.

this has no encapsulation

this creates security problems. All members declared on this are public.

class Timer{
 constructor(callback, interval){
    this.timerId = "secret";
  }
}
const timer = new Timer();
timer.timerId; //secret

No this, no custom prototypes

What if, instead of trying to fix this losing context and security problems, we get rid of it all together?

Removing this has a set of implications.

No this basically means no class, no function constructor, no new, no Object.create().

Removing this means no custom prototypes in general.

A Better Language

JavaScript is both a functional programming language and a prototype-based language. If we get rid of this, we are left with JavaScript as a functional programming language. That is even better.

At the same time, without this, JavaScript offers a new, unique way, of doing Object Oriented Programming without classes and inheritance.

Object Oriented Programming without this

The questions is how to build objects without this.

There will be two kind of objects:

  • pure data objects
  • behavior objects

Pure Data Objects

Pure data objects contain only data and have no behavior.

Any computed field will be fill-in at creation.

Pure data objects should be immutable. We need to Object.freeze() them at creation .

Behavior Objects

Behavior objects will be collections of closures sharing the same private state.

Let’s create the Timer object in a this-less approach.

function Timer(callback, interval){
  let timerId;
  function executeAndStartTimer(){
    callback().then(function makeNewCall(){
      timerId = setTimeout(executeAndStartTimer, interval);
    });
  }
  function stop(){
    if(timerId){
      clearTimeout(timerId);
      timerId = 0;
    }
  }
  function start(){
    if(!timerId){
      executeAndStartTimer();
    }
  }
  return Object.freeze({
    start,
    stop
  });  
}
const timer = Timer(getTodos, 2000);
timer.start();

The timer object has two public methods: start and stop. Everything else is private. There are no this losing context problems as there is no this.

Components without this

this may be required by many components’ frameworks, like React or Vue for example.

In React, we can create stateless functional components, without this, as pure functions.

function ListItem({ todo }){
  return (
    <li>
      <div>{ todo.title}</div>
      <div>{ todo.userName }</div>
    </li>
  );
}

We can also create stateful components without this with React Hooks. Take a look at the next example:

import React, { useState } from "react";
function SearchForm({ onSearch }) {
  const [query, setQuery] = useState({ text: "" });
  function handleChange(event) {
    const newQuery = Object.freeze({ text: event.target.value });
    setQuery(newQuery);
  }
  function search() {
    const newQuery = Object.freeze({ text: query.text });
    if (onSearch) onSearch(newQuery);
  }
  return (
    <form>
      <input type="text" onChange={handleChange} />
      <button onClick={search} type="button">Search</button>
    </form>
  );
};

Removing arguments

If we get rid of this, we should also get rid of arguments as they have the same dynamic binding behavior.

Getting rid of arguments is pretty simple. We just use the new rest parameter syntax. This time the rest parameter is an array object:

function addNumber(total, value){
  return total + value;
}
function sum(...args){
  return args.reduce(addNumber, 0);
}
sum(1,2,3); //6

Conclusion

The best way to avoid this related problems is to not use this at all.

JavaScript without this is a better language. And more specifically, JavaScript without this is a better functional programming language.

We can build encapsulated objects, without using this, as collections of closures.

With React Hooks we can create this-less stateful components.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.