mcpField
J
javascript-fundamentals

javascript-fundamentals

github.com/manutej开发62460 次安装39 周前更新
代码仓库

关于 javascript-fundamentals

javascript-fundamentals 是 JavaScript 基础技能指南,面向编写、审查和维护 JavaScript 项目的开发者。内容覆盖 ES6+、异步编程、常见模式与工程实践。

主要功能

  1. 01变量、作用域与数据类型
  2. 02ES6+ 语法与模块
  3. 03Promise 与 async/await
  4. 04设计模式与代码组织
  5. 05错误处理和性能实践

适用场景

  1. 01编写 JavaScript 应用
  2. 02审查或重构旧代码
  3. 03排查异步执行问题

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/manutej/luxor-claude-marketplace --skill javascript-fundamentals

安装后在 Claude Code 中输入/javascript-fundamentals确认已加载。

附带文件EXAMPLES.mdREADME.md

详细介绍

JavaScript 基础

一份全面的指南,涵盖 JavaScript 核心概念、现代 ES6+ 特性、异步编程模式,以及构建稳健应用的行业最佳实践。

何时使用此技能

以下情况必备此技能:

  • 编写 JavaScript 代码:构建 Web 应用、Node.js 后端或任何基于 JavaScript 的项目
  • 代码审查:评估代码质量、识别反模式并提出改进建议
  • 教学/指导:讲解 JavaScript 概念、调试问题、结对编程
  • 重构遗留代码:使用 ES6+ 特性和更好的模式改造代码库
  • 架构设计:为应用选择合适的模式和结构
  • 性能优化:了解内存管理、事件循环和高效模式
  • 调试:跟踪执行流程、了解作用域链和异步行为
  • 面试准备:掌握技术面试考查的基础概念

核心概念

变量和作用域

JavaScript 有三种变量声明方式,各自具有不同的作用域规则:

var:函数作用域,会提升,可以重复声明

function varExample() {
  var x = 1;
  if (true) {
    var x = 2; // Same variable!
    console.log(x); // 2
  }
  console.log(x); // 2
}

let:块级作用域,不会提升到可用状态,不能重复声明

function letExample() {
  let x = 1;
  if (true) {
    let x = 2; // Different variable
    console.log(x); // 2
  }
  console.log(x); // 1
}

const:块级作用域,必须初始化,引用不能重新赋值

const PI = 3.14159;
// PI = 3; // Error: Assignment to constant variable

const user = { name: 'John' };
user.name = 'Jane'; // OK - modifying object properties
// user = {}; // Error - reassigning reference

最佳实践:默认使用 const,需要重新赋值时使用 let,避免使用 var。

数据类型

JavaScript 有 7 种原始类型和对象:

原始类型:

  • String:文本数据
  • Number:整数和浮点数
  • BigInt:任意精度整数
  • Boolean:true/false
  • undefined:未初始化的变量
  • null:有意表示值缺失
  • Symbol:唯一标识符

对象:键值对的集合,包括数组、函数、日期等。

// Type checking
typeof "hello"        // "string"
typeof 42             // "number"
typeof true           // "boolean"
typeof undefined      // "undefined"
typeof null           // "object" (historical bug!)
typeof {}             // "object"
typeof []             // "object"
typeof function(){}   // "function"

// Better array checking
Array.isArray([])     // true
Array.isArray({})     // false

// Null checking
value === null        // true only for null
value == null         // true for null AND undefined
函数

函数是 JavaScript 中的一等公民——可以赋值给变量、作为参数传入,也可以由其他函数返回。

函数声明:

function greet(name) {
  return `Hello, ${name}!`;
}

函数表达式:

const greet = function(name) {
  return `Hello, ${name}!`;
};

箭头函数(ES6+):

const greet = (name) => `Hello, ${name}!`;

// Multiple parameters
const add = (a, b) => a + b;

// Single parameter (parentheses optional)
const double = x => x * 2;

