javascript-fundamentals
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseJavaScript Fundamentals
JavaScript核心基础
A comprehensive guide to core JavaScript concepts, modern ES6+ features, asynchronous programming patterns, and industry best practices for building robust applications.
本指南全面介绍JavaScript核心概念、现代ES6+特性、异步编程模式,以及构建健壮应用的行业最佳实践。
When to Use This Skill
何时使用本技能
This skill is essential when:
- Writing JavaScript Code: Building web applications, Node.js backends, or any JavaScript-based project
- Code Reviews: Evaluating code quality, identifying anti-patterns, suggesting improvements
- Teaching/Mentoring: Explaining JavaScript concepts, debugging issues, pair programming
- Refactoring Legacy Code: Modernizing codebases with ES6+ features and better patterns
- Architecture Design: Choosing appropriate patterns and structures for your application
- Performance Optimization: Understanding memory management, event loops, and efficient patterns
- Debugging: Tracing execution flow, understanding scope chains, and async behavior
- Interview Preparation: Mastering fundamental concepts tested in technical interviews
在以下场景中,本技能至关重要:
- 编写JavaScript代码:构建Web应用、Node.js后端或任何基于JavaScript的项目
- 代码评审:评估代码质量、识别反模式、提出改进建议
- 教学/指导:讲解JavaScript概念、调试问题、结对编程
- 重构遗留代码:使用ES6+特性和更优模式现代化代码库
- 架构设计:为应用选择合适的模式与结构
- 性能优化:理解内存管理、事件循环与高效模式
- 调试:追踪执行流程、理解作用域链与异步行为
- 面试准备:掌握技术面试中常考的核心概念
Core Concepts
核心概念
Variables and Scope
变量与作用域
JavaScript has three ways to declare variables, each with different scoping rules:
var: Function-scoped, hoisted, can be redeclared
javascript
function varExample() {
var x = 1;
if (true) {
var x = 2; // Same variable!
console.log(x); // 2
}
console.log(x); // 2
}let: Block-scoped, not hoisted to usable state, cannot be redeclared
javascript
function letExample() {
let x = 1;
if (true) {
let x = 2; // Different variable
console.log(x); // 2
}
console.log(x); // 1
}const: Block-scoped, must be initialized, reference cannot be reassigned
javascript
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 referenceBest Practice: Use by default, when reassignment is needed, avoid .
constletvarJavaScript有三种变量声明方式,每种都有不同的作用域规则:
var:函数作用域,存在变量提升,可重复声明
javascript
function varExample() {
var x = 1;
if (true) {
var x = 2; // 同一个变量!
console.log(x); // 2
}
console.log(x); // 2
}let:块级作用域,不会被提升至可用状态,不可重复声明
javascript
function letExample() {
let x = 1;
if (true) {
let x = 2; // 不同的变量
console.log(x); // 2
}
console.log(x); // 1
}const:块级作用域,必须初始化,引用不可重新赋值
javascript
const PI = 3.14159;
// PI = 3; // 错误:给常量变量赋值
const user = { name: 'John' };
user.name = 'Jane'; // 允许 - 修改对象属性
// user = {}; // 错误 - 重新赋值引用最佳实践:默认使用,需要重新赋值时使用,避免使用。
constletvarData Types
数据类型
JavaScript has 7 primitive types and objects:
Primitives:
- : Text data
String - : Integers and floating-point numbers
Number - : Arbitrary precision integers
BigInt - : true/false
Boolean - : Uninitialized variable
undefined - : Intentional absence of value
null - : Unique identifiers
Symbol
Objects: Collections of key-value pairs, including arrays, functions, dates, etc.
javascript
// 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 undefinedJavaScript包含7种原始类型和对象:
原始类型:
- :文本数据
String - :整数与浮点数
Number - :任意精度整数
BigInt - :true/false
Boolean - :未初始化的变量
undefined - :值的有意缺失
null - :唯一标识符
Symbol
对象:键值对集合,包括数组、函数、日期等。
javascript
// 类型检查
typeof "hello" // "string"
typeof 42 // "number"
typeof true // "boolean"
typeof undefined // "undefined"
typeof null // "object" (历史遗留bug!)
typeof {} // "object"
typeof [] // "object"
typeof function(){} // "function"
// 更准确的数组检查
Array.isArray([]) // true
Array.isArray({}) // false
// Null检查
value === null // 仅当值为null时返回true
value == null // 当值为null或undefined时返回trueFunctions
函数
Functions are first-class citizens in JavaScript - they can be assigned to variables, passed as arguments, and returned from other functions.
Function Declaration:
javascript
function greet(name) {
return `Hello, ${name}!`;
}Function Expression:
javascript
const greet = function(name) {
return `Hello, ${name}!`;
};Arrow Function (ES6+):
javascript
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;
};Key Differences:
- Arrow functions don't have their own binding
this - Arrow functions cannot be used as constructors
- Arrow functions don't have object
arguments - Function declarations are hoisted, expressions are not
在JavaScript中,函数是一等公民——它们可以被赋值给变量、作为参数传递、从其他函数返回。
函数声明:
javascript
function greet(name) {
return `Hello, ${name}!`;
}函数表达式:
javascript
const greet = function(name) {
return `Hello, ${name}!`;
};箭头函数(ES6+):
javascript
const greet = (name) => `Hello, ${name}!`;
// 多个参数
const add = (a, b) => a + b;
// 单个参数(括号可选)
const double = x => x * 2;
// 多条语句(需要大括号和显式return)
const complexFunction = (x, y) => {
const result = x + y;
return result * 2;
};关键差异:
- 箭头函数没有自己的绑定
this - 箭头函数不能用作构造函数
- 箭头函数没有对象
arguments - 函数声明会被提升,函数表达式不会
Objects and Arrays
对象与数组
Object Creation:
javascript
// 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 = 'john@example.com';
person.age = 31;
// Deleting properties
delete person.email;Array Methods:
javascript
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对象创建:
javascript
// 对象字面量
const person = {
name: 'John',
age: 30,
greet() {
return `Hello, I'm ${this.name}`;
}
};
// 访问属性
person.name // 点表示法
person['name'] // 方括号表示法(支持动态键)
// 添加/修改属性
person.email = 'john@example.com';
person.age = 31;
// 删除属性
delete person.email;数组方法:
javascript
const numbers = [1, 2, 3, 4, 5];
// 转换
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
// 迭代
numbers.forEach(n => console.log(n));
// 搜索
numbers.find(n => n > 3) // 4
numbers.findIndex(n => n > 3) // 3
numbers.includes(3) // true
// 变更(修改原数组)
numbers.push(6) // 添加到末尾
numbers.pop() // 从末尾移除
numbers.unshift(0) // 添加到开头
numbers.shift() // 从开头移除
numbers.splice(2, 1) // 移除索引2处的1个元素
// 非变更
numbers.slice(1, 3) // [2, 3]
numbers.concat([6, 7]) // [1, 2, 3, 4, 5, 6, 7]
[...numbers, 6, 7] // 展开运算符Closures
闭包
A closure is a function that has access to variables in its outer (enclosing) lexical scope, even after the outer function has returned.
javascript
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 accessibleUse Cases:
- Data privacy/encapsulation
- Factory functions
- Event handlers
- Callbacks maintaining state
- Module pattern implementation
闭包是一个函数,即使外部函数已返回,它仍能访问其外部(封闭)词法作用域中的变量。
javascript
function createCounter() {
let count = 0; // 私有变量
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无法直接访问使用场景:
- 数据隐私/封装
- 工厂函数
- 事件处理程序
- 保持状态的回调
- 模块模式实现
Prototypes and Inheritance
原型与继承
JavaScript uses prototypal inheritance. Every object has an internal link to another object.
[[Prototype]]javascript
// 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)JavaScript使用原型继承。每个对象都有一个内部的链接指向另一个对象。
[[Prototype]]javascript
// 构造函数
function Animal(name) {
this.name = name;
}
// 向原型添加方法
Animal.prototype.speak = function() {
return `${this.name} makes a sound`;
};
const dog = new Animal('Dog');
console.log(dog.speak()); // "Dog makes a sound"
// 继承
function Dog(name, breed) {
Animal.call(this, name); // 调用父构造函数
this.breed = breed;
}
// 设置原型链
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"(继承的方法)
console.log(myDog.bark()); // "Buddy barks!"(自身方法)Classes (ES6+)
类(ES6+)
Classes provide syntactic sugar over prototypal inheritance:
javascript
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
class Animal {
constructor(name) {
this.name = name;
}
speak() {
return `${this.name} makes a sound`;
}
// 静态方法
static create(name) {
return new Animal(name);
}
}
class Dog extends Animal {
constructor(name, breed) {
super(name); // 调用父构造函数
this.breed = breed;
}
speak() {
return `${super.speak()} - Woof!`;
}
// 取值器
get info() {
return `${this.name} is a ${this.breed}`;
}
// 赋值器
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';Modern JavaScript (ES6+)
现代JavaScript(ES6+)
Destructuring
解构赋值
Extract values from arrays or properties from objects:
javascript
// 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"从数组中提取值或从对象中提取属性:
javascript
// 数组解构
const [first, second, ...rest] = [1, 2, 3, 4, 5];
console.log(first); // 1
console.log(second); // 2
console.log(rest); // [3, 4, 5]
// 对象解构
const user = { name: 'John', age: 30, city: 'NYC' };
const { name, age } = user;
console.log(name); // "John"
// 重命名
const { name: userName, age: userAge } = user;
// 默认值
const { country = 'USA' } = user;
// 嵌套解构
const data = {
user: { name: 'John', address: { city: 'NYC' } }
};
const { user: { address: { city } } } = data;
// 函数参数
function greet({ name, age = 0 }) {
return `${name} is ${age} years old`;
}
greet({ name: 'John', age: 30 }); // "John is 30 years old"Spread and Rest Operators
展开与剩余运算符
Spread () expands elements:
...javascript
// 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 };Rest () collects elements:
...javascript
// 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]展开运算符():展开元素
...javascript
// 数组
const arr1 = [1, 2, 3];
const arr2 = [...arr1, 4, 5]; // [1, 2, 3, 4, 5]
const combined = [...arr1, ...arr2];
// 对象
const obj1 = { a: 1, b: 2 };
const obj2 = { ...obj1, c: 3 }; // { a: 1, b: 2, c: 3 }
// 函数参数
Math.max(...arr1); // 3
// 浅拷贝
const copy = [...arr1];
const objCopy = { ...obj1 };剩余运算符():收集元素
...javascript
// 函数参数
function sum(...numbers) {
return numbers.reduce((total, n) => total + n, 0);
}
sum(1, 2, 3, 4); // 10
// 与其他参数结合
function multiply(multiplier, ...numbers) {
return numbers.map(n => n * multiplier);
}
multiply(2, 1, 2, 3); // [2, 4, 6]Template Literals
模板字面量
Multi-line strings and string interpolation:
javascript
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."多行字符串与字符串插值:
javascript
const name = 'John';
const age = 30;
// 字符串插值
const greeting = `Hello, ${name}!`;
// 表达式
const message = `In 5 years, you'll be ${age + 5}`;
// 多行
const multiline = `
This is a
multi-line
string
`;
// 标签模板
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."Optional Chaining and Nullish Coalescing
可选链与空值合并
Optional Chaining (): Safely access nested properties:
?.javascript
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];Nullish Coalescing (): Default values for null/undefined:
??javascript
// || 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"可选链():安全访问嵌套属性
?.javascript
const user = {
name: 'John',
address: {
city: 'NYC'
}
};
// 不使用可选链
const city = user && user.address && user.address.city;
// 使用可选链
const city = user?.address?.city; // "NYC"
const zip = user?.address?.zip; // undefined(无错误!)
// 与方法结合
user.getName?.(); // 仅当方法存在时调用
// 与数组结合
const firstItem = arr?.[0];空值合并():为null/undefined设置默认值
??javascript
// ||会对任何假值返回右侧值
const value1 = 0 || 'default'; // "default"
const value2 = '' || 'default'; // "default"
const value3 = false || 'default'; // "default"
// ??仅针对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"Modules
模块
Exporting:
javascript
// 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;Importing:
javascript
// 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
// 具名导出
export const PI = 3.14159;
export function add(a, b) {
return a + b;
}
export class Calculator {
// ...
}
// 批量导出
const multiply = (a, b) => a * b;
const divide = (a, b) => a / b;
export { multiply, divide };
// 默认导出(每个文件只能有一个)
export default class App {
// ...
}
// 或者
class App { }
export default App;导入:
javascript
// 具名导入
import { PI, add } from './math.js';
import { multiply as mult } from './math.js'; // 重命名
// 默认导入
import App from './App.js';
// 混合默认与具名导入
import App, { PI, add } from './App.js';
// 导入全部
import * as Math from './math.js';
Math.PI;
Math.add(1, 2);
// 仅为副作用导入
import './polyfills.js';Asynchronous Patterns
异步模式
The Event Loop
事件循环
JavaScript is single-threaded but handles async operations through the event loop:
- Call Stack: Executes synchronous code
- Web APIs: Browser/Node APIs (setTimeout, fetch, etc.)
- Callback Queue: Completed async operations wait here
- Event Loop: Moves callbacks from queue to stack when stack is empty
javascript
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)JavaScript是单线程的,但通过事件循环处理异步操作:
- 调用栈:执行同步代码
- Web APIs:浏览器/Node.js API(setTimeout、fetch等)
- 回调队列:已完成的异步操作在此等待
- 事件循环:当调用栈为空时,将回调从队列移至调用栈
javascript
console.log('1');
setTimeout(() => {
console.log('2');
}, 0);
Promise.resolve().then(() => {
console.log('3');
});
console.log('4');
// 输出:1, 4, 3, 2
// 微任务(Promises)优先级高于宏任务(setTimeout)Callbacks
回调函数
Traditional async pattern (can lead to "callback hell"):
javascript
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);
});
});传统异步模式(可能导致“回调地狱”):
javascript
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);
}
// 回调地狱
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);
});
});Promises
Promises
Promises represent eventual completion (or failure) of an async operation:
javascript
// 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)
});Promise表示异步操作的最终完成(或失败):
javascript
// 创建Promise
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
const success = true;
if (success) {
resolve('Success!');
} else {
reject(new Error('Failed!'));
}
}, 1000);
});
// 使用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工具函数
Promise.all([promise1, promise2, promise3])
.then(results => {
// 全部resolve:[result1, result2, result3]
});
Promise.race([promise1, promise2])
.then(result => {
// 第一个resolve的结果
});
Promise.allSettled([promise1, promise2])
.then(results => {
// 全部完成(resolve或reject)
// [{ status: 'fulfilled', value: ... }, { status: 'rejected', reason: ... }]
});
Promise.any([promise1, promise2])
.then(result => {
// 第一个fulfill(resolve)的结果
});Async/Await
Async/Await
Modern syntax for handling promises (ES2017+):
javascript
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];
}处理Promise的现代语法(ES2017+):
javascript
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;
}
}
// 使用异步函数
fetchUserData(1)
.then(data => console.log(data))
.catch(error => console.error(error));
// 并行执行
async function fetchAllData() {
const [users, posts, comments] = await Promise.all([
fetchUsers(),
fetchPosts(),
fetchComments()
]);
return { users, posts, comments };
}
// 串行 vs 并行
async function sequential() {
const result1 = await operation1(); // 等待完成
const result2 = await operation2(); // 再等待完成
return [result1, result2];
}
async function parallel() {
const [result1, result2] = await Promise.all([
operation1(), // 同时启动
operation2() // 两个操作
]);
return [result1, result2];
}Error Handling in Async Code
异步代码中的错误处理
javascript
// 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();
});javascript
// 使用try-catch处理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; // 重新抛出或处理
}
}
// Promise的catch方法
fetchData()
.then(data => processData(data))
.catch(error => {
// 捕获fetchData和processData中的错误
console.error(error);
});
// 全局错误处理程序
window.addEventListener('unhandledrejection', event => {
console.error('Unhandled promise rejection:', event.reason);
event.preventDefault();
});Common Patterns
常见模式
Module Pattern
模块模式
Encapsulate private data and expose public API:
javascript
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"]封装私有数据并暴露公共API:
javascript
const Calculator = (function() {
// 私有变量
let history = [];
// 私有函数
function log(operation) {
history.push(operation);
}
// 公共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]; // 返回副本
},
clearHistory() {
history = [];
}
};
})();
Calculator.add(5, 3); // 8
console.log(Calculator.getHistory()); // ["5 + 3 = 8"]Revealing Module Pattern
暴露模块模式
Cleaner variation of module pattern:
javascript
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
};
})();模块模式的更简洁变体:
javascript
const UserManager = (function() {
// 私有部分
let users = [];
function findUserById(id) {
return users.find(u => u.id === id);
}
function validateUser(user) {
return user && user.name && user.email;
}
// 公共方法
function addUser(user) {
if (validateUser(user)) {
users.push(user);
return true;
}
return false;
}
function getUser(id) {
return findUserById(id);
}
function getAllUsers() {
return [...users];
}
// 暴露公共API
return {
add: addUser,
get: getUser,
getAll: getAllUsers
};
})();Factory Pattern
工厂模式
Create objects without specifying exact class:
javascript
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无需指定具体类即可创建对象:
javascript
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')); // falseSingleton Pattern
单例模式
Ensure only one instance exists:
javascript
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确保仅存在一个实例:
javascript
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
// 现代ES6类版本
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); // trueObserver Pattern
观察者模式
Subscribe to and publish events:
javascript
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订阅与发布事件:
javascript
class EventEmitter {
constructor() {
this.events = {};
}
on(event, listener) {
if (!this.events[event]) {
this.events[event] = [];
}
this.events[event].push(listener);
// 返回取消订阅函数
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);
}
}
// 使用示例
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 }); // 无输出Memoization
记忆化
Cache function results for performance:
javascript
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;
})
};缓存函数结果以提升性能:
javascript
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;
};
}
// 计算成本高的函数
function fibonacci(n) {
if (n <= 1) return n;
return fibonacci(n - 1) + fibonacci(n - 2);
}
const memoizedFib = memoize(fibonacci);
console.log(memoizedFib(40)); // 第一次较慢
console.log(memoizedFib(40)); // 瞬间返回(已缓存)
// 用于对象方法
const calculator = {
multiplier: 2,
calculate: memoize(function(n) {
return n * this.multiplier;
})
};Best Practices
最佳实践
Naming Conventions
命名规范
javascript
// 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() { }javascript
// 常量 - 大写蛇形命名法
const MAX_RETRIES = 3;
const API_BASE_URL = 'https://api.example.com';
// 变量与函数 - 小驼峰命名法
let userName = 'John';
function getUserData() { }
// 类 - 大驼峰命名法
class UserAccount { }
class HTTPHandler { }
// 私有约定 - 以下划线开头
class Widget {
constructor() {
this._privateProperty = 'internal';
}
_privateMethod() {
// 实现代码
}
}
// 布尔变量 - 使用is/has/can前缀
const isActive = true;
const hasPermission = false;
const canEdit = true;
// 函数 - 使用动词前缀
function getUser() { }
function setConfig() { }
function validateInput() { }
function handleClick() { }Error Handling
错误处理
javascript
// 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)));
}
}
}javascript
// 自定义错误类
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;
}
}
// 抛出特定错误
function validateEmail(email) {
if (!email.includes('@')) {
throw new ValidationError('Invalid email format', 'email');
}
return true;
}
// 处理不同类型的错误
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 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; // 最后一次重试仍失败则抛出
console.log(`Retry ${i + 1}/${retries}`);
await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1)));
}
}
}Performance Tips
性能优化技巧
javascript
// 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 toojavascript
// 1. 避免在循环中执行不必要的操作
// 不良写法
for (let i = 0; i < array.length; i++) { } // 每次迭代都计算长度
// 良好写法
const len = array.length;
for (let i = 0; i < len; i++) { }
// 更好的写法 - 使用内置方法
array.forEach(item => { });
// 2. 防抖昂贵操作
function debounce(fn, delay) {
let timeoutId;
return function(...args) {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => fn.apply(this, args), delay);
};
}
const expensiveSearch = debounce((query) => {
// API调用
}, 300);
// 3. 节流高频事件
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(() => {
// 处理滚动事件
}, 100));
// 4. 使用对象/Map进行查找
// 不良写法 - O(n)
const colors = ['red', 'blue', 'green'];
colors.includes('blue'); // 线性搜索
// 良好写法 - O(1)
const colorSet = new Set(['red', 'blue', 'green']);
colorSet.has('blue'); // 常数时间
// 5. 避免内存泄漏
// 不良写法 - 未移除事件监听器
element.addEventListener('click', handler);
// 良好写法
const handler = () => { };
element.addEventListener('click', handler);
// 后续...
element.removeEventListener('click', handler);
// 6. 使用WeakMap存储私有数据
const privateData = new WeakMap();
class MyClass {
constructor() {
privateData.set(this, { secret: 'value' });
}
getSecret() {
return privateData.get(this).secret;
}
}
// 当实例被垃圾回收时,WeakMap中的条目也会被移除Code Organization
代码组织
javascript
// 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
}javascript
// 1. 单一职责原则
// 不良写法 - 函数职责过多
function processUserData(userData) {
// 验证
// 转换
// 保存到数据库
// 发送邮件
// 更新UI
}
// 良好写法 - 分离关注点
function validateUser(userData) { }
function transformUserData(userData) { }
function saveUser(userData) { }
function sendWelcomeEmail(user) { }
function updateUI(user) { }
// 2. 纯函数(无副作用)
// 不良写法 - 修改输入参数
function addToCart(cart, item) {
cart.items.push(item);
return cart;
}
// 良好写法 - 返回新对象
function addToCart(cart, item) {
return {
...cart,
items: [...cart.items, item]
};
}
// 3. 避免魔法数字
// 不良写法
if (user.role === 2) { }
// 良好写法
const ROLES = {
ADMIN: 1,
EDITOR: 2,
VIEWER: 3
};
if (user.role === ROLES.EDITOR) { }
// 4. 使用默认参数
// 不良写法
function greet(name) {
name = name || 'Guest';
return `Hello, ${name}`;
}
// 良好写法
function greet(name = 'Guest') {
return `Hello, ${name}`;
}
// 5. 使用卫语句提前返回
// 不良写法
function processOrder(order) {
if (order) {
if (order.items.length > 0) {
if (order.total > 0) {
// 处理订单
}
}
}
}
// 良好写法
function processOrder(order) {
if (!order) return;
if (order.items.length === 0) return;
if (order.total <= 0) return;
// 处理订单
}Memory Management
内存管理
javascript
// 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);
};
}javascript
// 1. 清除定时器与间隔器
const timerId = setTimeout(() => { }, 1000);
clearTimeout(timerId);
const intervalId = setInterval(() => { }, 1000);
clearInterval(intervalId);
// 2. 移除事件监听器
const handler = () => { };
element.addEventListener('click', handler);
element.removeEventListener('click', handler);
// 3. 使用完毕后将引用设为null
let largeData = fetchLargeDataset();
// 使用数据...
largeData = null; // 允许垃圾回收
// 4. 使用WeakMap/WeakSet作为缓存
const cache = new WeakMap();
let obj = { data: 'value' };
cache.set(obj, 'cached value');
obj = null; // 缓存条目会自动被移除
// 5. 避免全局变量
// 不良写法
var globalUser = { };
// 良好写法 - 使用模块/闭包
(function() {
const user = { };
// 局部使用user
})();
// 6. 注意闭包的使用
function createHeavyObject() {
const heavyData = new Array(1000000);
// 不良写法 - 闭包会保留heavyData在内存中
return function() {
console.log(heavyData.length);
};
// 良好写法 - 仅捕获需要的内容
const length = heavyData.length;
return function() {
console.log(length);
};
}Testing Considerations
测试注意事项
javascript
// 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;
}javascript
// 1. 编写可测试的代码 - 纯函数
// 可测试
function calculateTotal(items) {
return items.reduce((sum, item) => sum + item.price, 0);
}
// 难以测试 - 依赖外部状态
function calculateTotal() {
return cart.items.reduce((sum, item) => sum + item.price, 0);
}
// 2. 依赖注入
// 难以测试
class UserService {
constructor() {
this.api = new ApiClient();
}
}
// 易于测试 - 注入依赖
class UserService {
constructor(apiClient) {
this.api = apiClient;
}
}
// 3. 避免副作用
// 有副作用
function processData(data) {
console.log('Processing...'); // 副作用
updateDatabase(data); // 副作用
return transform(data);
}
// 纯函数
function transformData(data) {
return transform(data);
}
// 分离副作用
function processData(data) {
const transformed = transformData(data);
console.log('Processing...');
updateDatabase(transformed);
return transformed;
}Quick Reference
快速参考
Array Methods Cheat Sheet
数组方法速查表
javascript
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!)javascript
const arr = [1, 2, 3, 4, 5];
// 转换
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
// 搜索
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
// 变更原数组
arr.push(6) // 添加到末尾
arr.pop() // 从末尾移除
arr.unshift(0) // 添加到开头
arr.shift() // 从开头移除
arr.splice(2, 1, 99) // 在指定索引处移除/添加元素
// 不修改原数组
arr.slice(1, 3) // [2, 3]
arr.concat([6, 7]) // [1, 2, 3, 4, 5, 6, 7]
[...arr] // 拷贝数组
arr.join(', ') // "1, 2, 3, 4, 5"
arr.reverse() // [5, 4, 3, 2, 1](会修改原数组!)
arr.sort((a, b) => a - b) // 排序(会修改原数组!)Object Methods Cheat Sheet
对象方法速查表
javascript
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)javascript
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 } // 与上面结果相同
Object.freeze(obj) // 设为不可变
Object.seal(obj) // 阻止添加/删除属性
Object.preventExtensions(obj) // 阻止添加属性
Object.hasOwnProperty.call(obj, 'a') // true
'a' in obj // true
obj.hasOwnProperty('a') // true(不推荐使用)Common Gotchas
常见陷阱
javascript
// 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;This comprehensive guide covers the essential JavaScript fundamentals needed for modern development. Practice these concepts regularly and refer to the EXAMPLES.md file for detailed implementation scenarios.
javascript
// 1. 相等性
0 == '0' // true(类型转换)
0 === '0' // false(严格相等)
null == undefined // true
null === undefined // false
// 2. 类型转换
'5' + 3 // "53"(字符串拼接)
'5' - 3 // 2(数值减法)
+'5' // 5(一元加号转换为数字)
!!'value' // true(双重否定转换为布尔值)
// 3. this绑定
const obj = {
name: 'Object',
regular: function() { console.log(this.name); },
arrow: () => { console.log(this.name); }
};
obj.regular(); // "Object"
obj.arrow(); // undefined(箭头函数使用词法this)
// 4. 假值
false, 0, -0, 0n, '', null, undefined, NaN
// 5. 数组/对象比较
[] === [] // false(不同引用)
{} === {} // false(不同引用)
// 6. 浮点数精度
0.1 + 0.2 === 0.3 // false(实际结果为0.30000000000000004)
Math.abs(0.1 + 0.2 - 0.3) < Number.EPSILON // true
// 7. 变量提升
console.log(x); // undefined(var被提升)
var x = 5;
console.log(y); // ReferenceError(let不会被提升至可用状态)
let y = 5;本全面指南涵盖了现代开发所需的JavaScript核心基础。请定期练习这些概念,并参考EXAMPLES.md文件获取详细的实现场景。