name: JavaScript精通 description: “全面的JavaScript参考,涵盖每位开发者都应知道的33+个关键概念。从基础如原始类型和闭包,到高级模式如async/await和函数式编程。用于解释JS概念、调试JavaScript问题或教学JavaScript基础。”
🧠 JavaScript精通
每位开发者都应知道的33+个关键JavaScript概念,灵感来自 33-js-concepts。
何时使用此技能
使用此技能当:
- 解释JavaScript概念
- 调试棘手的JS行为
- 教学JavaScript基础
- 审查代码以遵循JS最佳实践
- 理解语言特性
1. 基础
1.1 原始类型
JavaScript有7种原始类型:
// 字符串
const str = "hello";
// 数字(整数和浮点数)
const num = 42;
const float = 3.14;
// BigInt(用于大整数)
const big = 9007199254740991n;
// 布尔值
const bool = true;
// 未定义
let undef; // undefined
// 空值
const empty = null;
// 符号(唯一标识符)
const sym = Symbol("description");
关键点:
- 原始类型是不可变的
- 通过值传递
typeof null === "object"是一个历史错误
1.2 类型强制转换
JavaScript隐式转换类型:
// 字符串强制转换
"5" + 3; // "53"(数字→字符串)
"5" - 3; // 2 (字符串→数字)
// 布尔强制转换
Boolean(""); // false
Boolean("hello"); // true
Boolean(0); // false
Boolean([]); // true (!)
// 相等性强制转换
"5" == 5; // true (强制转换)
"5" === 5; // false (严格)
假值(共8个):
false, 0, -0, 0n, "", null, undefined, NaN
1.3 相等运算符
// == (宽松相等) - 强制转换类型
null == undefined; // true
"1" == 1; // true
// === (严格相等) - 无强制转换
null === undefined; // false
"1" === 1; // false
// Object.is() - 处理边界情况
Object.is(NaN, NaN); // true(NaN === NaN 是 false!)
Object.is(-0, 0); // false(0 === -0 是 true!)
规则:除非有特定原因,否则始终使用 ===。
2. 作用域与闭包
2.1 作用域类型
// 全局作用域
var globalVar = "global";
function outer() {
// 函数作用域
var functionVar = "function";
if (true) {
// 块作用域(仅限let/const)
let blockVar = "block";
const alsoBlock = "block";
var notBlock = "function"; // var 忽略块作用域!
}
}
2.2 闭包
闭包是一个函数,它记住其词法作用域:
function createCounter() {
let count = 0; // “闭包”变量
return {
increment() {
return ++count;
},
decrement() {
return --count;
},
getCount() {
return count;
},
};
}
const counter = createCounter();
counter.increment(); // 1
counter.increment(); // 2
counter.getCount(); // 2
常见用例:
- 数据隐私(模块模式)
- 函数工厂
- 部分应用
- 记忆化
2.3 var vs let vs const
// var - 函数作用域,提升,可重新声明
var x = 1;
var x = 2; // 可行
// let - 块作用域,提升(TDZ),不可重新声明
let y = 1;
// let y = 2; // 错误!
// const - 类似let,但不可重新赋值
const z = 1;
// z = 2; // 错误!
// 但是:const对象是可变的
const obj = { a: 1 };
obj.a = 2; // 可行
obj.b = 3; // 可行
3. 函数与执行
3.1 调用栈
function first() {
console.log("first start");
second();
console.log("first end");
}
function second() {
console.log("second");
}
first();
// 输出:
// "first start"
// "second"
// "first end"
栈溢出示例:
function infinite() {
infinite(); // 无基本情况!
}
infinite(); // RangeError: 最大调用栈大小超出
3.2 提升
// 变量提升
console.log(a); // undefined(提升,但未初始化)
var a = 5;
console.log(b); // ReferenceError(TDZ)
let b = 5;
// 函数提升
sayHi(); // 可行!
function sayHi() {
console.log("Hi!");
}
// 函数表达式不提升
sayBye(); // TypeError
var sayBye = function () {
console.log("Bye!");
};
3.3 this 关键字
// 全局上下文
console.log(this); // window(浏览器)或 global(Node)
// 对象方法
const obj = {
name: "Alice",
greet() {
console.log(this.name); // "Alice"
},
};
// 箭头函数(词法this)
const obj2 = {
name: "Bob",
greet: () => {
console.log(this.name); // undefined(继承外部this)
},
};
// 显式绑定
function greet() {
console.log(this.name);
}
greet.call({ name: "Charlie" }); // "Charlie"
greet.apply({ name: "Diana" }); // "Diana"
const bound = greet.bind({ name: "Eve" });
bound(); // "Eve"
4. 事件循环与异步
4.1 事件循环
console.log("1");
setTimeout(() => console.log("2"), 0);
Promise.resolve().then(() => console.log("3"));
console.log("4");
// 输出:1, 4, 3, 2
// 为什么?微任务(Promises)在宏任务(setTimeout)之前运行
执行顺序:
- 同步代码(调用栈)
- 微任务(Promise回调,queueMicrotask)
- 宏任务(setTimeout,setInterval,I/O)
4.2 回调
// 回调模式
function fetchData(callback) {
setTimeout(() => {
callback(null, { data: "result" });
}, 1000);
}
// 错误优先约定
fetchData((error, result) => {
if (error) {
console.error(error);
return;
}
console.log(result);
});
// 回调地狱(避免这个!)
getData((data) => {
processData(data, (processed) => {
saveData(processed, (saved) => {
notify(saved, () => {
// 😱 金字塔困境
});
});
});
});
4.3 承诺
// 创建Promise
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("Success!");
// 或:reject(new Error("Failed!"));
}, 1000);
});
// 消费Promises
promise
.then((result) => console.log(result))
.catch((error) => console.error(error))
.finally(() => console.log("Done"));
// Promise组合器
Promise.all([p1, p2, p3]); // 所有必须成功
Promise.allSettled([p1, p2]); // 等待所有,获取状态
Promise.race([p1, p2]); // 第一个settle的
Promise.any([p1, p2]); // 第一个成功的
4.4 async/await
async function fetchUserData(userId) {
try {
const response = await fetch(`/api/users/${userId}`);
if (!response.ok) throw new Error("Failed to fetch");
const user = await response.json();
return user;
} catch (error) {
console.error("Error:", error);
throw error; // 重新抛出供调用者处理
}
}
// 并行执行
async function fetchAll() {
const [users, posts] = await Promise.all([
fetch("/api/users"),
fetch("/api/posts"),
]);
return { users, posts };
}
5. 函数式编程
5.1 高阶函数
接受或返回函数的函数:
// 接受函数
const numbers = [1, 2, 3];
const doubled = numbers.map((n) => n * 2); // [2, 4, 6]
// 返回函数
function multiply(a) {
return function (b) {
return a * b;
};
}
const double = multiply(2);
double(5); // 10
5.2 纯函数
// 纯函数:相同输入→相同输出,无副作用
function add(a, b) {
return a + b;
}
// 非纯函数:修改外部状态
let total = 0;
function addToTotal(value) {
total += value; // 副作用!
return total;
}
// 非纯函数:依赖外部状态
function getDiscount(price) {
return price * globalDiscountRate; // 外部依赖
}
5.3 map, filter, reduce
const users = [
{ name: "Alice", age: 25 },
{ name: "Bob", age: 30 },
{ name: "Charlie", age: 35 },
];
// map:转换每个元素
const names = users.map((u) => u.name);
// ["Alice", "Bob", "Charlie"]
// filter:保留匹配条件的元素
const adults = users.filter((u) => u.age >= 30);
// [{ name: "Bob", ... }, { name: "Charlie", ... }]
// reduce:累加为单个值
const totalAge = users.reduce((sum, u) => sum + u.age, 0);
// 90
// 链式调用
const result = users
.filter((u) => u.age >= 30)
.map((u) => u.name)
.join(", ");
// "Bob, Charlie"
5.4 柯里化与组合
// 柯里化:将f(a, b, c)转换为f(a)(b)(c)
const curry = (fn) => {
return function curried(...args) {
if (args.length >= fn.length) {
return fn.apply(this, args);
}
return (...moreArgs) => curried(...args, ...moreArgs);
};
};
const add = curry((a, b, c) => a + b + c);
add(1)(2)(3); // 6
add(1, 2)(3); // 6
add(1)(2, 3); // 6
// 组合:结合函数
const compose =
(...fns) =>
(x) =>
fns.reduceRight((acc, fn) => fn(acc), x);
const pipe =
(...fns) =>
(x) =>
fns.reduce((acc, fn) => fn(acc), x);
const addOne = (x) => x + 1;
const double = (x) => x * 2;
const addThenDouble = compose(double, addOne);
addThenDouble(5); // 12 = (5 + 1) * 2
const doubleThenAdd = pipe(double, addOne);
doubleThenAdd(5); // 11 = (5 * 2) + 1
6. 对象与原型
6.1 原型继承
// 原型链
const animal = {
speak() {
console.log("Some sound");
},
};
const dog = Object.create(animal);
dog.bark = function () {
console.log("Woof!");
};
dog.speak(); // "Some sound"(继承)
dog.bark(); // "Woof!"(自有方法)
// ES6类(语法糖)
class Animal {
speak() {
console.log("Some sound");
}
}
class Dog extends Animal {
bark() {
console.log("Woof!");
}
}
6.2 对象方法
const obj = { a: 1, b: 2 };
// 键、值、条目
Object.keys(obj); // ["a", "b"]
Object.values(obj); // [1, 2]
Object.entries(obj); // [["a", 1], ["b", 2]]
// 浅拷贝
const copy = { ...obj };
const copy2 = Object.assign({}, obj);
// 冻结(不可变)
const frozen = Object.freeze({ x: 1 });
frozen.x = 2; // 静默失败(或在严格模式下抛出)
// 密封(无添加/删除,可修改)
const sealed = Object.seal({ x: 1 });
sealed.x = 2; // 可行
sealed.y = 3; // 失败
delete sealed.x; // 失败
7. 现代JavaScript(ES6+)
7.1 解构
// 数组解构
const [first, second, ...rest] = [1, 2, 3, 4, 5];
// first = 1, second = 2, rest = [3, 4, 5]
// 对象解构
const { name, age, city = "Unknown" } = { name: "Alice", age: 25 };
// name = "Alice", age = 25, city = "Unknown"
// 重命名
const { name: userName } = { name: "Bob" };
// userName = "Bob"
// 嵌套
const {
address: { street },
} = { address: { street: "123 Main" } };
7.2 展开与剩余
// 展开:扩展可迭代对象
const arr1 = [1, 2, 3];
const arr2 = [...arr1, 4, 5]; // [1, 2, 3, 4, 5]
const obj1 = { a: 1 };
const obj2 = { ...obj1, b: 2 }; // { a: 1, b: 2 }
// 剩余:收集剩余参数
function sum(...numbers) {
return numbers.reduce((a, b) => a + b, 0);
}
sum(1, 2, 3, 4); // 10
7.3 模块
// 命名导出
export const PI = 3.14159;
export function square(x) {
return x * x;
}
// 默认导出
export default class Calculator {}
// 导入
import Calculator, { PI, square } from "./math.js";
import * as math from "./math.js";
// 动态导入
const module = await import("./dynamic.js");
7.4 可选链与空值合并
// 可选链 (?.)
const user = { address: { city: "NYC" } };
const city = user?.address?.city; // "NYC"
const zip = user?.address?.zip; // undefined(无错误)
const fn = user?.getName?.(); // 如果无方法则为undefined
// 空值合并 (??)
const value = null ?? "default"; // "default"
const zero = 0 ?? "default"; // 0(非空值!)
const empty = "" ?? "default"; // ""(非空值!)
// 与 || 比较
const value2 = 0 || "default"; // "default"(0是假值)
快速参考卡
| 概念 | 关键点 |
|---|---|
== vs === |
始终使用 === |
var vs let |
优先使用 let/const |
| 闭包 | 函数 + 词法作用域 |
this |
取决于函数如何调用 |
| 事件循环 | 微任务在宏任务之前 |
| 纯函数 | 相同输入 → 相同输出 |
| 原型 | __proto__ → 原型链 |
?? vs ` |