// Multiple statements (need braces and explicit return)
const complexFunction = (x, y) => {
  const result = x + y;
  return result * 2;
};

主要区别:

  • 箭头函数没有自己的 this 绑定
  • 箭头函数不能用作构造函数
  • 箭头函数没有 arguments 对象
  • 函数声明会提升,函数表达式不会
对象和数组

创建对象:

// Object literal
const person = {
  name: 'John',
  age: 30,
  greet() {
    return `Hello, I'm ${this.name}`;
  }
};

// Accessing properties
person.name           // Dot notation
person['name']        // Bracket notation (dynamic keys)

// Adding/modifying properties
person.email = '[email protected]';
person.age = 31;

// Deleting properties
delete person.email;

数组方法:

const numbers = [1, 2, 3, 4, 5];

// Transformation
numbers.map(n => n * 2)           // [2, 4, 6, 8, 10]
numbers.filter(n => n > 2)        // [3, 4, 5]
numbers.reduce((sum, n) => sum + n, 0) // 15

// Iteration
numbers.forEach(n => console.log(n));

// Search
numbers.find(n => n > 3)          // 4
numbers.findIndex(n => n > 3)     // 3
numbers.includes(3)               // true

// Mutation (modify original)
numbers.push(6)                   // Add to end
numbers.pop()                     // Remove from end
numbers.unshift(0)                // Add to start
numbers.shift()                   // Remove from start
numbers.splice(2, 1)              // Remove 1 item at index 2

// Non-mutating
numbers.slice(1, 3)               // [2, 3]
numbers.concat([6, 7])            // [1, 2, 3, 4, 5, 6, 7]
[...numbers, 6, 7]                // Spread operator
闭包

闭包是一个函数,即使外层函数已经返回,它仍然可以访问外层(包含它的)词法作用域中的变量。

function createCounter() {
  let count = 0; // Private variable

  return {
    increment() {
      return ++count;
    },
    decrement() {
      return --count;
    },
    getCount() {
      return count;
    }
  };
}

const counter = createCounter();
console.log(counter.increment()); // 1
console.log(counter.increment()); // 2
console.log(counter.getCount());  // 2
// count is not directly accessible

使用场景:

  • 数据隐私/封装
  • 工厂函数
  • 事件处理器
  • 保持状态的回调
  • 模块模式实现
原型和继承

JavaScript 使用原型继承。每个对象都有一个指向另一个对象的内部 [[Prototype]] 链接。

// Constructor function
function Animal(name) {
  this.name = name;
}

// Add method to prototype
Animal.prototype.speak = function() {
  return `${this.name} makes a sound`;
};

const dog = new Animal('Dog');
console.log(dog.speak()); // "Dog makes a sound"

// Inheritance
function Dog(name, breed) {
  Animal.call(this, name); // Call parent constructor
  this.breed = breed;
}

// Set up prototype chain
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;

Dog.prototype.bark = function() {
  return `${this.name} barks!`;
};

const myDog = new Dog('Buddy', 'Golden Retriever');
console.log(myDog.speak()); // "Buddy makes a sound" (inherited)
console.log(myDog.bark());  // "Buddy barks!" (own method)
类(ES6+)

类为原型继承提供了语法糖:

class Animal {
  constructor(name) {
    this.name = name;
  }

  speak() {
    return `${this.name} makes a sound`;
  }

  // Static method
  static create(name) {
    return new Animal(name);
  }
}

class Dog extends Animal {
  constructor(name, breed) {
    super(name); // Call parent constructor
    this.breed = breed;
  }

  speak() {
    return `${super.speak()} - Woof!`;
  }

  // Getter
  get info() {
    return `${this.name} is a ${this.breed}`;
  }

  // Setter
  set nickname(value) {
    this._nickname = value;
  }
}

const myDog = new Dog('Buddy', 'Golden Retriever');
console.log(myDog.speak());     // "Buddy makes a sound - Woof!"
console.log(myDog.info);        // "Buddy is a Golden Retriever"
myDog.nickname = 'Bud';

现代 JavaScript(ES6+)

解构

从数组中提取值,或从对象中提取属性:

// Array destructuring
const [first, second, ...rest] = [1, 2, 3, 4, 5];
console.log(first);  // 1
console.log(second); // 2
console.log(rest);   // [3, 4, 5]

// Object destructuring
const user = { name: 'John', age: 30, city: 'NYC' };
const { name, age } = user;
console.log(name); // "John"

// Renaming
const { name: userName, age: userAge } = user;

// Default values
const { country = 'USA' } = user;

// Nested destructuring
const data = {
  user: { name: 'John', address: { city: 'NYC' } }
};
const { user: { address: { city } } } = data;

// Function parameters
function greet({ name, age = 0 }) {
  return `${name} is ${age} years old`;
}
greet({ name: 'John', age: 30 }); // "John is 30 years old"
展开和剩余运算符

展开(...)用于展开元素:

// Arrays
const arr1 = [1, 2, 3];
const arr2 = [...arr1, 4, 5]; // [1, 2, 3, 4, 5]
const combined = [...arr1, ...arr2];

// Objects
const obj1 = { a: 1, b: 2 };
const obj2 = { ...obj1, c: 3 }; // { a: 1, b: 2, c: 3 }

// Function arguments
Math.max(...arr1); // 3

// Shallow copy
const copy = [...arr1];
const objCopy = { ...obj1 };

剩余(...)用于收集元素:

// Function parameters
function sum(...numbers) {
  return numbers.reduce((total, n) => total + n, 0);
}
sum(1, 2, 3, 4); // 10

// With other parameters
function multiply(multiplier, ...numbers) {
  return numbers.map(n => n * multiplier);
}
multiply(2, 1, 2, 3); // [2, 4, 6]
模板字面量

多行字符串和字符串插值:

const name = 'John';
const age = 30;

// String interpolation
const greeting = `Hello, ${name}!`;

// Expressions
const message = `In 5 years, you'll be ${age + 5}`;

// Multi-line
const multiline = `
  This is a
  multi-line
  string
`;

// Tagged templates
function highlight(strings, ...values) {
  return strings.reduce((result, str, i) => {
    return result + str + (values[i] ? `<mark>${values[i]}</mark>` : '');
  }, '');
}

const html = highlight`Hello, ${name}! You are ${age} years old.`;
// "Hello, <mark>John</mark>! You are <mark>30</mark> years old."
可选链和空值合并

可选链(?.):安全地访问嵌套属性:

const user = {
  name: 'John',
  address: {
    city: 'NYC'
  }
};

// Without optional chaining
const city = user && user.address && user.address.city;

// With optional chaining
const city = user?.address?.city; // "NYC"
const zip = user?.address?.zip;   // undefined (no error!)

// With methods
user.getName?.(); // Only calls if method exists

// With arrays
const firstItem = arr?.[0];

空值合并(??):为 null/undefined 提供默认值:

// || returns right side for ANY falsy value
const value1 = 0 || 'default';     // "default"
const value2 = '' || 'default';    // "default"
const value3 = false || 'default'; // "default"

// ?? only for null/undefined
const value4 = 0 ?? 'default';     // 0
const value5 = '' ?? 'default';    // ""
const value6 = false ?? 'default'; // false
const value7 = null ?? 'default';  // "default"
const value8 = undefined ?? 'default'; // "default"
模块

导出:

// Named exports
export const PI = 3.14159;
export function add(a, b) {
  return a + b;
}
export class Calculator {
  // ...
}

// Export multiple
const multiply = (a, b) => a * b;
const divide = (a, b) => a / b;
export { multiply, divide };

// Default export (one per file)
export default class App {
  // ...
}

// Or
class App { }
export default App;

导入:

// Named imports
import { PI, add } from './math.js';
import { multiply as mult } from './math.js'; // Rename

// Default import
import App from './App.js';

