-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
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
Add _.restParam #2140
Add _.restParam #2140
Conversation
252be49
to
0e551d8
Compare
This is heavily inspired by jashkenas/backbone#3489 - related jsperf http://jsperf.com/trigger-with-for-loop-vs-slice/8 |
Super nifty. How about naming it |
@jashkenas the name is based off of ES6 Also arguments is ~ a reserved word On Wed, Apr 8, 2015 at 12:37 PM, Jeremy Ashkenas notifications@github.com
|
The "parameter/argument" naming dichotomy would be unfortunate to introduce — Underscore has historically called them "arguments". How about |
ping @jridgewell @buzzdecafe @davidchambers @jdalton Implementation proves to be uglier than I had hoped :z going to write some benchmarks after we head for lunch
Fix error This is the last time I write things in Github editor Tricky slice Allow startIndex param really, really fix it this time Don't redeclare
I'm not against Also, updated to it merges nicely. |
"parameters" and "arguments" are synonyms for the purposes of JavaScript. "Arguments" is already the established word choice — both for JavaScript with the |
Sigh, updated. |
Groovy. No way to combine those two similar loops, eh? |
Not without perf JIT penalties (see the initial 2 commits) megawac#3 |
Yah, there's a pretty bad performance hit, which would defeat the goal of adding this to Backbone's |
edit: Crap, |
|
// Similar to ES6's rest param (http://ariya.ofilabs.com/2013/03/es6-and-rest-parameter.html) | ||
// This accumulates the arguments passed into an array, after a given index. | ||
var restArgs = function(func, startIndex) { | ||
startIndex = startIndex == null ? func.length - 1 : +startIndex; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using function.length means functions bound with the _.bind
fallback will work inconsistently with ones bound with Function.prototype.bind
btw. Is this acceptable? @megawac @jridgewell
var func = function(a,b,c,d,e,f,g) {};
func.length; // 7
func.bind().length; // 7
Function.prototype.bind = null;
_.bind(func).length; // 0
(edit: remove bind(null) for clarity)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the usefulness of not having to give the startIndex
every times outweighs this trip-up. A lot of what I imagine using it for is in parse-time. You would then bind the returned function.
var args = _.restArgs(function(args) { return args; }).bind(null);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok cool. You could still pass startIndex
to restArgs if you needed the fallback behavior, that seems reasonable.
_.prototype[name] = function() { | ||
var args = [this._wrapped]; | ||
push.apply(args, arguments); | ||
_.prototype[name] = restArgs(function(args) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this faster? It's certainly not clearer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seemed faster when I profiled it locally on node - I'll check again this weekend
I'm 👎 on this change. It may be ugly but I'd also argue all of these extra helper methods make Underscore itself harder to read. I really wish we'd simplify a lot of these. |
I agree that this one is a little bit weird — but it's a neat pattern to automatically capture varargs, and to avoid dealing with the arguments object. I think it's worth having. |
The point of this was to get us closer to idiomatic ES6, and provide a speed boost since |
That's great, I just really don't like the "lodashification of Underscore" we've been seeing recently -- helper methods everywhere and a cargo-cult-like focus on microbenchmarks and minor speed improvements at the expense of readability. One of the best things about Underscore of days past was that it looked like code you might actually write in your project, and in a pinch you could pull out just the parts you needed. Lodash already exists as a separate approach, I'm not sure we need to be copying them here. |
I agree with you and thats why I've avoided several refactors in the past. Me and @jridgewell have just been refactoring in the places which will gain maximum benefit for the library in terms of size and speed. The purpose of a library such as underscore/lodash should be to help devs write quality code Also a distinction is that nearly all of the helpers used internally are exposed and documented in the API. I'd say its fine for a library to eat its own dog food like this |
Is this the jsperf you're talking about? Sure twice as fast is always awesome, but when you need to trigger 400,000 events in a second, I highly doubt the trigger method (or its args de-opt) is going to be your bottleneck.
Sure. I'm more referring to the internal |
Those are indeed much more problematic. So perhaps this particular issue isn't the right place to make this argument? It would be great to look at a PR that conceptually simplified the create* mega-methods... |
Totally. This was kinda the straw that broke the camel's back. I wanted to register that I see this change as part of a larger more unfortunate trend. A PR or discussion of how to fix this would be excellent. |
@akre54 Mind creating it with your thoughts? |
Will do when I get some time. Work business and non work busyness and all |
👍 |
_.restParam
is the equivalent of ES6's rest parameter. It's particularly useful as an alternative toslice.call(arguments, index)
(numerous examples in this PR), and it's a reusable, very fast version of inline for-loop slicing, eg. jashkenas/backbone#3489.