5 ms·
Do you mean you wouldn’t have named it “this”? Because if `this` weren’t set by the means of calling in ES5 and earlier, it would have no point at all.
by minitech 7y ago
Do you mean you wouldn’t have named it “this”? Because if `this` weren’t set by the means of calling in ES5 and earlier, it would have no point at all.
- DonHopkins 7y agoIt doesn't matter what it's named. It matters how it's passed. Python, Common Lisp CLOS, ScriptX, even NeWS's object oriented PostScript, all pass "self" as a first explicit parameter. C++ does it behind the scenes, but it's just a hidden parameter, not a property of the hidden "virtual machine", because C++ doesn't have a virtual machine. But if you look at the C code generated by the CFront C++=>C compiler, you will see that every method has an explicit first "this" parameter whose type is the class it's defined in. The way "this" is defined in JavaScript unnecessarily exposes the internal implementation details of the first JavaScript interpreter, which all subsequent JavaScript interpreters and compilers then had to be compatible with. Simply knowing about normal function parameters and lexical binding like in Python is not enough: There is an invisible a VM interpreter thread somewhere that you have to know about, which has a "this" property (or "horrible global object", as Douglas Crockford puts it), and the only way to change it is indirectly through method applications with ".", or by using call and apply. So JavaScript "this" is a magic keyword, not just a normal parameter like all the rest. In the same way JavaScript "arguments" is magic, not just a normal argument like Python or Lisp &rest arguments. And this needlessly adds to the complexity and surface area of the language, and bakes in unwanted behaviors like dynamic binding, when most of the civilized world agrees that lexical binding is superior, less surprising, and easier to reason about, and dynamic binding should be the exception that you have to go out of your way to use, not the default behavior for the implicit first argument of every method or function.
- minitech 7y ago> Simply knowing about normal function parameters and lexical binding like in Python is not enough: There is an invisible a VM interpreter thread somewhere that you have to know about, which has a "this" property, and the only way to change it is indirectly through method applications with ".", or by using call and apply. So "this" is not just a normal parameter like all the rest. That sounds like an unnecessarily complicated and possibly wrong way to think about it. `this` acts exactly like a parameter in ES5 strict mode (`x.f()` being `f.call(x)` and `f()` being `f.call(undefined)`), and does not act like dynamic binding.
- DonHopkins 7y agoAnd ES5 strict mode was retroactively designed in 2008, in a way that had to maintain backwards compatibility with the mistakes of 1997, 11 years earlier. By then the mistake was already irreversibly baked deeply into the language. JavaScript will always suffer from that mistake, no matter how much they try to paper over it with strict mode or TypeScript. It's way too late to remove non-fat-arrow functions from JavaScript, so they will always be a foot gun, whether or not you're using strict mode. If you define a non-fat-arrow function and mention "this", and then pass it out to somebody you don't know or have any control over or contact with, who calls that function without going out of their way to properly bind it with call or apply, then they will be screwed.
- minitech 7y agoI don’t think it’s a mistake. I think it’s a sensible design choice (after strict mode disconnected it from the actual misfeature that is primitive wrappers). There are arguments to be made that it’s confusing coming from other languages given that it acts nothing like their “this”es, but I’m not sure that “properties of invisible VM interpreter threads” are related at all.
- DonHopkins 7y agoIf "this" wasn't a mistake and a loaded footgun, then why did Brendan Eich himself literally say that "dynamic this binding is an oft-fired footgun" in the "Rationale" section of his original fat "Arrow Functions" proposal? And why did Douglas Crockford say "this" was "horrible", and that ES5/strict mode was "much less wrong than binding the global object, but is still not right"? And why is "this" always showing up as #1 in the lists of "10 Most Common JavaScript Mistakes"? https://www.toptal.com/javascript/10-most-common-javascript-mistakes https://www.toptal.com/javascript/10-most-common-javascript-... >Buggy JavaScript Code: The 10 Most Common Mistakes JavaScript Developers Make >Common Mistake #1: Incorrect references to this >I once heard a comedian say: >I’m not really here, because what’s here, besides there, without the ‘t’? >That joke in many ways characterizes the type of confusion that often exists for developers regarding JavaScript’s this keyword. I mean, is this really this, or is it something else entirely? Or is it undefined? >As JavaScript coding techniques and design patterns have become increasingly sophisticated over the years, there’s been a corresponding increase in the proliferation of self-referencing scopes within callbacks and closures, which are a fairly common source of “this/that confusion”. https://javascriptissexy.com/understand-javascripts-this-with-clarity-and-master-it/ https://javascriptissexy.com/understand-javascripts-this-wit... >Understand JavaScript’s “this” With Clarity, and Master It >(Also learn all the scenarios when this is most misunderstood.) >The this keyword in JavaScript confuses new and seasoned JavaScript developers alike. This article aims to elucidate this in its entirety. By the time we make it through this article, this will be one part of JavaScript we never have to worry about again. We will understand how to use this correctly in every scenario, including the ticklish situations where it usually proves most elusive. https://dev.to/joelnet/rethinking-javascript-the-complete-elimination-and-eradication-of-javascripts-this-3m3j https://dev.to/joelnet/rethinking-javascript-the-complete-el... >Rethinking JavaScript: The complete elimination and eradication of JavaScript's this. >If this is so difficult to reason about, why don't we just stop using it? Seriously. Why. don't. we. just. stop. using. it.? >If you have read How I rediscovered my love for JavaScript after throwing 90% of it in the trash, then you won't be surprised when I say I am throwing this away. this is gone. goodbye. this won't be missed. >With functional JavaScript, you will almost never see this. I say almost never because even though your code doesn't contain this, you have little control over 3rd party libraries. Popular libraries like React, jQuery, eventemitter2 and many others will force this down your throat. >Here are some examples of how libraries force us to use this. [...] https://softwareengineering.stackexchange.com/questions/306082/why-doesnt-es6-have-thin-arrow-functions https://softwareengineering.stackexchange.com/questions/3060... >Why doesn't ES6 have thin-arrow functions? >See the proposal to add arrow functions: http://wiki.ecmascript.org/doku.php?id=harmony:arrow_function_syntax1 http://wiki.ecmascript.org/doku.php?id=harmony:arrow_functio... [That link is broken but this one works: https://tc39wiki.calculist.org/es6/arrow-functions/ https://tc39wiki.calculist.org/es6/arrow-functions/ ] >What it says is: >However, we don’t want CoffeeScript’s ->, it’s confusing to have two arrows and dynamic this binding is an oft-fired footgun. That's right: the original fat arrow proposal championed by Brendan Eich himself literally called "dynamic this binding" an "oft-fired footgun", citing it as the rationale to justify the design of fat arrow functions. That comes directly from the horse's mouth. Do you really disagree with Brendan Eich on that point? More interesting discussion about this and that: Douglas Crockford on Fat Arrow Functions in JavaScript (yuiblog.com) https://news.ycombinator.com/item?id=3780367 https://news.ycombinator.com/item?id=3780367 What is the meaning of this? https://yuiblog.com/blog/2012/03/30/what-is-the-meaning-of-this/ https://yuiblog.com/blog/2012/03/30/what-is-the-meaning-of-t... >JavaScript is an amalgam of good parts and bad parts. Its best parts came from Self (prototypes) and Scheme (lexically scoped nested functions). But the interaction of those two very good parts produced some bad parts. >When a function is called with the function invocation pattern, its this is not bound to the outer function's this as we would hope, but is instead bound to the global object, which is horrible. (ES5/strict binds the inner function's this to undefined, which is much less wrong than binding the global object, but is still not right.) The workarounds for this include the use of bind functions and riddles like >var that = this; I could go on. There are literally THOUSANDS of blog posts by people who got screwed by "this", and then posted about it to warn other people not to make the same mistake they did.
- saagarjha 7y ago> C++ doesn't have a virtual machine C++ is designed to compile to an implementation of an abstract virtual machine defined by the standard.
- DonHopkins 7y agoC++ certainly doesn't have a concrete virtual machine in the way JavaScript does, and C++'s abstract virtual machine certainly doesn't expose as many irrelevant implementation details of that virtual machine as JavaScript does. JavaScript's abstractions are much leakier than C++'s. https://en.wikipedia.org/wiki/Leaky_abstraction https://en.wikipedia.org/wiki/Leaky_abstraction https://www.joelonsoftware.com/2002/11/11/the-law-of-leaky-abstractions/ https://www.joelonsoftware.com/2002/11/11/the-law-of-leaky-a... Don't get what I mean by leaky abstractions? Take non-fat-arrow functions for example. They're more expensive than fat-arrow functions, because they have a "prototype" property. And that's used to IMPLEMENT JavaScript's weird quirky form of object oriented programming, by giving you yet another way to call that function with "new" to create an object using that prototype, in a way that makes it a dangerous mistake to call that function the normal way without "new" (by sorta working on the surface usually without throwing an error, but causing deep subtle hard to diagnose bugs). That is yet another double barreled footgun, thanks to a leaky abstraction with functions and "new": mistakenly calling a JavaScript class directly instead of using "new", or mistakenly calling "new" on a non-class function or fat arrow function, which doesn't have a prototype and can't be used as a class. Non-fat-arrow functions and "new" are like a footgun whose barrel is bent around aiming at the head of person who's shooting it. Fat-arrow functions don't solve the problem or eliminate the footgun, they merely add another barrel to the gun, aimed directly at your foot, too. So if you can't directly call or apply a class function that has a prototype like a normal function, then why the hell is it a function anyway, instead just being a class like most other oop languages have, and why the hell does that irrelevant feature of functions having an optional prototype force that overhead on ALL the other functions in the system, whether or not they need it, even if you're using purely functional programming without objects? That was one of the original rationals for fat arrow functions, as well as papering over the dynamic "this" binding mistake: to get rid of the overhead of the function prototype link, since non-class-constructor functions were so predominantly common. But they didn't bother to fix the obnoxious quirk about overloading functions with behaving like classes, but having to call them differently with "new", instead of simply having classes that were not callable functions, and being able to support multiple constructors with different names and signatures, like so many other object oriented programming languages do (but which JavaScript can't support, since class === function === constructor, there can only be one constructor per class by definition). Conflating functions and classes and constructors is just insane, a pointless mistake and implementation detail with no upside and many downsides. That's what I call a functionally classic leaky abstraction. ;) https://news.ycombinator.com/item?id=3780748 https://news.ycombinator.com/item?id=3780748 >mattbriggs on Mar 31, 2012 | parent | favorite | on: Douglas Crockford on Fat Arrow Functions in JavaSc... >the this keyword still works exactly the same, just a terse syntax for functions and for function binding to the current scope. >currently, function(){} is the exact same as the proposed ()->{}, and (function(){}).bind(this) is the exact same as ()=>{} >starwed on Mar 31, 2012 [-] >This is not just about syntax. Unless using bind somehow grants the mentioned property that >>"Fat arrow functions do not have prototype properties, which makes them cheaper to make. They are immutable." [That was quoting Douglas Crockford: https://yuiblog.com/blog/2012/03/30/what-is-the-meaning-of-this/ https://yuiblog.com/blog/2012/03/30/what-is-the-meaning-of-t... ] >mattbriggs on Mar 31, 2012 [-] >granted, but that sounds more like a micro optimization rather then significantly changing the behavior of the language Perl originally had the exact same problem of leaky abstractions, only much much worse. The language design was deeply defined by nothing more than the one implementation of the Perl interpreter itself. There was no "abstract virtual machine" design written down. There was only the source code to the one existing implementation of Perl. You had to understand many trivial details about how that one Perl interpreter just happened to be implemented, in order to truly understand Perl. (Try explaining Perl references without making all kinds of nuanced excuses and implicit references to how the Perl interpreter itself works.) It took Perl (or whatever the kids are calling it these days) decades and decades to dig its way out of that hole, and by the time they did, it was irrelevant. JavaScript got a lot luckier.
- rienbdj 7y agoI've written large js projects without using 'this'. Crisis averted, world saved.
- goto11 7y agoIt has nothing to do with dynamic binding. "this" has lexical scope just like regular parameters. I agree 'this' is confusing, but you are making it sound more mysterious than it is. It is just some syntactic sugar around an implicit first parameter.
- DonHopkins 7y agoNope. "this" is formally defined as a keyword in the JavaScript syntax, not a variable, not a property name, not an identifier, and not syntactic sugar, since there is no source level transformation you can make that behaves the same (like with C++, the way CFront translated "this" into an actual first parameter). JavaScript's "this" is magic, that's why it has to be a keyword, not a variable. It looks like a variable, and it kind of but not really behaves like an implicit first parameter in some circumstances, but that's not really what's going on at all. And that is the danger, and source of misunderstanding and bugs: it looks like something that it's not. For one thing, you can't assign to "this" like a variable. For another thing, "this" doesn't show up in "arguments" (which is also magic). If you think "this" is not mysterious and just a normal but implicit argument, you don't really understand it. Which is my point: "this" is such a terribly designed language feature that even experienced JavaScript programmers misunderstand it, and it causes subtle hard to find bugs, even for experienced JavaScript developers. It's not just mysterious, it's dangerous. https://books.google.nl/books?id=4RChxt67lvwC&pg=PA169&lpg=PA169&dq=%22Note+that+this+is+a+keyword,+not+a+variable+or+property+name.+JavaScript+syntax+does+not+allow+you+to+assign+a+value+to+this.%22&source=bl&ots=ti16DhFWo9&sig=ACfU3U3PKQUh_RnM1VwI4DZYXPAsxz8lyg&hl=en&sa=X&ved=2ahUKEwjoyO-56L3oAhWFyqQKHV5ED2AQ6AEwAHoECAoQAQ#v=onepage&q=%22Note%20that%20this%20is%20a%20keyword%2C%20not%20a%20variable%20or%20property%20name.%20JavaScript%20syntax%20does%20not%20allow%20you%20to%20assign%20a%20value%20to%20this.%22&f=false https://books.google.nl/books?id=4RChxt67lvwC&pg=PA169&lpg=P... >JavaScript: The Definitive Guide >Note that this is a keyword, not a variable or property name. JavaScript syntax does not allow you to assign a value to this. >Unlike variables, the this keyword does not have a scope, and nested functions do not inherit the this value of their caller. [...] Here is how "this" is explicitly defined as a keyword in the JavaScript BNF grammer, in this example as the very first option of PrimaryExpression. Definitely not a variable or Identifier. Quite magic. No other "variable" name is defined as a top level PrimaryExpression. "this" is very special. https://tomcopeland.blogs.com/EcmaScript.html https://tomcopeland.blogs.com/EcmaScript.html PrimaryExpression ::= "this" | ObjectLiteral | ( "(" Expression ")" ) | Identifier | ArrayLiteral | Literal You can even ask devtools for its opinion: >var this = 1; VM2547:1 Uncaught SyntaxError: Unexpected token 'this'