What is the difference between String.slice and String.substring?

I’ve worked with JavaScript for quite a while now, and one of the early confusions I faced was the subtle difference between slice and substring. Here’s the gist of it when it comes to javascript substring vs slice:

In JavaScript, the slice method extracts characters from a string starting from the given start index up to, but not including, the end index. It also accepts negative values, which means it can count from the end of the string. On the other hand, the substring method also returns a portion of the string, but it does not support negative values. If the start index is greater than the end index, substring will automatically swap the two values before extracting.

let str = "Hello, world!";
console.log(str.slice(0, 5));     // "Hello"
console.log(str.substring(0, 5)); // "Hello"

So both seem similar until you start playing with edge cases.