Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 15 additions & 3 deletions src/reduce.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,33 @@
'use strict';
'use strict';

/**
* Custom implementation of Array.prototype.reduce
*
* @param {function} callback
* @param {*} startValue
*
* @returns {*}
*/
function reduce(callback, startValue) {
let prev = startValue;
if (typeof callback !== 'function') {
throw new TypeError(callback + ' is not a function');
}

let prev;
let startIndex = 0;

if (arguments.length < 2) {
startIndex = 1;
if (this.length === 0) {
throw new TypeError('Reduce of empty array with no initial value');
}
prev = this[0];
startIndex = 1;
} else {
prev = startValue;
}

for (let i = startIndex; i < this.length; i++) {
if (!(i in this)) continue; // skip sparse array holes
prev = callback(prev, this[i], i, this);
}

Expand Down
47 changes: 45 additions & 2 deletions src/reduce.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,52 @@ describe('reduce', () => {
delete Array.prototype.reduce2;
});

it('should ', () => {
it('should sum numbers in an array', () => {
const arr = [1, 2, 3, 4];
const result = arr.reduce2((acc, val) => acc + val, 0);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add an explicit test ensuring reduce itself does not modify the original array (unless the reducer deliberately mutates it). For example, copy the array before/after calling reduce2 and assert the array content and length are unchanged when the reducer doesn't mutate the array.

expect(result).toBe(10);
Comment on lines +14 to +17

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Include tests that exercise non-number types to ensure accumulator propagation works across types. For example, a string concatenation test (['a','b','c'].reduce2((a,b)=>a+b, '')) and an object-merge test (accumulating properties into an object) are required by the description.

});

it('should multiply numbers in an array', () => {
const arr = [1, 2, 3, 4];
const result = arr.reduce2((acc, val) => acc * val, 1);
expect(result).toBe(24);
Comment on lines +20 to +23

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add tests that verify mutation-during-reduction semantics. Specifically, check that elements appended after reduction starts are not visited (length captured at start) and elements removed before being visited are skipped. Create a test where the reducer mutates the array (push/splice/pop) and then assert which indices were visited and how many times the callback was called.

});

it('should work without initial value', () => {
const arr = [1, 2, 3];
const result = arr.reduce2((acc, val) => acc + val);
expect(result).toBe(6);
Comment on lines +26 to +29

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add tests for single-element arrays with and without an initial value. For example: (1) [5].reduce2((acc, v) => acc + v) should return 5; (2) [5].reduce2((acc, v) => acc + v, 10) should return 15. These confirm correct behavior when using the first element as the initial accumulator and when an explicit initial is provided.

});

// Add tests here
it('should handle empty array with initial value', () => {
const arr = [];
const mockCb = jest.fn();
const result = arr.reduce2(mockCb, 5);

expect(result).toBe(5);
expect(mockCb).toHaveBeenCalledTimes(0);
});

it('should throw error when empty array and no initial value', () => {
const arr = [];
expect(() =>
arr.reduce2((acc, val) => acc + val)
).toThrow(TypeError);
});

it('should pass correct arguments to callback', () => {
const arr = [10, 20];

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a test for sparse arrays (holes). For example: const arr = [1, , 3]; const cb = jest.fn((acc, v, idx) => acc + v); arr.reduce2(cb, 0); then assert cb was called for indices 0 and 2 only and that the hole at index 1 was skipped. This matches native reduce semantics and is required by the description.

const mockCb = jest.fn((acc, val, idx, array) => acc + val);
arr.reduce2(mockCb, 0);

const argsCall1 = [0, 10, 0, arr];
const argsCall2 = [10, 20, 1, arr];

expect(mockCb).toHaveBeenCalledTimes(2);
expect(mockCb).toHaveBeenNthCalledWith(1, ...argsCall1);
expect(mockCb).toHaveBeenNthCalledWith(2, ...argsCall2);
});
});