// Mix default and named
import App, { PI, add } from './App.js';

// Import all
import * as Math from './math.js';
Math.PI;
Math.add(1, 2);

// Import for side effects only
import './polyfills.js';

异步模式

事件循环

JavaScript 是单线程的,但通过事件循环处理异步操作:

  1. 调用栈:执行同步代码
  2. Web API:浏览器/Node API(setTimeout、fetch 等)
  3. 回调队列:已完成的异步操作在此等待
  4. 事件循环:当调用栈为空时,将回调从队列移至调用栈
console.log('1');

setTimeout(() => {
  console.log('2');
}, 0);

Promise.resolve().then(() => {
  console.log('3');
});

console.log('4');

// Output: 1, 4, 3, 2
// Microtasks (Promises) have priority over macrotasks (setTimeout)
回调

传统的异步模式(可能导致“回调地狱”):

function fetchUser(userId, callback) {
  setTimeout(() => {
    callback(null, { id: userId, name: 'John' });
  }, 1000);
}

function fetchPosts(userId, callback) {
  setTimeout(() => {
    callback(null, [{ id: 1, title: 'Post 1' }]);
  }, 1000);
}

// Callback hell
fetchUser(1, (error, user) => {
  if (error) {
    console.error(error);
    return;
  }

  fetchPosts(user.id, (error, posts) => {
    if (error) {
      console.error(error);
      return;
    }

    console.log(user, posts);
  });
});
Promise

Promise 表示异步操作最终完成(或失败):

// Creating a promise
const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    const success = true;
    if (success) {
      resolve('Success!');
    } else {
      reject(new Error('Failed!'));
    }
  }, 1000);
});

// Using a promise
promise
  .then(result => {
    console.log(result); // "Success!"
    return result.toUpperCase();
  })
  .then(upperResult => {
    console.log(upperResult); // "SUCCESS!"
  })
  .catch(error => {
    console.error(error);
  })
  .finally(() => {
    console.log('Cleanup');
  });

// Promise utilities
Promise.all([promise1, promise2, promise3])
  .then(results => {
    // All resolved: [result1, result2, result3]
  });

Promise.race([promise1, promise2])
  .then(result => {
    // First to resolve
  });

Promise.allSettled([promise1, promise2])
  .then(results => {
    // All completed (resolved or rejected)
    // [{ status: 'fulfilled', value: ... }, { status: 'rejected', reason: ... }]
  });

Promise.any([promise1, promise2])
  .then(result => {
    // First to fulfill (resolve)
  });
Async/Await

用于处理 Promise 的现代语法(ES2017+):

async function fetchUserData(userId) {
  try {
    const user = await fetchUser(userId);
    const posts = await fetchPosts(user.id);
    const comments = await fetchComments(posts[0].id);

    return { user, posts, comments };
  } catch (error) {
    console.error('Error:', error);
    throw error;
  }
}

// Using the async function
fetchUserData(1)
  .then(data => console.log(data))
  .catch(error => console.error(error));

// Parallel execution
async function fetchAllData() {
  const [users, posts, comments] = await Promise.all([
    fetchUsers(),
    fetchPosts(),
    fetchComments()
  ]);

  return { users, posts, comments };
}

// Sequential vs Parallel
async function sequential() {
  const result1 = await operation1(); // Wait
  const result2 = await operation2(); // Then wait
  return [result1, result2];
}

async function parallel() {
  const [result1, result2] = await Promise.all([
    operation1(), // Start both
    operation2()  // simultaneously
  ]);
  return [result1, result2];
}
异步代码中的错误处理
// Try-catch with async/await
async function robustFetch(url) {
  try {
    const response = await fetch(url);

    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }

    const data = await response.json();
    return data;
  } catch (error) {
    if (error.name === 'TypeError') {
      console.error('Network error:', error);
    } else {
      console.error('Error:', error);
    }
    throw error; // Re-throw or handle
  }
}

