Find palindromic substrings as efficiently as possible
You code looks pretty neat, i do not think that using recursion would improve it very much, but i have some minor suggestions;

1) Performance-wise improvements

The only thing that seems odd at first glance is how you reverse the string to compare subString.split('').reverse().join('');

I had to look it up, but i found that the way that you are doing its the right way using In-built functions, and its pretty much good for almost all cases, but if you want to improve a little the performance you could use something like:

function reverse(s) {
  var o = [];
  for (var i = 0, len = s.length; i &lt;= len; i++)
    o.push(s.charAt(len - i));
   return o.join('');
}


Using this function is has an improve in performance over your current implementation.

2) Readability

You could extract your conditional and use it as a function so your intent would be more clear:

let isPalindrome = function (word, words) {
  return word === word.split('').reverse().join('') &amp;&amp; !words.includes(word)
}


and use this function in the conditional as:

if(isPalisdrome(subString, subStrings)) {
          subStrings.push(subString);
 }


3) Conclusion

In the end putting all together the code would be something like:

function reverse(s) {
  var o = [];
  for (var i = 0, len = s.length; i &lt;= len; i++)
   o.push(s.charAt(len - i));
   return o.join('');
}

function isPalindrome(word, words) {
  return word === reverse(word) &amp;&amp; !words.includes(word)
}

function countPalindromesInString(s) {
    let subStrings = [];
    for (let i = 0; i &lt; s.length; i++) {
      for(let j = 0; j &lt; s.length - i; j++) {
        let subString = s.substring(j, j + i + 1);
        if(isPalindrome(subString, subStrings)) {
          subStrings.push(subString);
        }
    }
  }
  return subStrings.length;
}