Correction for guide of "Understand the Hazards of Using Imperative Code"

Understand the Hazards of Using Imperative Code


Problem Explanation

What you should notice is the fact that output is not as suggested in instructions, which should be the following array:
['FB', 'Gitter', 'Reddit', 'Twitter', 'Medium', 'new tab', 'Netflix', 'YouTube', 'Vine', 'GMail', 'Work mail', 'Docs', 'freeCodeCamp', 'new tab'].

Instead, you will receive this array: [‘FB’, ‘Gitter’, ‘Reddit’, ‘Twitter’, ‘Medium’, ‘new tab’, ‘Netflix’, ‘YouTube’, ‘GMail’, ‘Docs’, ‘freeCodeCamp’, ‘new tab’].
Take a look at the last part of code to make a conclusion where is the issue.

Part 1

const finalTabs = socialWindow

After this part of the code is executed, our array is ['FB', 'Gitter', 'Reddit', 'Twitter', 'Medium']

Part 2

.tabOpen() // Open a new tab for cat memes  

Part 3
After adding a ‘new tab’ to the array, our array is now ['FB', 'Gitter', 'Reddit', 'Twitter', 'Medium' , 'new tab']

.join(videoWindow.tabClose(2)) // Close third tab in video window, and join

This part of the code should supposedly close the third tab (index 2 as the count starts from 0) and return video window without the third tab which is 'Vimeo' in this case. So, returned array should look like ['Netflix', 'YouTube', 'Vine']** and after adding it to the main array, our array should be **['FB', 'Gitter', 'Reddit', 'Twitter', 'Medium' , 'new tab', 'Netflix', 'YouTube', 'Vine']

Part 4

.join(workWindow.tabClose(1).tabOpen());

This part would close second tab (index 1) in the workWindow [‘GMail’, ‘Inbox’, ‘Work mail’, ‘Docs’, ‘freeCodeCamp’], which would be ‘Inbox’, and after that push a ‘new tab’ to the array, returning [‘GMail’, ‘Work mail’, ‘Docs’, ‘freeCodeCamp’, ‘new tab’] and adding it to the main array.

If we compare the requested array and the one we received after running the initial code, we can see that values ‘Vine’ and ‘Work mail’ are omitted. Therefore, we need to see what is the cause of this.
Now that we know this, we will check the operations done on that array. This is done in Part 3:

.join(videoWindow.tabClose(2)) // Close third tab in video window, and join

We can see that tabClose() is performed on this array, so we will analyze the code contained in that method.

tabClose = function (index) {
 1. const tabsBeforeIndex = this.tabs.splice(0, index); // get the tabs before the tab
 2. const tabsAfterIndex = this.tabs.splice(index); // get the tabs after the tab

 3. this.tabs = tabsBeforeIndex.concat(tabsAfterIndex); // join them together 
 4. return this;
 };

For an index, we will take 2 - as done in the challenge.

  1. At the beginning, our array videoWindow looks like this:
    ['Netflix', 'YouTube', 'Vimeo', 'Vine'].
  2. After first line is executed, variable tabsBeforeIndex will take 2 (index) values starting from 0 (splice(0,2)) and create a new array containing them.
    Arrays now look like this:
    tabsBeforeIndex: ['Netflix', 'YouTube']
    videoWindow: ['Vimeo', 'Vine']
    You can already see why splice() can be very hazardous, as it always modifies the array it is executed upon and returns that modified array - it is not deterministic.
  3. After second line is executed, tabsAfterIndex should take values starting from index (in this case 2) and remove them from videoWindow array. As we can see that in the current state (['Vimeo', 'Vine']), videoWindow does not have index 2 so empty array is returned. Final state:
    tabsBeforeIndex: ['Netflix', 'YouTube']
    videoWindow: ['Vimeo', 'Vine']
    tabsAfterIndex: []
    After the third line and concatenation the returned array is the same as tabsBeforeIndex, which results in both 'Vimeo' and 'Vine' values not being in the array.

Solutions

Solution 1 (Click to Show/Hide)

using splice(). This creates side effects(changes to the original array) and should be avoided in practice.

In order for the method tabClose to work properly,

 const tabsAfterIndex = this.tabs.splice(index + 1);

should be replaced with

 const tabsAfterIndex = this.tabs.splice(1);

This way, after second line is executed on the current array [‘Vimeo’, ‘Vine’], it will always omit the first value (index 0) and the one with index 1 until the end, resulting in the proper array returned.

Solution 2 (Click to Show/Hide)

using slice(). This does not create side effects and should be preferred over splice().

This part of the code:

 const tabsBeforeIndex = this.tabs.splice(0, index); // get the tabs before the tab
 const tabsAfterIndex = this.tabs.splice(index + 1); // get the tabs after the tab

should be replaced with:

 const tabsBeforeIndex = this.tabs.slice(0, index); // get the tabs before the tab
 const tabsAfterIndex = this.tabs.slice(index + 1); // get the tabs after the tab

Word of caution

splice() should be always used carefully as it modifies the contents it is working on. For documentation and differences between splice and slice please take a look at:

I dont know how can I edit wiki page (even is this possible). This took 1 hour to prepare it in markdown.

  1. I replaced var with const.
  2. A few “window” word converted to “tab” word as it is meant (tabs).
  3. In solution 1, I edited first code line for consistency about actual challenge page / guide page. (Sorry for my bad English but, if needed, i will provide more information.)

Hi, I ended up with the following solution:

Solution 3

using splice(). This creates side effects (changes to the original array) and should be avoided in practice.
In order for the method tabClose to work properly,


  const tabsBeforeIndex = this.tabs.splice(0, index);
  const tabsAfterIndex = this.tabs.splice(index);
  this.tabs = tabsBeforeIndex.concat(tabsAfterIndex);

should be replace with

this.tabs.splice(index, 1);

Thank you for your guide post contribution. I have taken your suggestions and included them in the guide post.

We look forward to your further contribution.