JavaScript
by @wscats
A comprehensive JavaScript style guide skill. When activated, it provides best-practice JavaScript coding conventions and generates code that strictly follow...
clawhub install javascript-skillsπ About This Skill
name: JavaScript license: MIT description: > A comprehensive JavaScript style guide skill. When activated, it provides best-practice JavaScript coding conventions and generates code that strictly follows the style guide, covering variables, functions, objects, arrays, classes, modules, async patterns, error handling, naming conventions, and more.
JavaScript Style Guide Skill
Activation
This skill activates when the user mentions or implies JavaScript in their request. Once activated, it:
Complete Style Rules
1. References
const for all references; avoid var.let instead of var.const and let are block-scoped, whereas var is function-scoped.// bad
var count = 1;// good
const count = 1;
let mutableValue = 1;
mutableValue += 1;
2. Objects
...) over Object.assign to shallow-copy objects.// bad
const item = new Object();// good
const item = {};
// computed property names
const key = 'name';
const obj = { [key]: 'value' };
// method & property shorthand
const name = 'Alice';
const atom = {
name,
value: 1,
addValue(val) {
return atom.value + val;
},
};
// shallow copy
const original = { a: 1, b: 2 };
const copy = { ...original, c: 3 };
3. Arrays
Array.from or the spread operator to convert array-like objects.return statements in array method callbacks.// bad
const items = new Array();// good
const items = [];
// convert iterable
const nodes = Array.from(document.querySelectorAll('.item'));
const uniqueValues = [...new Set(arr)];
// array methods
[1, 2, 3].map((x) => x + 1);
[1, 2, 3].map((x) => {
const y = x + 1;
return x * y;
});
4. Destructuring
// bad
function getFullName(user) {
const firstName = user.firstName;
const lastName = user.lastName;
return ${firstName} ${lastName};
}// good
function getFullName({ firstName, lastName }) {
return ${firstName} ${lastName};
}
// array destructuring
const [first, , third] = [1, 2, 3];
// multiple return values β use object destructuring
function processInput(input) {
return { left, right, top, bottom };
}
const { left, top } = processInput(input);
5. Strings
'' for strings.eval() on a string.// bad
const name = "Alice";
const greeting = 'Hello, ' + name + '!';// good
const name = 'Alice';
const greeting = Hello, ${name}!;
6. Functions
if, while, etc.).arguments.Function constructor to create a new function.... to call variadic functions....args) instead of arguments.// named function expression
const short = function longUniqueMoreDescriptiveLexicalFoo() {
// ...
};// default parameters last
function handleThings(name, opts = {}) {
// ...
}
// rest parameters
function concatenateAll(...args) {
return args.join('');
}
// spread to call
const values = [1, 2, 3];
console.log(Math.max(...values));
7. Arrow Functions
// bad
[1, 2, 3].map(function (x) {
const y = x + 1;
return x * y;
});// good
[1, 2, 3].map((x) => {
const y = x + 1;
return x * y;
});
// implicit return
[1, 2, 3].map((x) => x * 2);
// multiline implicit return
[1, 2, 3].map((number) => (
A long string with the ${number}. It's so long that we don't want it to take up space on the .map line!
));
8. Classes & Constructors
class; avoid manipulating prototype directly.extends for inheritance.this to enable method chaining.// bad
function Queue(contents = []) {
this.queue = [...contents];
}
Queue.prototype.pop = function () {
return this.queue.pop();
};// good
class Queue {
constructor(contents = []) {
this.queue = [...contents];
}
pop() {
return this.queue.pop();
}
}
// inheritance
class PeekableQueue extends Queue {
peek() {
return this.queue[0];
}
}
9. Modules
import/export) over a non-standard module system.imports above non-import statements.// bad
const utils = require('./utils');
module.exports = utils.fetchData;// good
import { fetchData } from './utils';
export default fetchData;
// single place import
import { named1, named2 } from 'module';
// multiline
import {
longNameA,
longNameB,
longNameC,
} from 'path/to/module';
10. Iterators and Generators
for-in or for-of loops.map, filter, reduce, find, findIndex, every, some, etc.const numbers = [1, 2, 3, 4, 5];// bad
let sum = 0;
for (const num of numbers) {
sum += num;
}
// good
const sum = numbers.reduce((total, num) => total + num, 0);
// filtering
const evens = numbers.filter((num) => num % 2 === 0);
11. Properties
[] when accessing properties with a variable.** instead of Math.pow.const luke = { jedi: true, age: 28 };// dot notation
const isJedi = luke.jedi;
// bracket notation
const prop = 'jedi';
const isJedi = luke[prop];
// exponentiation
const result = 2 ** 10;
12. Variables
const or let; never use var.const or let declaration per variable or assignment.consts and then group all lets.++, --); use += 1 / -= 1 instead.= in an assignment.// bad
const items = getItems(),
goSportsTeam = true,
dragonball = 'z';// good
const items = getItems();
const goSportsTeam = true;
const dragonball = 'z';
// group const then let
const a = 1;
const b = 2;
let c = 3;
let d = 4;
// avoid unary
let count = 0;
count += 1;
13. Hoisting
var declarations get hoisted; const and let are in Temporal Dead Zone.14. Comparison Operators & Equality
=== and !== over == and !=.case and default clauses that contain lexical declarations.**, +, -).// bad
if (isValid == true) { /* ... */ }
if (name != '') { /* ... */ }// good
if (isValid) { /* ... */ }
if (name !== '') { /* ... */ }
if (collection.length > 0) { /* ... */ }
// no nested ternaries
const thing = foo === 123 ? bar : foobar;
15. Blocks
else on the same line as the if block's closing brace.if block always executes a return, the subsequent else block is unnecessary.// bad
if (test)
return false;// good
if (test) return false;
if (test) {
return false;
}
// if/else
if (test) {
thing1();
} else {
thing2();
}
16. Control Statements
if, while, etc.) gets too long, each grouped condition should be on a new line, with the logical operator at the beginning of the line.if (
foo === 123
&& bar === 'abc'
) {
thing1();
}
17. Comments
/** ... */ for multiline comments.// for single-line comments. Place them on a new line above the subject.FIXME: or TODO: to annotate problems or suggest actions.// good single line
// This is a comment
const active = true;/**
* Multiline comment explaining the function.
* @param {string} tag - The tag name.
* @returns {Element} The created element.
*/
function make(tag) {
return document.createElement(tag);
}
// TODO: implement caching
// FIXME: should not use global state
18. Whitespace
// bad
function foo(){
const name='Alice';
}// good
function foo() {
const name = 'Alice';
}
// method chaining
$('#items')
.find('.selected')
.highlight()
.end()
.find('.open')
.updateCount();
19. Commas
// bad β leading commas
const hero = {
firstName: 'Ada'
, lastName: 'Lovelace'
};// good β trailing commas
const hero = {
firstName: 'Ada',
lastName: 'Lovelace',
};
const heroes = [
'Batman',
'Superman',
];
20. Semicolons
// bad
const name = 'Alice'// good
const name = 'Alice';
21. Type Casting & Coercion
String() for strings, Number() for numbers, Boolean() or !! for booleans.parseInt always with a radix.const val = '4';// bad
const totalScore = val + 0;
// good
const totalScore = Number(val);
const inputValue = String(someNum);
const hasAge = Boolean(age);
const hasName = !!name;
const count = parseInt(inputValue, 10);
22. Naming Conventions
// bad
const OBJEcttsssss = {};
function c() {}
const u = new user();// good
const thisIsMyObject = {};
function calculateTotal() {}
const user = new User();
// constants
export const API_BASE_URL = 'https://api.example.com';
export const MAX_RETRY_COUNT = 3;
// filename examples
// file: makeStyleGuide.js β export default function makeStyleGuide() {}
// file: User.js β export default class User {}
23. Accessors
getVal() and setVal('value').isVal() or hasVal().// bad
dragon.age();// good
dragon.getAge();
dragon.setAge(25);
dragon.isAlive();
dragon.hasWings();
24. Events
// bad
emitter.emit('itemUpdate', item.id);// good
emitter.emit('itemUpdate', { itemId: item.id });
25. Promises & Async/Await
async/await over chaining .then() and .catch().try...catch in async functions.Promise.all for concurrent independent async operations.Promise.allSettled when you need results of all promises regardless of rejection.// bad
function fetchData() {
return getData()
.then((data) => parseData(data))
.then((parsed) => validate(parsed))
.catch((err) => console.error(err));
}// good
async function fetchData() {
try {
const data = await getData();
const parsed = await parseData(data);
return validate(parsed);
} catch (err) {
console.error(err);
throw err;
}
}
// concurrent operations
async function loadDashboard() {
const [user, posts, notifications] = await Promise.all([
fetchUser(),
fetchPosts(),
fetchNotifications(),
]);
return { user, posts, notifications };
}
26. Error Handling
Error objects (or subclasses of Error).// bad
throw 'Something went wrong';
throw { message: 'error' };// good
throw new Error('Something went wrong');
class ValidationError extends Error {
constructor(message, field) {
super(message);
this.name = 'ValidationError';
this.field = field;
}
}
throw new ValidationError('Invalid email', 'email');
27. Optional Chaining & Nullish Coalescing
?.) to access nested properties that may not exist.??) instead of || when you want to allow falsy values like 0 or ''.// bad
const city = user && user.address && user.address.city;
const port = config.port || 3000; // breaks if port is 0// good
const city = user?.address?.city;
const port = config.port ?? 3000;
28. Standard Library
Number.isNaN instead of global isNaN.Number.isFinite instead of global isFinite.// bad
isNaN('1.2');
isFinite('2e3');// good
Number.isNaN('1.2');
Number.isFinite('2e3');
Usage
This is a Prompt-based Skill (natural language activation).
How to Use
1. Automatic Activation: Simply mention "JavaScript" in your request. The skill will be activated automatically.
2. Ask for Style Guidance:
"How should I write a JavaScript function that fetches user data?"
3. Request Code Review:
"Review this JavaScript code for style issues: [paste code]"
4. Generate Compliant Code:
"Write a JavaScript module to handle form validation"
5. Ask About Specific Rules:
"What's the correct way to declare variables in JavaScript?"
"How should I handle async errors in JavaScript?"
Examples
User: Write a JavaScript utility function to deep clone an object.
Skill Response: Generates clean, style-guide-compliant code:
/**
* Deep clones a plain object or array using structured cloning.
* Falls back to JSON serialization for environments without structuredClone.
*
* @param {Object|Array} source - The value to clone.
* @returns {Object|Array} A deep copy of the source.
*/
function deepClone(source) {
if (typeof structuredClone === 'function') {
return structuredClone(source);
} return JSON.parse(JSON.stringify(source));
}
export default deepClone;
π‘ Examples
User: Write a JavaScript utility function to deep clone an object.
Skill Response: Generates clean, style-guide-compliant code:
/**
* Deep clones a plain object or array using structured cloning.
* Falls back to JSON serialization for environments without structuredClone.
*
* @param {Object|Array} source - The value to clone.
* @returns {Object|Array} A deep copy of the source.
*/
function deepClone(source) {
if (typeof structuredClone === 'function') {
return structuredClone(source);
} return JSON.parse(JSON.stringify(source));
}
export default deepClone;