Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

I think the main reason "this" is considered confusing is that many programmers learning JS have already spent years coding in Java or C#. They expect it to work the same, then get frustrated when it doesn't. But the reason it doesn't is due to the fact that functions in JS are first-class, and don't intrinsically belong to a particular class and object instance they way they do in those languages. As such, the context represented by "this" has to be more fluid in JS.

That's not to say that the design of "this" is perfect. And it doesn't help that JS' syntax was designed to resemble C-family languages that it differs from significantly. But nor it is some entirely arbitrary and illogical flaw. If you take the time, it's possible to gain an intuitive grasp of how functions and "this" work in JS. But instead, learners are too often told that "JS is quirky" by others who also have come to it from Java / C#, and never move past memorizing to a list of these "quirks" to genuine proficiency. They then grumble whenever they need to work on a JS codebase, because their incomplete understanding makes it feel like they're standing on quicksand.

Soon such devs fall into a circular trap: They don't like coding in JS because it feels weird and unintuitive. And they don't take the time to learn about it more deeply because they don't like coding with it, and don't want to waste time learning about something they dislike. But since they have to code with it, because it's part of their job, they just stumble along, hacking away and getting frustrated when things don't work, then come onto Hacker News and blow off steam about what a garbage language JS is.



> due to the fact that functions in JS are first-class

I don't agree with that. There are plenty of languages with first-class functions that don't have this kind of confusion. There's nothing about a function being a value and being able to pass functions around that necessitates the awkwardness of JavaScript's 'this'.

What does necessitate it is the lack of separation between functions and objects. The fact that a function can also have its own properties is, to my mind, a mistake in the design of the language. And it's a decision that those other languages with first-class functions and no 'this' problem didn't make. If objects and functions are distinct concepts in the language, it's trivial to make 'this' be dead simple and allow programmers to have a simpler mental model.


You're correct that other languages have first-class functions which are capable of handling context without the implicit-this style like JS. Rust, for instance, uses `self`-as-first-parameter style.

However, `this` has nothing to do with functions being objects, besides the fact that the prototype object is a member to the constructor function.


What model, exactly?

In perl/c[++]/#/java, you have to carry object around with a method (or use functors), otherwise you’ll call it with wrong arguments. In python methods are bound implicitly in a class, but explicitly in assignment (iirc). In Lua you’re explicit with obj:mtd() instead of obj.fun(). In js, obj.mtd() is eqv. to obj:mtd() in that sense, but you can bind() to anything.

Which model is preferable? ‘this’ is natural complexity, and under ‘use strict’ it behaves just okay. It is programmers who don’t care to grasp it.

Saying that as a natural js hater.


> In python methods are bound implicitly in a class, but explicitly in assignment (iirc).

Oh, it's quite a bit more involved than that :)

I'm going to ignore Python 2 and the C API here.

In Python functions are descriptors. This means they have (mostly) a __get__ function which returns a closure passing self or cls or nothing (corresponding to a regular method, a class method and a static method; @classmethod and @staticmethod change the implementation of __get__, but of course they don't, because everything is a special case in CPython; note that "regular methods" are "regular functions" — all functions behave like methods if you treat them like one). If you write

   class Class:
       def foo(self, x): print(x)
then foo is a regular old function. The magic is in the dot operator (quite literally): instance.foo is a different operator from Class.foo, and instance.foo is not Class.foo (one is a bound method the other is a plain function). The former invokes the descriptor protocol to the effect of, roughly, type(instance).__dict['foo']__.__get__(type(instance), instance), which returns a closure calling the "real foo" (Class.foo) with instance as the first argument. Similarly @classmethod has the effect of __get__ returning a different closure, which passes type(instance) as the first argument instead.

Python. It's complicated®.


Yeah, one most complex way to do it. I just tested my assertion for the sake of truth and it seems correct:

  class Foo:
      def bar(self, x):
          print 'bar', x
  
  def f(x): print 'f', x
  
  foo = Foo()
  foo.baz = f

  print(foo.bar)  # <bound method Foo.bar of <__main__.Foo object>>
  print(foo.baz)  # <function f>
  foo.bar(5)      # bar 5
  foo.baz(6)      # f 6
Now who wants to say that 'js this' is quirky and complicated?


Having very different semantics hiding under identical syntax is still a design fault with the language though, especially considering that Javascript's adherence to Java syntax is deliberate not accidental.

I really don't blame programmers for getting confused by this.


>I think the main reason "this" is considered confusing is that many programmers learning JS have already spent years coding in Java or C#. They expect it to work the same, then get frustrated when it doesn't. But the reason it doesn't is due to the fact that functions in JS are first-class, and don't intrinsically belong to a particular class and object instance they way they do in those languages. As such, the context represented by "this" has to be more fluid in JS.

As someone who’s “native” language is JS, I think that’s spot on. I never had the baggage of thinking in terms of Java or C++, and so I couldn’t understand why people would get confused over “this” because it was fundamental to learning the language and thus to my mental model of programming in general.


I believe that’s because you ask ‘what this really is’ and get another ton of bullshit articles that never do a strict definition of the mechanism, instead resorting to vague examples with bad names. MDN included.


Java ushered in with it, a sort of tunnel vision that class-based inheritance was _the_ fundamental theorem of business programming. When people see prototypal inheritance like in JS, they call it "quirky" or "poorly designed", as if it were haphazardly evolved as opposed to deliberately designed. When languages like Go or Rust came out, it was shocking how many times I saw "where's classes?" come up on the mailing list.


No.

'this' is confusing because it is a novel abstraction that has no analog/referent to anything familiar, even if JavaScript is your first language. It is completely unintuitive and simply must be internalized with time

Effectively, 'this' forces you to understand the majority of the prototypal nature of JavaScript just to simply call some functions.

Alternatively, don't use this at all, ever. You can pass explicit arguments for anything you need.


Sums it up pretty good. 'this' was a minor problem when promises came out and bind got sort of sprinkled everywhere. Arrow notations can now take care of that by making it less verbose by binding 'this' behind the scenes.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: