**Exercise 1.** Make a shallow copy of an array of any length in one destructuring assignment! If you don't know what a shallow copy is, make sure you read about it, as you will need these concepts during your programming career. I can highly recommend my article on Cloning Objects in JavaScript.

**Solution**:

Use the Spread operator on the left to create assignments between each element in the original array and the cloned array.

1 2 3 4 5 6 7 8 9 10 |
let originalArray = [ 2, 3, { a: 4 } ]; let [...clonedArray] = originalArray; console.log( clonedArray == originalArray, clonedArray, originalArray ); // false [2, 3, 4] [2, 3, 4] console.log( originalArray[2] === clonedArray[2] ); // true |

**Exercise 2**: Determine the value logged to the console on Google Chrome without running it. Write down the mechanism behind it using your own words.

1 2 3 4 5 6 7 |
let f = () => [..."12345"]; let A = f().map( f ); console.table( A ); |

**Solution:**:

An array of five vectors of `['1', '2', '3', '4', '5']`

is printed out as a table.

The mechanism is the exact same as the explanation in the next exercise.

The function `f`

creates the array `['1', '2', '3', '4', '5']`

.

in `f().map( f )`

, only the length of `f()`

matters, as the values are thrown away by the mapping function. Each element of the `f()`

array is mapped onto the array `['1', '2', '3', '4', '5']`

, making a 2 dimensional array of vectors `['1', '2', '3', '4', '5']`

.

**Exercise 3.** Create an 10x10 matrix of `null`

values.

**Solution**:

1 2 3 4 |
let nullVector = () => new Array(10).fill( null ); this.field = nullVector().map( nullVector ); |

Study the `fill`

method for more details here.

We create a `null`

vector of size 10 with the `nullVector`

function. The values of the first `nullVector()`

return value don't matter, as we map each of the ten elements to another value. The `nullVector`

mapping function throws each `null`

value away, and inserts an array of ten nulls in its place.

**Exercise 4.** Rewrite the `sumArgs`

function of this tutorial in ES2015, using a rest parameter and arrow functions.

1 2 3 4 5 6 7 |
function sumArgs() { var result = 0; for( var i = 0; i < arguments.length; ++i ) result += arguments[i]; return result; } |

**Solution:**

1 2 3 4 5 |
function sumArgs( ...numbers ) { return numbers.reduce( (sum,num) => sum+num, 0 ); } |

Reminder of how `reduce`

works: the first argument of the reduce function is an accumulator, which is initialized to `0`

. The upcoming element of the original array is stored in `num`

. Let's log each iteration of the reduction:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
function sumArgs( ...numbers ) { return numbers.reduce( (sum,num) => { console.log( '(sum, num): ', sum, num ); return sum+num; }, 0 ); } sumArgs(2,3,4,5,6) // console output: (sum, num): 0 2 (sum, num): 2 3 (sum, num): 5 4 (sum, num): 9 5 (sum, num): 14 6 // result: 20 |

**Exercise 5.** Complete the following ES2015 function that accepts two String arguments, and returns the length of the longest common substring in the two strings. The algorithmic complexity of the solution does not matter.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
let maxCommon = ([head1,...tail1], [head2,...tail2], len = 0) => { if ( typeof head1 === 'undefined' || typeof head2 === 'undefined' ) /* Write code here */ if ( head1 === head2 ) /* Write code here */ let firstBranch = /* Write code here */ let secondBranch = /* Write code here */ return Math.max( ...[len, firstBranch, secondBranch ] ); } maxCommon( '123', '1' ); // 1 maxCommon( '11111', '11f111g'); // 3 maxCommon( 'abc', '111cab' ); // 2 |

**Solution:**

We will use an optional `len`

argument to store the number of character matches before the current iteration of `maxCommon`

was called.

We will use recursion to process the strings.

If any of the strings have a length of `0`

, either `head1`

, or `head2`

becomes `undefined`

. This is our exit condition for the recursion, and we return `len`

, i.e. the number of matching characters right before one of the strings became empty.

If both strings are non-empty, and the heads match, we recursively call `maxCommon`

on the tails of the strings, and increase the length of the counter of the preceding common substring sequence by `1`

.

If the heads don't match, we remove one character from either the first string or from the second string, and calculate their `maxCommon`

score, with `len`

initialized to `0`

again. The longest string may either be in one of these branches, or it is equal to `len`

, counting the matches preceding the current strings `[head1,...tail1]`

and `[head2,...tail2]`

.

1 2 3 4 5 6 7 8 9 |
maxCommon = ([head1,...tail1], [head2,...tail2], len = 0) => { if ( typeof head1 === 'undefined' || typeof head2 === 'undefined' ) return len; if ( head1 === head2 ) return maxCommon( tail1, tail2, len+1 ); let firstBranch = maxCommon( tail1, [head2, ...tail2], 0 ); let secondBranch = maxCommon([head1,...tail1], tail2, 0 ); return Math.max( ...[len, firstBranch, secondBranch ]); } |

Note that this solution is very complex, and requires `#(s1)! * #(s2)!`

steps, where `s1`

and `s2`

are the two input strings, and `#(...)`

denotes the length of a string. For those practising for a Google interview, note that you can solve the same problem in steps of `O( #(s1) * #(s2) )`

magnitude using dynamic programming.