0

I'm using the Jest testing library to test a function that invokes a callback that takes two parameters, element[i], and i.

Here is the function I am to test:

const each = (elements, cb) => {
  for (let i = 0; i < elements.length; i++) {
    cb(elements[i], i);
  }
};

I know the array will only have numbers, so in the testing function I'm trying to make the callback simply add the index to each number in the array; e.g., it should change an array of [1, 2, 3, 4] to [1, 3, 5, 7].

Here is what I tried to do:

const arrayFunctions = require('./arrays');

describe('Arrays', () => {
    it('each', () => {
        const callBack = (elem, indx) => {
            elem += indx;  
        }
        const arr = [1, 2, 3, 4];
        arrayFunctions.each(arr, callBack);
        expect(arr).toEqual([1, 3, 5, 7]);
    })
});

And here is the error I'm getting:

 Received:
      [1, 2, 3, 4]

    Difference:

    - Expected
    + Received

      Array [
        1,
    +   2,
        3,
    -   5,
    -   7,
    +   4,
      ]

      15 |         const arr = [1, 2, 3, 4];
      16 |         arrayFunctions.each(arr, callBack);
    > 17 |         expect(arr).toEqual([1, 3, 5, 7]);
         |                     ^
      18 |     })
      19 | });
      20 |

      at Object.it (advanced-javascript/arrays.spec.js:17:21)

Why is it not modifying the array as expected? To reiterate with an even simpler example, why does this work:

const arr = [1, 2, 3, 4];
for (let i = 0; i < arr.length; i++) {
  arr[i] += i;
}
console.log(arr) // [1, 3, 5, 7];

While this doesn't?

const arr = [1, 2, 3, 4];
each(arr, callBack);
console.log(arr); // [1, 2, 3, 4];
MadHatter
  • 366
  • 1
  • 7
  • 23
  • 1
    Numbers are immutable. Assigning a parameter does not affect the array. – SLaks Jun 28 '18 at 20:10
  • 1
    It sounds as though you're trying to get an `each` to work more like a `map`. `map` is about transforming the values. `each` is about creating side-effects. Which are you looking for? (And I'm assuming you understand that these are already built into `Array.prototype.) – Scott Sauyet Jun 28 '18 at 20:16
  • @ScottSauyet I'm a student in Lambda School, currently working on Jest testing with JavaScript; I'm aware of the built-in methods on arrays but for the sake of this exercise yes I'm trying to make `each` function more like `map`. Any suggestions? – MadHatter Jun 28 '18 at 20:23
  • 1
    Well, I don't know if your ˋeachˋ is correct, but I do know that the test isn't asking the right question. The other comments and answers should steer you in the right direction. – Scott Sauyet Jun 28 '18 at 20:50

1 Answers1

2

The difference is because of a subtlety of index assignment. It looks like two operators ([n] and +=) but it is actually one: [n]+=. In the end using += (add and assign) is not the same as [n] += (add and assign to value at index), so you can put spaces between the index and the assignment characters (and strangely, even parentheses, but that's just confusing), but you can't split it into separate statement lines, which is effectively what you are doing (see below).

Let's make our own array and look at how we would implement [n] (let's call it get(n)) and [n]=value (let's call that function set(n, value). For ease of readability, I'll use the new class syntax.

class FakeArray {
  get(index) {
    var valueAtIndex = // somehow get that value
    return valueAtIndex
  }

  set(index, value) {
    //somehow set that value
  }
}

Now think about if you could implement set using get. Would this work?:

  set(index, value) {
    this.get(index) = value
  }

It wouldn't. You would get an error: ReferenceError: Left side of assignment is not a reference. (you can change the values of references, but not the values of values). However, if you could, you wouldn't really need the set function. You could just use the get function combined with = (and also +=, -=, etc.). But you can't split them up, so they are completely different functions / operators. It's the same with [n] and [n]=. They work entirely different, they aren't combinations of the two.


Also, when you pass values to a function, you are essentially assigning them to a new variable:

var a = 1;

function foo (b) {
  b = b + 1
  console.log(b)
};

foo(a)
console.log(a)

is mostly equivalent to:

var a = 1;

var b = a
b = b + 1
console.log(b)

console.log(a)

This is called pass by value, and it is the only way to pass values in javascript. See this answer for more detail: What's the difference between passing by reference vs. passing by value?

Garrett Motzner
  • 3,021
  • 1
  • 13
  • 30
  • I understand the code examples but could you elaborate more on your explanation of the two operators `+=`? – MadHatter Jun 28 '18 at 20:59