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.
However, `this` has nothing to do with functions being objects, besides the fact that the prototype object is a member to the constructor function.
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.
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®.
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?I really don't blame programmers for getting confused by this.
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.
'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.
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.