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 thatthis
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 onthis
are public.class Timer{ constructor(callback, interval){ this.timerId = "secret"; } }const timer = new Timer(); timer.timerId; //secretNo 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 noclass
, no function constructor, nonew
, noObject.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
andstop
. Everything else is private. There are nothis
losing context problems as there is nothis
.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 ofarguments
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); //6Conclusion
The best way to avoid
this
related problems is to not usethis
at all.JavaScript without
this
is a better language. And more specifically, JavaScript withoutthis
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.
Removing JavaScript’s “this” keyword makes it a better language. Here’s why.
Pages: 1 2