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

joelnet

JavaScript Joel

Posted on August 8, 2018

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

R.I.P. this 1995-2018

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 React, jQuery, eventemitter2 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>
    )
  })
}
Enter fullscreen mode Exit fullscreen mode

Forced this in jQuery

// ๐Ÿ˜ž GROSS: this
$('p').on('click', function() {
  console.log($(this).text())
})
Enter fullscreen mode Exit fullscreen mode

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')
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

So let's just get rid of this completely.

NO. THIS.

I created a simple function decorator that to get rid of this. More 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>
    )
  }
}
Enter fullscreen mode Exit fullscreen mode

nothis in jQuery

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

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')
Enter fullscreen mode Exit fullscreen mode

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"
Enter fullscreen mode Exit fullscreen mode

But I need help...

Install it...

npm install -P nothis
Enter fullscreen mode Exit fullscreen mode

Add it to your libraries...

import nothis from 'nothis'
Enter fullscreen mode Exit fullscreen mode

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:

Hit me up on twitter with any questions @joelnet

๐Ÿ’– ๐Ÿ’ช ๐Ÿ™… ๐Ÿšฉ
joelnet
JavaScript Joel

Posted on August 8, 2018

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

ยฉ TheLazy.dev

About