DEV Community

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

Collapse
 
qm3ster profile image
Mihail Malo

I get how it could trip up someone new to js, but that's what makes this a method and not just any old function.
Do you suggest replacing all classes with object factory functions?

class ligma {
  constructor(prefix) {
    this.prefix = prefix
    this.counter = 0
    this.statement = "ligma"
  }
  speak() {
    return this.prefix + " " + this.statement + " " + this.counter++
  }
}
const sugma = prefix => {
  let counter = 0
  const statement = "sugma"
  return {
    speak() {
      return prefix + " " + statement + " " + counter++
    },
  }
}

const PRE = "Very nice"

const l = new ligma(PRE)
const s = sugma(PRE)

console.log(l.speak())
console.log(l.speak())
console.log(s.speak())
console.log(s.speak())

Sure, s.speak is already bound.
Sure, memory and even code cache difference can be negligible when you don't instantiate even a thousand of these objects.

But what meaning does const {speak} = s have as a freestanding function?
Should we have it a static function and not a closure and take a state POJO instead: speak(s)?

Thread Thread
 
joelnet profile image
JavaScript Joel

I get how it could trip up someone new to js

I'll disagree with this statement. null is a much easier concept to understand when compared to this. Yet null is now currently considered to be the Billion dollar mistake or "The worst mistake in computer science".

We all understand null and we understand it very well. Yet we are forever doomed to run into random NullReferenceException errors. Even though we fully understand and comprehend null, you can never guarantee you will not run into those bugs.

So to assume problems with this are limited to Junior developers, I would say is an Optimism Bias.

Do you suggest replacing all classes with object factory functions?

In my perfect world, Objects and behavior would be disconnected. So you would never have a function and data combined together. We would have Categories and Morphisms (transformations) and immutability.

Then the world becomes simplified:

// data
const ligma = prefix => ({ prefix, counter: 0, statement: 'ligma' })
// behavior
const speak = ({ counter, ...rest }) =>
  ({ ...rest, counter: counter + 1 })

const l = ligma('Very nice')
console.log(speak(l))
Thread Thread
 
qm3ster profile image
Mihail Malo

And instead of encapsulating the state of a resource beyond our control in an object? IO monad?
How would you handle a WebSocket, a File handle, and such?

Thread Thread
 
qm3ster profile image
Mihail Malo

null is terrible. It shifts the job of knowing whether a function might return zero instead of one expected result to to the caller. And in JS we have two different nulls 👌
TypeScript with strictNullChecks begins to solve this, but there's the risk that something external claiming to return one concrete value might return a nullish value at runtime.

this is quite different. There's a couple of rules, and once you get them it works perfectly:

  1. In arrow functions, this isn't special it's just the binding from the enclosing scope. (undefined if that's nothing)
  2. In all other functions, including the object method shorthand on an object literal or a class, it's the enclosing object (undefined if that's nothing)
  3. Function.protptype.{bind|call|apply} first get the function, so it can't possibly be a method any more, so you get to provide your own this
  4. A binded function forever loses those arguments, just like you can't rebind a curried function's argument you can't rebind this. All it really does is
  Function.prototype.bind = function(thisArg, ...args) {
    return (...args2) => this.apply(thisArg, args.concat(args2))
  }

No one could possibly be overwhelmed by this.

There are many ways properties are different from scope bindings.

For example, one would not expect

const a = {b:1}
a.b++
console.log(a)

To have the same result as

const a = {b:1}
let {b} = a
b++
console.log(a)

Or consider getters and other capabilities of Object.defineProperty()
Treating properties and bindings with the same expectations is a very novice thing in the context of JS.

On the other hand in this beginner period I can definitely appreciate, for example when using ES6 classes, that the methods would be forever bound to the newed object.
But once you see what that desugars to, one stops thinking that.

Thread Thread
 
joelnet profile image
JavaScript Joel

Probably a combination of event emitters and rxjs.

Check out a project of mine here where I use these techniques: github.com/joelnet/bitcoin-all-tim...

On this page you can see how I consume a WebSocket: github.com/joelnet/bitcoin-all-tim...

Thread Thread
 
joelnet profile image
JavaScript Joel

No one could possibly be overwhelmed by this.

I'm am perplexed by your ability to understand the complexities of null and at the same time miss the complexities of a more simple concept being this.

Thread Thread
 
qm3ster profile image
Mihail Malo

What's the advantage of pointfree propEq usage? Isn't that less immediately readable than x=>x.type==='match'?
I feel like passing key names around in strings is strictly worse and should be avoided whenever it can. So much so, that if you have to use index notation on a non-Array object because your name is truly dynamic, you should actually be using an ES6 Map instead.

I can see the top Event, message, has an excuse to use Observable to filter, but why is

  Observable.fromEvent(websocket, 'error')
    .subscribe(err => events.emit('gdax.ERROR', { exchange, err }))

not just

  websocket.on('error', err => events.emit('gdax.ERROR', { exchange, err }))

And such?

Most importantly, how do you clean up the observables when the websocket closes? It seems that the websocket object and the three observables will never be collected, and a new call to default would just make a new one in parallel.

Thread Thread
 
joelnet profile image
JavaScript Joel

What's the advantage of pointfree propEq usage?

I just got into the habbit of using it. I can go either way on this one. The advantage is when you use something like path(['one', 'two', 'three']) instead of obj && obj.one && obj.one.two && obj.one.two.three so prop and propEq are similar which is why I used them.

I can see the top Event, message, has an excuse to use Observable to filter, but why is

Just for consistency again. So all "subscriptions" have the same interface. Again, I could have gone either way.

Most importantly, how do you clean up the observables when the websocket closes?

If I remember correctly, I am handling this by exiting the app completely. I have another process that restarts it. I had some issues with closing / reopening some websockets and this app wasn't critical to stay open, so I hard exit.