New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

_.delay has no option to bind "this", and instead binds "this" to called function, which is useless #494

Closed
dgbeck opened this Issue Feb 29, 2012 · 10 comments

Comments

Projects
None yet
6 participants
@dgbeck

dgbeck commented Feb 29, 2012

_.delay is incompatible with _.bind and _.bindAll.

Since _.delay calls its target function "func" with:

func.apply(func, args);

any object that was previously bound to func using _.bind or _.bindAll will not be "this" when func is called. Many other underscore functions have a special parameter for "this".. why not _.delay? Moreover, it seems totally useless to me to have "this" be a reference to the function itself. Why not just call func directly, instead of using "apply", and then not mess with the value of "this"? Am I missing something? Here is code for the _.delay function for reference purposes:

_.delay = function(func, wait) {
return setTimeout(function(){ return func.apply(func, args); }, wait);
};

@kitcambridge

This comment has been minimized.

Show comment
Hide comment
@kitcambridge

kitcambridge Feb 29, 2012

Contributor

apply is needed to unpack the args array into individual arguments when invoking func...but I think the following implementation would certainly be more correct:

_.delay = function(func, wait) {
  // ...
  return setTimeout(function(){ return func.apply(this, args); }, wait);
};
Contributor

kitcambridge commented Feb 29, 2012

apply is needed to unpack the args array into individual arguments when invoking func...but I think the following implementation would certainly be more correct:

_.delay = function(func, wait) {
  // ...
  return setTimeout(function(){ return func.apply(this, args); }, wait);
};
@dgbeck

This comment has been minimized.

Show comment
Hide comment
@dgbeck

dgbeck Feb 29, 2012

Yes, I think that would be more consistent with the rest of the library, and more useful.

Thanks

dgbeck commented Feb 29, 2012

Yes, I think that would be more consistent with the rest of the library, and more useful.

Thanks

@jashkenas

This comment has been minimized.

Show comment
Hide comment
@jashkenas

jashkenas Apr 2, 2012

Owner

We can make that change -- but how would that possibly allow the value of this to be bound? Perhaps provide a test case?

Owner

jashkenas commented Apr 2, 2012

We can make that change -- but how would that possibly allow the value of this to be bound? Perhaps provide a test case?

@kitcambridge

This comment has been minimized.

Show comment
Hide comment
@kitcambridge

kitcambridge Apr 2, 2012

Contributor

Erm...whoops. A third context argument would need to be added; my suggestion above isn't useful at all.

Contributor

kitcambridge commented Apr 2, 2012

Erm...whoops. A third context argument would need to be added; my suggestion above isn't useful at all.

@jashkenas

This comment has been minimized.

Show comment
Hide comment
@jashkenas

jashkenas Apr 2, 2012

Owner

In that case, I'm going to change it to null.

Owner

jashkenas commented Apr 2, 2012

In that case, I'm going to change it to null.

@jashkenas

This comment has been minimized.

Show comment
Hide comment
@jashkenas

jashkenas Apr 2, 2012

Owner

Fixed in: 1366d90

Owner

jashkenas commented Apr 2, 2012

Fixed in: 1366d90

@jashkenas jashkenas closed this Apr 2, 2012

@machineghost

This comment has been minimized.

Show comment
Hide comment
@machineghost

machineghost Mar 14, 2013

Quick note for any future readers who are still unsatisfied with:

_(
    _(function() {
        this.doSomething();
   }).bind(this)
).delay(500);

There are several alternative options you can use:

  1. Use the chain method (without needing to use the accompanying value method):
_(function() {
    this.doSomething();
}).chain().bind(this).delay(500);
  1. Mix-in your own boundDelay method so that you can do:
    _(function() {
        this.doSomething()
    }).boundDelay(this, 500);

That would look something like this (untested) code:

_.mixin({
    boundDelay: function(func, context, delayMs) {
        var boundVersion = _(func).bind(context);
        _(boundVersion).delay(delayMs);
    }
});
  1. You can Underscore Grease (https://github.com/machineghost/Underscore-Grease) to chain the two in to:
    _(function() {
        this.doSomething();
   }).bind_(this).delay(500);

Quick note for any future readers who are still unsatisfied with:

_(
    _(function() {
        this.doSomething();
   }).bind(this)
).delay(500);

There are several alternative options you can use:

  1. Use the chain method (without needing to use the accompanying value method):
_(function() {
    this.doSomething();
}).chain().bind(this).delay(500);
  1. Mix-in your own boundDelay method so that you can do:
    _(function() {
        this.doSomething()
    }).boundDelay(this, 500);

That would look something like this (untested) code:

_.mixin({
    boundDelay: function(func, context, delayMs) {
        var boundVersion = _(func).bind(context);
        _(boundVersion).delay(delayMs);
    }
});
  1. You can Underscore Grease (https://github.com/machineghost/Underscore-Grease) to chain the two in to:
    _(function() {
        this.doSomething();
   }).bind_(this).delay(500);
@jeff-h

This comment has been minimized.

Show comment
Hide comment
@jeff-h

jeff-h Apr 23, 2015

I don't understand how we can call this "fixed". The various solutions in the comment above all appear very unreadable to me.

The change in 1366d90 simply stops sending an odd context to the called function.

Is there a reason delay can't take a context argument as per #494 (comment) ? That, to me, would be awesome :)

jeff-h commented Apr 23, 2015

I don't understand how we can call this "fixed". The various solutions in the comment above all appear very unreadable to me.

The change in 1366d90 simply stops sending an odd context to the called function.

Is there a reason delay can't take a context argument as per #494 (comment) ? That, to me, would be awesome :)

@jridgewell

This comment has been minimized.

Show comment
Hide comment
@jridgewell

jridgewell Apr 23, 2015

Collaborator

There's no reason to change _.delay. If you want a context, bind it beforehand.

_.delay(_.bind(func, context), 500)
Collaborator

jridgewell commented Apr 23, 2015

There's no reason to change _.delay. If you want a context, bind it beforehand.

_.delay(_.bind(func, context), 500)
@jeff-h

This comment has been minimized.

Show comment
Hide comment
@jeff-h

jeff-h Apr 23, 2015

Thanks! I should have tried that I guess, but assumed wrongly based on the complexity of the above answers that something more complicated was needed.

jeff-h commented Apr 23, 2015

Thanks! I should have tried that I guess, but assumed wrongly based on the complexity of the above answers that something more complicated was needed.

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