// Promise catch
fetchData()
  .then(data => processData(data))
  .catch(error => {
    // Catches errors from fetchData AND processData
    console.error(error);
  });

// Global error handlers
window.addEventListener('unhandledrejection', event => {
  console.error('Unhandled promise rejection:', event.reason);
  event.preventDefault();
});

常见模式

模块模式

封装私有数据并公开公共 API:

const Calculator = (function() {
  // Private variables
  let history = [];

  // Private function
  function log(operation) {
    history.push(operation);
  }

  // Public API
  return {
    add(a, b) {
      const result = a + b;
      log(`${a} + ${b} = ${result}`);
      return result;
    },

    subtract(a, b) {
      const result = a - b;
      log(`${a} - ${b} = ${result}`);
      return result;
    },

    getHistory() {
      return [...history]; // Return copy
    },

    clearHistory() {
      history = [];
    }
  };
})();

Calculator.add(5, 3); // 8
console.log(Calculator.getHistory()); // ["5 + 3 = 8"]
揭示模块模式

模块模式的更简洁变体:

const UserManager = (function() {
  // Private
  let users = [];

  function findUserById(id) {
    return users.find(u => u.id === id);
  }

  function validateUser(user) {
    return user && user.name && user.email;
  }

  // Public methods
  function addUser(user) {
    if (validateUser(user)) {
      users.push(user);
      return true;
    }
    return false;
  }

  function getUser(id) {
    return findUserById(id);
  }

  function getAllUsers() {
    return [...users];
  }

  // Reveal public API
  return {
    add: addUser,
    get: getUser,
    getAll: getAllUsers
  };
})();
工厂模式

创建对象,而无需指定确切的类:

function createUser(name, role) {
  const roles = {
    admin: {
      permissions: ['read', 'write', 'delete'],
      level: 3
    },
    editor: {
      permissions: ['read', 'write'],
      level: 2
    },
    viewer: {
      permissions: ['read'],
      level: 1
    }
  };

  const roleConfig = roles[role] || roles.viewer;

  return {
    name,
    role,
    ...roleConfig,

    hasPermission(permission) {
      return this.permissions.includes(permission);
    },

    toString() {
      return `${this.name} (${this.role})`;
    }
  };
}

const admin = createUser('Alice', 'admin');
const editor = createUser('Bob', 'editor');

console.log(admin.hasPermission('delete')); // true
console.log(editor.hasPermission('delete')); // false
单例模式

确保只存在一个实例:

const Config = (function() {
  let instance;

  function createInstance() {
    return {
      apiUrl: 'https://api.example.com',
      timeout: 5000,
      retries: 3,

      get(key) {
        return this[key];
      },

      set(key, value) {
        this[key] = value;
      }
    };
  }

  return {
    getInstance() {
      if (!instance) {
        instance = createInstance();
      }
      return instance;
    }
  };
})();

const config1 = Config.getInstance();
const config2 = Config.getInstance();
console.log(config1 === config2); // true

// Modern ES6 class version
class Database {
  constructor() {
    if (Database.instance) {
      return Database.instance;
    }

    this.connection = null;
    Database.instance = this;
  }

  connect() {
    if (!this.connection) {
      this.connection = 'Connected to DB';
    }
    return this.connection;
  }
}

const db1 = new Database();
const db2 = new Database();
console.log(db1 === db2); // true
观察者模式

订阅并发布事件:

class EventEmitter {
  constructor() {
    this.events = {};
  }

  on(event, listener) {
    if (!this.events[event]) {
      this.events[event] = [];
    }
    this.events[event].push(listener);

    // Return unsubscribe function
    return () => this.off(event, listener);
  }

  off(event, listenerToRemove) {
    if (!this.events[event]) return;

    this.events[event] = this.events[event].filter(
      listener => listener !== listenerToRemove
    );
  }

  emit(event, ...args) {
    if (!this.events[event]) return;

    this.events[event].forEach(listener => {
      listener(...args);
    });
  }

