CEOToolSuite EcmaScript Style & Conventions By supervisor • December 1, 2025 10 years ago I started out on a quest to distill a full comprehension of javascript down to a functional set of conventions. Much of the internet is bogged down with javascript libraries atop other javascript libraries. Many times pages load slowly because of an incorrect management of web technologies. It's easy to overcomplicate frontend and adding frameworks certainly doesn't help. Most frameworks are reinventing the wheel. The ECMAScript standard has everything needed for fast performant sites. If a library is to be used it should be for a specific niche purpose & only if writing a custom solution would take much more time or the library is simply foundational (think bluebird promises before the Promise object was standardized). To this end below is a set of conventions I've found to be helpful in writing vanilla js sites. ## `_` The underscore is helpful for simplifying patterns. There's no point in naming a throw away variable. ## Namespacing By using namespacing, variables (effectively) never collide. ```javascript window.namespace__subspace = { e: {}, f: {}, g: {}, }; ``` - **e** - Element cache for DOM references - **f** - Functions for utilities and methods - **g** - Globals for constants, state, and configuration ## Variable Declarations Always use `var`, never use `const` or `let`. This is intentional - `var` has function scope which is more predictable and hoisting behavior is well understood. `const` and `let` add complexity with block scoping that rarely provides real benefits in well-structured code. ## Async Operations Always use `async`/`await` over promises with `.then()` chains. The code is more readable and easier to debug: ```javascript // note: preferred var data = await (await fetch(url)).json(); // note: avoid fetch(url).then(r => r.json()).then(data => {}); ``` ## Error Handling Avoid `try`/`catch` blocks - let errors surface for debugging. In production, errors should be caught at the top level and logged appropriately. Wrapping every operation in `try`/`catch` hides bugs and makes debugging harder. ## Naming Conventions - double underscore (`__`) separates namespace parts: `namespace__subspace` - single underscore (`_`) separates words within names: `word_in_phrase` - never use hyphens in identifiers ## DOM Access Cache DOM elements in the `e` object rather than querying repeatedly. Use a `refresh_elements()` function that automatically populates the cache: Note the `qsa`, this is a special case and recommendation for the ECMAScript standard: ```javascript window.qsa = document.querySelectorAll.bind(document); ``` More examples can be found in the example utility file @ the end. ```javascript namespace__subspace.f.refresh_elements = () => { namespace__subspace.e = {}; for (var _ of qsa('[namespace__subspace]')) { var tagname = _.tagName.toLowerCase(); var handle = _.getAttribute('namespace__subspace').toLowerCase(); namespace__subspace.e[`${tagname}__${handle}`] = _; } }; ``` ^^ `refresh_elements` is a phrase thus single underscore. ```html <button namespace__subspace="submit">Submit</button> ``` ```javascript namespace__subspace.e.button__submit.addEventListener('click', namespace__subspace.f.namespace__subspace); ``` ## Timing & Race Conditions With a few basic functions code becomes self documenting & timing issues disappear. ```javascript namespace__subspace.f.load__style namespace__subspace.f.load__script namespace__subspace.f.load__html namespace__subspace.f.wait_for_self namespace__subspace.f.wait_for_load namespace__subspace.f.wait_for_elem ``` see example file @ the end. ## No Frameworks Vanilla javascript is sufficient, frameworks add technical debt. - bundle size overhead - learning curve - version upgrade maintenance - abstraction that hides what's actually happening ## Example <a href="https://sites.ceots.io/es/ceots__sites.js" target="_blank">ceots__sites.js</a> ## In The Wild <a href="https://alfred.stlouisfed.org/js/fed.js" target="_blank">fed.js</a>