Arrow functions are not the solution you’ve been looking for

JavaScript’s Arrow functions were supposed to solve all our this-related problems but instead just replaced those this-related problems with other this-related problems.

A friend of mine posted this in our local Slack channel, and I’ve seen a variation of this problem a number of times already:

function foo(ddb) {
  return {
    listTables: (params = {}, cb = idFunc) => {
      const self = this
      let currentList = params.currentList || []
      return toPromise(ddb, ddb.listTables, omit(params, 'currentList'), cb)
        .then(r => {
          console.log('LISTTABLES result', r)
          currentList = currentList.concat(r.TableNames || [])
          if (!r.LastEvaluatedTableName || r.TableNames.length === 0) {
            return { ...r, TableNames: currentList }

          return self.listTables({   // <- Fails here
              ExclusiveStartTableName: r.LastEvaluatedTableName,
            }, cb)

Note the <- Fails here. Can you spot why? I’ll wait…

Figure it out…


Ok, I’ll tell you. this inside of listTables is lexically-bound, so it’s the same this as foo, not the returned object. So if the function is called in global scope, which it likely is, this === window, or even this === undefined, depending on whether we’re in strict mode.

We’re just moving our problems around, and we’re even getting to the point of introducing more syntax to solve the problem arrow functions were supposed to solve in the first place (see the new class fields proposal, which will allow you to write this:

class MyClass {
  myMethod = () => {
    // ...code

and the function stays bound to the class instance. None of this really solves the underlying problem, which is the repeated attempt to shoehorn patterns into the language that don’t belong.

JavaScript is not a traditional class-oriented language. Stop trying to make it one.

Edit this post on GitHub.