  once(event, listener) {
    const onceWrapper = (...args) => {
      listener(...args);
      this.off(event, onceWrapper);
    };
    this.on(event, onceWrapper);
  }
}

// Usage
const emitter = new EventEmitter();

const unsubscribe = emitter.on('data', (data) => {
  console.log('Received:', data);
});

emitter.emit('data', { id: 1 }); // "Received: { id: 1 }"
unsubscribe();
emitter.emit('data', { id: 2 }); // Nothing logged
记忆化

缓存函数结果以提升性能:

function memoize(fn) {
  const cache = new Map();

  return function(...args) {
    const key = JSON.stringify(args);

    if (cache.has(key)) {
      console.log('Cached result');
      return cache.get(key);
    }

    const result = fn.apply(this, args);
    cache.set(key, result);
    return result;
  };
}

// Expensive function
function fibonacci(n) {
  if (n <= 1) return n;
  return fibonacci(n - 1) + fibonacci(n - 2);
}

const memoizedFib = memoize(fibonacci);
console.log(memoizedFib(40)); // Slow first time
console.log(memoizedFib(40)); // Instant (cached)

// With object methods
const calculator = {
  multiplier: 2,

  calculate: memoize(function(n) {
    return n * this.multiplier;
  })
};

最佳实践

命名约定
// Constants - UPPERCASE_SNAKE_CASE
const MAX_RETRIES = 3;
const API_BASE_URL = 'https://api.example.com';

// Variables and functions - camelCase
let userName = 'John';
function getUserData() { }

// Classes - PascalCase
class UserAccount { }
class HTTPHandler { }

// Private convention - prefix with underscore
class Widget {
  constructor() {
    this._privateProperty = 'internal';
  }

  _privateMethod() {
    // Implementation
  }
}

// Boolean variables - use is/has/can prefix
const isActive = true;
const hasPermission = false;
const canEdit = true;

// Functions - use verb prefix
function getUser() { }
function setConfig() { }
function validateInput() { }
function handleClick() { }
错误处理
// Custom error classes
class ValidationError extends Error {
  constructor(message, field) {
    super(message);
    this.name = 'ValidationError';
    this.field = field;
  }
}

class NetworkError extends Error {
  constructor(message, statusCode) {
    super(message);
    this.name = 'NetworkError';
    this.statusCode = statusCode;
  }
}

// Throw specific errors
function validateEmail(email) {
  if (!email.includes('@')) {
    throw new ValidationError('Invalid email format', 'email');
  }
  return true;
}

// Handle different error types
try {
  validateEmail('invalid');
} catch (error) {
  if (error instanceof ValidationError) {
    console.error(`Validation failed for ${error.field}: ${error.message}`);
  } else {
    console.error('Unexpected error:', error);
  }
}

// Async error handling
async function fetchWithRetry(url, retries = 3) {
  for (let i = 0; i < retries; i++) {
    try {
      const response = await fetch(url);
      if (!response.ok) {
        throw new NetworkError('Request failed', response.status);
      }
      return await response.json();
    } catch (error) {
      if (i === retries - 1) throw error; // Last retry
      console.log(`Retry ${i + 1}/${retries}`);
      await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1)));
    }
  }
}
性能提示
// 1. Avoid unnecessary operations in loops
// Bad
for (let i = 0; i < array.length; i++) { } // Length calculated each iteration

// Good
const len = array.length;
for (let i = 0; i < len; i++) { }

// Better - use built-in methods
array.forEach(item => { });

// 2. Debounce expensive operations
function debounce(fn, delay) {
  let timeoutId;
  return function(...args) {
    clearTimeout(timeoutId);
    timeoutId = setTimeout(() => fn.apply(this, args), delay);
  };
}

const expensiveSearch = debounce((query) => {
  // API call
}, 300);

// 3. Throttle high-frequency events
function throttle(fn, limit) {
  let inThrottle;
  return function(...args) {
    if (!inThrottle) {
      fn.apply(this, args);
      inThrottle = true;
      setTimeout(() => inThrottle = false, limit);
    }
  };
}

