The this.notes && ensures that this.notes exists first. If it doesn't exist, it'll return without throwing an error (to be more precise, it'll return the falsey value of this.notes - probably undefined).
If you unconditionally returned this.notes.sort, an error will be thrown if this.notes is not an array. For example:
class Notes {
  sortedNotes() {
    return (
      this.notes &&
      this.notes.sort((a, b) => {
        const aDate = new Date(a.createdAt)
        const bDate = new Date(b.createdAt)
        return bDate - aDate
      })
    )
  }
}
const n = new Notes();
// this.notes doesn't exist yet, so this doesn't do anything, but at least it doesn't throw an error:
n.sortedNotes();
console.log('done');
 
 
class Notes {
  sortedNotes() {
    return (
      this.notes.sort((a, b) => {
        const aDate = new Date(a.createdAt)
        const bDate = new Date(b.createdAt)
        return bDate - aDate
      })
    )
  }
}
const n = new Notes();
// Throws:
n.sortedNotes();
console.log('done');
 
 
So the test for this.notes' existence is needed to avoid an error when this.notes doesn't exist when sortedNotes is called.
It may have just been a typo, but make sure that something follows the return statement other than a plain newline - either use return this.notes.sort((a, b) => {, or put an opening parentheses ( right after it, to avoid ASI problems. (otherwise, nothing will be returned)
return (foo && bar);
means: Evaluate foo. If it is truthy, evaluate bar and return bar. Otherwise, return foo.
return (bar && foo);
means: Evaluate bar. If it is truthy, evaluate foo and return foo. Otherwise, return bar.
In your context, a more accurate minimal example would be when it's not known whether a property exists yet. Eg
return obj.fn()
will throw if obj is undefined, whereas
return obj && obj.fn();
will not throw.
All this said, this is odd code to write. It would be much more readable to have an explicit test instead, eg something like:
if (!obj) {
  return 'Not defined yet!';
} else {
  return obj.fn();
}