Longest Substring Without Repeating Characters in JS The task

is taken from leetcode


  Given a string, find the length of the longest substring without
  repeating characters.
  
  Example 1:
  
  Input: "abcabcbb"
  
  Output: 3 
  
  Explanation: The answer is "abc", with the length of 3. 
  
  Example 2:
  
  Input: "bbbbb"
  
  Output: 1
  
  Explanation: The answer is "b", with the length of 1.
  
  Example 3:
  
  Input: "pwwkew"
  
  Output: 3
  
  Explanation: The answer is "wke", with the length of 3. 
               Note that the answer must be a substring, "pwke" is a subsequence and not a substring.


My solution

var lengthOfLongestSubstring = function(s) {
    const len = s.length;
    if (len &lt; 2) { return len; }
    let res = [];
    let tmp = [];
    [...s].forEach(x =&gt; {
      if (tmp.includes(x)) {
        tmp = [...tmp.slice(tmp.findIndex(y =&gt; y === x ) + 1)];
      }
      tmp.push(x);    
      if (tmp.length &gt; res.length) { res = tmp; }
    });
  return res.length;
};
Style


Nice usage of arrow functions and spread operators. You can extend this to the function name as well: 

const lengthOfLongestSubstring = s =&gt; { ... };

The code switches between two and four spaces within a block and between blocks. Choose one and stick with it throughout the entire program (the auto-formatter built into Stack Exchange does the job well).
Avoid the intermediate variable len here:

    const len = s.length;
    if (len &lt; 2) { return len; }


The extra variable obfuscates the direct and explicit s.length and offers no performance benefit (as it would in C with strlen, which is linear). s.length is a numerical property and doesn't walk the list per call.
Use vertical whitespace around blocks. Here's how I'd rewrite the above lines:

    ...
    if (s.length &lt; 2) { 
      return s.length; 
    }

    let res = [];
    ...


Then again, I prefer to omit this logic because the rest of the function body will handle the precondition automatically.
Variable names can be a bit more specific: tmp => seen, x => char, res => longest.


Performance

Your solution runs in O(len(longest_subsequence) * n) time, which is in the 70th percentile of solutions for this problem. The culprits are includes, findIndex, slice and spread inside the for loop, all of which require visiting up to every element in tmp.

We can improve the time complexity to linear and reach the 99th percentile. The key is using an object as a hash map instead of an array to keep track of the history. For each character in s, add it to the object with a value of its latest-seen index. Keep track of the start of the current candidate run. Whenever we encounter an item already in the map, check to ensure its index is indeed inside the current run. If so, record a new longest (if applicable) and begin a new candidate run.

Here's the code:

const lengthOfLongestSubstring = s =&gt; {
  let longest = 0;
  let start = 0;
  const seen = {};

  [...s].forEach((char, i) =&gt; {
    if (char in seen &amp;&amp; start &lt;= seen[char]) {
      longest = Math.max(i - start, longest);
      start = seen[char] + 1;
    }

    seen[char] = i;
  });

  return Math.max(s.length - start, longest);
};