Hacker News new | past | comments | ask | show | jobs | submit login
Removing JavaScript's 'this' keyword makes it a better language (freecodecamp.org)
32 points by tejohnso 70 days ago | hide | past | web | favorite | 57 comments



If you want to be a C programmer, you need to learn how pointers work. If you want to be a C++ programmer, you need to learn STL and templates. Java, Python, every language has its idioms. Javascript is no exception ... it's a simple, untyped language that only has floats, uses prototypal inheritance and, yes, "this." These aren't bugs, they're features.

The web would be a better place if Javascript developers put all of their effort trying to write code in the language they would rather be using into writing better code in the language they are using.


Seems like maybe there's a balance here. On one hand, JS was designed with a particular vision (prototypal inheritance, etc.) and it's good for programmers to understand and follow that vision. On the other hand, even JS experts admit that there are plenty of warts and legacy oddities in JS, and we'd do a lot of things differently if designing the language from scratch. I guess it's unclear where `this` fits in. It's closely tied to the nice elegance of the language, but it's also a huge source of beginner-unfriendliness. IMO it could at the very least have some ease-of-use improvements.

JS has gone through lots of careful language changes (strict mode, arrow functions, classes), and tools like ESLint and TypeScript help limit confusing parts of the language, and I think it's worthwhile to put at least some effort into making JavaScript better rather than just accepting it.


Fair enough, but I don't think avoiding "this" altogether in order to pretend Javascript is only a functional and not also a prototypal language helps. Doing so is just going to make the language more confusing than it really is.


I think the problem is that people often do not have a choice what language they use at their job so the only choice is making the language work the way they want it to.


So what’s your point? People should shut up and stop wanting to improve things?

> The web would be a better place if Javascript developers put all of their effort trying to write code in the language they would rather be using into writing better code in the language they are using.

Right, but then no one would use “this”...


Ignoring or avoiding "this" isn't improving things... learning how "this" works and using it properly is improving things. Not wasting effort trying to make Javascript act like more of a functional language than it is would probably reduce the complexity and increase the efficiency of a lot of the code on the web.


JavaScript was a functional language from the beginning. OOP features were racked on for marketing reasons (Java was popular at the time). “This” isn’t inherently more efficient than programming in a functional style.


>This” isn’t inherently more efficient than programming in a functional style.

It is, because avoiding it requires extra and unnecessary abstractions. "this" is a fundamental part of the language regardless of the paradigm. If you want to use a functional style in javascript, you have to accept that it isn't a pure functional language, and do so using "this," not avoiding it.


That’s silly. “this” and other OOP features _are_ runtime abstractions built atop a more functional core.

> If you want to use a functional style in javascript, you have to accept that it isn't a pure functional language, and do so using "this," not avoiding it.

This is nonsense. You don’t have to do anything at all to program in a functional style in JS. You don’t need to use “this” and I can’t even imagine how using “this” would be helpful to that end.


>This is nonsense. You don’t have to do anything at all to program in a functional style in JS. You don’t need to use “this” and I can’t even imagine how using “this” would be helpful to that end.

I mean, the premise of the posted article is that javascript developers should avoid using "this" for functional (and OOP) programming, but OK... I can't tell if you disagree with me here, or the author, or what.


I disagree with this article. There's no such thing as "this losing context." Its simply changing context, and you can easily maintain the context with bind/call/apply/arrow functions. It's a very useful feature of JS that, like special features in all languages, must be treated with care so that other developers can reason about how you're using it.


You can also "easily" forget to call bind. In other languages, methods are simply bound by default. What's the argument for not doing it that way (besides "implementation details")? Why would you rebind a method in the first place? Seems like a "great" way to cause confusion.


In other languages, classes are a special entity. In JS it's just another object, and you can copy methods from one object to another. Benefit is that you can create mixins, for example.


Yep, the concept of the "prototype" is very integral to JavaScript, and I think its often not understood fully. I actually like the mixin concept much more than multiple inheritance, as I find the mental model to be a bit clearer. For example the "diamond problem" is very clear with a mixin and easily resolved (latest mixin wins) vs more confusing in many languages (looking at you Go with "ambiguous selector" error.)


Yes. I use it all the time. What's the best is that you can extend existsing prototypes and add your own functions even to native/host objects. And with a use of Symbols it's quite foolproof.


Rebinding `this` is the key for sharing methods using prototypal inheritance. It allows methods on the prototype object to dynamically dispatch to methods depending on the child you are calling it on.


I had always been taught that inheritance is an anti-pattern and my experience has been that it makes code more complicated. However, I don't have a lot of first hand experience with it. What would the argument be for why you would want to use "this" to implement prototypal inheritance?


