Reputation: 155
New to Javascript - I am attempting to rewrite forEach and filter to understand them. I'd like to be able to use filter to pass something like {"hello": 4, "world": 2, "hi": 1} and be able to filter based on the number.
Here's my forEach:
function myForEach(collection, callback) {
if (Array.isArray(collection)) {
for (var i = 0; i < collection.length; i++) {
callback(collection[i]);
}
}
else {
for (var key in collection) {
callback(collection[key]);
}
}
}
Here's filter:
function filterWithForEach (collection, predicate) {
if (Array.isArray(collection)) {
var newArray = [];
myForEach(collection, function (element) {
if (predicate(element)) {
newArray.push(element);
}
});
return newArray;
}
else {
var newCollection = {};
myForEach(collection, function (element) {
if (predicate(element)) {
newCollection[element] = element; //here's where I think it's wrong
}
});
return newCollection;
}
}
I know the issue is with how I am assigning them because when I test it I get these outputs:
console.log(filterWithForEach([1,2,3,4,5], function(num) {
return num > 2;
})); // works fine
console.log(filterWithForEach(aList, function(item) {
return item > 3;
})); // provides {4: 4}..
Upvotes: 2
Views: 1979
Reputation: 861
You can creat a filter own method into the Array prototype function. If you are looking for a different approach you can use Iterators and a recursive fuction like this:
Array.prototype.megaFilter = function(cb) {
const iterator = this[Symbol.iterator]();
const iteration = iterator.next();
const filteredArray = [];
iterate(iteration);
function iterate(iteration) {
if (iteration.done) return iteration;
if (cb(iteration.value)) filteredArray.push(iteration.value);
const nextIteration = iterator.next(iteration.value);
return iterate(nextIteration);
}
return filteredArray;
};
const array = [1, 2, 3, 4, 5, 6, 7];
console.log(array.megaFilter(v => v % 2 === 0));
The gist for that is here, you are very welcome to give me feedback: https://gist.github.com/jdtorregrosas/d69f67e8079f82fbc2a5904e76a8fb6c
Upvotes: 0
Reputation: 1074385
If you want to know what they do, the spec is fairly clear and can pretty reasonably be turned into JavaScript code (in fact, that's been done on MDN).
Some differences between yours and JavaScript's:
JavaScript's forEach
and filter
don't use for-in
, which is the fundamental difference between yours and JavaScript's. They just work with the object and array indexes, expecting the object to be a array-like (e.g., have a length
and properties with keys like "0"
, "1"
, and so on [and yes, all keys are strings, even the keys in standard arrays, which aren't really arrays at all).
JavaScript's version doesn't call the callback for entries that don't exist (e.g., in the case of sparse arrays). To add that to yours, you'd add hasOwnProperty(index)
at some stage.
JavaScript's version passes more arguments to the callbacks.
JavaScript's version lets you specify a value to use as this
when calling the callbacks.
JavaScript's version grabs the length before starting, so if the collection is modified, the old length is used. Depending on where the changes are made, entries might be skipped.
So for instance, your take on forEach
might look more like this:
function myForEach(collection, callback, thisArg) {
var l = +collection.length;
for (var i = 0; i < l; i++) {
if (collection.hasOwnProperty(i)) {
callback.call(thisArg, collection[i], i, collection);
}
}
}
Again, that's not (remotely) an accurate implementation of the algorithm in the spec, just a slight modification to yours to address the specific points I raised above.
Upvotes: 3
Reputation: 1360
If you are looking for an object to be returned then this is the way it should be.
function myForEach(collection, callback) {
if (Array.isArray(collection)) {
for (var i = 0; i < collection.length; i++) {
callback(collection[i]);
}
}
else {
for (var key in collection) {
callback(collection[key], key);
}
}
}
Here's filter:
function filterWithForEach (collection, predicate) {
if (Array.isArray(collection)) {
var newArray = [];
myForEach(collection, function (element) {
if (predicate(element)) {
newArray.push(element);
}
});
return newArray;
}
else {
var newCollection = {};
myForEach(collection, function (element,key) {
if (predicate(element)) {
newCollection[key] = element; }
});
return newCollection;
}
}
Upvotes: 1