javascript
JavaScript/Node.js Style Guide
Apply Google JavaScript Style Guide conventions to JavaScript and Node.js code. This skill provides essential coding standards, formatting rules, and best practices for writing clean, maintainable JavaScript.
Note: Google recommends migrating to TypeScript. This guide is for JavaScript projects that have not yet migrated.
Core Principles
File Basics
File naming:
- Use lowercase only
- Use underscores (
_) or dashes (-) but no other punctuation - Extension must be
.js - Examples:
my_module.js,user-service.js
File encoding:
- UTF-8 only
- Use special escape sequences for special characters (
\',\",\\,\b,\f,\n,\r,\t,\v) - For non-ASCII: use actual Unicode character (e.g.,
∞) or hex escape (e.g.,\u221e) based on readability
Indentation:
- Use 2 spaces (never tabs)
- No trailing whitespace
Module System
ES Modules (Preferred)
Use import and export statements:
// Imports
import './sideeffects.js';
import * as goog from '../closure/goog/goog.js';
import {name, value} from './sibling.js';
// Named exports only (no default exports)
export class Foo { ... }
export function bar() { ... }
// Or export together
class Foo { ... }
function bar() { ... }
export {Foo, bar};
Import rules:
- Include
.jsextension in paths (required) - Use
lowerCamelCasefor module import names:import * as fileOne from '../file-one.js'; - Keep same name for named imports, avoid aliasing unless necessary
- Do not use default exports
- Import statements are exception to 80-column limit (do not wrap)
Avoid circular dependencies - Do not create import cycles between modules.
Variable Declarations
Use const and let
// Use const by default
const MAX_COUNT = 100;
const users = [];
// Use let only when reassignment needed
let currentIndex = 0;
// NEVER use var
One variable per declaration:
// Good
const a = 1;
const b = 2;
// Bad
const a = 1, b = 2;
Declare close to first use:
// Good - declared when needed
function process(items) {
// ... some code ...
const result = items.map(x => x * 2);
return result;
}
Formatting
Braces
K&R style (Egyptian brackets):
class InnerClass {
constructor() {}
method(foo) {
if (condition(foo)) {
try {
something();
} catch (err) {
recover();
}
}
}
}
Rules:
- No line break before opening brace
- Line break after opening brace
- Line break before closing brace
- Line break after closing brace (except before
else,catch,while, comma, semicolon)
Always use braces for control structures (even single statements):
// Good
if (condition) {
doSomething();
}
// Exception: single-line if without else
if (shortCondition()) foo();
// Bad
if (condition)
doSomething();
Column Limit
80 characters with exceptions:
importandexport fromstatements- Long URLs, shell commands, file paths in comments
- Lines where wrapping is impossible
Line Wrapping
Break at higher syntactic levels:
// Good
currentEstimate =
calc(currentEstimate + x * currentEstimate) /
2.0;
// Bad
currentEstimate = calc(currentEstimate + x *
currentEstimate) / 2.0;
Continuation lines: indent at least +4 spaces from original line.
Whitespace
Horizontal spacing:
- Space after reserved words:
if (,for (,catch ( - No space for
functionandsuper:function(,super( - Space before opening brace:
if (x) {,class Foo { - Space around binary/ternary operators:
a + b,x ? y : z - Space after comma/semicolon:
foo(a, b); - Space after colon in objects:
{a: 1, b: 2} - Space around
//:// comment
Vertical spacing:
- Blank line between methods
- Blank lines within methods to create logical groups (sparingly)
Semicolons
Required - Every statement must end with semicolon:
const x = 1; // Required
doSomething(); // Required
Arrays and Objects
Array Literals
// Use trailing commas
const values = [
'first value',
'second value',
];
// Never use Array constructor
const a = [x1, x2, x3]; // Good
const b = new Array(x1, x2, x3); // Bad
// Destructuring
const [a, b, c, ...rest] = generateResults();
let [, b,, d] = someArray; // Skip unused elements
// Spread operator
[...foo] // Preferred over Array.prototype.slice.call(foo)
[...foo, ...bar] // Preferred over foo.concat(bar)
Object Literals
// Use trailing commas
const obj = {
a: 0,
b: 1,
};
// Never use Object constructor
const o = {a: 0, b: 1}; // Good
const o = new Object(); // Bad
// Don't mix quoted and unquoted keys
{
width: 42,
height: 50,
} // Good - all unquoted (struct style)
{
'width': 42,
'maxWidth': 43,
} // Good - all quoted (dict style)
{
width: 42,
'maxWidth': 43,
} // Bad - mixed
// Method shorthand
const obj = {
value: 1,
method() {
return this.value;
},
};
// Shorthand properties
const foo = 1;
const bar = 2;
const obj = {foo, bar};
// Destructuring
function process({num, str = 'default'} = {}) {}
Classes
Class Declaration
class MyClass {
// Constructor
constructor(value) {
/** @private @const */
this.value_ = value;
/** @private */
this.mutableField = 0;
}
// Methods
getValue() {
return this.value_;
}
/** @override */
toString() {
return `MyClass(${this.value_})`;
}
}
// Inheritance
class ChildClass extends MyClass {
constructor(value, extra) {
super(value); // Must call super() first
this.extra = extra;
}
}
Rules:
- Constructors are optional
- Define all fields in constructor
- Use
@constfor never-reassigned fields - Use
@private,@protectedfor non-public fields - Private field names may end with underscore
- No semicolons after methods
- Call
super()before accessingthisin subclasses
Functions
Arrow Functions
Preferred for callbacks and short functions:
// Good
const squares = numbers.map(n => n * n);
items.forEach((item) => {
process(item);
});
// Use when 'this' from outer scope needed
class Timer {
start() {
setInterval(() => {
this.tick(); // 'this' refers to Timer instance
}, 1000);
}
}
Rules:
- Prefer arrow functions for callbacks
- Use arrow functions to preserve
thisbinding - Omit parens for single parameter:
x => x * 2 - Use parens for zero or multiple params:
() => 42,(a, b) => a + b - Always use braces for multi-line bodies
Function Declarations
function myFunction(param1, param2) {
return param1 + param2;
}
// Optional parameters with defaults
function greet(name = 'Guest') {
return `Hello, ${name}`;
}
// Rest parameters
function sum(...numbers) {
return numbers.reduce((a, b) => a + b, 0);
}
Control Structures
Conditionals
// Standard if-else
if (condition) {
doSomething();
} else if (otherCondition) {
doOther();
} else {
doDefault();
}
// Ternary for simple cases
const value = condition ? trueValue : falseValue;
Loops
// For-of for iterables
for (const item of items) {
process(item);
}
// Traditional for loop
for (let i = 0; i < array.length; i++) {
process(array[i]);
}
// For-in for object properties (use with caution)
for (const key in object) {
if (object.hasOwnProperty(key)) {
process(object[key]);
}
}
Switch Statements
switch (value) {
case 'option1':
handleOption1();
break;
case 'option2':
handleOption2();
break;
default:
handleDefault();
}
Modern Features
Template Literals
// Use for string interpolation
const message = `Hello, ${name}!`;
// Multi-line strings
const html = `
<div>
<h1>${title}</h1>
</div>
`;
Promises and Async/Await
// Prefer async/await
async function fetchData() {
try {
const response = await fetch(url);
const data = await response.json();
return data;
} catch (error) {
console.error('Failed:', error);
throw error;
}
}
// Promise chains when appropriate
fetch(url)
.then(response => response.json())
.then(data => process(data))
.catch(error => console.error(error));
Comments
Implementation Comments
// Single-line comments use //
// Multiple single-line comments for
// longer explanations.
/*
* Multi-line comment style.
* Subsequent lines start with * aligned
* with the * on the previous line.
*/
// Parameter name comments for clarity
someFunction(obviousParam, /* shouldRender= */ true, /* name= */ 'hello');
JSDoc
Use JSDoc for:
- All classes
- All methods and functions (public and private)
- Properties when needed for clarity
/**
* Brief description of the function.
*
* @param {string} name The user's name
* @param {number=} age Optional age parameter
* @return {string} Greeting message
*/
function greet(name, age) {
return `Hello, ${name}`;
}
/**
* Class representing a point.
*/
class Point {
/**
* Create a point.
* @param {number} x The x coordinate
* @param {number} y The y coordinate
*/
constructor(x, y) {
/** @private @const {number} */
this.x_ = x;
/** @private @const {number} */
this.y_ = y;
}
}
Node.js Specific
Module Exports
// ES modules in Node.js (use .mjs or "type": "module" in package.json)
export class Service {}
export function helper() {}
// CommonJS (when ES modules not available)
class Service {}
function helper() {}
module.exports = {Service, helper};
Error Handling
// Always handle errors in async code
async function processFile(path) {
try {
const content = await fs.promises.readFile(path, 'utf8');
return JSON.parse(content);
} catch (error) {
console.error(`Failed to process ${path}:`, error);
throw error;
}
}
// Use Error objects
throw new Error('Something went wrong');
throw new TypeError('Expected string');
Common Patterns
Object Property Access
// Check existence
if (obj.property != null) {
// Property exists and is not null/undefined
}
// Use optional chaining
const value = obj?.deeply?.nested?.property;
// Nullish coalescing
const result = value ?? defaultValue;
Array Operations
// Prefer array methods over loops
const doubled = numbers.map(n => n * 2);
const evens = numbers.filter(n => n % 2 === 0);
const sum = numbers.reduce((acc, n) => acc + n, 0);
// Check if array contains item
if (array.includes(item)) { }
// Find item
const found = array.find(item => item.id === targetId);
Quick Reference
Variable declaration: const (default), let (when reassignment needed), never var
Indentation: 2 spaces
Semicolons: Required
String quotes: Single ' or backticks ` for templates
Braces: K&R style, always use for control structures
Line length: 80 characters
Naming: lowerCamelCase for variables/functions, UpperCamelCase for classes
Imports: Use .js extension, no default exports
Comments: // for single-line, /* */ for multi-line
Additional Resources
Reference Files
For comprehensive coverage of specific topics:
references/advanced-features.md- Advanced JavaScript patterns, promises, generators, proxiesreferences/jsdoc-guide.md- Complete JSDoc annotation guidereferences/naming-conventions.md- Detailed naming rules for all identifier typesreferences/disallowed-features.md- Features to avoid and their alternatives
Complete Style Guide
The full Google JavaScript Style Guide is available at: https://google.github.io/styleguide/jsguide.html
More from the-perfect-developer/the-perfect-opencode
html
Apply Google HTML style guide conventions to HTML code
19turso-libsql
This skill should be used when the user asks to "connect to Turso", "use libSQL", "set up a Turso database", "query Turso with TypeScript", or needs guidance on Turso Cloud, embedded replicas, or vector search with libSQL.
11alpinejs
This skill should be used when the user asks to "add Alpine.js", "create Alpine component", "use Alpine directives", "build interactive UI with Alpine", or needs guidance on Alpine.js development patterns and best practices.
10python-dependency-injection
This skill should be used when the user asks to "implement dependency injection in Python", "use the dependency-injector library", "decouple Python components", "write testable Python services", or needs guidance on Inversion of Control, DI containers, provider types, and wiring in Python applications.
3copilot-sdk
This skill should be used when the user asks to "integrate GitHub Copilot into an app", "use the Copilot SDK", "build a Copilot-powered agent", "embed Copilot in a service", or needs guidance on the GitHub Copilot SDK for Python, TypeScript, Go, or .NET.
3conventional-git-commit
This skill MUST be loaded on every git commit without exception. It should also be used when the user asks to "write a conventional commit", "format a commit message", "follow conventional commits spec", "create a semantic commit", "make a commit", "commit changes", or "git commit". Every commit message produced in this project MUST conform to this specification.
3