Hi I'm not sure but I think this is a bug:
_.chain([1,2,3,4]).each(function(current){ console.log(current) }).value(); // returns undefined
//where:
_.chain([1,2,3,4]).map(function(current){ return current; }).value() // returns expected.
I guess chained function have to return values but then tap is not an iterable, im looking for a way to access the values without un-chaining them and without mutation.
That's correct. Unlike map
, each
doesn't have a return value, so calling value
on it does nothing. If you need to pass a mutated array through the chain, it's best to stick with map
.
ok so map, how about _.chain().tap(function(values) { values.forEach(function(current) {}; });
does not seem elegant but seems like its logical...
Yep, looks good by me:
_.chain([1,2,3,4])
.tap(_.bind(console.log, console))
.map(function(val) { return val * 2 })
.value(); // [2,4,6,8]
It would be nice to mention that each doesn't return a value in the documentation.
@xixixao each
follows the semantics of Array#forEach, which also doesnt return any value. If you need something returned just use a map
.
I don't see anything preventing Underscore from making _.each
chainable. It breaks with native semantics for other methods. There are subtle differences with suggesting _.map
like it doesn't return the same array and it requires a return value in the callback.
Why would each need to be chainable? You're not mutating the array in any way (the way you are with something like a map or filter), so therefore there is no no expectations of the value being reusable.
Why would each need to be chainable?
Why not allow chaining, what could it hurt? It's handy for cases like _(collection).each(intermediateActions).filter(...)
.
I would make the method undefined in a wrapped object context.
@dw40 but what are you doing in those intermediate actions that can't better be handled with a map?
but what are you doing in those intermediate actions that can't better be handled with a map?
It doesn't really matter what the intermediate step is, it could be a number of things, the benefit of _.each
chaining is that the intermediate callback doesn't have to return a value and it doesn't need to create a new array.
@dw40 want to whip up a quick pull? You're talking about special-casing each
as part of the mix-in right?
@akre54 I know that each
follows forEach
, I literally meant that it would be good to mention the behavior in the documentation.
That said, I agree that each should just return the original collection for chaining (always, whatever syntax is each
being called with).
You're talking about special-casing each as part of the mix-in right?
Simpler than that. Just have_.each
return obj
. No need to special case.
But then you're breaking compat with the spec. That's not what each
does.
But then you're breaking compat with the spec. That's not what
each
does.
I previously wrote:
I don't see anything preventing Underscore from making _.each chainable. It breaks with native semantics for other methods.
I don't see that as a big deal. Underscore already parts with the spec'ed behavior for better dev usability in several methods. For example in edge _.keys(...)
doesn't throw if the argument passed is not an object, and methods like _.every
and _.some
work if you don't pass an iterator
.
I don't think it's a huge change, but it's definitely unexpected that each
will return anything, let alone the value it was passed (and a much bigger spec break than checking for nullish arguments).
To be clear, you're talking about making this change, right?
diff --git a/underscore.js b/underscore.js
index 7a30b0a..2b56536 100644
--- a/underscore.js
+++ b/underscore.js
@@ -74,7 +74,7 @@
// Handles objects with the built-in `forEach`, arrays, and raw objects.
// Delegates to **ECMAScript 5**'s native `forEach` if available.
var each = _.each = _.forEach = function(obj, iterator, context) {
- if (obj == null) return;
+ if (obj == null) return obj;
if (nativeForEach && obj.forEach === nativeForEach) {
obj.forEach(iterator, context);
} else if (obj.length === +obj.length) {
@@ -87,6 +87,7 @@
if (iterator.call(context, obj[keys[i]], keys[i], obj) === breaker) return;
}
}
+ return obj;
};
To be clear, you're talking about making this change, right?
Right.
I dont particularly care one way or another but it would be good to hear from more people about real use cases for or against this before merging.
I think you can go for it. Would be a little more useful.
In my opinion at least when working in a chained context, making _.each return a value is expected behavior, so +1 :)
@LeonFedotov @dw40 give that a try.
@akre54 Awesome.
@akre54 great, thanks!
Interestingly, we've reverted to the pre-1.1.3 behaviour.
The following addition to the 1.1.3 release notes was made in 3b916a2cf788a4588f08323c39786b6fb5ddbca6:
_.each
no longer returns the iterated collection, for improved consistency with ECMA5'sforEach
.
Ha. I knew it seemed familiar. Good spot.
On Feb 1, 2014 11:23 PM, "David Chambers" [email protected] wrote:
Interestingly, we've reverted to the pre-1.1.3 behaviour.
The following addition to the 1.1.3 release notes was made in 3b916a2https://github.com/jashkenas/underscore/commit/3b916a2cf788a4588f08323c39786b6fb5ddbca6
:_.each no longer returns the iterated collection, for improved
consistency with ECMA5's forEach.
Reply to this email directly or view it on GitHubhttps://github.com/jashkenas/underscore/issues/1391#issuecomment-33883825
.
Is there now an alternative method that can be chained and allow modifying elements of an array in place? I was searching for something like a peek
:
_.chain(myArray)
...
.peek(e -> e.craftedVar = e.otherVar * 2)
...
.value();
Most helpful comment
Is there now an alternative method that can be chained and allow modifying elements of an array in place? I was searching for something like a
peek
: