javascript-mastery

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

🧠 JavaScript Mastery

🧠 JavaScript 精通指南

33+ essential JavaScript concepts every developer should know, inspired by 33-js-concepts.
每位开发者都应掌握的33+个JavaScript核心概念,灵感来源于33-js-concepts

When to Use This Skill

何时使用本技能

Use this skill when:
  • Explaining JavaScript concepts
  • Debugging tricky JS behavior
  • Teaching JavaScript fundamentals
  • Reviewing code for JS best practices
  • Understanding language quirks

在以下场景使用本技能:
  • 讲解JavaScript概念
  • 调试复杂的JS行为
  • 教授JavaScript基础知识
  • 审查JS代码的最佳实践
  • 理解语言特性 quirks

1. Fundamentals

1. 基础知识

1.1 Primitive Types

1.1 基本类型

JavaScript has 7 primitive types:
javascript
// String
const str = "hello";

// Number (integers and floats)
const num = 42;
const float = 3.14;

// BigInt (for large integers)
const big = 9007199254740991n;

// Boolean
const bool = true;

// Undefined
let undef; // undefined

// Null
const empty = null;

// Symbol (unique identifiers)
const sym = Symbol("description");
Key points:
  • Primitives are immutable
  • Passed by value
  • typeof null === "object"
    is a historical bug
JavaScript有7种基本类型:
javascript
// String
const str = "hello";

// Number (整数和浮点数)
const num = 42;
const float = 3.14;

// BigInt (用于大整数)
const big = 9007199254740991n;

// Boolean
const bool = true;

// Undefined
let undef; // undefined

// Null
const empty = null;

// Symbol (唯一标识符)
const sym = Symbol("description");
核心要点:
  • 基本类型是不可变的
  • 按值传递
  • typeof null === "object"
    是历史遗留bug

1.2 Type Coercion

1.2 类型转换

JavaScript implicitly converts types:
javascript
// String coercion
"5" + 3; // "53" (number → string)
"5" - 3; // 2    (string → number)

// Boolean coercion
Boolean(""); // false
Boolean("hello"); // true
Boolean(0); // false
Boolean([]); // true (!)

// Equality coercion
"5" == 5; // true  (coerces)
"5" === 5; // false (strict)
Falsy values (8 total):
false
,
0
,
-0
,
0n
,
""
,
null
,
undefined
,
NaN
JavaScript会隐式转换类型:
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 Equality Operators

1.3 相等运算符

javascript
// == (loose equality) - coerces types
null == undefined; // true
"1" == 1; // true

// === (strict equality) - no coercion
null === undefined; // false
"1" === 1; // false

// Object.is() - handles edge cases
Object.is(NaN, NaN); // true (NaN === NaN is false!)
Object.is(-0, 0); // false (0 === -0 is true!)
Rule: Always use
===
unless you have a specific reason not to.

javascript
// == (松散相等) - 会转换类型
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. Scope & Closures

2. 作用域与闭包

2.1 Scope Types

2.1 作用域类型

javascript
// Global scope
var globalVar = "global";

function outer() {
  // Function scope
  var functionVar = "function";

  if (true) {
    // Block scope (let/const only)
    let blockVar = "block";
    const alsoBlock = "block";
    var notBlock = "function"; // var ignores blocks!
  }
}
javascript
// 全局作用域
var globalVar = "global";

function outer() {
  // 函数作用域
  var functionVar = "function";

  if (true) {
    // 块级作用域(仅let/const)
    let blockVar = "block";
    const alsoBlock = "block";
    var notBlock = "function"; // var 会忽略块级作用域!
  }
}

2.2 Closures

2.2 闭包

