Skip to content

Instantly share code, notes, and snippets.

@getify
Last active December 17, 2020 05:21
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save getify/4596011 to your computer and use it in GitHub Desktop.
Save getify/4596011 to your computer and use it in GitHub Desktop.
A native syntax alternative for `Function.prototype.bind`? This is an open exploration and soft proposal. Feedback appreciated. The main problem I'm trying to solve with `Function.prototype.bind()` is that it creates a new function that's wrapped around the function you specify. This means if you do that a lot, you're creating (and throwing away…
function foo() {
console.log(this.bar);
}
function doSomething(fn, overrideThis) {
if (overrideThis) fn.call(overrideThis);
else fn();
}
var bar = "bar1";
var obj1 = { bar: "bar2" };
var obj2 = { bar: "bar3" };
foo(); // "bar1"
foo.call(obj1); // "bar2";
var foo2 = foo.bind(obj1); // creates a whole new function... can be "ouch" for memory if done a lot
foo2 === foo; // false -- whole new function!
foo2(); // "bar2"
foo2.call(obj2); // "bar2" (not "bar3", `this` can't be overridden here)
doSomething( foo.bind(obj2) ); // "bar3"
doSomething( foo.bind(obj2), obj1 ); // "bar3" (`this` still can't be overriden)
// ATTENTION: new syntax proposal.
var foo3 = foo#obj1; // not a new function, just a special decorated reference to the same function
foo3 === foo; // true... same function!
foo3(); // "bar2" (defaulted `this` to `obj1`)
foo3.call(obj2); // "bar3" (`this` overridable, unlike Function.prototype.bind)
doSomething( foo#obj2 ); // "bar3"
doSomething( foo#obj2, obj1 ); // "bar2" (because `this` is still overridable)
@juandopazo
Copy link

What I meant is that my guess is that they'd have to add a flag for all references, not just references to bound functions, which would impact a lot more than just bound functions. Of course it'd be nice if you could get feedback from someone who writes language implementations.

What I can say is:

  • If there was a way to optimize bindings, I'm sure engine implementors will eventually do it for foo.bind(bar). It looks optimizable up to a certain level because it doesn't have anything in its internal scope, so no scope object, just a copy of the previous function with a different |this| value.
  • Messing with references adds an extra level of complexity to the language. As a developer references are something I don't remotely want to think about.
  • If foo.bar !== foo#bar and typeof foo#bar === 'string' then I'm going to assume it's a new function. Whether it's a new function or a magic reference, that is an implementation detail.

@getify
Copy link
Author

getify commented Jan 24, 2013

@juanpodazo:

If there was a way to optimize bindings, I'm sure engine implementors will eventually do it for foo.bind(bar)

If the VM's were able to transparently make it so a new function wasn't actually being created, that'd be great, but I think it might be problematic in the converse way to how my proposal is being seen as possibly problematic.

For "legacy" reasons (if we can call ourselves in a post-ES5 era yet!), bind() has to return a function reference that's different than the original function, even if the VM is able to go so far as to literally reuse the same function in both instances. Maybe this reference faking/breaking is easy for VM's, maybe not. Not really sure. But could be an issue for them. I'm not sure how much of a perf win, if any, we'd get if the VM still had to create (and later GC) a shell function ("wrapper") just for maintaining these itinerant this bindings.

Moreover, their bind() optimization, even if they worked out that concern, wouldn't, as we've said, address re-bindability, because again for legacy reasons, bind() would have to return non-rebindable refs at the least. softBind would still be necessary.

I would obviously like to see both problems addressed, and if they can be addressed by the same mechanism, I'd consider that preferable.

Messing with references adds an extra level of complexity to the language. As a developer references are something I don't remotely want to think about.

I agree, we shouldn't complicate how references work.

But this would surely be an opaque change to references. It wouldn't be an observable (or mutable) "property" or anything like that. It's just simply a way of preserving with a reference the intended this binding. JS already has several other mechanisms for specifying this, so I'm not sure that adding some rule/mechanism into that mix would really make references across the board any harder for devs to handle.

Whether it's a new function or a magic reference, that is an implementation detail.

Totally agreed. Not sure what you meant by "string" though. Typo?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment