News for hackers. Stuff that matters.
Re:How JavaScript Works: deep dive into call, apply, and bind by bluepnume on Friday July 09, 2021 @05:42PM (#27788865)
Call, bind and apply should be discarded and forgotten about, they add too much confusion, there are better ways, and they end up being used as terrible interview questions.

Incidentally, we should also discard `this`, unless directly inside an instance method of a class.

Re:How JavaScript Works: deep dive into call, apply, and bind by JoeCortopassi on Friday July 09, 2021 @07:15PM (#27789572)
Every language has parts that are harder to understand because they unlock the deep magic.

If you really haven't found a use case for call/apply/bind, or are confused by `this`, it's more likely that your focus has been on thin-client user facing applications for most of your career. These language features are invaluable for tool building, and are foundational to most of the tools you probably leverage to make thin-client user facing apps

NOTE: most developers work in thin-client user facing applications, that's not a dig or anything, it's just where 99% of the work exists

Re:How JavaScript Works: deep dive into call, apply, and bind by bluepnume on Friday July 09, 2021 @07:20PM (#27789598)
I've worked full-stack in javascript for many years, and I've written plenty of libraries and tooling. I've used call/apply/bind/this extensively and I understand them to a fault.

I would still remove them in favor of arrow functions and spreads. Unless you can show me any code which is pivotal to writing some tool which absolutely can not be done using the alternatives.

Re:How JavaScript Works: deep dive into call, apply, and bind by asiachick on Friday July 09, 2021 @08:04PM (#27789838)
arrow functions and spread do not cover all use cases of call/apply/bind

proxies and wrappers are two areas where you need call because you need be able able to pass the correct "this" which arrow functions will fail to do

Re:How JavaScript Works: deep dive into call, apply, and bind by munchbunny on Saturday July 10, 2021 @12:54AM (#27791220)
Yup in terms of patterns that are easier/harder to understand, I much prefer arrow functions over bind and map/forEach over apply. And explicit function parameters over call though how to replace call is often contextual.

It’s not that I inherently think call/apply/bind are bad (JS programmers should understand them), it’s just that they are old JS-isms and arrow functions/map/forEach/etc. follow pretty consistent conventions across multiple programming languages (readability) and with JS compilers you mostly don’t have to explicitly write JS in the old way any more.

It’s kind of like using malloc/variants in C++, you should be able to understand it, but you mostly shouldn’t need it in new code.

Re:How JavaScript Works: deep dive into call, apply, and bind by lhorie on Friday July 09, 2021 @09:00PM (#27790183)
Detecting that a value is an Object as opposed to an Array/Arguments/etc (or more generally, reading the StringTag of a value) still requires a toString.call(value) AFAIK.

This is still used a lot in recursive polymorphic code like virtual dom, AST traversal, deep cloning, etc.

Re:How JavaScript Works: deep dive into call, apply, and bind by JoeCortopassi on Friday July 09, 2021 @07:31PM (#27789649)
`Array.prototype.slice.call(arguments)` is a good example. In fact, I'm struggling to think why you would replace anything other than bind with an arrow function

EDIT: My example is bad, you could just `[...arguments]`

Re:How JavaScript Works: deep dive into call, apply, and bind by bluepnume on Friday July 09, 2021 @07:32PM (#27789654)
`Array.prototype.slice.call(arguments)` can be replaced with `Array.from(arguments)` (or as you mentioned `[ ...arguments ]`)
Re:How JavaScript Works: deep dive into call, apply, and bind by megous on Saturday July 10, 2021 @08:07AM (#27792817)
It's a pointless argument. These can't be removed from the language, without breaking a lot of code.
Re:How JavaScript Works: deep dive into call, apply, and bind by jffry on Saturday July 10, 2021 @08:43AM (#27792986)
They can't be removed from the language, sure, but we can benefit by shunning the bad parts of the language, and using newer additions that are easier to reason about.

When's the last time you considered using a with(x){} block in JS? Would you still use var instead of let or const?

Re:How JavaScript Works: deep dive into call, apply, and bind by megous on Sunday July 11, 2021 @06:55PM (#27805162)
Quite a few years since I used `with` the last time. Not going back to that one.

`call/apply/bind` are normal functions though, not some fancy syntax construct, and `this` is important if you want to play with prototypes/Object.create, which is what you want to do if you found class syntax sugar lacking in features/extensibility/overrideability.

Re:How JavaScript Works: deep dive into call, apply, and bind by BlissWaves on Friday July 09, 2021 @10:36PM (#27790681)
>I would still remove them in favor of arrow functions and spreads.

Entire Javascript needs to be removed in favor of some other language. It's literally garbage. Callback hells, prototypal inheritance, constant new features ala async/await, Promises and a new framework every 2 years. It's not even a functional langauge just some features of functional language. Endless introduction of new syntactic sugar to cover up the old fuck-ups and weird behavior on every corner.

Re:How JavaScript Works: deep dive into call, apply, and bind by conqueso on Saturday July 10, 2021 @09:15AM (#27793151)
I hear this sentiment pretty often but don't really get it. New features like async/await and Promises are added so that we don't have to do things the old/bad/confusing way any more - isn't that a good thing? Tools like linters and Typescript make it much easier to avoid the various 'old fuck-ups' and 'weird behavior'.
Re:How JavaScript Works: deep dive into call, apply, and bind by porknubbins on Saturday July 10, 2021 @12:07AM (#27791031)
There is something slightly demoralizing about writing JS as if because of the language itself there is cruft, ugly workarounds, and type confusion from day one instead of developing over time. That said I find it effective and doubt it will ever be replaced by a more pure clean language.
Re:How JavaScript Works: deep dive into call, apply, and bind by golergka on Friday July 09, 2021 @09:41PM (#27790390)
You might not want to use magic not because you don't understand it, but because you don't want to rely on the future maintainer understanding it.

If you want to write future-proof software, you have to do it as simple as possible.

Re:How JavaScript Works: deep dive into call, apply, and bind by userbinator on Saturday July 10, 2021 @01:56AM (#27791446)
Assuming that future programmers will be less intelligent is a dangerous self-fulfilling prophecy.

Then again, I think we're already well on that path with some languages' ecosystems... if you don't want your jobs replaced by idiots, maybe you should not write code for idiots.

Re:How JavaScript Works: deep dive into call, apply, and bind by cj on Friday July 09, 2021 @06:05PM (#27789052)
> should be discarded and forgotten about, they add too much confusion

How does it add confusion?

Bind, call and apply are fairly straightforward and not difficult concepts to grasp for any mid to advanced level JS dev and they're useful in many scenarios (although bind is less useful / less needed now that we have arrow functions, but call and apply are definitely not something to be "discarded").

Re:How JavaScript Works: deep dive into call, apply, and bind by Arnavion on Friday July 09, 2021 @06:19PM (#27789162)
`call` and `apply` can also be replaced with arrow functions and splats.
Re:How JavaScript Works: deep dive into call, apply, and bind by hajile on Friday July 09, 2021 @06:23PM (#27789193)
How would you replace the classic `Array.prototype.map.call($nodeList, myFn)` with arrows and splat?
Re:How JavaScript Works: deep dive into call, apply, and bind by lhorie on Friday July 09, 2021 @07:41PM (#27789708)
> The Array.from() static method creates a new, shallow-copied Array instance from an array-like or iterable object[0]

So, do this instead:

    Array.from($nodeList, myFn)
[0] https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
Re:How JavaScript Works: deep dive into call, apply, and bind by merrywhether on Saturday July 10, 2021 @12:16AM (#27791071)
I never knew this mapping variation of Array.from, that is slick!

Also serves as a great example of how JS is standardizing useful patterns that were previously accomplished via bending the language a bit.

Re:How JavaScript Works: deep dive into call, apply, and bind by guntars on Friday July 09, 2021 @06:53PM (#27789439)
You should forget about that too. It's applying a function from one object to something else that it wasn't designed for. It happens to work in this case because $nodeList and Arrays are both array-like, but that's a lucky happenstance.
Re:How JavaScript Works: deep dive into call, apply, and bind by sgentle on Saturday July 10, 2021 @03:18AM (#27791713)
Array prototype methods are designed to be applied to other objects. There's explicit language about it dating back to the first edition of the ECMAScript spec: "The map function is intentionally generic; it does not require that its this value be an Array object. Therefore it can be transferred to other kinds of objects for use as a method."
Re:How JavaScript Works: deep dive into call, apply, and bind by guntars on Sunday July 11, 2021 @10:21PM (#27806263)
Yep, I just looked it up and it does indeed say that, at least for the 2016 version when all of these features were introduced. Fine! Carry on applying your maps to your non-Arrays!

Personally I think Array.of($nodeList).map(…) should be guaranteed to allocate once and then there’d be no more discussion here.

https://262.ecma-international.org/7.0/#sec-array.prototype....

Re:How JavaScript Works: deep dive into call, apply, and bind by bluepnume on Friday July 09, 2021 @07:39PM (#27789696)
Right. If NodeList is compatible with Array methods, it honestly feels like it should just inherit those methods. Or implement them separately.
Re:How JavaScript Works: deep dive into call, apply, and bind by megous on Saturday July 10, 2021 @08:10AM (#27792827)
You can just copy them to NodeList prototype.
Re:How JavaScript Works: deep dive into call, apply, and bind by nicoburns on Friday July 09, 2021 @06:31PM (#27789252)
You could do it like this:

    const mapNodeList = (...nodeList) => nodeList.map(myFn);
    mapNodeList(...$nodeList)
Re:How JavaScript Works: deep dive into call, apply, and bind by kevincox on Friday July 09, 2021 @07:06PM (#27789524)
Or simply [...nodeList].map()
Re:How JavaScript Works: deep dive into call, apply, and bind by moron4hire on Friday July 09, 2021 @08:13PM (#27789883)
I don't think you can use splats with a NodeList. At least, the TypeScript compiler complains about it.
Re:How JavaScript Works: deep dive into call, apply, and bind by webstrand on Friday July 09, 2021 @10:53PM (#27790748)
`[ ...document.body.childNodes ]` is legal. You need to have the `DOM.Iterable` enabled in your compilerOptions.libs` for TypeScript to permit it, though.
Re:How JavaScript Works: deep dive into call, apply, and bind by edflsafoiewq on Friday July 09, 2021 @09:37PM (#27790374)
Works for me. Splats work for any iterable.
Re:How JavaScript Works: deep dive into call, apply, and bind by hajile on Friday July 09, 2021 @06:36PM (#27789287)
That creates an entire extra list of garbage.
Re:How JavaScript Works: deep dive into call, apply, and bind by lhorie on Friday July 09, 2021 @07:28PM (#27789635)

    const mapNodeList = (...nodeList) => nodeList.map(myFn);
    mapNodeList(...$nodeList)
Garbage collection really isn't the biggest of concerns here considering this code is susceptible to a stack overflow...
Re:How JavaScript Works: deep dive into call, apply, and bind by chrisseaton on Friday July 09, 2021 @06:42PM (#27789337)
Doesn’t the compiler optimise it away?
Re:How JavaScript Works: deep dive into call, apply, and bind by hajile on Friday July 09, 2021 @06:57PM (#27789470)
Those aren't the same types. One is a DOM array and the other is a JS array. They don't share the same constructor or the same prototype chain.
Re:How JavaScript Works: deep dive into call, apply, and bind by Arnavion on Friday July 09, 2021 @06:47PM (#27789380)
If the goal is to call functions on things whose prototype does not define them, then yes arrow functions cannot replace `call` and `apply`. They can't replace `bind` in such a situation either, but the precondition of this subthread was where `bind` can be replaced with an arrow function, ie the bound function is being called on the same `this` in the first place.
Re:How JavaScript Works: deep dive into call, apply, and bind by Jcampuzano2 on Friday July 09, 2021 @06:31PM (#27789254)
You can do it without either of those with this:

Array.from(nodeList$).map(myFunc)

or if you want to spread

[...nodeList$].map(myFunc)

Re:How JavaScript Works: deep dive into call, apply, and bind by hajile on Friday July 09, 2021 @06:37PM (#27789303)
That creates a new array that must be GC'd.
Re:How JavaScript Works: deep dive into call, apply, and bind by afavour on Friday July 09, 2021 @07:01PM (#27789489)
Is there actually a performance hit, though? Smells like premature optimisation to be worrying about this over readable code until you’ve profiled the actual effects.
Re:How JavaScript Works: deep dive into call, apply, and bind by hajile on Friday July 09, 2021 @07:27PM (#27789633)
yes, there is a performance hit.

In this case, the code size is about the same if you run as-is (if you're doing DOM manipulation, performance is likely a real concern). I'd agree it would be premature optimization if we were talking about moving from a map to a full-blown loop or something, but it's hardly a huge change.

Another great example is chaining myarr.filter().filter().map().map() or some such that I sometimes see. Lodash shortcuts normal map with the assumption of arrays without holes and then uses their own iterators to avoid multiple copies. This results in a huge performance boost.

A final consideration here is transpiling. The above methods would actually increase the code size quite a bit trying to work around any edge cases and hit performance even more.

"Premature Optimization" is always a matter of opinion. Some people might consider implementing quicksort instead of bubble sort to be a premature optimization. Others might disagree with me and believe that you should always use loops instead of forEach or map. In any case, this is hardly the only case for using call/apply.

Re:How JavaScript Works: deep dive into call, apply, and bind by afavour on Friday July 09, 2021 @07:50PM (#27789761)
Obviously there is a performance hit, my point is whether that hit is noteworthy at all. JavaScript VMs are incredibly efficient and have all manner of optimisations that aren’t apparent at first sight. Absent profiling data we can’t know and any best practises are really just shooting in the dark. For example: is Array.prototype.map just as efficient on non-arrays? What does it do internally, do we know it doesn’t create an array anyway?
Re:How JavaScript Works: deep dive into call, apply, and bind by Jcampuzano2 on Friday July 09, 2021 @06:47PM (#27789385)
Sure if you want to get nitty gritty, but you just asked how to replace it in the context of someone saying you can go without call and apply, which both of these do with the same input and output.

Unless your nodelist is insanely large, this is going to be a trivial GC to perform.

Re:How JavaScript Works: deep dive into call, apply, and bind by IggleSniggle on Friday July 09, 2021 @09:14PM (#27790259)
You know, people say stuff like this a lot, and I used to believe it.

But the web just feels like it’s getting slower, grinding up CPU. I think in aggregate, this stuff does matter and it’s just wishful thinking to say it doesn’t.

It’s like at some point as a profession we took the mantra of “don’t prematurely optimize” as an excuse.

Honestly, js feels like a much better language today, especially with ts, and hopefully there are improvements that can be made with modern approaches at the JIT layer, but until then, I’d love it if we could just have a more performant web. It might not matter to you on your powerful dev machine, but it does to me now that I’ve given up the powerful dev machine.

Re:How JavaScript Works: deep dive into call, apply, and bind by gassiss on Friday July 09, 2021 @09:42PM (#27790402)
any loop in a few hundred elements is going be trivial regardless of the amount of work you do.

I don't think the web is getting slower because we're using more map() instead of for...of loops. It's getting slower because what is being developed is getting more complex.

Feature bloat and excessive network load are the main reasons that the web feels slower imo.

Re:How JavaScript Works: deep dive into call, apply, and bind by IggleSniggle on Friday July 09, 2021 @10:24PM (#27790634)
I’m not sure this is a true disagreement is what I’m saying.

I can tell you that when I navigate around the web doing nothing more than having some web apps open, the UI for the whole OS will start stuttering and the fans will kick into action. `top` says this is all chrome.

I buy that the problem is “feature bloat,” but I also think a great deal of these features are possible with a heck of a lot less code and a heck of a lot less pointless GC etc.

.filter().map() may not itself be alarming for a few hundred elements…but it is for a few hundred elements multiplied by a few hundred features. If you still want those few hundred features, maybe it would be nice if some thought had gone into making them individually perform better.

Tangent: I love the Unix philosophy! Do one thing well. Nothing more satisfying than being able to pipe inputs to outputs and put together little programs out of modular components. But when you want to build a program, you don’t do that, because you care about the “well” part of “do one thing well.”

Context does matter for a lot of this, and I think there’s probably a lot of grey area here. Doing something high level? Whatever, just get the job done, focus on readability, don’t worry about the weird performance edges of it. It’s just that those chunks have a tendency to become bigger chunks and get included where they were never intended, or where their underlying implementation is accidentally replicated multiple times for slightly different outputs (in the abstract, like doing .map().map().map()).

Anyway I can tell I’m losing the thread and ranting mindlessly now…

Re:How JavaScript Works: deep dive into call, apply, and bind by bluepnume on Friday July 09, 2021 @07:27PM (#27789630)
The fact that NodeList doesn't have a native map feels to me like a wart, and doesn't really justify `Array.prototype.map.call` having to exist as a fallback in the language.
Re:How JavaScript Works: deep dive into call, apply, and bind by greggman3 on Saturday July 10, 2021 @04:46AM (#27792070)
no they can not.

arrow binds a different "this" than call and apply. Call and apply get the this passed in at call time. Arrow gets the this at creation time.

Re:How JavaScript Works: deep dive into call, apply, and bind by Arnavion on Saturday July 10, 2021 @05:21AM (#27792210)
Re:How JavaScript Works: deep dive into call, apply, and bind by user3939382 on Friday July 09, 2021 @06:00PM (#27789008)
I figure there’s 3 possibilities: I’m just dumb, I don’t use it enough, or JavaScript is poorly designed. For some reason, even after 20 years of using JavaScript on and off and reading a dozen books about it, I can’t articulate exactly how the language works, how scope is evaluated, the composition of objects and prototypes which has some kind of turtles-all-the-way-down thing going on with it. When I read explanations in books it’s like hmm ok.. I guess that makes sense. Then a week later I don’t remember. The languages I’ve spent the most time with are SQL, PHP, Bash, and Clojure, and I never felt that way about them. Maybe it’s just me.
Re:How JavaScript Works: deep dive into call, apply, and bind by nicoburns on Friday July 09, 2021 @06:35PM (#27789286)
Prototypes are quite simple. An object may have a prototype. If it does then that prototype is just another object, which is considered the first objects parent (which works with method calls like class based inheritance). The chain ends because it's also possible for an object not to have a prototype.
Re:How JavaScript Works: deep dive into call, apply, and bind by bluepnume on Friday July 09, 2021 @07:31PM (#27789650)
My advice is to start of with javascript by forgetting 100% about classes, inheritance, prototypes, and so on.

Just use vanilla functions and objects, and when in need of something that looks like a class, reach for the revealing module pattern:

https://gist.github.com/zcaceres/bb0eec99c02dda6aac0e041d0d4...

Re:How JavaScript Works: deep dive into call, apply, and bind by moron4hire on Friday July 09, 2021 @08:20PM (#27789929)
Not recommended if you have lots of objects with this interface. Each object will have its own copy of each function. Using a class with the methods in a prototype ensures there is only one copy for all object instances.

It also makes specialization and calling super methods super verbose.

And you've ultimately not done anything other than reimplementing OOP, poorly.

Re:How JavaScript Works: deep dive into call, apply, and bind by bokwoon on Friday July 09, 2021 @09:52PM (#27790457)
You're not supposed to use `super` or specialization with factory functions, call the functions you need instead.

OOP inheritance does not belong in this pattern, even if you could hamfist it in (which you've already observed as unwieldy).

Re:How JavaScript Works: deep dive into call, apply, and bind by rustyminnow on Friday July 09, 2021 @07:52PM (#27789772)
I've used this pattern before, but run into issues when you want to write tests for "private" functions (like loadSong() in this example). What I've done is name them like _loadSong and expose them anyways, but that doesn't feel great.

Is there a better way?

Re:How JavaScript Works: deep dive into call, apply, and bind by moron4hire on Friday July 09, 2021 @08:21PM (#27789933)
You don't write tests for private methods.
Re:How JavaScript Works: deep dive into call, apply, and bind by dotancohen on Saturday July 10, 2021 @02:20AM (#27791521)
Of course private methods should be tested. These are unit tests, not functional/integration tests.
Re:How JavaScript Works: deep dive into call, apply, and bind by shawnz on Saturday July 10, 2021 @07:21AM (#27792631)
You don't unit test private methods, the "unit" is the exposed surface of the class.
Re:How JavaScript Works: deep dive into call, apply, and bind by exdsq on Friday July 09, 2021 @11:59PM (#27791000)
Why not?
Re:How JavaScript Works: deep dive into call, apply, and bind by bmy78 on Saturday July 10, 2021 @07:45AM (#27792718)
Because it’s assumed those private methods’ usage happens within public methods, which should be tested. By testing the public methods and all of its use cases you are also testing private ones. That way you can arbitrarily modify private methods without touching the tests (presuming you’re refactoring and don’t need to modify behavior).
Re:How JavaScript Works: deep dive into call, apply, and bind by exdsq on Saturday July 10, 2021 @12:13PM (#27794384)
This seems to be building on rocky foundations though. It's unlikely a functions entire test vector gets checked during testing. This is a known risk (you can't test everything) but by leaving all the functions under a public function untested there is no safety net.
Re:How JavaScript Works: deep dive into call, apply, and bind by moron4hire on Saturday July 10, 2021 @12:46PM (#27794677)
If the code of the private methods cannot be fully exercised through the class' public interface, then that code never executes and should not even be in the function.
Re:How JavaScript Works: deep dive into call, apply, and bind by shawnz on Saturday July 10, 2021 @07:26AM (#27792646)
The most obvious reason is that they're private and not normally reachable from your test code.

But even conceptually there are problems with testing private methods. For example they likely expect to be called only while the class is in some specific state or in the middle of some atomic operation. Otherwise they could have just been made public.

Re:How JavaScript Works: deep dive into call, apply, and bind by zebraflask on Friday July 09, 2021 @08:53PM (#27790141)
+1

Maybe I don't write very complicated material, but I can't think of a single time I've needed to use the more OOP features of JS because one of them was the best or only solution.

Re:How JavaScript Works: deep dive into call, apply, and bind by wruza on Friday July 09, 2021 @06:50PM (#27789408)
I also had this trouble, because for all other languages you can just tead the spec once and that’s it. But ES specs are too technical to be used as such. After few years I just read non-boring parts of ES6 and it cleared all dark corners.

I’d say all of the articles on the internet are rehashing the spec in (at best) a dubious and ritualistic way, and have zero technical value if you ask me.

Re:How JavaScript Works: deep dive into call, apply, and bind by SPBS on Friday July 09, 2021 @09:46PM (#27790426)
FWIW the scoping in JavaScript is exactly the same in Go, so it's not something obscure that only JavaScript cooked up.
Re:How JavaScript Works: deep dive into call, apply, and bind by orangecat on Friday July 09, 2021 @08:14PM (#27789891)
JavaScript is poorly designed. It was barely designed at all; Brendan Eich wrote it in ten days, and we would be better off if he had been a worse developer and hadn't been able to accomplish that. Instead Netscape shipped what should have been an internal 0.1, and got its deficiencies enshrined as documented features so they could never be fixed.
Re:How JavaScript Works: deep dive into call, apply, and bind by BrendanEich on Sunday July 11, 2021 @09:02PM (#27805853)
Ten day Mocha had strict ==, so better in that regard. History is detailed at https://youtu.be/krB0enBeSiE. Rather than assuming a too-simple version, check out the details for how things went down.

Do-overs not possible, by better new forms over time helped. Honest q: Do you actually use modern JS at all?

Re:How JavaScript Works: deep dive into call, apply, and bind by jenseng on Friday July 09, 2021 @05:56PM (#27788976)
You get "clean and DRY" at the expense of "not beginner-friendly" and "you need be to very careful".

Thanks, but no thanks. I'll take clear, understandable code over clever footguns any day.

Re:How JavaScript Works: deep dive into call, apply, and bind by matheusmoreira on Saturday July 10, 2021 @10:48AM (#27793672)
> Incidentally, we should also discard `this`, unless directly inside an instance method of a class.

We should discard classes instead. People have trouble understanding `this` because they insist on thinking in terms of classes and methods which are second class concepts in Javascript. Once I understood objects and prototypes, `this` also became easy to understand.

Programming with Object.create produced the cleanest code I've ever seen. Nothing but functions, objects and prototypes. I simply don't understand why the new versions of Javascript insist on adding even more of this class stuff.

Re:How JavaScript Works: deep dive into call, apply, and bind by kecupochren on Friday July 09, 2021 @05:53PM (#27788955)
I've literally never used them during my 8 years of working as a JS dev. Maybe I'm doing it wrong.

Edit: actually I did use .bind with React before arrow functions came

Re:How JavaScript Works: deep dive into call, apply, and bind by hajile on Friday July 09, 2021 @06:19PM (#27789155)
Until for..of came around, `Array.prototype.map.call($nodeList, myFn)` was pretty much the way to iterate over things that were "array-like" but didn't actually inherit from Array, so didn't have such methods.
Re:How JavaScript Works: deep dive into call, apply, and bind by nicoburns on Friday July 09, 2021 @06:33PM (#27789267)
They were pretty widely used (especially in library code) before arrow functions were added to the language.
Re:How JavaScript Works: deep dive into call, apply, and bind by hajile on Friday July 09, 2021 @06:22PM (#27789184)
There is literally NO substitute for either call or apply as they are low-level JS primitives. Arrow functions can go a long way toward handling .bind() scenarios, but I believe there are situations where you must still use .bind() to prevent constantly creating new functions (and the related garbage).
Re:How JavaScript Works: deep dive into call, apply, and bind by wruza on Friday July 09, 2021 @07:36PM (#27789681)
.bind() does create a new function, though it has far less “slots” than a regular one. It doesn’t modify the original function. The spec doesn’t specify anything beyond that, afair, and if binds aren’t cached in some way (easy to check with === or roll up your own cachedBind()), GC barely can make any benefit out of collecting slightly smaller objects (but the interpreted part of a runtime may still process bound functions a little faster than closures doing the same thing).

As of source code or p-code or by whatever structure {<code>} body is represented inside, it is always* static for all closures, so there is no overhead apart from a closure itself between:

  function foo() {<code>} // func
  for (;;) foo()
and

  let i = 0
  for (;;) {
    let j = 0
    function foo() {i++; j++; <code>} // closure
    foo()
  }
Because {…<code>} is a singleton in both snippets.

* of course jit may blur this distinction a lot, but that’s unrelated

Re:How JavaScript Works: deep dive into call, apply, and bind by bluepnume on Friday July 09, 2021 @07:14PM (#27789559)
Show me some code you can only write using either call, apply, or bind.
Re:How JavaScript Works: deep dive into call, apply, and bind by wruza on Friday July 09, 2021 @07:48PM (#27789745)
Anything that substitutes ‘this’ but doesn’t want to put a function into that object.

  const {filter} = []
  class Foo {
    less() {
      return filter.call(this, sometest)
    }
  }
There is no way to closure it somehow without (temporarily) modifying an instance of Foo. (The next obvious question is “why” and the answer is “metaprogramming”.)
Re:How JavaScript Works: deep dive into call, apply, and bind by bluepnume on Saturday July 10, 2021 @07:51PM (#27797317)
I would rather re-implement `filter` in a way that is specific to `Foo`, than to attempt to use an array method on my class.
Re:How JavaScript Works: deep dive into call, apply, and bind by normac2 on Friday July 09, 2021 @06:02PM (#27789024)
> Incidentally, we should also discard `this`, unless directly inside a class method.

When you say it has to be "directly," do you mean we should never use arrow functions (or use them only for looks)? Since the purpose of those is to add "this" support to inner functions?

Re:How JavaScript Works: deep dive into call, apply, and bind by bluepnume on Friday July 09, 2021 @07:15PM (#27789570)
Sorry, yeah, I did allow for closures inside class methods with that statement. That's fine by me.
Re:How JavaScript Works: deep dive into call, apply, and bind by Sephr on Friday July 09, 2021 @07:23PM (#27789610)
I've had to cache a secure reference to call() in a JS library intended to exist in potentially hostile environments.

This call helper is often used to avoid prototype pollution vulnerabilities when patching native prototypes.

Re:How JavaScript Works: deep dive into call, apply, and bind by bluepnume on Friday July 09, 2021 @07:25PM (#27789624)
Very interested to learn more about this use case. This is to protect against hostile environments blocking function calls by polluting prototypes?

I do a lot of work on SDKs which run in semi-hostile environments, so prototype pollution is something I'm frequently running up against.

Re:How JavaScript Works: deep dive into call, apply, and bind by Sephr on Friday July 09, 2021 @08:46PM (#27790102)
> This is to protect against hostile environments blocking function calls by polluting prototypes?

Correct. I go into more detail about into our problem space and use cases here: https://transcend.io/blog/defeating-cookie-banners

Re:How JavaScript Works: deep dive into call, apply, and bind by ubaltaci on Friday July 09, 2021 @06:12PM (#27789098)
that list should also include anything that touches prototypes
Re:How JavaScript Works: deep dive into call, apply, and bind by bluepnume on Friday July 09, 2021 @07:16PM (#27789573)
You have my full agreement. You can write great javascript without ever touching prototypes, and probably even avoiding inheritance altogether unless you have a really succinct use-case.
Re:How JavaScript Works: deep dive into call, apply, and bind by Tade0 on Saturday July 10, 2021 @04:37AM (#27792040)
How do you want to do partial application if not through bind? All the other methods are much more verbose.
Re:How JavaScript Works: deep dive into call, apply, and bind by wruza on Friday July 09, 2021 @07:15PM (#27789567)
Sadly (or not, really) there are no class/instance methods in javascript, cause its key lookup model is prototype-based and ‘method’ functions just get ‘this’ lexically (in x.y.f(), f() operates on x.y). The combination of these two facts builds up an entire OOP in js. If you really want to free your code of these ideas, it’s much easier to use some js-transpilable language out there.
Re:How JavaScript Works: deep dive into call, apply, and bind by bluepnume on Friday July 09, 2021 @07:23PM (#27789612)
> in x.y.f(), f() operates on x.y

Yep, and I think that determining `this` at the call-site is really awful, and has been the cause of many more bugs than is reasonable.

OOP you can do in JS with just `class` and `extends`, you no longer need to care too much about prototypes and how they work. Prototypes have become much more of an implementation detail in recent years.

Re:How JavaScript Works: deep dive into call, apply, and bind by wruza on Friday July 09, 2021 @08:03PM (#27789829)
I think that determining `this` at the call-site is really awful, and has been the cause of many more bugs than is reasonable

That’s what almost all (more or less) dynamic languages do, except those that don’t have an arbitrary “object” struct. Out of few dynamic languages only python does what you need, at the cost of the enormous GC pressure. It’s okay for python because it was meant to be slow as hell by design.

And even then the solution would be more error-prone than the “issue” itself. Consider this code:

  app.use(sass({
    src: “.”,
    log: console.log,
    log2: function () {…},
  }))
Should the anonymous object overtake console.log()’s “this”? And for log2()? And if you create an object and assign a bunch of functions to it in a literal? Later in the code?

Your frustration is understandable, but I assure you that python’s “bound methods” are really awful to debug as well (been there done that), because the issue is not in functions taking “this” one way or another, but in a mismatch between developer’s expectations and reality.

Re:How JavaScript Works: deep dive into call, apply, and bind by bluepnume on Saturday July 10, 2021 @07:57PM (#27797340)
I agree with you, it's definitely a trade-off between developer ease and perf.

I get around that in js mostly by avoiding classes and `this` entirely unless I'm sure I'm going to have a large number of instances of something. But there is the mental overhead of "Do I need to wrap this function in an arrow function before passing it around to avoid getting an unexpected `this`?"

So yeah, not saying I have a great solution -- just that none of the existing solutions really seem ideal.

Re:How JavaScript Works: deep dive into call, apply, and bind by wruza on Friday July 09, 2021 @08:15PM (#27789893)
Prototypes have become much more of an implementation detail in recent years.

First of all, it’s just a single-handed point of view. I’m using them from time to time, because js doesn’t end with reactjs hooks or frontend, and even frontend doesn’t end with just writing “frontend glueware”.

But even if it did, what exact mechanism do you propose to bind methods to instances? Automagic? It’s not just an “implementation detail”, it is a way of doing OOP in dynamic languages. Do you want all your objects to contain references to bound copies of all of the inherited methods? The way it is is for a reason, and the reason is, it doesn’t come for free.

Re:How JavaScript Works: deep dive into call, apply, and bind by arcosdev on Saturday July 10, 2021 @02:36AM (#27791587)
We shouldn't use 'class' either
Re:How JavaScript Works: deep dive into call, apply, and bind by jollybean on Friday July 09, 2021 @06:28PM (#27789232)
I came here to write exactly that.

There was once a time when such 'js ninja' skills were appropriate, but now they almost represent an anti-pattern in normal usage.

For some kind of framework, maybe.

But otherwise, they're just going to cause problems and they don't really provide something really valuable wherein another more basic use case wouldn't be better.

A pragmatic approach might be to 'stick to a solid version of Typescript' and even then be wary of the fancy stuff unless it's truly needed. (Say, you're building a lib or some core module).