A closure is a function that remembers its lexical scope:
javascript
function createCounter() {
  let count = 0; // "closed over" variable

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

const counter = createCounter();
counter.increment(); // 1
counter.increment(); // 2
counter.getCount(); // 2
Common use cases:
  • Data privacy (module pattern)
  • Function factories
  • Partial application
  • Memoization
闭包是指能记住其词法作用域的函数:
javascript
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
常见用例:
  • 数据隐私(模块模式)
  • 函数工厂
  • 部分应用
  • 记忆化(Memoization)

2.3 var vs let vs const

2.3 var vs let vs const

javascript
// var - function scoped, hoisted, can redeclare
var x = 1;
var x = 2; // OK

// let - block scoped, hoisted (TDZ), no redeclare
let y = 1;
// let y = 2; // Error!

// const - like let, but can't reassign
const z = 1;
// z = 2; // Error!

// BUT: const objects are mutable
const obj = { a: 1 };
obj.a = 2; // OK
obj.b = 3; // OK

javascript
// 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. Functions & Execution

3. 函数与执行

3.1 Call Stack

3.1 调用栈

javascript
function first() {
  console.log("first start");
  second();
  console.log("first end");
}

function second() {
  console.log("second");
}

first();
// Output:
// "first start"
// "second"
// "first end"
Stack overflow example:
javascript
function infinite() {
  infinite(); // No base case!
}
infinite(); // RangeError: Maximum call stack size exceeded
javascript
function first() {
  console.log("first start");
  second();
  console.log("first end");
}

function second() {
  console.log("second");
}

first();
// 输出:
// "first start"
// "second"
// "first end"
栈溢出示例:
javascript
function infinite() {
  infinite(); // 没有基线条件!
}
infinite(); // RangeError: 超出最大调用栈大小

3.2 Hoisting

3.2 变量提升

javascript
// Variable hoisting
console.log(a); // undefined (hoisted, not initialized)
var a = 5;

console.log(b); // ReferenceError (TDZ)
let b = 5;

// Function hoisting
sayHi(); // Works!
function sayHi() {
  console.log("Hi!");
}

// Function expressions don't hoist
sayBye(); // TypeError
var sayBye = function () {
  console.log("Bye!");
};
javascript
// 变量提升
console.log(a); // undefined (已提升,但未初始化)
var a = 5;

console.log(b); // ReferenceError (暂时性死区)
let b = 5;

// 函数提升
sayHi(); // 可以正常执行!
function sayHi() {
  console.log("Hi!");
}

// 函数表达式不会被提升
sayBye(); // TypeError
var sayBye = function () {
  console.log("Bye!");
};

3.3 this Keyword

3.3 this关键字

javascript
// Global context
console.log(this); // window (browser) or global (Node)

// Object method
const obj = {
  name: "Alice",
  greet() {
    console.log(this.name); // "Alice"
  },
};

// Arrow functions (lexical this)
const obj2 = {
  name: "Bob",
  greet: () => {
    console.log(this.name); // undefined (inherits outer this)
  },
};

// Explicit binding
function greet() {
  console.log(this.name);
}
greet.call({ name: "Charlie" }); // "Charlie"
greet.apply({ name: "Diana" }); // "Diana"
const bound = greet.bind({ name: "Eve" });
bound(); // "Eve"

javascript
// 全局上下文
console.log(this); // 浏览器中为window,Node中为global

// 对象方法
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. Event Loop & Async

4. 事件循环与异步

4.1 Event Loop

4.1 事件循环

javascript
console.log("1");

setTimeout(() => console.log("2"), 0);

Promise.resolve().then(() => console.log("3"));

console.log("4");

// Output: 1, 4, 3, 2
// Why? Microtasks (Promises) run before macrotasks (setTimeout)
Execution order:
  1. Synchronous code (call stack)
  2. Microtasks (Promise callbacks, queueMicrotask)
  3. Macrotasks (setTimeout, setInterval, I/O)
javascript
console.log("1");

setTimeout(() => console.log("2"), 0);

Promise.resolve().then(() => console.log("3"));

console.log("4");

// 输出: 1, 4, 3, 2
// 原因? 微任务(Promise回调)会在宏任务(setTimeout)之前执行
执行顺序:
  1. 同步代码(调用栈)
  2. 微任务(Promise回调、queueMicrotask)
  3. 宏任务(setTimeout、setInterval、I/O)

4.2 Callbacks

4.2 回调函数

javascript
// Callback pattern
function fetchData(callback) {
  setTimeout(() => {
    callback(null, { data: "result" });
  }, 1000);
}

// Error-first convention
fetchData((error, result) => {
  if (error) {
    console.error(error);
    return;
  }
  console.log(result);
});

// Callback hell (avoid this!)
getData((data) => {
  processData(data, (processed) => {
    saveData(processed, (saved) => {
      notify(saved, () => {
        // 😱 Pyramid of doom
      });
    });
  });
});
javascript
// 回调模式
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 Promises

4.3 Promise

javascript
// Creating a Promise
const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("Success!");
    // or: reject(new Error("Failed!"));
  }, 1000);
});

// Consuming Promises
promise
  .then((result) => console.log(result))
  .catch((error) => console.error(error))
  .finally(() => console.log("Done"));

// Promise combinators
Promise.all([p1, p2, p3]); // All must succeed
Promise.allSettled([p1, p2]); // Wait for all, get status
Promise.race([p1, p2]); // First to settle
Promise.any([p1, p2]); // First to succeed
javascript
// 创建Promise
const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("Success!");
    // 或者: reject(new Error("Failed!"));
  }, 1000);
});

// 消费Promise
promise
  .then((result) => console.log(result))
  .catch((error) => console.error(error))
  .finally(() => console.log("Done"));

// Promise组合器
Promise.all([p1, p2, p3]); // 所有Promise必须成功
Promise.allSettled([p1, p2]); // 等待所有Promise完成,返回状态
Promise.race([p1, p2]); // 第一个完成的Promise
Promise.any([p1, p2]); // 第一个成功的Promise

4.4 async/await

4.4 async/await

javascript
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; // Re-throw for caller to handle
  }
}

// Parallel execution
async function fetchAll() {
  const [users, posts] = await Promise.all([
    fetch("/api/users"),
    fetch("/api/posts"),
  ]);
  return { users, posts };
}

javascript
async function fetchUserData(userId) {
  try {
    const response = await fetch(`/api/users/${userId}`);
    if (!response.ok) throw new Error("获取数据失败");
    const user = await response.json();
    return user;
  } catch (error) {
    console.error("错误:", error);
    throw error; // 重新抛出,让调用方处理
  }
}

// 并行执行
async function fetchAll() {
  const [users, posts] = await Promise.all([
    fetch("/api/users"),
    fetch("/api/posts"),
  ]);
  return { users, posts };
}

5. Functional Programming

5. 函数式编程

5.1 Higher-Order Functions

5.1 高阶函数

Functions that take or return functions:
javascript
// Takes a function
const numbers = [1, 2, 3];
const doubled = numbers.map((n) => n * 2); // [2, 4, 6]

// Returns a function
function multiply(a) {
  return function (b) {
    return a * b;
  };
}
const double = multiply(2);
double(5); // 10
接收函数作为参数或返回函数的函数:
javascript
// 接收函数作为参数
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 Pure Functions

5.2 纯函数

javascript
// Pure: same input → same output, no side effects
function add(a, b) {
  return a + b;
}

// Impure: modifies external state
let total = 0;
function addToTotal(value) {
  total += value; // Side effect!
  return total;
}

// Impure: depends on external state
function getDiscount(price) {
  return price * globalDiscountRate; // External dependency
}
javascript
// 纯函数: 相同输入→相同输出,无副作用
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

5.3 map, filter, reduce

javascript
const users = [
  { name: "Alice", age: 25 },
  { name: "Bob", age: 30 },
  { name: "Charlie", age: 35 },
];

// map: transform each element
const names = users.map((u) => u.name);
// ["Alice", "Bob", "Charlie"]

// filter: keep elements matching condition
const adults = users.filter((u) => u.age >= 30);
// [{ name: "Bob", ... }, { name: "Charlie", ... }]

// reduce: accumulate into single value
const totalAge = users.reduce((sum, u) => sum + u.age, 0);
// 90

// Chaining
const result = users
  .filter((u) => u.age >= 30)
  .map((u) => u.name)
  .join(", ");
// "Bob, Charlie"
javascript
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 Currying & Composition

5.4 柯里化与组合

javascript
// Currying: transform f(a, b, c) into 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

// Composition: combine functions
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

javascript
// 柯里化: 将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. Objects & Prototypes

6. 对象与原型

6.1 Prototypal Inheritance

6.1 原型继承

javascript
// Prototype chain
const animal = {
  speak() {
    console.log("Some sound");
  },
};

const dog = Object.create(animal);
dog.bark = function () {
  console.log("Woof!");
};

dog.speak(); // "Some sound" (inherited)
dog.bark(); // "Woof!" (own method)

// ES6 Classes (syntactic sugar)
class Animal {
  speak() {
    console.log("Some sound");
  }
}

class Dog extends Animal {
  bark() {
    console.log("Woof!");
  }
}
javascript
// 原型链
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 Object Methods

6.2 对象方法

javascript
const obj = { a: 1, b: 2 };

// Keys, values, entries
Object.keys(obj); // ["a", "b"]
Object.values(obj); // [1, 2]
Object.entries(obj); // [["a", 1], ["b", 2]]

// Shallow copy
const copy = { ...obj };
const copy2 = Object.assign({}, obj);

// Freeze (immutable)
const frozen = Object.freeze({ x: 1 });
frozen.x = 2; // Silently fails (or throws in strict mode)

// Seal (no add/delete, can modify)
const sealed = Object.seal({ x: 1 });
sealed.x = 2; // OK
sealed.y = 3; // Fails
delete sealed.x; // Fails

javascript
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. Modern JavaScript (ES6+)

7. 现代JavaScript(ES6+)

7.1 Destructuring

7.1 解构赋值

javascript
// Array destructuring
const [first, second, ...rest] = [1, 2, 3, 4, 5];
// first = 1, second = 2, rest = [3, 4, 5]

// Object destructuring
const { name, age, city = "Unknown" } = { name: "Alice", age: 25 };
// name = "Alice", age = 25, city = "Unknown"

// Renaming
const { name: userName } = { name: "Bob" };
// userName = "Bob"

// Nested
const {
  address: { street },
} = { address: { street: "123 Main" } };
javascript
// 数组解构
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 Spread & Rest

7.2 展开与剩余运算符

javascript
// Spread: expand iterable
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 }

// Rest: collect remaining
function sum(...numbers) {
  return numbers.reduce((a, b) => a + b, 0);
}
sum(1, 2, 3, 4); // 10
javascript
// 展开运算符: 展开可迭代对象
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 Modules

7.3 模块

javascript
// Named exports
export const PI = 3.14159;
export function square(x) {
  return x * x;
}

// Default export
export default class Calculator {}

// Importing
import Calculator, { PI, square } from "./math.js";
import * as math from "./math.js";

// Dynamic import
const module = await import("./dynamic.js");
javascript
// 具名导出
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 Optional Chaining & Nullish Coalescing

7.4 可选链与空值合并运算符

javascript
// Optional chaining (?.)
const user = { address: { city: "NYC" } };
const city = user?.address?.city; // "NYC"
const zip = user?.address?.zip; // undefined (no error)
const fn = user?.getName?.(); // undefined if no method

// Nullish coalescing (??)
const value = null ?? "default"; // "default"
const zero = 0 ?? "default"; // 0 (not nullish!)
const empty = "" ?? "default"; // "" (not nullish!)

// Compare with ||
const value2 = 0 || "default"; // "default" (0 is falsy)

javascript
// 可选链 (?.)
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(0不是空值!)
const empty = "" ?? "default"; // ""(空字符串不是空值!)

// 与||对比
const value2 = 0 || "default"; // "default"(0是假值)

Quick Reference Card

快速参考卡片

ConceptKey Point
==
vs
===
Always use
===
var
vs
let
Prefer
let
/
const
ClosuresFunction + lexical scope
this
Depends on how function is called
Event loopMicrotasks before macrotasks
Pure functionsSame input → same output
Prototypes
__proto__
→ prototype chain
??
vs
||
??
only checks null/undefined

概念核心要点
==
vs
===
始终使用
===
var
vs
let
优先使用
let
/
const
闭包函数 + 词法作用域
this
取决于函数的调用方式
事件循环微任务优先于宏任务执行
纯函数相同输入→相同输出
原型
__proto__
→ 原型链
??
vs `

Resources

参考资源