Traditional class-based inheritance is an antipattern compared to composition because the child class's API is tightly coupled to its parent: multiple inheritance of implementations is a mess to reason about, and single inheritance unduly privileges a single parent object that makes refactoring hard when the API of the child or parent has to change.

Composition does not face these issues because instead of a parent class, the outside class's API is not beholden to the inside class's API.

Similarly, in prototypal inheritance, you get to specifically control API by binding or calling 'this' to any choice of object, or select methods to put in other objects, or even replace a method of an object with another method of the same name at runtime, or declare new fields and methods on objects at runtime. This makes prototypal inheritance very open for extension in a way that class-based inheritance cannot be. The downside to this is that JS does not have language features that sufficiently guarantee that an object is closed for modification: in class-based languages classes are a language feature that give a sort of guarantee about the API of an object, but JS objects have no mechanism as powerful as that, and you will need to roll your own. Hence the eventual development of languages and extensions to JS like TS, Reason, Flow that offer these guarantees that transpile to JS.


> Similarly, in prototypal inheritance, you get to specifically control API by binding or calling 'this' to any choice of object, or select methods to put in other objects, or even replace a method of an object with another method of the same name at runtime, or declare new fields and methods on objects at runtime.

None of this sounds like a good idea to me.


Indeed it isn't, and is very lousy to reason about with... until you avail yourself to the sophisticated type systems more commonly found in ML and Haskell through, say, Flow or TypeScript that gives you good guarantees through static analysis as you write.


Honestly there’s no use for prototypical inheritance. You get simpler code by avoiding it altogether as with standard OOP inheritance. You were taught correctly.


super fixes that use case though.


Just popping in to recommend Kyle Simpson’s “You Don’t Know JS” series. He breaks down “this” and other potentially confusing JS concepts in an easy-to-understand way. https://github.com/getify/You-Dont-Know-JS/blob/master/READM...


Looked like a really great resource but it would have been so much better if it was an epub or pdf. I tried it but now it's asking me to download some app :/ (Maybe I missed a step)


This [https://gittobook.org/books/57/You-Dont-Know-JS] may be what you need. It seems to be the whole six books on one page, with .EPUB and .MOBI available for download.


Thanks, this is just what I needed :)


My take is that `this` is fine and straightforward as long as you follow a few rules:

1.) `this` should only be used inside a class method.

2.) Never use `someClassInstance.someMethod` as a value (invoking it is ok, but accessing it without invoking it isn't). Make it a bound method using class field syntax or wrap it in an arrow function and invoke it there.

3.) Never use `function` syntax for function expressions (e.g. callbacks), only arrow functions. Callbacks should never need `this` because the information they need should be provided via arguments.

Fortunately, modern tools make this pretty easy to follow. #1 is mostly enforced naturally by TypeScript; if you try using `this` in a plain function, it will yell at you unless you explicitly annotate what `this` means. #2 is enforced by the TSLint rule no-unbound-method. #3 is enforced by the ESLint rule prefer-arrow-callback. With these rules, even beginners on my team have rarely/never made `this`-related JS mistakes.


people keep wanting to make JS fit into the space of C#/Java OOP class-based stuff. Prototypical inheritance is so cool and useful and lightweight, this is quite versatile once you understand the mechanisms and how to bind it. Why people keep trying to "fix" JS so that it conforms to their class-based expectations is beyond me. I like how it works now.


They do that a lot. Look at Swift, its basically "I hate that Smalltalk-style stuff" and want my own version of C++. Java and JavaScript are examples of the same thinking. I often wonder what would have happened if Netscape had actually allowed a Scheme-like language in its browser.


I think you may be conflating two things here: C#/Java/etc style static OO vs Smalltalk/Python/etc dynamic OO, on the one hand, and class-based vs. prototype based OO, on the other. IMO most of the good bits of JavaScript's object system come from it being dynamic, not from it being prototype based (indeed, JS and Python's object systems are very similar, except that Python has language level support for treating some objects as representing types).


