| description | Vibe coding guidelines and architectural constraints for JavaScript within the frontend domain. | |||||
|---|---|---|---|---|---|---|
| technology | JavaScript | |||||
| domain | frontend | |||||
| level | Senior/Architect | |||||
| version | ES6-ES2024 | |||||
| tags |
|
|||||
| ai_role | Senior JavaScript Performance Expert | |||||
| last_updated | 2026-03-22 |
Context: Scoping and hoisting mechanisms in modern JavaScript. var is function-scoped and hoisted, leading to unpredictable behavior and accidental global leakage.
var price = 100;
if (true) {
var price = 200; // Overwrites outer variable
}
console.log(price); // 200var does not respect block scope. Its hoisting behavior allows variables to be accessed before declaration (as undefined), which bypasses the Temporal Dead Zone (TDZ) safety mechanism, increasing cognitive load and bug density.
const price = 100;
if (true) {
const price = 200; // Block-scoped, unique to this block
}
console.log(price); // 100Use const by default to ensure immutability of the reference. Use let only when reassigning a variable is strictly necessary. This enforces block-level scoping and prevents accidental overrides.
Context: JavaScript's type coercion rules are complex and often counter-intuitive.
if (userCount == '0') {
// Executes if userCount is 0 (number) or '0' (string)
}The Abstract Equality Comparison Algorithm (==) performs implicit type conversion. This leads to edge cases like [] == ![] being true or 0 == '' being true, which can cause silent logic failures.
if (userCount === 0) {
// Strict comparison
}Always use strict equality === and inequality !==. This forces the developer to handle type conversions explicitly, making the code's intent clear and predictable.
Context: The global namespace is shared. Overwriting global properties can break third-party libraries or browser APIs.
// In a script file
const config = { api: '/v1' };
function init() { /* ... */ }Variables declared in the top-level scope of a non-module script are attached to window (in browsers) or global (in Node). This increases the risk of name collisions and memory leaks.
// use modules
export const config = { api: '/v1' };
// or IIFE if modules aren't available
(() => {
const config = { api: '/v1' };
})();Use ES Modules (import/export) to encapsulate code. Modules have their own scope and do not leak to the global object.
Context: Readability and handling of multi-line strings/expressions.
const greeting = 'Hello, ' + user.firstName + ' ' + user.lastName + '! ' +
'Welcome to ' + siteName + '.';Concatenation with + is error-prone, hard to read, and difficult to maintain for multi-line strings. It often leads to missing spaces and poor visual structure.
const greeting = `Hello, ${user.firstName} ${user.lastName}!
Welcome to ${siteName}.`;Use Template Literals (backticks). They allow for embedded expressions, multi-line strings, and superior readability.
Context: Numbers with no context make the codebase hard to maintain.
if (user.age >= 18) {
grantAccess();
}"18" is a magic number. If the legal age changes, you must find and replace every instance, risking errors if the same number is used for different contexts elsewhere.
const LEGAL_AGE = 18;
if (user.age >= LEGAL_AGE) {
grantAccess();
}Extract magic numbers into named constants. This provides semantic meaning and a single source of truth for configuration.
Context: Redundancy in conditional logic.
if (isValid === true) { /* ... */ }Comparing a boolean to true or false is redundant. It adds visual noise without increasing safety.
if (isValid) { /* ... */ }
if (!isPending) { /* ... */ }Leverage JavaScript's truthiness/falsiness or direct boolean evaluation. It makes the code more concise and idiomatic.
Context: Object and Array instantiation.
const list = new Array(1, 2, 3);
const map = new Object();The Array constructor is inconsistent: new Array(3) creates an empty array of length 3, while new Array(3, 4) creates [3, 4]. Literals are faster and more readable.
const list = [1, 2, 3];
const map = {};Use literals [] and {}. They are visually cleaner and perform slightly better as they don't involve a function call.
Context: The Single Responsibility Principle (SRP).
function processOrder(order) {
// 100 lines of validation, DB saving, email sending...
}Large functions are hard to test, debug, and reuse. High cyclomatic complexity makes it difficult for the JIT compiler to optimize the function.
function validateOrder(order) { /* ... */ }
function saveToDatabase(order) { /* ... */ }
function notifyUser(order) { /* ... */ }
function processOrder(order) {
validateOrder(order);
saveToDatabase(order);
notifyUser(order);
}Break functions into smaller, pure components. Aim for functions under 20 lines that do exactly one thing.
Context: Cognitive load and code readability.
function getData(user) {
if (user) {
if (user.isActive) {
if (user.hasPermission) {
return fetchData();
}
}
}
}"Arrow code" (code that expands horizontally) is hard to follow. It forces the reader to keep track of multiple nesting levels in their mental stack.
function getData(user) {
if (!user || !user.isActive || !user.hasPermission) {
return null;
}
return fetchData();
}Use "Guard Clauses" to return early. This flattens the structure and handles edge cases first, leaving the happy path at the lowest nesting level.
Context: Self-documenting code.
const d = new Date();
const u = users.map(i => i.n);Single-letter variables (except for standard loop indices like i or j) provide no context. They make the code unsearchable and confusing for other developers.
const today = new Date();
const userNames = users.map(user => user.name);Use descriptive, camelCase names that convey the intent and data type of the variable.
For further reading, please refer to the following specialized guides: