Sort Function Debugging, Adding to Array.prototype, Default Array.prototype Method Behavior, Constructor Functions, and ESLint

Dean Gladish
5 min readAug 11, 2022

--

Debugging sort functions and nested loops is not about understanding why we are using them, but about understanding how they are implemented; the default behavior of .push() is to mutate the input array and return the new array length. The same goes for .unshift()

If we want to alter the default behavior of .prototype functions, for example to implement the default filter and map functions using the built-in reduce function, we should do the following:

Array.prototype.filterReduce = function(filter) {
this.arr = this.reduce( (acc, element) => {
if (filter(element)) {
acc.push(element);
}
return acc;
}, []);
return this.arr;
};
Array.prototype.mapReduce = function(map) {
this.arr = this.reduce( (acc, element) => {
acc.push(map(element));
return acc;
}, []);
return this.arr;
};
let list = ([
{ item: 'new', price: 3},
{ item: 'prototype', price: 4},
{ item: 'using', price: 5},
{ item: 'classic', price: 3 },
{ item: 'function', price: 6},
{ item: 'notation', price: 3},
]);
Array.prototype.inYourBudget = function(budget) {
return this
.filterReduce(element => element.price <= budget)
.mapReduce(element => element.item);
};
console.log(list.inYourBudget(3));

[“new”, “classic”, “notation”]

There’s an article about .prototype methods saving memory space.² By allowing each instance to have its own copy of .push() and .unshift(); there are a few reasons to define methods outside the function on the prototype instead of sticking them inside the constructor. One of the big ones is that defining a method in prototype will only be stored in memory once; if you create a million instances of your object, it will still only be stored in memory once. However, if you put the property directly on the object, it will exist a million times. Each array has its own values, however adding elements is the same across all arrays — so it makes more sense to add it onto the prototype, where it will exist once and be shared identically across all object instances.³ When we’re writing prototypical methods or, for example, implementing a sort function:

Array.prototype.sort = function() {
let items = this;
let length = this.length;
for (let i = length - 1; i >= 0; i--) {
//Number of passes
for (let j = length - i; j > 0; j--) {
//Compare the adjacent positions
if (items[j] < items[j - 1]) {
//Swap the numbers
debugger;
let tmp = items[j];
items[j] = items[j - 1];
items[j - 1] = tmp;
}
}
}
return items;
}

On the let j = length — i part, if i = length — 1 that would make j = 1 on the first iteration.

The why is simply a process of getting an example array. The how is figuring out the correct values for j and i each iteration, and then making your nested loop based on that. To turn this into a nested loop you use i = length — 1, j = length — i.

The debugger keyword calls the Chrome DevTools console debugger (⌘ j ), on which you’ll see that on the first pass because items[4 — 1] > items[4], that is 6 > 4, the function swaps those elements. The if statement determines whether or not a swap is needed. Still on the first pass, items[2 — 1] > items[2], that is 4 > 3, so those two elements are swapped, modifying the original items array.

For example, if we have a random array with 5 elements, to sort it the comparisons would go:

1, 0 (j done, i decreases, so next iteration, j will be +1)

2, 1 1, 0

3, 2 2, 1 1, 0

4, 3 3, 2 2, 1 1, 0

5, 4 4, 3 3, 2 2, 1 1, 0 (nested is done).

To turn this into a nested loop you use i = length — 1, j = length — i. There’s also a way to go up (like i++ and j++). We actually don’t even need i = 0; it seems like i > 0 makes the code more efficient.⁴

The nested loops in the solution sort this array [4, 3, 2, 1] in the following steps: (1) compare the first two numbers and swap them [3, 4, 2, 1],
i = 3, j = 1, and j — 1 = 0, (2) compare the second and third number and swap them [2, 3, 4, 1], i = 2, j = 2, and j — 1=1, (3) since the first two numbers are out of order again, go back to swap them [2, 3, 4, 1], i = 2, j = 1, and j — 1 = 0, (4) since the first three numbers are all good, compare the third number and the fourth number and swap them [2, 3, 1, 4], i = 1, j = 3, and j — 1 = 2, (5) the second number and third number are out of order again, so we swap them [2, 1, 3, 4], i = 1, j = 2, and j — 1=1, (6) the first two numbers need to be swapped too [1, 2, 3, 4], i = 1, j = 1, and j — 1 = 0. So i loops 3 times and for each time j loops as follows:

i = 3; j only loops once and j = 1;

i = 2; j loops twice from 2 to 1;

i = 1; j loops three times from 3 to 1;

Note: j does not need to be 0, because j — 1 covers that; also i does not have to loop from 3 to 1, it could loop from 1 to 3 too. The most important thing is that, since this is a kind of bubble sort, we should dynamically change the bounds of j.⁵

Debugging with ESLint is so fun; ESLint is a popular JS-related add-on and linting tool which serves the purpose of preventing errors in our code. For example, ESLint can prevent an error related to variables which are declared and not used, and it can turn the overly strict style-guide rule that discourages accessing certain Object.prototype properties off for a given file by adding this comment to the top of the file: /*eslint no-prototype-builtins: "off"*/.⁶ There’s a guide about how to ignore rules in ESLint.⁷

We have to tell it to ignore the rule in the file context in which functions are invoked, not the files in which they are defined. If you have ESLint running, it won’t show an error state for the specified rule; you can also remove the rule across all files by adding a line to your ~/.eslintrc.json.

[1] Michael Koshakow, who has made this possible, explains the syntax of ECMAScript with startling ease.

[2] The purpose of prototype | Codecademy
https://www.codecademy.com/forum_questions/549e589bd3292f3d0e00fa85

[3] Thanks to Aleks Mitrovic, who knows that defining a method in prototype will only be stored in memory once.

[4] Nadia Collado says that the answer to the question “why” is simply a process of getting the method, while Alex Dunne confirms the example of the nested loop.

[5] Yuanxin Chen says the origin of Bubble Sort really is just one of the many ways to sort an array.

[6] no-unused-vars — ESLint — Pluggable JavaScript Linter
https://eslint.org/docs/latest/rules/no-unused-vars

[7] ESLint. Okay, I’m not going to write a whole… | by Ian Coppa | Medium
https://medium.com/@iancoppa/eslint-d14617ee3558

--

--