1

function rot13(str) {
  let alphArr = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".split("");
  let n = 13;
  let arr = str.split("");
  let len = alphArr.length;

  for (let i of arr) {
    if (alphArr.includes(i)) {
      if (alphArr.indexOf(i) + n <= len - 1) {
        i = (alphArr[alphArr.indexOf(i) + n])
        console.log(i) // This is as expected
      }
    }
  }

  console.log(arr) // Array itself did not mutate and is showing the initial array. 
  return str;
}

rot13("SERR PBQR PNZC");

The value of i inside the second if statement is proper as can be seen in the console.log statement but the array in itself did not mutate. Why was that?

P.S. I've solved it by using map function and it works properly because map function does not mutate the original array.

pretzelhammer
  • 13,874
  • 15
  • 47
  • 98
progTurd
  • 21
  • 5
  • what are you trying to do and what is the expected result? – HW Siew Jun 23 '20 at 15:43
  • Try console.log `alphArr[alphArr.indexOf(i)+n]` – luek baja Jun 23 '20 at 15:46
  • 4
    assigning to `i` does not change the array. You are merely reassigning an unrelated variable in this case. – VLAZ Jun 23 '20 at 15:46
  • @VLAZ ohkay... but why is it an unrelated variable. I'd assume it was the current element of the array. Please elaborate a bit more and share any documentation if available. I'd really like to get to the bottom of this and would be very grateful . – progTurd Jun 23 '20 at 16:15
  • 1
    It's the *value* of the current array item. However, changing it won't change the array, since [JavaScript is not pass-by-reference](https://stackoverflow.com/questions/518000/is-javascript-a-pass-by-reference-or-pass-by-value-language) – VLAZ Jun 23 '20 at 16:16
  • 1
    @VLAZ Now I get it. Its due to the pass by value as its just represents the value of the element. Thank you so much for the clarification! – progTurd Jun 23 '20 at 16:20
  • @HWSiew Actually its just part of the entire problem that i needed to solve. My bad. I should have provided the entire context but then it was enough for the specific query that I had. – progTurd Jun 23 '20 at 16:24
  • @luekbaja That works. I get it now as to why it wasn't working. – progTurd Jun 23 '20 at 16:25

3 Answers3

2

It's worth mentioning that your code can be simplified:

let rot = (str, n, asciiStart='A'.charCodeAt(0), asciiEnd='Z'.charCodeAt(0), asciiRange=asciiEnd-asciiStart+1) =>
  str.split('')
    .map(c => {
      let code = c.charCodeAt(0) - asciiStart;
      if (code >= 0 && code <= asciiRange) code = (code + n) % asciiRange;
      return String.fromCharCode(asciiStart + code);
    })
    .join('');

let inp = document.getElementsByTagName('input')[0];
let p = document.getElementsByTagName('p')[0];

inp.addEventListener('input', () => p.innerHTML = rot(inp.value, 13));
<input type="text" placeholder="test here (use capital letters)"/>
<p></p>

Your code wasn't working because replacing the value of i does not effect the array index that i was initially based off of. Once you define i, it doesn't remember how it was defined (e.g. it doesn't think to itself, "I originated from a value within an array')

Gershom Maes
  • 7,358
  • 2
  • 35
  • 55
1

You can't directly set value to element in for of loop try the following...

function rot13(str) {
  let alphArr = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".split("");

  let n = 13;
  let arr = str.split("");
  let len = alphArr.length;

  let j=0
  for (let i of arr) {
    if (alphArr.includes(i)) {
      if (alphArr.indexOf(i) + n <= len - 1) {

        arr[j]= (alphArr[alphArr.indexOf(i) + n])
        console.log(i) // This is as expected

      }
    }
    j++
  }
  console.log(arr) // Array itself did not mutate and is showing the initial array. 


  return str;
}

rot13("SERR PBQR PNZC");
  • If you are going to use a loop counter, you may as well use a regular loop `for (let i = 0; i < arr.length; i++)` and use `arr[i]` inside it. Mixing a `for..of` and counters is just messy. A better solution would be to just iterate over the entries in the array, which includes the index: `for (let [index, element] of arr.entries())` – VLAZ Jun 23 '20 at 16:00
  • Yes I would have done that for my code but here I used the code which was provided by the questioner. –  Jun 23 '20 at 16:04
  • Sorry for messy solution –  Jun 23 '20 at 16:05
  • I didn't know that you couldn't do and I didn't find any documentation saying it can't be done. Please share if you have if you find something. – progTurd Jun 23 '20 at 16:13
  • 1
    The element in for of loop only contains the value of a particular property you can see it on MDN docs. –  Jun 23 '20 at 16:30
  • I got the answer. It's because of the pass by value condition. – progTurd Jun 23 '20 at 16:33
  • Thank you Parth. You're spot on! VLAZ pointed it out above and it just rung a bell. – progTurd Jun 23 '20 at 16:34
  • You are Welcome –  Jun 23 '20 at 16:38
1

Instead of using a for of loop you should use map to create a new array and used the newly mapped array. Fixed fulling working example:

function rot13(str) {
  let alphArr = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".split("");

  let n = 13;
  let arr = str.split("");
  let len = alphArr.length;

  arr = arr.map((i) => {
    if (alphArr.includes(i)) {
      let index = (alphArr.indexOf(i) + n) % len;
        return alphArr[index];
      }
     return i;
  });

  return arr.join("");
}

console.log(rot13("SERR PBQR PNZC")); // logs "FREE CODE CAMP"
pretzelhammer
  • 13,874
  • 15
  • 47
  • 98
  • I did solve it with map as it does not mutate the original array as Matt pointed out but I'm just confused as to why the original array did not get mutated in this case. – progTurd Jun 23 '20 at 16:10
  • I got the answer thanks to VLAZ. It's because of the pass by value thing and that's why alphArr[alphArr.indexOf(i)+n] would work. – progTurd Jun 23 '20 at 16:32