I've found this article that says that JavaScript function calls are really just a syntactic sugar for func.call(...).
I would like to ask if that's really true, because I've not found anything like that in the spec (haven't really examined it thoroughly, just brief glance and search for the word call()).
It would be really nice if someone could enlighten me, cause if this article is true, my admiration of the EcmaScript language may reduced.
I can see why the article would say it, and it kind of is to an extent.
The reason they probably claim that is because functions when used directly are unbound, meaning if I create an object:
const a = { say: function() { console.log(this.message) } };
a.message = 'hello';
a.say();
When I run the function a.say(), the this context inside of say() is a. That is equivalent to a.say.call(a).
Since I haven't bound that function explicitly, if I pass it somewhere else can call it, it won't necessarily have the context of a anymore:
const a = { say: function() { console.log(this.message) } };
const b = {};
a.message = 'hello';
b.message = 'goodbye';
b.say = a.say;
b.say();
Notice that even though I copied a's say(), when called with b, it ended up being called with b as it's context (this). Thus, it's essentially equivalent to a.say.call(b).
If you explicitly bind the function, then it will always use a fixed context:
const a = { say: function() { console.log(this.message); } };
const b = {};
a.message = 'hello';
b.message = 'goodbye';
b.say = a.say.bind(a);
b.say();
With it bound, it'll now always use the context of a, even though I may pass the function to other places.
Now, that said, I'm not sure why your admiration would be crippled. I actually find this an awesome feature of the language and makes it very powerful and flexible. It is what allows you to do things like this:
Array.prototype.slice.call(document.querySelectorAll('div'))
.forEach(el => console.log(el.innerHTML));
<div>A</div>
<div>B</div>
<div>C</div>
In that example, document.querySelectorAll() returns a NodeList, which doesn't normally have forEach(). However, since it is compatible enough, I can use call() to pass it to Array.prototype.slice to transform it into an Array with those elements. (You can also just give it to forEach() directly, but I prefer to transform it with slice() then do further things.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With