window.addEventListener('scroll', throttle(() => {
  // Handle scroll
}, 100));

// 4. Use object/map for lookups
// Bad - O(n)
const colors = ['red', 'blue', 'green'];
colors.includes('blue'); // Linear search

// Good - O(1)
const colorSet = new Set(['red', 'blue', 'green']);
colorSet.has('blue'); // Constant time

// 5. Avoid memory leaks
// Bad - event listener not removed
element.addEventListener('click', handler);

// Good
const handler = () => { };
element.addEventListener('click', handler);
// Later...
element.removeEventListener('click', handler);

// 6. Use WeakMap for private data
const privateData = new WeakMap();

class MyClass {
  constructor() {
    privateData.set(this, { secret: 'value' });
  }

  getSecret() {
    return privateData.get(this).secret;
  }
}
// When instance is garbage collected, WeakMap entry is too
代码组织
// 1. Single Responsibility Principle
// Bad - function does too much
function processUserData(userData) {
  // Validate
  // Transform
  // Save to database
  // Send email
  // Update UI
}

// Good - separate concerns
function validateUser(userData) { }
function transformUserData(userData) { }
function saveUser(userData) { }
function sendWelcomeEmail(user) { }
function updateUI(user) { }

// 2. Pure functions (no side effects)
// Bad - modifies input
function addToCart(cart, item) {
  cart.items.push(item);
  return cart;
}

// Good - returns new object
function addToCart(cart, item) {
  return {
    ...cart,
    items: [...cart.items, item]
  };
}

// 3. Avoid magic numbers
// Bad
if (user.role === 2) { }

// Good
const ROLES = {
  ADMIN: 1,
  EDITOR: 2,
  VIEWER: 3
};

if (user.role === ROLES.EDITOR) { }

// 4. Use default parameters
// Bad
function greet(name) {
  name = name || 'Guest';
  return `Hello, ${name}`;
}

// Good
function greet(name = 'Guest') {
  return `Hello, ${name}`;
}

// 5. Guard clauses for early returns
// Bad
function processOrder(order) {
  if (order) {
    if (order.items.length > 0) {
      if (order.total > 0) {
        // Process order
      }
    }
  }
}

// Good
function processOrder(order) {
  if (!order) return;
  if (order.items.length === 0) return;
  if (order.total <= 0) return;

  // Process order
}
内存管理
// 1. Clear timers and intervals
const timerId = setTimeout(() => { }, 1000);
clearTimeout(timerId);

const intervalId = setInterval(() => { }, 1000);
clearInterval(intervalId);

// 2. Remove event listeners
const handler = () => { };
element.addEventListener('click', handler);
element.removeEventListener('click', handler);

// 3. Set references to null when done
let largeData = fetchLargeDataset();
// Use data...
largeData = null; // Allow garbage collection

// 4. Use WeakMap/WeakSet for caches
const cache = new WeakMap();
let obj = { data: 'value' };
cache.set(obj, 'cached value');
obj = null; // Cache entry automatically removed

// 5. Avoid global variables
// Bad
var globalUser = { };

// Good - use modules/closures
(function() {
  const user = { };
  // Use user locally
})();

// 6. Be careful with closures
function createHeavyObject() {
  const heavyData = new Array(1000000);

  // Bad - closure keeps heavyData in memory
  return function() {
    console.log(heavyData.length);
  };

  // Good - only capture what you need
  const length = heavyData.length;
  return function() {
    console.log(length);
  };
}
测试注意事项
// 1. Write testable code - pure functions
// Testable
function calculateTotal(items) {
  return items.reduce((sum, item) => sum + item.price, 0);
}

// Hard to test - depends on external state
function calculateTotal() {
  return cart.items.reduce((sum, item) => sum + item.price, 0);
}

