Interview question for a Senior Js Developer, final part (Answer)
Tags: javascript, webdev, node, devjournal
Published: 2021-01-15 21:37:31

In my [last post](https://dev.to/eulier/interview-question-for-a-senior-js-developer-pt-1-questions-1lpm) i talked about, how i went from looking for a job using the [ApplyByAPI](https://applybyapi.com/) to an interview question.

I split this in two part, so you can watch it in another tab, and switch it easily, instead of wheeling up and down with the mouse.

This is just for educational purposes.

### Answer 1

The error take place when the condition evaluate the `"Superman is awesome!"` and the `indexOf ` method return 0 (which is the index) and it's evaluate as false, so to prevent this, we could wrap the expression and compare to less than 0. (-1 means it could not found it).

    function validateString(str) {
        if ((str.toUpperCase().indexOf('superman'.toUpperCase())) < 0) {
            throw new Error('String does not contain superman');
        } 
    }

### Answer 2 

If you need to search elements in a **sorted** array, binary search algorithm is the way to go, their Big O is O(log n), so the steps to do it is:

1. Define `let start = 0` and `let end = n-1` (where n-1 is the last element of the **sorted** array) 
2. If `start` < `end`, then stop: target is not present in array. Return -1.
3. 2. Compute `guess` as the average of `start` and `end`, rounded down (so that get an integer). 
4. If `array[guess]` equals `target`, then stop. You found it! Return `guess`.
5. If the `guess` was too low, that is, `array[guess] < target`, then set `start = guess + 1`.
6. Otherwise, the `guess` was too high. Set `end = guess - 1`.
7. Go to step 2
  
```
function binarySearch(sortedArray, key){
    let start = 0;
    let end = sortedArray.length - 1;

    while (start <= end) {
        let guess = Math.floor((start + end) / 2);

        if (sortedArray[middle] === key) {
            return guess;
        } else if (sortedArray[middle] < key) {
            start = guess + 1;
        } else {
            end = guess - 1;
        }
    }
    return -1;
}
```

### Answer 3

```
const phonenumberFormatter = (numberString, delimiter = '-') => {
    let arrayInputPhoneNumberString = numberString.trim().split('')
    let arrayOutputPhoneNumberString = []
    const lengthUSPhoneBlock = 10 // 3-3-4 US block standard
    let counterLenPhoneBlock = 0

    arrayInputPhoneNumberString.forEach( (value) => {
        if (parseInt(value) === 0 || parseInt(value)) {
            counterLenPhoneBlock++
            arrayOutputPhoneNumberString.push(value)
            if (counterLenPhoneBlock === 3 || counterLenPhoneBlock === 6 ) {
                arrayOutputPhoneNumberString.push(delimiter)
            }
        }
    })

    if(counterLenPhoneBlock === lengthUSPhoneBlock) {
        return arrayOutputPhoneNumberString.join('').toString()
    }

    return 'missing numbers, check your phonenumber again'
}
```

### Answer 4

```
// Assuming we set up our enviroment to use Import ES6 Syntax

import fizzBuzz from './fizzbuzz';

describe('Fizzbuzz Test', () => {
    
    test('output 1 for input 1', () => {
        expect(fizzBuzz).toEqual(1)
    });

    test('output "Fizz" for input 3', () => {
        expect(fizzBuzz).toEqual('Fizz')
    });

    test('output "Buzz" for input 5', () => {
        expect(fizzBuzz).toEqual('Buzz')
    });

    test('output 7 for input 7', () => {
        expect(fizzBuzz).toEqual(7)
    });
    
    test('output "Fizz" for input 9', () => {
        expect(fizzBuzz).toEqual('Fizz')
    });

    test('output "Buzz" for input 10', () => {
        expect(fizzBuzz).toEqual('Buzz')
    });

    test('output "FizzBuzz" for input 15', () => {
        expect(fizzBuzz).toEqual('FizzBuzz')
    });

    test('output "FizzBuzz" for input 45', () => {
        expect(fizzBuzz).toEqual('FizzBuzz')
    });
})
```

### Answer 5

```
    const hash = (name) => {
      let hash = 0;
      for (var i = 0; i < name.length; i++) {
        /* 
        * retrieve the UTF-16 value 
        * while shift left the hash value 
        * (an hex value can be represent up to (2^5 -1) from 0 - 15 )
        * minus the previous hash value ( for more random purpose )
        */
        hash = name.charCodeAt(i) + ((hash << 5) - hash);
      }
      return hash;
    }

    const getColorFromName = (name) => {
        let hashCode = hash(name)
        let value = 0
        let color = "#"
        /*
        * Build the hex char, i.e. #000000 
        */
        for (let i = 0; i < 3; i++) {
            /*
            * Nudge right 8 position from the hash up to 3 times 
            * and bring the commons bits from the hexadecimal higgest value.
            * Then, build the color string.
            */
            value = (hashCode >> (i * 8)) & 0xFF;
            color += ('00' + value.toString(16)).substr(-2);
        }
        return color
    }
```
To make code much modular and easy to maintain, we can pass to `getColorFromName()` the `hash` function as a second parameter.

### Answer 6

In our IIFE, we need to access to `addEventListener` from the `getElementById`, so when listen the 'click' event,
we can trigger our code.

```
(function(){
	for (var i = 0, l = 10; i < l; i++) {
        document.getElementById('button-' + i).addEventListener('click', function (event) {
            console.log('Line %s', i);
        })
	}
})();
```

However there is a couple gotchas here, hoisting and closure. You see, hosting is a very annyoning concept in the ES5
and below, is the process of initialize all functions and variables and place them into memory.
Functions are hosted in memory, but variable are initializes as `undefined`, this is a behaviour we can avoid using
`let` & `const` thanks to the block scope, but this is for ES6, and we need to solve this on ES5.

So, we can use closure, and they allow functions to gain access variables to outer scope from inner scope. The Javascript Engine will keep those variables around inside function if they have reference to them, instead of "sweeping" them away after they popped off the call stack. Here is how we can solve this.

```
(function(){
	for (var i = 0, l = 10; i < l; i++) {
        (function(i){
            document.getElementById('button-' + i).addEventListener('click', function (event) {
                console.log('Line %s', i);
            })
        })(i)
	}
})();
```

Here is the code sample with the html

```
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <button id="button-0">click 0</button>
    <button id="button-1">click 1</button>
    <button id="button-2">click 2</button>
    <button id="button-3">click 3</button>
    <button id="button-4">click 4</button>
    <button id="button-5">click 5</button>
    <button id="button-6">click 6</button>
    <button id="button-7">click 7</button>
    <button id="button-8">click 8</button>
    <button id="button-9">click 9</button>
</body>
<script>
(function(){
	for (var i = 0, l = 10; i < l; i++) {
        (function(i){
            document.getElementById('button-' + i).addEventListener('click', function (event) {
                console.log('Line %s', i);
            })
        })(i)
	}
})();
</script>
</html>
```

### Answer 7

An iterable is a generalization of arrays, and technically having a method `Symbol.iterator` makes one.

```
function isIterable(obj) {
  // checks for null and undefined
  if (obj == null) {
    return false;
  }
  return typeof obj[Symbol.iterator] === 'function';
}
```