基础不牢、面试白考,快给我练起来!
#️⃣ 1. 闭包 —— 别背概念,用例子秒懂
闭包出现的关键:
👉 函数里返回一个函数,并引用了外部的变量。
最经典示例:
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100);
}
输出:
3
3
3
原因:
var 只有函数作用域,没有块级作用域 → 循环里所有回调共享同一个 i → 最后是 3。
解决:
✔ 用 let
✔ 用立即执行函数(IIFE)让每次循环都有自己的作用域
for (var i = 0; i < 3; i++) {
(function(i){
setTimeout(() => console.log(i), 100);
})(i)
}
闭包的本质:
函数记住了它诞生时所在的作用域(变量环境)。
#️⃣ 2. 防抖 debounce —— 只执行最后一次
适用于:搜索框输入、窗口 resize、按钮点太快…
function debounce(fn, delay) {
let timer;
return function (...args) {
const context = this;
clearTimeout(timer);
timer = setTimeout(() => {
fn.apply(context, args);
}, delay);
};
}
🤩 效果:你点 10 次按钮,它只执行一次。
#️⃣ 3. 节流 throttle —— 一段时间内只执行一次
适用于:滚动、拖拽、抢红包狂点。
function throttle(fn, delay) {
let last = 0;
return function (...args) {
const now = Date.now();
if (now - last >= delay) {
last = now;
fn.apply(this, args);
}
};
}
#️⃣ 4. call / apply / bind —— 三兄弟的区别
| 方法 | 是否立刻执行 | 参数写法 |
|---|---|---|
| call | ✔ 是 | 多个参数 |
| apply | ✔ 是 | 数组 |
| bind | ❌ 否(返回新函数) | 多个参数 |
真正用途:
✔ 改变 this 指向
✔ 借用构造函数实现“继承”
例如:
function fn(a, b) {
console.log(this, a + b);
}
fn.call({x:1}, 1, 2);
fn.apply({x:1}, [1, 2]);
fn.bind({x:1}, 1)(2);
#️⃣ 5. 寄生组合继承 —— ES5 最优继承方案
function Parent(name) {
this.name = name;
this.hobby = ["game", "music"];
}
Parent.prototype.sayHi = function () {
console.log("Hi, I am " + this.name);
};
function Child(name, age) {
Parent.call(this, name); // 继承实例属性
this.age = age;
}
// 关键代码
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;
优点:
✔ 实例属性靠 call 拿到
✔ 原型方法靠 Object.create 继承
✔ 避免多次调用父构造函数(经典组合继承最大问题)
这就是传说中的 “JavaScript 继承最优解”。
#️⃣ 6. ES6 class 继承 —— 语法糖版
class Parent {
constructor(name) {
this.name = name;
}
sayHi() {
console.log("Hi from Parent");
}
}
class Child extends Parent {
constructor(name, age) {
super(name);
this.age = age;
}
}
语法更现代,但本质仍是原型链。
#️⃣ 7. 柯里化 —— 一个函数拆成多次调用
function curry(fn) {
return function curried(...args) {
if (args.length >= fn.length) {
return fn(...args);
}
return function (...next) {
return curried(...args, ...next);
};
};
}
使用:
const add = (a,b,c) => a + b + c;
const curried = curry(add);
curried(1)(2)(3); // 6
意义:
✔ 参数复用
✔ 让函数更灵活
✔ 常用于函数式编程 / React hook 工具
#️⃣ 8. Promise —— 异步编程的轻量写法
const p = new Promise((resolve, reject) => {
setTimeout(() => {
const ok = true;
ok ? resolve("成功") : reject("失败");
}, 1000);
});
p.then(res => console.log(res))
.catch(err => console.log(err))
.finally(() => console.log("总会执行"));
Promise 的状态:
✔ pending
✔ fulfilled
✔ rejected
状态一旦改变就不会再变(不可逆)。
#️⃣ 9. 手写发布订阅 —— EventBus
实现事件中心:Vue2、Node.js 都有类似机制。
const EventBus = {
events: {},
on(event, cb) {
this.events[event] = this.events[event] || [];
this.events[event].push(cb);
},
emit(event, data) {
(this.events[event] || []).forEach(cb => cb(data));
},
off(event, cb) {
if (!this.events[event]) return;
this.events[event] = this.events[event].filter(fn => fn !== cb);
}
};
使用:
function handler(msg) {
console.log("收到:", msg);
}
EventBus.on("msg", handler);
EventBus.emit("msg", "Hello!");