I don't see any reason why this wouldn't work if finished. Some untested suggestions that you may have already thought of on your own:
Make an object base class that all things which exist in the game world can inherit from. This will ideally have a collidedWith method, taking as its parameter the other object with which a collision happened and doing nothing. You may also want a doDamage method here, so that enemies and the player can subclass and you don't have to do a bunch of checks to see what type of object it is. The point of this subclass is to do nothing conveniently: if it's a game action, then the default is to let it be called but have an empty implementation. This does not scale, but will be fine for five or ten actions. This gets rid of the if trees that you would otherwise need, no matter how many types of enemy or object you add. The other thing that can easily go here is whether the object has a sound and, if it does, what exactly it is.
There's two ways you can go at that point.
The first is to continue along the lines of what you have but to replace the enemies array with an objects array. If every object in the game world has a width, then collision detection can be implemented with two nested for loops. The basic check is this: if a.pos+a.width/2 > b.pos-b.width/2. By not adding the obvious second case (a.pos-a.width/2 < b.pos+b.width/2) you should avoid duplicates: it will switch a and b before it finishes, and the tests are then equivalent. You may or may not want to use >= instead; in some configurations it does not matter, but for games where everything can only move by one "tile" it will be noticeable.
The advantage of this approach is that it's simple and it lets you do stuff on a granularity that's not always 1 tile. The checks will work fine for objects that are 3.4 units wide and positioned at 3.628. The callback lets you implement obstacles in the same manner as enemies by simply subclassing, so there's no need to flag tiles and this can therefore work fine. The disadvantage is that the algorithm is O(n^2). This basically means that your game will start choking at some point (at some point is hard to define) and then literally go from there to unplayable within just a few enemies (think maybe ten). The at some point could be 100 enemies in a level or 10000, there's no telling without testing.
The second approach is harder but faster, and allows for things like radars that we don't usually need in a side-scroller of this type. Instead of having an array of enemies, have an array of tile classes that are denoted with a terrain. Each tile class can hold one or more objects, and two objects collide every tick in which they occupy the same tile. This will give you performance if you need it as well as the ability to play different sounds based on what the player is walking over. In addition, checking for collisions is O(n) on enemies, which means that if 5 enemies takes 5 seconds, 10 enemies takes 10 seconds, etc. The method is to remember which objects belong to which tiles by putting a handle to a tile in the object; every tick, collide this object with all other objects in its tile.
I'd use the second because it's more general. The first only works for 1d side-scrollers of this type. The checks become much too expensive for something 2d unless you break up your world into rooms or sectors of some sort, and I'm adverse to doing that until and unless I have to. In addition, you will eventually want carpet and tile at the same time or something, and the tiles give you a place to put that. And you can still do nonstandard obstacles by subclassing your object class, just they're only one tile wide. To be completely honest, you can have things that are more than one tile wide, but the book-keeping code becomes formidable at that point.
My BlogTwitter: @ajhicks1992