I've seen this a lot, although personally I've come to prefer a functional programming style with closures for state (i.e. a poor man's Scheme), which means I also happen to avoid using "this", but not due to any love of OOP/C#/Java/etc.


The fact that Javascript is prototypal language is really cool once you get your head around it. It doesn't seem like an advantage to get rid of this (which would make it no longer prototype-based) just to have another functional language.


Reading You Don't Know JS really made me appreciate certain aspects as features and not whimsical bugs.


JavaScript: The Definitive Guide by David Flanagan did that for me. Once I finally got prototypes and this, my JS code really took off.


I have heard about it. I have to check it out someday, even if just for historical purposes.


Not really. It just allows for some behavior that in the end makes the code worse.


Medium and "blog-driven development"... six months later the person changes their mind and you're left with an architecture to maintain.

Subscribe here [link].

Like my post [link].

My Amazon wishlist [link].

Follow me on Twitter [link].


My opinion is that generally, implicit `this` is in many ways similar to null pointers in that it was a big design mistake that was somehow copied to to many common languages without a good reason. It adds a special case to so many things, and it could instead just be a regular function parameter and some syntactic sugar. If e.g. object.method(param) expands to Class.method(object, param), you just end up with a special case less and a more cohesive language in general. I'm very happy more modern languages like Rust seem to be taking this path.


`this` is just an environment parameter in JS and must be treated as such.

Any function call in JS is a short form of this:

    func.call(its_this,arg0,arg1)
In the same way as arguments at call site are passed through named parameters into function body, `this` parameter is passed to the function from outside.

That stands true for any language that uses this keyword. C++, Java, etc.

No rocket science in all this.


I'd say it's a fundamental language design question of how to properly mix classes and first-class functions, and there's no clear answer. More specifically, if you access `myInstance.myMethod` without invoking it, what should happen? Should it "carry along" `myInstance`, and how should that work? Different languages have different answers:

* In Java, their solution is to simply not have first-class functions, so the syntax isn't possible. Method invocation (`myInstance.myMethod()`) is a special syntactic form; it's not just a property access and function invocation. There's a special `myInstance::myMethod` syntax that's like a lambda and behaves as expected, including allocating a new instance each time it's used.

* In Python, `myInstance.myMethod` always allocates a new function object, just like `myInstance.myMethod.bind(myInstance)` would do in JS. This avoids the mistakes from JS, but is a bit magical and inefficient (though I'm sure the implementation can optimize it). For example, `arr.append is arr.append` is false because simply accessing a method creates a new function object, so you'll get two different function objects. Still, this has a certain elegance because method invocation doesn't need to be seen as a special syntax like it is in Java and JS.

* In JavaScript, method invocation (`myInstance.myMethod()`) is a special syntactic form like in Java that passes along `this`, but `myInstance.myMethod` is also allowed and drops `myInstance`. This is efficient if you didn't care about `this`, but can be surprising to beginners and requires more care than in other languages.

To compare these: Python and JavaScript are flexible because they allow dot syntax, i.e. methods as first-class functions. JavaScript and Java are efficient because they don't do an unnecessary allocation unless you opt into it. Python and Java are harder to misuse because they don't provide a syntax for accessing `myMethod` without `myInstance` bound to it.


Douglas Crockford has argued against using "this" for years:

https://vimeo.com/118740253

(start around 35:40)


This (no pun intended) is just a a rehash of the Functional vs Object Oriented Programming debate. And certainly Javascript's ability to do FP is one of Javascript's strengths. But personally, I find OOP to be an excellent metaphors in the web programming world that matches the environment quite well. FP has its place but it's not a magic bullet and even if it is amazing that doesn't mean that other paradigms are never appropriate.


I have found that the best way to avoid any confusion over the use of ‘this’ is to use arrow functions.


This sounds more like a problem with people not knowing how this works in Javascript and not a reason to avoid this altogether.


The "this" problem is already solve by arrow functions.


Oh, fuck off. I'm tired of people who don't get that 'this' is a feature, not a problem. What a skewed perspective of JavaScript some people have gotten over the years :(


[flagged]


It has nothing to do with OOP. Off the top of my head, I cannot think of another OOP language where "this" (or "self") works the way it does in Javascript. There are pitfalls associated with it and I can't think of any benefit that would outweigh that.


I like the "Python/Perl/Probably others" approach of the self object just being passed as the first element to methods. No magic names.


That would be horrible in JS. All functions would have to have an explicit frist parameter that would be often unused, because you don't know how someone will use the function.

function x(obj, param1) {}

class X {}

X.prototype.x = x;

o = new X();

o.x(123);


Well, yes, you would have to only apply it to methods, as Python and Perl do. I'm not suggesting it's practical to graft all that into JS at this point.


JS doesn't have classes and doesn't have methods. Only objects and functions exist in JS.


Hence why it's not practical.


Good luck doing OOP in JS without `this` with minimal contortions. And to be clear, there is no `self` in JS.


I find this comment amusing, considering that Javascript's OOP ideas are descended from Self ( https://en.wikipedia.org/wiki/Self_(programming_language) )


var self = this;


Yes, I know. That doesn't make an assertion about the "pitfalls" of `self` less muddy. It's literally a variable. It's a code smell too, but that's another conversation. Are we calling out variables in JS now? Maybe we should just hold ourselves to bootcamp standards, copy and paste StackOverflow or something like that. Programming is hard, etc.


Why would you want to do OOP in JS?




Applications are open for YC Summer 2019

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

Search: