闭包是指一个函数能够记住并访问其词法作用域,即使该函数在其词法作用域之外执行。
function outer() {
const message = "Hello, Closure!";
function inner() {
console.log(message); // 访问外部函数变量
}
return inner;
}
const myFunc = outer();
myFunc(); // "Hello, Closure!" - 闭包!
function createCounter() {
let count = 0; // 自由变量
return function () {
count++; // 访问并修改外部变量
return count;
};
}
const counter = createCounter();
console.log(counter()); // 1
console.log(counter()); // 2
console.log(counter()); // 3
// 每个闭包都有自己的词法环境
const counter2 = createCounter();
console.log(counter2()); // 1 (独立计数)
function createMultiplier(multiplier) {
// 闭包记住了 multiplier 参数
return function (x) {
return x * multiplier;
};
}
const double = createMultiplier(2);
const triple = createMultiplier(3);
console.log(double(5)); // 10
console.log(triple(5)); // 15
function delayedGreeting(name) {
const message = `Hello, ${name}!`;
setTimeout(function () {
console.log(message); // 闭包记住了 message
}, 1000);
}
delayedGreeting("Alice");
// 创建私有作用域
const module = (function () {
let privateVar = "I'm private";
function privateMethod() {
console.log(privateVar);
}
return {
publicMethod: function () {
privateMethod();
},
};
})();
module.publicMethod(); // "I'm private"
console.log(module.privateVar); // undefined
// 常见问题
for (var i = 1; i <= 3; i++) {
setTimeout(function () {
console.log(i); // 都是 4!
}, i * 1000);
}
// 解决方案1:使用 IIFE
for (var i = 1; i <= 3; i++) {
(function (j) {
setTimeout(function () {
console.log(j); // 1, 2, 3
}, j * 1000);
})(i);
}
// 解决方案2:使用 let (块级作用域)
for (let i = 1; i <= 3; i++) {
setTimeout(function () {
console.log(i); // 1, 2, 3
}, i * 1000);
}
const calculator = (function () {
let memory = 0;
function validateNumber(num) {
return typeof num === "number" && !isNaN(num);
}
return {
add: function (x, y) {
if (!validateNumber(x) || !validateNumber(y)) {
throw new Error("Invalid numbers");
}
return x + y;
},
store: function (value) {
memory = value;
},
recall: function () {
return memory;
},
clear: function () {
memory = 0;
},
};
})();
console.log(calculator.add(2, 3)); // 5
calculator.store(10);
console.log(calculator.recall()); // 10
// 柯里化:把多参数函数转化为单参数函数序列
function curry(fn) {
return function curried(...args) {
if (args.length >= fn.length) {
return fn.apply(this, args);
} else {
return function (...args2) {
return curried.apply(this, args.concat(args2));
};
}
};
}
// 使用示例
function add(a, b, c) {
return a + b + c;
}
const curriedAdd = curry(add);
console.log(curriedAdd(1)(2)(3)); // 6
console.log(curriedAdd(1, 2)(3)); // 6
console.log(curriedAdd(1)(2, 3)); // 6
// 实用的柯里化应用
function createLogger(prefix) {
return function (message) {
return function (level) {
return `[${level.toUpperCase()}] ${prefix}: ${message}`;
};
};
}
const appLogger = createLogger("App");
const errorLogger = appLogger("Something went wrong");
console.log(errorLogger("error")); // [ERROR] App: Something went wrong
function memoize(fn) {
const cache = new Map();
return function (...args) {
const key = JSON.stringify(args);
if (cache.has(key)) {
console.log("Cache hit!");
return cache.get(key);
}
console.log("Calculating...");
const result = fn.apply(this, args);
cache.set(key, result);
return result;
};
}
// 使用示例
function expensiveCalculation(n) {
console.log(`Calculating ${n}...`);
let result = 0;
for (let i = 0; i < n * 1000000; i++) {
result += Math.random();
}
return result;
}
const memoizedCalculation = memoize(expensiveCalculation);
console.log(memoizedCalculation(10)); // 第一次计算
console.log(memoizedCalculation(10)); // 从缓存读取
console.log(memoizedCalculation(20)); // 新的计算
function createStateMachine(initialState) {
let state = initialState;
let listeners = [];
function getState() {
return state;
}
function setState(newState) {
const oldState = state;
state = newState;
// 通知所有监听者
listeners.forEach(listener => {
listener(state, oldState);
});
}
function subscribe(listener) {
listeners.push(listener);
// 返回取消订阅函数
return function unsubscribe() {
listeners = listeners.filter(l => l !== listener);
};
}
return {
getState,
setState,
subscribe,
};
}
// 使用示例
const store = createStateMachine({ count: 0 });
const unsubscribe = store.subscribe((state, oldState) => {
console.log("State changed:", oldState, "→", state);
});
store.setState({ count: 1 }); // 触发监听
store.setState({ count: 2 }); // 触发监听
unsubscribe();
store.setState({ count: 3 }); // 不会触发监听
// 防抖 (Debounce)
function debounce(fn, delay) {
let timeoutId;
return function (...args) {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => {
fn.apply(this, args);
}, delay);
};
}
// 节流 (Throttle)
function throttle(fn, limit) {
let inThrottle;
return function (...args) {
if (!inThrottle) {
fn.apply(this, args);
inThrottle = true;
setTimeout(() => {
inThrottle = false;
}, limit);
}
};
}
// 使用示例
const handleResize = debounce(function () {
console.log("Window resized:", window.innerWidth);
}, 300);
window.addEventListener("resize", handleResize);
const handleScroll = throttle(function () {
console.log("Scrolling...");
}, 1000);
window.addEventListener("scroll", handleScroll);
function Person(name, age) {
// 私有变量
let _age = age;
this.name = name; // 公共属性
// 特权方法:可以访问私有变量
this.getAge = function () {
return _age;
};
this.setAge = function (newAge) {
if (newAge > 0) {
_age = newAge;
}
};
// 私有方法
function validateName(name) {
return typeof name === "string" && name.length > 0;
}
// 在构造函数中验证
if (!validateName(name)) {
throw new Error("Invalid name");
}
}
const person = new Person("Alice", 25);
console.log(person.name); // 'Alice'
console.log(person.getAge()); // 25
console.log(person._age); // undefined
person.setAge(26);
console.log(person.getAge()); // 26
function createPerson(name) {
let mood = "happy";
let secrets = [];
return {
getName: () => name,
greet: () => {
return `Hi, I'm ${name} and I'm feeling ${mood}!`;
},
changeMood: newMood => {
const validMoods = ["happy", "sad", "angry", "excited"];
if (validMoods.includes(newMood)) {
mood = newMood;
}
},
addSecret: secret => {
secrets.push(secret);
console.log(`${name} now has ${secrets.length} secrets`);
},
revealSecrets: () => {
if (mood === "happy") {
return secrets;
}
return ["I cannot reveal secrets when I'm not happy"];
},
};
}
const alice = createPerson("Alice");
console.log(alice.greet()); // "Hi, I'm Alice and I'm feeling happy!"
alice.addSecret("I once broke a vase");
alice.changeMood("sad");
console.log(alice.revealSecrets()); // ["I cannot reveal secrets when I'm not happy"]
// 组合多个函数
function compose(...fns) {
return function (x) {
return fns.reduceRight((acc, fn) => fn(acc), x);
};
}
// 管道(从左到右执行)
function pipe(...fns) {
return function (x) {
return fns.reduce((acc, fn) => fn(acc), x);
};
}
// 使用示例
const add5 = x => x + 5;
const multiply3 = x => x * 3;
const square = x => x * x;
const composed = compose(square, multiply3, add5);
console.log(composed(2)); // ((2 + 5) * 3)^2 = 441
const piped = pipe(add5, multiply3, square);
console.log(piped(2)); // ((2 + 5) * 3)^2 = 441
// 实用示例:数据处理管道
const users = [
{ name: "Alice", age: 25 },
{ name: "Bob", age: 30 },
{ name: "Charlie", age: 35 },
];
const processUsers = pipe(
users => users.filter(u => u.age >= 30),
users => users.map(u => ({ ...u, isSenior: true })),
users => users.sort((a, b) => b.age - a.age)
);
console.log(processUsers(users));
function partial(fn, ...presetArgs) {
return function (...laterArgs) {
return fn.apply(this, presetArgs.concat(laterArgs));
};
}
// 使用示例
function sendRequest(method, url, data, headers) {
console.log(`Sending ${method} request to ${url}`);
console.log("Data:", data);
console.log("Headers:", headers);
}
const sendGetRequest = partial(sendRequest, "GET", "https://api.example.com");
const sendPostRequest = partial(sendRequest, "POST", "https://api.example.com");
// 使用部分应用的函数
sendGetRequest(null, { "Content-Type": "application/json" });
sendPostRequest({ id: 1 }, { Authorization: "Bearer token" });
// 更灵活的偏函数
function partialRight(fn, ...presetArgs) {
return function (...earlyArgs) {
return fn.apply(this, earlyArgs.concat(presetArgs));
};
}
const sendRequestWithHeaders = partialRight(sendRequest, { "Content-Type": "application/json" });
sendRequestWithHeaders("PUT", "https://api.example.com/data", { id: 1 });
// 潜在的内存泄漏
function createLeakyClosure() {
const largeData = new Array(1000000).fill("data");
return function () {
console.log("I have access to largeData");
// 即使不需要,largeData 也无法被垃圾回收
};
}
// 解决方案:及时清理引用
function createSafeClosure() {
const largeData = new Array(1000000).fill("data");
function processData() {
const result = largeData.length;
// 处理完数据后,清除对大数据的引用
// 注意:这里只是示例,实际需要根据具体情况处理
return function () {
return result; // 只保留需要的结果
};
}
const inner = processData();
// 帮助垃圾回收
// delete largeData; // 不能直接删除,但可以赋值为 null
return inner;
}
// 避免在热代码路径中创建不必要的闭包
function processItems(items) {
// 不好的做法:每次循环都创建新函数
return items.map(function (item) {
return function () {
return item * 2;
};
});
// 更好的做法:预定义函数
const double = x => x * 2;
return items.map(item => () => double(item));
}
// 闭包缓存
function createCachedClosure() {
const cache = new Map();
return function (key, compute) {
if (cache.has(key)) {
return cache.get(key);
}
const value = compute();
cache.set(key, value);
return value;
};
}
const cached = createCachedClosure();
const expensive = cached("expensive", () => {
console.log("Computing...");
return Math.random();
});
console.log(expensive);
console.log(cached("expensive", () => Math.random())); // 从缓存读取
// 简化的 useState 实现
function createUseState(initialValue) {
let state = initialValue;
let listeners = [];
return function useState() {
// 闭包记住了 state 和 listeners
const setState = newValue => {
state = newValue;
listeners.forEach(listener => listener());
};
const subscribe = listener => {
listeners.push(listener);
return () => {
listeners = listeners.filter(l => l !== listener);
};
};
return [state, setState, subscribe];
};
}
// 使用示例
const useCustomState = createUseState(0);
function Counter() {
const [count, setCount, subscribe] = useCustomState();
// 模拟 React 的重新渲染
subscribe(() => {
console.log("State changed:", count);
});
return {
increment: () => setCount(count + 1),
getCount: () => count,
};
}
const counter = Counter();
console.log(counter.getCount()); // 0
counter.increment(); // State changed: 0
console.log(counter.getCount()); // 1
function createMiddleware() {
const middlewares = [];
function use(middleware) {
middlewares.push(middleware);
}
function dispatch(action) {
let index = 0;
function next() {
if (index < middlewares.length) {
const middleware = middlewares[index];
index++;
return middleware(action, next);
}
return action;
}
return next();
}
return { use, dispatch };
}
// 使用示例
const middlewareSystem = createMiddleware();
// 日志中间件
middlewareSystem.use((action, next) => {
console.log("Action started:", action);
const result = next();
console.log("Action completed:", action);
return result;
});
// 验证中间件
middlewareSystem.use((action, next) => {
if (action.type === "INCREMENT") {
console.log("Validating increment...");
}
return next();
});
const result = middlewareSystem.dispatch({ type: "INCREMENT", payload: 5 });