JavaScript's built-in array methods such as filter(), sort(), and map() are incredibly useful for working with arrays, but there may be situations where you can't use them. For example, you may be working in an environment that doesn't support these methods, or you may need to optimize your code for performance reasons. In these cases, it's important to know how to recreate these methods without using them.
First, let's take a look at the filter() method. The filter() method is used to create a new array with all elements that pass a certain test. One way to recreate this method without using it is to use a for loop and a temporary array to store the filtered elements. Here is an example:
function customFilter(arr, callback) {
let filtered = [];
for (let i = 0; i < arr.length; i++) {
if (callback(arr[i], i, arr)) {
filtered.push(arr[i]);
}
}
return filtered;
}
This function takes in an array and a callback function as arguments. The callback function is used to test each element in the array. If an element passes the test, it is added to the filtered array.
Here's an example usage of the customFilter function:
const numbers = [1, 2, 3, 4, 5];
const evenNumbers = customFilter(numbers, (num) {
return num % 2 === 0;
});
console.log(evenNumbers); // [2, 4]
In this example, the customFilter function is called with numbers as the first argument and an anonymous callback function as the second argument. The anonymous function checks if each number is even by checking if the remainder when divided by 2 is equal to 0. The customFilter function returns a new array evenNumbers containing only the even numbers from numbers.
Next, let's take a look at the sort() method. The sort() method is used to sort the elements of an array in ascending or descending order. One way to recreate this method without using it is to use a nested for loop and an if statement. Here is an example:
function compareFn(a, b) {
if (a < b) {
return -1;
}
if (a > b) {
return 1;
}
return 0;
}
function customSort(arr, compareFn) {
for (let i = 0; i < arr.length; i++) {
for (let j = i + 1; j < arr.length; j++) {
if (compareFn(arr[i], arr[j]) > 0) {
let temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
}
return arr;
}
This function takes in an array and a compareFn function as argument, the compareFn function is used to compare two elements of the array and determine their relative order.
Finally, let's take a look at the map() method. The map() method is used to create a new array with the results of calling a provided function on every element in the original array. One way to recreate this method without using it is to use a for loop and a temporary array to store the mapped elements.
function customMap(arr, callback) {
let mapped = [];
for (let i = 0; i < arr.length; i++) {
mapped.push(callback(arr[i], i, arr));
}
return mapped;
}
This function takes in an array and a callback function as arguments. The callback function is called on each element of the array and the result is added to the mapped array.
The Array method reduce() allows you to iterate over an array and apply a callback function to each element, accumulating the results in a single value. Here is an example of how you can recreate the reduce()
method without using reduce()
:
function myReduce(arr, callback, initialValue) {
let accumulator = initialValue;
for (let i = 0; i < arr.length; i++) {
if (accumulator === undefined) {
accumulator = arr[i];
} else {
accumulator = callback(accumulator, arr[i], i, arr);
}
}
return accumulator;
}
This function takes in an array arr
, a callback function callback
, and an optional initial value for the accumulator. It uses a for loop to iterate over the array, and for each element, it applies the callback function to the accumulator and the current element. If the initial value for the accumulator is not provided, the first element of the array is used as the initial value. The callback function is called with four arguments: the accumulator, the current element, the current index and the array.
Here's an example of how you can use the myReduce()
function to add up the values of an array like the reduce()
method:
let numbers = [1, 2, 3, 4];
let sum = myReduce(numbers, (acc, curr) => acc + curr);
console.log(sum) // 10
Note that, this function will not work with arrays that are not fully dense (arrays that have undefined
values between the defined values)
That's correct, the myReduce()
function I provided uses a for loop to iterate over the array, which will skip over any undefined
values in the array. If you need to support arrays with non-dense values, you will need to use a different iteration method, such as for...of
or while
loop, to iterate over the array, or use Array.prototype.filter() to filter out the undefined values before running the loop.
In conclusion, recreating JavaScript's array methods such as filter(), sort(), and map() without using them is not difficult. By using for loops and temporary arrays, you can recreate these methods in a way that is compatible with any environment and can also be optimized for performance. It's always a good practice to know the underlying mechanism of those array methods, this will make you a more confident developer, who can decide which method is the most appropriate for his use case.
Top comments (5)
Although it is a good intellectual exercise, I have a few comments.
1) in what environment are you going to be using js without access to the array prototypes
2) I very much doubt that for general programming you will be able to out-optimise the built in methods. Please explain how this would be possible
3) I don't believe your implementation is equivalent. It is my understanding that .sort() returns the original mutated array while . filter() and .map() return a new array
š My first very good question comment, and I'll try to answer it (without making too many English mistakes š ).
It's possible that the environment in which the code will be executed doesn't support array prototypes or there's a coding policy that prohibits them for security reasons.
It's true that in most cases, built-in methods are very performant and optimized for common use cases. However, there are specific use cases where writing manual methods can be more performant.
For example, built-in sorting methods like .sort() are very efficient for small arrays, but can become very processing time expensive for large arrays. In such cases, a manual sorting method written using an appropriate sorting algorithm can offer much better performance.
Another example is iterating over very large arrays. Built-in methods like .forEach() can become very processing time expensive for large arrays, as they involve calling a callback function for each element in the array. In such cases, it may be more effective to write a manual loop to iterate over the array.
The benefit of an article like this, which explains how to manually recreate JavaScript methods such as filter(), sort(), map() and reduce(), is to understand how these built-in methods work to help developers solve more complex problems by giving them a better understanding of the tools at their disposal and how to use them optimally. It can also help avoid common mistakes when using these built-in methods, as developers will better understand how they work and what they return.
In other words, improving programming skills in general by learning to create more efficient algorithms for manipulating arrays and other types of data.
I hope I have addressed your questions ?
I don't be believe this is true. No sort() in a modern JS runtime is going to be any worse that O(nlog(n)). Even if it were, your replacement has the worst possible performance of any sort. Not only is its performance O(n^2), you didn't even do the basic optimization of iterating one fewer time on each execution of the inner loop. Oh, and for a given comparator function, yours sorts in the reverse direction of the built in sort.
There's nothing wrong with asking how the array functions work, but positing your code as any kind of alternative to the real thing is a bit of a stretch, I think.
š Thank you for your feedback, the debate is on š¤. Let me present some arguments to defend the article and its experimental approach.
It is true that the complexity of the sorting algorithm used in JavaScript's sort() method is generally O(nlog(n)). However, there are cases where this may be slower due to algorithm overhead, such as sorting arrays with already sorted or almost sorted elements.
The alternative sorting algorithm proposed in the article uses a selection sort approach, which is indeed O(n^2). In some cases, this may be faster than JavaScript's sort() method due to the lower overhead of the selection sort algorithm compared to the sort() method.
Regarding the comparison function, the sorting order is defined by the compareFn function. This can be easily modified by changing the comparison logic to match the desired order. I have just added this to the article.
š¤ maybe I write an article on the benefits of this type of experimental approach. Your feedback will be of great help to me. I remain convinced that this type of approach can be beneficial for junior developers, as it can improve their understanding of JavaScript, their problem-solving skills, and allow them to customize functions to meet the specific needs of their project. However, this may take more time and effort and present a risk of error. It is therefore important to weigh the pros and cons before deciding to rewrite existing functions. Perhaps it is best reserved for a development environment and not for production.
Thank you for this insightful article on custom function for array.prototype. After reading it, I feel like I have a much clearer understanding.
The way the article explained the map, filter, reduce and sort function really helped me grasp the concept better. I particularly appreciated the detailed explanation of each function with examples.
For instance, I never fully understood the Array.prototype as in how to apply it as a custom function, but after reading your article, it makes much more sense.
Overall, I'm grateful for the clarity your article provided on this topic. Looking forward to reading more from you!