NOTE: I have never used this in production code, but I think it's a pretty nifty idea for sort of achieving decoupling between HTML and JavaScript.
The method you chose is the one I use all of the time. If you know your variable names won't change but the selectors that they reference might, here is a solution that might work for you (although you sacrifice a few things while doing this).
You could have a container that fills itself with variables for you. You're going to have to name the variable either way, so you can store the name in an attribute and initialize the container when the DOM loads.
Here is an example of this technique in Vanilla JS:
function test() {
// access elements from container
console.log(DOMComponents.example);
}
function initializeDOMComponentContainer() {
// create a container if it doesn't exist
if (!window.DOMComponents || typeof window.DOMComponents === 'undefined') {
window.DOMComponents = {};
}
// look for all elements with data-var attribute and add to container
[].forEach.call(document.querySelectorAll('[data-var]'), function (el) {
var id = el.id,
name = el.getAttribute('data-var');
if (typeof id !== 'undefined' && name.length > 0) {
DOMComponents[name] = '#' + id;
}
});
}
document.addEventListener('DOMContentLoaded', function () {
initializeDOMComponentContainer();
test();
});
You would just add an attribute to your HTML to take advantage of this:
<table id="example" class="display" data-var="example" cellspacing="0" width="100%">
...
</table>
So you would define the variable names in a data-var
attribute and never change them and continue to access the elements like you would normally.
Personally, I think it's a pretty neat idea, but you sacrifice having an object you can view from statically inspecting the code. You can always open a console to inspect it, but there's just something nice about seeing the map in code.