tc39 / proposal-partial-application

Proposal to add partial application to ECMAScript
https://tc39.es/proposal-partial-application/
BSD 3-Clause "New" or "Revised" License
1.02k stars 25 forks source link

Can you change the `this` with `call` and `apply`? #52

Open matthewp opened 2 years ago

matthewp commented 2 years ago

I think the answer is that you can, but it was unclear to me from the examples. For example:

const introduceBob = bob.introduce~();
introduceBob();

What if you do:

const introduceBob = bob.introduce~();
introduceBob.call(barbara);

I assume the this in introduce refers to barbara and not bob, correct?

matthewp commented 2 years ago

Actually reading the entire readme and I'm really unsure, especially given the semantics: https://github.com/tc39/proposal-partial-application#semantics

How can I partially apply a function who's this value is determined by the caller (via call/apply)?

ljharb commented 2 years ago

I would assume that introduceBob is a bound function, and thus can not have the receiver changed with call and apply.

matthewp commented 2 years ago

Thanks, that's my interpretation after rereading the semantics as well. Could you create an unbound version some how? Maybe like this?

const introduceBob = bob.introduce.call~(?);
introduceBob.call(barbara);
ljharb commented 2 years ago

Yes, but in that case it'd be introduceBob(barbara).

ljharb commented 2 years ago

If you want it to work with .call and .apply, you need to use a normal function, like const introduceBob = function (...args) { return bob.introduce.call(this, ...args); };

matthewp commented 2 years ago

Hm, I'm a little confused, that doesn't use this new syntax proposal. Are you saying that you can't use this new syntax and then use call/apply on the created function to pass the this value?

ashwell commented 2 years ago

I think what @ljharb is getting at is your example would be this,

const introduceBob = bob.introduce.call~(?);
introduceBob(barbara);

because introduceBob would be a partially applied version of introduce.call not introduce. The other point is that bob.introduce would need to be a normal function, not an arrow or bound function.

edit: I might be wrong as I am just a random dude on the internet.

ljharb commented 2 years ago

Right you can't use this proposal's syntax, and end up with a normal function whose receiver can be dynamically changed via .call/.apply

matthewp commented 2 years ago

Ok, thanks for the clarity there. Then fn.call~(?) is a bit of a workaround. Maybe an acceptable one, I'm not sure yet.

@ashwell My example was taken from the readme which is:

const bob = {
  name: "Bob",
  introduce() {
    console.log(`Hello, my name is ${this.name}.`);
  }
};

This function can have call/apply used on it.


From the readme it sounded like the proposal wanted to fix the issue with .bind() that you need to know the this value ahead of time, but it sounds like it doesn't. This is one of the biggest disadvantages to bind() that I often find.

So I guess this thread should turn into a request that this feature be considered.