This can be solved at a language level by making if-else and switch (aka match) expressions. I don't understand why more languages don't do this. It doesn't seem like it would too hard to implement, and C# 8 has shown that it can integrate well an existing C-like language.
Of course some libraries like cheerio require a callback with an available ‘this’ bound into it.
> ({ literalProperty: () => {} }).literalProperty.name
'literalProperty'
> ({ ['computedName']: () => {} }).computedName.name
'computedName'
> const variable = () => {};
> variable.name
'variable'
So if you want to name an arrow function, you can usually assign it to a variable.* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
* https://developer.mozilla.org/id/docs/Web/JavaScript/Referen...
new Error().stack
The following demonstrations take the prior examples and put the stack call into the arrow function bodies and wrap that in an arbitrary function for an additional line in the stack trace output.The first example assigns the arrow function to an object property. And then generates the name of the object's property name. This does nothing to describe the function. Here is a better example:
var stack,a=function(){({ myProperty: () => {stack = new Error().stack;} }).myProperty();};a();stack;
In the browser that outputs: "myProperty@debugger eval code:1:59
a@debugger eval code:1:82
@debugger eval code:1:102
Its a bit more clear in Node's REPL 'Error\n' +
' at Object.myProperty (repl:1:59)\n' +
' at a (repl:1:82)\n' +
' at repl:1:102\n' +
' at Script.runInThisContext (vm.js:120:20)\n' +
' at REPLServer.defaultEval (repl.js:432:29)\n' +
' at bound (domain.js:429:14)\n' +
' at REPLServer.runBound [as eval] (domain.js:442:12)\n' +
' at REPLServer.onLine (repl.js:759:10)\n' +
' at REPLServer.emit (events.js:333:22)\n' +
' at REPLServer.EventEmitter.emit (domain.js:485:12)'
Essentially the stack traces represent a method call as designated by a function whose identity is bound to an object property, but the function itself remains unnamed. The second example is logically identical to the first except for the minor syntax difference of array notation versus a word type variable name.The third example is logically different than the prior two examples:
var stack,a=function(){var myVariable = () => {stack = new Error().stack;};myVariable();};a();stack;
Browser:
"myVariable@debugger eval code:1:51
a@debugger eval code:1:71
@debugger eval code:1:81Node: 'Error\n' + ' at myVariable (repl:1:51)\n' + ' at a (repl:1:71)\n' + ' at repl:1:81\n' + ' at Script.runInThisContext (vm.js:120:20)\n' + ' at REPLServer.defaultEval (repl.js:432:29)\n' + ' at bound (domain.js:429:14)\n' + ' at REPLServer.runBound [as eval] (domain.js:442:12)\n' + ' at REPLServer.onLine (repl.js:759:10)\n' + ' at REPLServer.emit (events.js:333:22)\n' + ' at REPLServer.EventEmitter.emit (domain.js:485:12)'
The output of assigning an arrow function is identical, in both environments, to assigning a regular anonymous function:
var stack,a=function(){var myVariable = function () {stack = new Error().stack;};myVariable();};a();stack;
That is different than assigning to a named function: var stack,a=function(){var myVariable = function myFunctionName() {stack = new Error().stack;};myVariable();};a();stack;
'Error\n' +
' at myFunctionName (repl:1:76)\n' +
' at a (repl:1:96)\n' +
' at repl:1:111\n' +
' at Script.runInThisContext (vm.js:120:20)\n' +
' at REPLServer.defaultEval (repl.js:432:29)\n' +
' at bound (domain.js:429:14)\n' +
' at REPLServer.runBound [as eval] (domain.js:442:12)\n' +
' at REPLServer.onLine (repl.js:759:10)\n' +
' at REPLServer.emit (events.js:333:22)\n' +
' at REPLServer.EventEmitter.emit (domain.js:485:12)'
And both of those are different to anonymous functions not assigned to a variable. Both of the following examples produce the same output: var stack,a=function(){(function () {stack = new Error().stack;}());};a();stack;
var stack,a=function(){() => {stack = new Error().stack;};};a();stack;
'Error\n' +
' at repl:1:46\n' +
' at a (repl:1:65)\n' +
' at repl:1:71\n' +
' at Script.runInThisContext (vm.js:120:20)\n' +
' at REPLServer.defaultEval (repl.js:432:29)\n' +
' at bound (domain.js:429:14)\n' +
' at REPLServer.runBound [as eval] (domain.js:442:12)\n' +
' at REPLServer.onLine (repl.js:759:10)\n' +
' at REPLServer.emit (events.js:333:22)\n' +
' at REPLServer.EventEmitter.emit (domain.js:485:12)'
You can see in the first anonymous function example that an IIFE (immediately invoked function expression) is used. Function's require identity, aside from 3 exceptions, otherwise they throw an error. The three exceptions are arrow functions, IIFE, and function arguments.So much of this discussion is nonsense though, because it doesn't make sense to arbitrarily complicate your code with unnecessary objects merely to provide your anonymous arrow functions with identity. The whole point of arrow functions is to reduce syntax and thereby provide easier to read code, which only the third of those three examples provide.
It is also helpful to understand that a function's name is an identity known to the function, which means it is available to the internal logic of the function as a local reference and not a scoped reference. The identity of a variable name to which a function is assigned will always be a scoped reference, and that distinction also results in different output in stack traces.
Furthermore, none of those examples demonstrates the most important use case, callbacks, or functions as arguments to event handlers. In Node the callbacks become nested very quickly and often times many layers deep. Each use of an arrow function is an anonymous line in the call stack and several layers of anonymous calls is less helpful to read. It's not hopeless because the stack trace provides the location of each call, but you have to dive into the code on each line mentioned to see what is actually happening instead of just reading the function names from a more helpful stack trace.
What I was saying is if you are currently using a named function:
function foo(bar) {
// …
}
you don’t lose the name by making it an arrow function: const foo = bar => {
// …
};
and yes, you can name your callbacks and event handlers like this before passing them to functions. Introducing variables to name values (any values, not just functions) doesn’t really complicate code. Many times, it can be a readability improvement.https://www.artima.com/weblogs/viewpost.jsp?thread=147358
>All Things Pythonic: Language Design Is Not Just Solving Puzzles. By Guido van van Rossum, February 10, 2006.
>Summary:
>An incident on python-dev today made me appreciate (again) that there's more to language design than puzzle-solving. A ramble on the nature of Pythonicity, culminating in a comparison of language design to user interface design.
[...]
http://lambda-the-ultimate.org/node/1298
>Guido: Language Design Is Not Just Solving Puzzles
>And there's the rub: there's no way to make a Rube Goldberg language feature appear simple. Features of a programming language, whether syntactic or semantic, are all part of the language's user interface. And a user interface can handle only so much complexity or it becomes unusable.
>The discussion is about multi-statement lambdas, but I don't want to discuss this specific issue. What's more interesting is the discussion of language as a user interface (an interface to what, you might ask), the underlying assumption that languages have character (e.g., Pythonicity), and the integrated view of semantics and syntax of language constructs when thinking about language usability.
[...]
In the original language design I mean, since non-arrow functions with dynamic "this" only make sense in the context of having been mistakenly baked into the language from day one (or so). If JavaScript started out with only fat arrow functions, and had a simpler way of passing the current object like Python's or CLOS's or Dylan's or ScriptX's explicit "self" parameter, there would have been no confusion or automatic nuclear foot guns or need for two subtly semantically and syntactically different kinds of functions.
Any JavaScript programmer who doesn't clearly understand the difference between non-arrow and arrow functions, and the nuances of dynamically bound "this", and when to use each type of function, is dangerous and libel to write subtly buggy code. Because there should only be one type of function!
There was no reason to design the language and function syntax and semantics in such a mistakenly complex fragile way, that eventually spawned millions of blog posts explaining the nuances and dangers of "this". Because you know that behind every one of those helpful blog posts is a well intentioned programmer who got screwed by "this", and wanted to help other people avoid their mistakes.
I've been programming JavaScript for years, and I STILL get screwed by "this". Whenever something goes inexplicable wrong and I find myself pounding my head up against a cinderblock in frustration because I can't figure it out, I take a step back and search my recent changes for "this", and in most cases, I've just accidentally used a function instead of a fat arrow.
There were plenty of other languages that could have served as examples of the right way to do it, like Smalltalk or Python or Common Lisp CLOS or Dylan, but they were ignored when JavaScript was designed.
It depends. Often you can optimize them out.
Fat arrow functions struck me like one of those half-assed solutions Trump (edit: or Obama) comes up with for a terrible problem of his own creation, a foolish mistake that nobody in their right mind would have ever made in the first place. And then he expects praise for his solution, and nobody remembers he caused the problem it was supposed to solve in the first place.
I agree with the sibling comment by austincheney: JavaScript would have been a much simpler and less bug-prone language if not for "this" being dynamically scoped and magical, which later required nailing fat arrow functions onto the side, that were almost but not quite entirely unlike functions.
Have you ever tried explaining why there are two different kinds of functions in JavaScript to a beginning programmer, and seen their eyes glaze over when you digressed into the nuances of "this", lexical scoping, dynamic scoping, call and apply, closures, and binding functions? You have to understand all that before you truly understand functions in JavaScript, and much of it is irrelevant crap.
Lexical, dynamic, both, or neither? Pick a lane, JavaScript!
>"dynamic this binding is an oft-fired footgun" -Brendan Eich
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.
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.
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.
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.
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-...
>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-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-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/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_functio...
[That link is broken but this one works: 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
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.
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=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
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'You’re also misusing terminology by saying `this` is “dynamically scoped” (it does not have dynamic scope[1], that would be terrible) when documents you’re quoting say “dynamically bound”. The difference is important, which is why three people have corrected you on that now.
[1] https://en.wikipedia.org/wiki/Scope_(computer_science)#Dynam...
Explain just how "this" is lexically scoped, what "lexically scoped" means, and then explain why they had to add fat arrow to the language, if "this" is "just like regular parameters", please?
If "this" is lexically scoped, then why can call and apply change it at runtime?
And how do explain this stackexchange discussion, which directly addresses and answers the question? The detailed answer "yes" got five votes and was accepted. The other answer "no" got one vote and was not accepted. What's your answer?
https://softwareengineering.stackexchange.com/questions/3961...
Question> Is `this` in JavaScript an example of dynamic scoping?
Accepted Answer> To be clear, JavaScript does not, in fact, have dynamic scope. It has lexical scope. Plain and simple. But the this mechanism is kind of like dynamic scope.
>The key contrast: lexical scope is write-time, whereas dynamic scope (and this!) are runtime. Lexical scope cares where a function was declared, but dynamic scope cares where a function was called from.
>Finally: this cares how a function was called, which shows how closely related the this mechanism is to the idea of dynamic scoping.
And you ironically wrote:
>(it does not have dynamic scope[1], that would be terrible)
Whatever you call it and however you define dynamic scope, the dynamic way "this" behaves IS terrible, and undeniably causes lots of easy to make, hard to diagnose bugs. That is why Brendan Eich called it a "footgun". That was my point, and that was why they had to add fat arrow to the language.
8.3.2 GetThisEnvironment ( )
The abstract operation GetThisEnvironment finds the Environment Record that currently supplies the binding of the keyword this. GetThisEnvironment performs the following steps:
1. Let lex be the running execution context’s LexicalEnvironment.
2. Repeat
a. Let envRec be lex’s EnvironmentRecord.
b. Let exists be envRec.HasThisBinding().
c. If exists is true, return envRec.
d. Let outer be the value of lex’s outer environment reference.
e. Let lex be outer.
NOTE The loop in step 2 will always terminate because the list of environments always ends with the global environment which has a this binding.Source: http://www.ecma-international.org/ecma-262/6.0/#sec-getthise...
This is pretty unambiguous. The "this" binding is resolved in the lexical scope, not the dynamic scope.
Yes.
> Explain just how "this" is lexically scoped, what "lexically scoped" means, and then explain why they had to add fat arrow to the language, if "this" is "just like regular parameters", please?
`this` is lexically scoped* because the function it belongs to is determined by where it appears in the code.
Fat arrow was added to the language with this difference because it’s useful to have a function without its own `this`.
> If "this" is lexically scoped, then why can call and apply change it at runtime?
It’s always set at call time. Not a matter of scope. (Parameters: also have values determined at call time, also lexically scoped.)
function a() { return this; }
let obj = {a};
obj.a() === obj
> And how do explain this stackexchange discussion, which directly addresses and answers the question? The detailed answer "yes" got five votes and was accepted. The other answer "no" got one vote and was not accepted. What's your answer?The answer is wrong despite its votes. The comment on it by JacquesB is correct: “This is confusing values and variables. this cares cares how a function is called the same way parameters care how a function is called - they get their value at runtime when the function is called. But the scope of all variables (including this) is lexical and not dynamic.”
> Whatever you call it and however you define dynamic scope, the dynamic way "this" behaves IS terrible, and undeniably causes lots of easy to make, hard to diagnose bugs. That is why Brendan Eich called it a "footgun". That was my point, and that was why they had to add fat arrow to the language.
I disagree, but am mostly here to argue against objectively wrong information rather than opinions.
* in contrast to dynamically scoped. In JavaScript it’s also common to use “lexical scope” in contrast to “function scope” to distinguish `let`/`const` vs. `var`. In the JavaScript spec, the lexical thisMode refers to where the (arrow) function appears, not the position of the `this`.
Reality check: Are we even talking about the same language? I'm talking about JavaScript. Which language are you talking about, C++? If you're not talking about JavaScript, then you replied to the wrong comment. Or are you just trolling and gaslighting, because you were offended by the Trump reference? I'll give you the benefit of the doubt that you're also referring to JavaScript, and that you sincerely believe what you say, because you need to change your beliefs.
Please go read any elementary JavaScript tutorial, or any of the thousands of blog posts by people who got screwed by accidentally mis-understanding for a moment and mistakenly thinking that "this" was lexically scoped, then got burnt, but learned from the experience, and wanted to share with everyone else what they learned by shooting themselves with an "oft-fired footgun": "this" is dynamically scoped, and changes meaning at runtime, regardless of the surrounding lexical environment in which it was defined, UNLESS you use fat arrow functions, which were specifically designed to work around that problem.
If "this" behaved like an implicit parameter with lexical scope, then why did they bother adding fat arrow functions to the language as an afterthought, to work around the problem you don't seem to believe exists?
One more time, I will quote the rationale section of Brendan Eich's fat arrow proposal:
https://tc39wiki.calculist.org/es6/arrow-functions/
>"dynamic this binding is an oft-fired footgun" -Brendan Eich, ES6 Arrow Functions Proposal
If you're right, then Brendan Eich, Douglas Crockford, Anders Hejlsberg, many other expert designers and programmers of JavaScript and TypeScript, and a whole lot of other people, are also extremely confused:
https://www.forumone.com/ideas/typescript-application-scale-...
>TypeScript borrows some features from the upcoming ECMAScript 6 specification, too. There is convenience syntax for day-to-day programming tasks, such as the arrow function, borrowed from CoffeeScript. The arrow function, which looks like this: (foo, bar) => baz, is shorthand notation for (function (foo, bar) { return baz; }).bind(this). This automatically captures the current value of “this” in scope, which is more often than not what you want. The proposal even states “dynamic this binding is an oft-fired footgun.”
http://jsnext.blogspot.com/2012/07/arrow-functions.html
>Arrow Functions are lexically bound to the 'this' of where it is declared. In other words, when an Arrow Function is declared, whatever the scope is at that time, that is 'this'. [...] Why add Arrow Functions? Why add this? We already understood what was going on... so why change it? I think that Brendan Eich has provided a great list of reasons ('Rationale' section): [...] However, we don’t want CoffeeScript’s ->, it’s confusing to have two arrows and dynamic this binding is an oft-fired footgun.
What exactly do you believe Brendan Eich meant by "dynamic this binding"? How can "this" be dynamically bound, yet behave "like an implicit parameter with lexical scope" (as you wrongly claim) at the same time?
Is Brendan Eich and everyone else in the JavaScript and TypeScript communities mistaken, and they foolishly added fat arrow functions to JavaScript for no reason, but nobody pointed out that embarrassing mistake until you came along?
If you're right, then you're barking up the wrong tree by arguing with me about it, so by all means, get on Twitter and tell Brendan Eich himself, ASAP! Your argument is with him and everyone else, not me. Maybe it's not too late to turn that ship around, but in my opinion it's already sailed.
But if you're wrong, then you probably have a lot of bugs to fix in your code, and should stay off Twitter.
If you truly believe in your heart of hearts that "this" is lexically scoped, you have definitely proven my and Brendan's point that "this" is a terrible "oft-fired footgun" that causes lots of deep confusion and insidious misunderstanding: just take a step back and look at how sure you are of yourself. Because "this" is certainly more mysterious and dangerous than YOU believe it is.
Dynamic scope means something different. Dynamic scope means that a variable binding from the call site is visible in a called function and down the call stack. This is not how "this" works. The "this" binding at the call site is never visible inside the called function, unless the called function happen to be nested inside the same lexical scope.
"this" is confusing because it gets rebound at every call, even if the function is not called using dot expression. But it is not because of dynamic scoping.
C++ is designed to compile to an implementation of an abstract virtual machine defined by the standard.
https://en.wikipedia.org/wiki/Leaky_abstraction
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
>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-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.
"Please don't use Hacker News for political or ideological battle. That destroys the curiosity this site exists for."