One way to work around JS's lack of lookbehind is to use non-capturing (?: ) and capturing groups (). Non-capturing groups are matched but not 'remembered', and capturing groups are stored.
As it is with regex, the following is a little dense, but you can see there are three sets of parentheses - a non-capturing, a capturing, and then a non-capturing:
let regexString = /(?:[A-Z]{4}[\d]{3}\s)([A-za-z0-9 ]+)(?:\s\d)/g
The first non-captured group (?:[A-Z]{4}[\d]{3}\s) matches but doesn't remember the course alphanumeric code. The second ([A-za-z0-9 ]+) matches and captures any list of A-Za-z0-9 characters at least once + in the () – i.e. the title. The last tells it to stop matching for the space+'3' with (?:\s\d).
The second issue with capturing groups and javascript is that they are only returned when you use regexString.exec(), and not when you use .match(). .exec() returns an array, with the matched text as the zeroth (not what is wanted here as it includes the non-capturing groups), and then the subsequent indices are capturing groups.
let match1 = x.exec('AAFS209 American Music 3')[1] = 'American Music'.
let match2 = x.exec('AAFS241 3D American Musical Theatre 3')[1] = '3D American Musical Theatre'. (Not sure if that is a course, let alone a thing, but one can hope. Also, wanted to make the regex worked with digits in the title).