// 2. Dependency injection
// Hard to test
class UserService {
  constructor() {
    this.api = new ApiClient();
  }
}

// Easy to test - inject dependencies
class UserService {
  constructor(apiClient) {
    this.api = apiClient;
  }
}

// 3. Avoid side effects
// Side effects
function processData(data) {
  console.log('Processing...'); // Side effect
  updateDatabase(data); // Side effect
  return transform(data);
}

// Pure
function transformData(data) {
  return transform(data);
}

// Separate side effects
function processData(data) {
  const transformed = transformData(data);
  console.log('Processing...');
  updateDatabase(transformed);
  return transformed;
}

快速参考

数组方法速查表
const arr = [1, 2, 3, 4, 5];

// Transform
arr.map(x => x * 2)              // [2, 4, 6, 8, 10]
arr.filter(x => x > 2)           // [3, 4, 5]
arr.reduce((sum, x) => sum + x)  // 15

// Search
arr.find(x => x > 3)             // 4
arr.findIndex(x => x > 3)        // 3
arr.indexOf(3)                   // 2
arr.includes(3)                  // true
arr.some(x => x > 3)             // true
arr.every(x => x > 0)            // true

// Mutation
arr.push(6)                      // Add to end
arr.pop()                        // Remove from end
arr.unshift(0)                   // Add to start
arr.shift()                      // Remove from start
arr.splice(2, 1, 99)             // Remove/add at index

// Non-mutating
arr.slice(1, 3)                  // [2, 3]
arr.concat([6, 7])               // [1, 2, 3, 4, 5, 6, 7]
[...arr]                         // Copy
arr.join(', ')                   // "1, 2, 3, 4, 5"
arr.reverse()                    // [5, 4, 3, 2, 1] (mutates!)
arr.sort((a, b) => a - b)        // Sort (mutates!)
对象方法速查表
const obj = { a: 1, b: 2, c: 3 };

Object.keys(obj)                 // ['a', 'b', 'c']
Object.values(obj)               // [1, 2, 3]
Object.entries(obj)              // [['a', 1], ['b', 2], ['c', 3]]
Object.fromEntries([['a', 1]])   // { a: 1 }

Object.assign({}, obj, { d: 4 }) // { a: 1, b: 2, c: 3, d: 4 }
{ ...obj, d: 4 }                 // Same as above

Object.freeze(obj)               // Make immutable
Object.seal(obj)                 // Prevent add/remove properties
Object.preventExtensions(obj)    // Prevent adding properties

Object.hasOwnProperty.call(obj, 'a') // true
'a' in obj                       // true
obj.hasOwnProperty('a')          // true (not recommended)
常见陷阱
// 1. Equality
0 == '0'          // true (type coercion)
0 === '0'         // false (strict)
null == undefined // true
null === undefined // false

// 2. Type coercion
'5' + 3           // "53" (string concatenation)
'5' - 3           // 2 (numeric subtraction)
+'5'              // 5 (unary plus converts to number)
!!'value'         // true (double negation to boolean)

// 3. this binding
const obj = {
  name: 'Object',
  regular: function() { console.log(this.name); },
  arrow: () => { console.log(this.name); }
};
obj.regular();    // "Object"
obj.arrow();      // undefined (arrow uses lexical this)

// 4. Falsy values
false, 0, -0, 0n, '', null, undefined, NaN

// 5. Array/Object comparison
[] === []         // false (different references)
{} === {}         // false (different references)

// 6. Floating point
0.1 + 0.2 === 0.3 // false (0.30000000000000004)
Math.abs(0.1 + 0.2 - 0.3) < Number.EPSILON // true

// 7. Hoisting
console.log(x);   // undefined (var hoisted)
var x = 5;

console.log(y);   // ReferenceError (let not hoisted to usable state)
let y = 5;

本指南全面介绍了现代开发所需的 JavaScript 基础知识。请定期练习这些概念,并参阅 EXAMPLES.md 文件,了解详细的实现示例。

评论

支持 Markdown