Rethinking JavaScript: The complete elimination and eradication of JavaScript’s this.

nothis demo

If this is so difficult to reason about, why don’t we just stop using it? Seriously. Why. don’t. we. just. stop. using. it.?

If you have read How I rediscovered my love for JavaScript after throwing 90% of it in the trash, then you won’t be surprised when I say I am throwing this away. this is gone. goodbye. this won’t be missed.

With functional JavaScript, you will almost never see this. I say almost never because even though your code doesn’t contain this, you have little control over 3rd party libraries. Popular libraries like ReactjQueryeventemitter2 and many others will force this down your throat.

Here are some examples of how libraries force us to use this.

Forced this in React

// 😞 GROSS: this
class Counter extends React.Component {
  constructor() {
    super()
    this.increment = this.increment.bind(this)
  }

  increment() {
    this.setState(s => ({ count: s.count + 1 }))
  }

  render() {
    return (
      <div>
        <button onClick={() => this.increment}>{this.state.count}</button>
        <button onClick={this.increment.bind(this)}>{this.state.count}</button>
      </div>
    )
  })
}

Forced this in jQuery

// 😞 GROSS: this
$('p').on('click', function() {
  console.log($(this).text())
})

Forced this in eventemitter2

const events = new EventEmitter2({ wildcard: true })

// 😞 GROSS: this
events.on('button.*', function() {
  console.log('event:', this.event)
})

events.emit('button.click')

this is everywhere!

So what’s the problem?

One problem is this is not accessible if you use an arrow function. Sometimes I prefer to write an arrow function instead of a classic function. Okay, I always prefer to write arrow functions.

Another problem is this can be unintentionally reassigned. So your function might fail based on how others use it.

// WTF? these will produce different outputs
const say = cat => cat.speak() //=> "meow"
const say = ({ speak }) => speak() //=> Error: Cannot read property 'sound' of undefined

// WTF? these will produce different outputs
cat.speak() //=> "meow"

const speak = cat.speak
speak() //=> undefined

So let’s just get rid of this completely.

NO. THIS.

I created a simple function decorator that to get rid of thisMore on function decorators here.

After creating nothis, I created a package so I can use it in all my projects.

So what would this look like you ask?

nothis this in React

import React from 'react'
import nothisAll from 'nothis/nothisAll'

// 🔥 LIT: no this in sight!
class Counter extends React.Component {
  state = { count: 0 }

  constructor() {
    super()
    nothisAll(this)
  }

  increment({ setState }) {
    setState(({ count }) => ({ count: count + 1 }))
  }

  render({ increment, state }) {
    return (
      <div>
        <button onClick={increment}>{state.count}</button>
      </div>
    )
  }
}

nothis in jQuery

$('p').on('click', nothis(ctx => console.log($(ctx).text())))

nothis in eventemitter2

const events = new EventEmitter2({ wildcard: true })

// 🔥 LIT: nothis + destructuring!
events.on('button.*', nothis(({ event }) => console.log('event', event)))

events.emit('button.click')

But wait! There’s more!

fixthis can fix some of your existing this rebinding problems!

import fixthis from 'nothis/fixthis'

const cat = {
  sound: 'meow',
  speak: function() {
    return this.sound
  }
}

// 😞 GROSS: this is unintentionally rebound
const speak = cat.speak;
speak() //=> Error: Cannot read property 'sound' of undefined

// 🔥 LIT: this stays this
const fixedCat = fixthis(cat)
const speak = fixedCat.speak;
speak() //=> "meow"

But I need help…

Install it…

npm install -P nothis

Add it to your libraries…

import nothis from 'nothis'

Play with it…

… and report bugs, request features or contribute to the project here https://github.com/joelnet/nothis.

This is the latest addition to my Rethinking JavaScript series. If this made you curious, check out a few of my other articles in this series:

Source: dev