Classes and ID have their advantages and disadvantages (it is also very dependant on how you use them).
Classes - they were designed to convey styling info, but with advent of jQuery now they have dual purpose, sometimes signifying action (or data) and sometimes styling. This is quite confusing especially on large scale projects. Imagine a designer trying to "re-factor" the CSS and changing these class names on elements that have javascript/jQuery hooked up to it - bad things ensue. You could mitigate against that prefixing your non-styling class names with a "namespace" like ".donttouchthis-jqueryclass", which differentiates the logic from presentation is a very primitive manner. The advantage of using a class is that it can be "stacked" thus it can convey more complex "logic" than an ID for example. From a pure javascript (no jQuery) point of view reliance on classes in your code introduces some backward compatibility issues (getElementsByClassName).
IDs - as the name implies were designed to uniquely identify elements. From a programming point of view IDs offer the fastest way to access elements in the DOM (getElementById). They can also be styled, however the potential to remove an ID when re-factoring is lower (as you can always remove ID styling and give it a class). IDs are unique thus making extensive use of them to store any complex data is very, very limited. But they are great to bind click handlers or uniquely identify chunks of the DOM as long as you only need one of elements identified by them.
Both Classes and IDs have one important rule which limits their usefulness as means for conveying any business logic - they cannot start with a number (and often you just need that database id conveniently assigned to an element)
Custom attributes (not data-) - they can be anything which is kinda cool, however if you care about "validity" of your HTML you will be restricted to certain DTD types and you will need to specify them in your DTD. In reality they do not harm your HTML as browsers are specifically obliged (under the W3C convention) to ignore unknown attributes. The only problem being a clash with potential future developments. If you are using pure javascript they will also be a bit of a pain to use (but this is a subjective option - as suggested in one of the answers above this is a good supplementary option to use them as data storage). The potential for a mixup when re-factoring CSS is small.
Custom data- attributes - these are great if you are using jQuery because you can store really complex data against it (objects etc), when used correctly they really kick ass and give you a nice vocabulary to describe function of your DOM elements. "data-" namespace nicely protects it from any future conflicts with non name-spaced attributes.
Having said all that the best solution is not to overtly rely on any of these, but implement javascript patterns which allow you to pass a parent DOM element and later apply functionality to it based on markup (like a standard jQuery plugin pattern). This way you remove a lot of dependencies on specific attributes/classes/ids that are a part of static HTML source.