JavaScript V8 引擎内置对象和方法

简介

V8 是 Google 开发的 JavaScript 引擎,被 Chrome 和 Node.js 使用。V8 实现了 ECMAScript 标准中定义的所有内置对象和方法。

注意:这些内置对象属于 JavaScript 语言标准,不是 V8 特有的。只是通过 V8 引擎来实现。

已在前文详细介绍的对象

以下对象在之前的文档中已详细介绍,本文仅提供速查引用:

对象 详见文档 说明
String js-data-types.md 字符串,详见"字符串"章节
Array js-data-types.md 数组,详见"数组"章节
Object js-data-types.md 对象,详见"对象"章节
Function js-function.md 函数,全文介绍
Error 及子类 js-exception.md 错误对象,全文介绍

全局对象(Global Object)

全局对象在全局作用域中可直接访问。在浏览器中是 window,在 Node.js 中是 global

全局属性

console.log(NaN);        // NaN(不是数字)
console.log(Infinity);    // Infinity(无穷大)
console.log(undefined);   // undefined

// ES2020:全局 this(统一浏览器和 Node.js)
console.log(globalThis);  // 浏览器: window, Node.js: global

全局函数

eval() — 执行字符串中的 JavaScript 代码

// 不推荐使用!存在安全和性能问题
let x = 10;
eval('x = 20; console.log(x);');  // 20

// 严格模式下,eval 有自己的作用域
(function() {
  'use strict';
  let y = 10;
  eval('let y = 30; console.log(y);');  // 30(局部作用域)
  console.log(y);  // 10(未被影响)
})();

parseInt() — 解析字符串为整数

console.log(parseInt('123'));      // 123
console.log(parseInt('123.45'));   // 123(小数部分被截断)
console.log(parseInt('abc'));      // NaN
console.log(parseInt('123abc'));   // 123(从开头解析,遇到非数字停止)
console.log(parseInt('0xFF'));     // 255(支持十六进制)
console.log(parseInt('1010', 2)); // 10(二进制解析)
console.log(parseInt('777', 8));  // 511(八进制解析)
console.log(parseInt('FF', 16));  // 255(十六进制解析)

parseFloat() — 解析字符串为浮点数

console.log(parseFloat('3.14'));    // 3.14
console.log(parseFloat('123.45abc')); // 123.45
console.log(parseFloat('abc'));      // NaN

isNaN() — 判断是否为 NaN

console.log(isNaN(NaN));        // true
console.log(isNaN(123));        // false
console.log(isNaN('abc'));     // true(字符串 'abc' 转为数字为 NaN)

// 注意:isNaN 会先尝试将参数转为数字
console.log(isNaN('123'));     // false('123' 转为 123)
console.log(isNaN(null));      // false(null 转为 0)
console.log(isNaN(undefined)); // true

// 更好的方式:使用 Number.isNaN()(ES6)
console.log(Number.isNaN(NaN));    // true
console.log(Number.isNaN('abc')); // false(不会类型转换!)

isFinite() — 判断是否为有限数字

console.log(isFinite(123));      // true
console.log(isFinite(Infinity)); // false
console.log(isFinite(-Infinity)); // false
console.log(isFinite(NaN));     // false
console.log(isFinite('123'));    // true(类型转换)

URI 编码函数

// encodeURI() / decodeURI() — 编码/解码整个 URI
let uri = 'https://example.com/搜索?q=hello world';
let encoded = encodeURI(uri);
console.log(encoded);  // https://example.com/%E6%90%9C%E7%B4%A2?q=hello%20world
console.log(decodeURI(encoded));  // 原 URI

// encodeURIComponent() / decodeURIComponent() — 编码/解码 URI 组件
let param = 'hello world & more';
console.log(encodeURIComponent(param));  // hello%20world%20%26%20more
console.log(decodeURIComponent('hello%20world'));  // hello world

// 区别:encodeURI 不会编码 ? = & 等 URI 特殊字符;encodeURIComponent 会全部编码

escape() / unescape() — 已废弃,不推荐使用

// 不推荐使用!仅作了解
// console.log(escape('hello world'));  // hello%20world

定时器函数(运行时提供)

注意setTimeoutsetInterval 等定时器函数不是 ECMAScript 标准规定的,而是由运行时环境(浏览器/Node.js)提供的全局函数。但它们在开发中极为常用。

setTimeout — 延迟调用(一次性)

在指定延迟后执行一次回调函数。

// 基本语法
let timerId = setTimeout(() => {
  console.log('1 秒后执行');
}, 1000);  // 延迟 1000 毫秒(1 秒)

// 带参数的回调
setTimeout((name) => {
  console.log('Hello, ' + name);
}, 500, 'Alice');  // 500ms 后输出:Hello, Alice

// 取消定时器
let timer = setTimeout(() => {
  console.log('这行不会执行');
}, 2000);
clearTimeout(timer);  // 取消定时

setInterval — 循环调用(重复执行)

每隔指定时间重复执行回调函数。

// 基本语法:每 500ms 执行一次
let counter = 0;
let timer = setInterval(() => {
  counter++;
  console.log('计数:', counter);
  if (counter >= 3) {
    clearInterval(timer);  // 停止定时器
    console.log('定时器已停止');
  }
}, 500);

// 输出:
// 计数: 1(0.5秒后)
// 计数: 2(1秒后)
// 计数: 3(1.5秒后)
// 定时器已停止

setTimeout vs setInterval 对比

// setInterval 的问题:代码执行时间可能超过间隔时间
// 假设每次执行需要 400ms,间隔设为 500ms:
// 执行 400ms → 等待 100ms → 下次执行(看起来正常)
// 但如果执行时间超过间隔,会"堆积"回调

// 替代方案:使用嵌套的 setTimeout(更精确)
let count = 0;
function tick() {
  count++;
  console.log('计数:', count);
  if (count < 3) {
    setTimeout(tick, 500);  // 执行完再安排下次
  }
}
setTimeout(tick, 500);

this 指向问题

// 在浏览器中,setTimeout/setInterval 的回调中 this 指向 window(非严格模式)
// 在 Node.js 中,this 指向 setTimeout 的上下文(通常是全局)

let obj = {
  name: 'Alice',
  greet() {
    setTimeout(function() {
      console.log(this);  // 浏览器: window,Node.js: global 或 undefined(严格模式)
    }, 100);
  },
  greetArrow() {
    setTimeout(() => {
      console.log(this.name);  // 'Alice'(箭头函数继承外层 this)
    }, 100);
  }
};

obj.greet();       // this 不是 obj
obj.greetArrow();  // this 是 obj(箭头函数)

最小延迟和时间精度

// 浏览器中,最小延迟实际受限制(特别是后台标签页)
// HTML5 规范:嵌套的 setTimeout 延迟至少 4ms
// 但是,现代浏览器对前台标签页通常更精确

// Node.js 中
setTimeout(() => console.log('1ms 后'), 1);   // 可能稍长于 1ms
setTimeout(() => console.log('0ms 后'), 0);    // 实际上有最小延迟(约 1-4ms)

setImmediate(Node.js 特有)

Node.js 提供的定时器,在当前事件循环迭代结束后执行。

// 仅在 Node.js 中可用
// setImmediate(() => console.log('立即执行(当前轮次结束后)'));

// setTimeout vs setImmediate 顺序不确定
// setTimeout(() => console.log('timeout'), 0);
// setImmediate(() => console.log('immediate'));
// 两者顺序可能因情况而异

requestAnimationFrame(浏览器特有)

浏览器提供的定时器,在下次页面重绘前执行,适合动画。

// 仅在浏览器中可用
// let start = null;
// function step(timestamp) {
//   if (!start) start = timestamp;
//   let progress = timestamp - start;
//   console.log('动画进度:', progress, 'ms');
//   if (progress < 2000) {
//     requestAnimationFrame(step);
//   }
// }
// requestAnimationFrame(step);

queueMicrotask(ES2020)

将微任务排入队列,在当前任务完成后、下一个宏任务之前执行。

console.log('1 - 同步代码');

setTimeout(() => console.log('4 - setTimeout(宏任务)'), 0);

queueMicrotask(() => console.log('3 - queueMicrotask(微任务)'));

Promise.resolve().then(() => console.log('2 - Promise(微任务)'));

console.log('5 - 同步代码');

// 输出顺序:
// 1 - 同步代码
// 5 - 同步代码
// 2 - Promise(微任务)
// 3 - queueMicrotask(微任务)
// 4 - setTimeout(宏任务)

定时器速查表

函数 说明 取消函数 环境
setTimeout(fn, delay) 延迟执行一次 clearTimeout(id) 浏览器 + Node.js
setInterval(fn, delay) 每隔 delay 执行 clearInterval(id) 浏览器 + Node.js
setImmediate(fn) 当前轮次结束后执行 clearImmediate(id) Node.js 仅
requestAnimationFrame(fn) 下次重绘前执行 cancelAnimationFrame(id) 浏览器仅
queueMicrotask(fn) 排队微任务(ES2020) 不可取消 浏览器 + Node.js

综合示例

// 示例 1:防抖(debounce)实现
function debounce(fn, delay) {
  let timer;
  return function(...args) {
    clearTimeout(timer);
    timer = setTimeout(() => fn.apply(this, args), delay);
  };
}

let debouncedInput = debounce((value) => {
  console.log('搜索:', value);
}, 500);

debouncedInput('hello');
debouncedInput('hello w');
debouncedInput('hello world');  // 只有最后一次会在 500ms 后执行

// 示例 2:节流(throttle)实现
function throttle(fn, limit) {
  let inThrottle;
  return function(...args) {
    if (!inThrottle) {
      fn.apply(this, args);
      inThrottle = true;
      setTimeout(() => inThrottle = false, limit);
    }
  };
}

// 示例 3:倒计时
function countdown(seconds) {
  let remaining = seconds;
  let timer = setInterval(() => {
    console.log('剩余:', remaining, '秒');
    remaining--;
    if (remaining < 0) {
      clearInterval(timer);
      console.log('倒计时结束!');
    }
  }, 1000);
}
// countdown(5);  // 每秒输出一次,5秒后结束

// 示例 4:延迟重试
function retryWithDelay(fn, retries, delay) {
  return new Promise((resolve, reject) => {
    function attempt(remaining) {
      fn()
        .then(resolve)
        .catch(error => {
          if (remaining === 0) {
            reject(error);
          } else {
            console.log(`重试剩余 ${remaining} 次...`);
            setTimeout(() => attempt(remaining - 1), delay);
          }
        });
    }
    attempt(retries);
  });
}

Math 对象

Math 是一个内置对象,包含数学常数和函数。不能实例化,直接调用其静态方法和属性。

数学常数

console.log(Math.E);        // 2.718281828459045(自然对数底)
console.log(Math.PI);       // 3.141592653589793(圆周率)
console.log(Math.LN2);      // 0.6931471805599453(2 的自然对数)
console.log(Math.LN10);     // 2.302585092994046(10 的自然对数)
console.log(Math.LOG2E);    // 1.4426950408889634(以 2 为底 E 的对数)
console.log(Math.LOG10E);   // 0.4342944819032518(以 10 为底 E 的对数)
console.log(Math.SQRT1_2);  // 0.7071067811865476(1/2 的平方根)
console.log(Math.SQRT2);    // 1.4142135623730951(2 的平方根)

四舍五入

// Math.floor() — 向下取整
console.log(Math.floor(3.9));  // 3
console.log(Math.floor(-3.1)); // -4

// Math.ceil() — 向上取整
console.log(Math.ceil(3.1));   // 4
console.log(Math.ceil(-3.9));  // -3

// Math.round() — 四舍五入
console.log(Math.round(3.4));  // 3
console.log(Math.round(3.5));  // 4
console.log(Math.round(-3.5)); // -3(注意:.5 时向大数方向舍入)

// Math.trunc() — 截断小数部分(ES6)
console.log(Math.trunc(3.9));   // 3
console.log(Math.trunc(-3.9));  // -3

最大值、最小值

console.log(Math.max(1, 3, 2, 5, 4));  // 5
console.log(Math.min(1, 3, 2, 5, 4));  // 1

// 结合 spread 运算符用于数组
let numbers = [3, 1, 4, 1, 5, 9];
console.log(Math.max(...numbers));  // 9
console.log(Math.min(...numbers));  // 1

随机数

// Math.random() — 返回 [0, 1) 之间的随机数
console.log(Math.random());

// 生成指定范围的随机整数:[min, max]
function randomInt(min, max) {
  return Math.floor(Math.random() * (max - min + 1)) + min;
}
console.log(randomInt(1, 10));  // 1-10 之间的随机整数

// 生成指定范围的随机浮点数:[min, max)
function randomFloat(min, max) {
  return Math.random() * (max - min) + min;
}
console.log(randomFloat(1.5, 5.5));

幂和平方根

console.log(Math.pow(2, 3));   // 8(2 的 3 次方,等价于 2 ** 3)
console.log(Math.sqrt(16));     // 4(平方根)
console.log(Math.cbrt(27));    // 3(立方根,ES6)
console.log(Math.hypot(3, 4)); // 5(勾股定理:√(3²+4²),ES6)

绝对值和符号

console.log(Math.abs(-5));    // 5(绝对值)
console.log(Math.sign(-5));   // -1(符号:-1 负数,1 正数,0 为零)
console.log(Math.sign(5));    // 1
console.log(Math.sign(0));    // 0

对数和指数

console.log(Math.exp(1));     // 2.718281828459045(e 的 1 次方)
console.log(Math.log(Math.E)); // 1(自然对数)
console.log(Math.log10(100)); // 2(以 10 为底)
console.log(Math.log2(8));    // 3(以 2 为底)

Math 方法速查表

方法 说明
Math.floor(x) 向下取整
Math.ceil(x) 向上取整
Math.round(x) 四舍五入
Math.trunc(x) 截断小数
Math.max(...nums) 最大值
Math.min(...nums) 最小值
Math.random() [0,1) 随机数
Math.pow(x,y) x 的 y 次方
Math.sqrt(x) 平方根
Math.abs(x) 绝对值
Math.sign(x) 符号函数
Math.log(x) 自然对数
Math.sin(x) / Math.cos(x) / Math.tan(x) 三角函数
Math.asin(x) / Math.acos(x) / Math.atan(x) 反三角函数

Date 对象

Date 用于处理日期和时间。

创建 Date 对象

// 当前时间
let now = new Date();
console.log(now);  // 当前日期时间字符串

// 指定时间
let date1 = new Date('2024-01-15');           // 字符串
let date2 = new Date(2024, 0, 15);           // 年, 月(0-11), 日
let date3 = new Date(2024, 0, 15, 10, 30, 0); // 年,月,日,时,分,秒
let date4 = new Date(1705315200000);           // 时间戳(毫秒)

// 注意:月份是从 0 开始的!0=一月,11=十二月
console.log(new Date(2024, 0, 1).getMonth());  // 0(一月)

获取日期部分

let date = new Date('2024-05-15T10:30:45');

console.log(date.getFullYear());  // 2024(年)
console.log(date.getMonth());    // 4(月,0-11,所以是五月)
console.log(date.getDate());    // 15(日,1-31)
console.log(date.getDay());     // 3(星期几,0=周日,1=周一...)
console.log(date.getHours());   // 10(时,0-23)
console.log(date.getMinutes()); // 30(分,0-59)
console.log(date.getSeconds()); // 45(秒,0-59)
console.log(date.getMilliseconds()); // 0(毫秒,0-999)

// 获取时间戳(自 1970-01-01 00:00:00 UTC 以来的毫秒数)
console.log(date.getTime());    // 1715736645000
console.log(Date.now());       // 当前时间戳(静态方法)

设置日期部分

let date = new Date();

date.setFullYear(2025);
date.setMonth(11);     // 12月(0-11)
date.setDate(25);
date.setHours(12);
date.setMinutes(0);
date.setSeconds(0);

console.log(date);

格式化输出

let date = new Date('2024-05-15');

// 转为字符串
console.log(date.toString());    // "Wed May 15 2024 ..."
console.log(date.toDateString());  // "Wed May 15 2024"
console.log(date.toTimeString());  // "00:00:00 GMT+..."
console.log(date.toISOString());   // "2024-05-15T00:00:00.000Z"

// 本地化格式
console.log(date.toLocaleDateString('zh-CN'));  // "2024/5/15"
console.log(date.toLocaleString('zh-CN'));     // "2024/5/15 08:00:00"

日期计算

// 计算时间差
let start = new Date('2024-01-01');
let end = new Date('2024-12-31');
let diffMs = end - start;  // 日期相减得到毫秒数
let diffDays = diffMs / (1000 * 60 * 60 * 24);
console.log(diffDays);  // 364(或 365,取决于闰年)

// 增加天数
let tomorrow = new Date();
tomorrow.setDate(tomorrow.getDate() + 1);
console.log(tomorrow);

// 计算年龄
function getAge(birthDate) {
  let today = new Date();
  let birth = new Date(birthDate);
  let age = today.getFullYear() - birth.getFullYear();
  let monthDiff = today.getMonth() - birth.getMonth();
  if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birth.getDate())) {
    age--;
  }
  return age;
}
console.log(getAge('1990-05-15'));

Date 静态方法

console.log(Date.now());              // 当前时间戳
console.log(Date.parse('2024-01-15')); // 解析字符串为时间戳
console.log(Date.UTC(2024, 0, 15));  // UTC 时间戳

RegExp 对象

正则表达式用于匹配字符串模式。

创建正则表达式

// 字面量方式(推荐)
let regex1 = /ab+c/;
let regex2 = /\d+/g;

// 构造函数方式(动态创建)
let pattern = 'ab+c';
let regex3 = new RegExp(pattern, 'g');

正则方法

let str = 'Hello 123 World 456';

// test() — 测试是否匹配
console.log(/\d+/.test(str));     // true(包含数字)
console.log(/^[a-z]+$/i.test('Hello'));  // true(仅字母)

// exec() — 执行匹配,返回匹配结果或 null
let match = /\d+/.exec(str);
console.log(match[0]);  // "123"
console.log(match.index); // 6(匹配位置)
console.log(match.input); // "Hello 123 World 456"

// 全局匹配时,exec 会记录 lastIndex
let regex = /\d+/g;
console.log(regex.exec(str));  // ["123", index: 6, ...]
console.log(regex.exec(str));  // ["456", index: 16, ...]
console.log(regex.exec(str));  // null

// 重置 lastIndex
regex.lastIndex = 0;

字符串中的正则方法(回顾)

let str = 'Hello 123 World 456';

console.log(str.match(/\d+/g));     // ["123", "456"]
console.log(str.replace(/\d+/g, '#')); // "Hello # World #"
console.log(str.search(/\d+/));      // 6(首次匹配位置)
console.log(str.split(/\s+/));       // ["Hello", "123", "World", "456"]

常用正则模式

// 数字
console.log(/^\d+$/.test('123'));      // true
console.log(/^\d+$/.test('12a3'));   // false

// 邮箱(简化版)
let emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
console.log(emailRegex.test('[email protected]'));  // true

// 手机号(中国大陆,简化版)
let phoneRegex = /^1[3-9]\d{9}$/;
console.log(phoneRegex.test('13812345678'));  // true

// 中文字符
let chineseRegex = /[一-龥]+/;
console.log(chineseRegex.test('你好'));  // true

JSON 对象

JSON 对象用于处理 JavaScript 对象表示法(JSON)数据。

JSON.parse() — 解析 JSON 字符串

let jsonStr = '{"name":"Alice","age":25,"city":"Beijing"}';
let obj = JSON.parse(jsonStr);
console.log(obj.name);  // "Alice"
console.log(obj.age);   // 25

// 第二个参数:reviver 函数(转换值)
let json = '{"date":"2024-01-15T00:00:00.000Z"}';
let data = JSON.parse(json, (key, value) => {
  if (key === 'date') return new Date(value);
  return value;
});
console.log(data.date instanceof Date);  // true

// 无效 JSON 会抛出错误
try {
  JSON.parse('{invalid json}');
} catch (e) {
  console.log('JSON 解析失败:', e.message);
}

JSON.stringify() — 转为 JSON 字符串

let obj = {
  name: 'Alice',
  age: 25,
  city: 'Beijing',
  greet: function() { console.log('hello'); }  // 函数不会被序列化
};

let jsonStr = JSON.stringify(obj);
console.log(jsonStr);  // "{"name":"Alice","age":25,"city":"Beijing"}"
// 注意:函数、undefined、Symbol 会被忽略

// 第二个参数:replacer(过滤或转换)
let filtered = JSON.stringify(obj, ['name', 'age']);  // 只序列化指定属性
console.log(filtered);  // "{"name":"Alice","age":25}"

// 使用函数转换值
let withTypes = JSON.stringify(obj, (key, value) => {
  if (typeof value === 'string') return undefined;  // 排除字符串
  return value;
});
console.log(withTypes);

// 第三个参数:space(格式化缩进)
let pretty = JSON.stringify(obj, null, 2);  // 2 空格缩进
console.log(pretty);
// {
//   "name": "Alice",
//   "age": 25,
//   "city": "Beijing"
// }

JSON 方法速查

方法 说明
JSON.parse(text, reviver?) 解析 JSON 字符串为 JS 值
JSON.stringify(value, replacer?, space?) 将 JS 值转为 JSON 字符串

Map 对象(ES6)

Map 是键值对的集合,键可以是任意类型(对象、函数等)。

基本用法

// 创建 Map
let map = new Map();

// 设置值
map.set('name', 'Alice');
map.set(123, '数字键');
map.set(true, '布尔键');
map.set({ id: 1 }, '对象键');

// 获取值
console.log(map.get('name'));  // "Alice"
console.log(map.get(123));     // "数字键"

// 检查键是否存在
console.log(map.has('name'));  // true
console.log(map.has('age'));   // false

// 删除
map.delete('name');
console.log(map.has('name'));  // false

// 大小
console.log(map.size);  // 3

// 清空
// map.clear();

使用数组初始化

let map = new Map([
  ['name', 'Alice'],
  ['age', 25],
  ['city', 'Beijing']
]);

console.log(map.get('name'));  // "Alice"

遍历 Map

let map = new Map([
  ['a', 1],
  ['b', 2],
  ['c', 3]
]);

// for...of 遍历
for (let [key, value] of map) {
  console.log(key, value);
}

// forEach 遍历
map.forEach((value, key) => {
  console.log(key, value);
});

// 只遍历键
for (let key of map.keys()) {
  console.log(key);
}

// 只遍历值
for (let value of map.values()) {
  console.log(value);
}

// 转为数组
console.log([...map.keys()]);   // ["a", "b", "c"]
console.log([...map.values()]); // [1, 2, 3]
console.log([...map.entries()]); // [["a",1], ["b",2], ["c",3]]

Map vs Object

特性 Map Object
键的类型 任意类型 String 或 Symbol
大小 size 属性 需手动计算
迭代 可直接迭代 需转换
性能 频繁增删时更好 适合简单场景
默认键 有原型链上的键

Set 对象(ES6)

Set 是值的集合,每个值只出现一次(唯一性)。

基本用法

// 创建 Set
let set = new Set([1, 2, 2, 3, 3, 4]);
console.log(set);  // Set { 1, 2, 3, 4 }(自动去重)

// 添加值
set.add(5);
console.log(set.has(3));  // true
console.log(set.has(6));  // false

// 删除值
set.delete(1);
console.log(set.size);  // 4

// 清空
// set.clear();

// 遍历
for (let value of set) {
  console.log(value);
}

set.forEach(value => console.log(value));

数组去重

// 使用 Set 去重
let arr = [1, 2, 2, 3, 3, 3, 4, 5, 5];
let unique = [...new Set(arr)];
console.log(unique);  // [1, 2, 3, 4, 5]

// 或使用 Array.from
let unique2 = Array.from(new Set(arr));
console.log(unique2);  // [1, 2, 3, 4, 5]

Set 运算

let setA = new Set([1, 2, 3, 4]);
let setB = new Set([3, 4, 5, 6]);

// 并集
let union = new Set([...setA, ...setB]);
console.log(union);  // Set { 1, 2, 3, 4, 5, 6 }

// 交集
let intersection = new Set([...setA].filter(x => setB.has(x)));
console.log(intersection);  // Set { 3, 4 }

// 差集(A - B)
let difference = new Set([...setA].filter(x => !setB.has(x)));
console.log(difference);  // Set { 1, 2 }

WeakMap 和 WeakSet(ES6)

WeakMap

WeakMap 的键必须是对象,且是"弱引用"(不阻止垃圾回收)。

let weakMap = new WeakMap();
let obj = { name: 'Alice' };

weakMap.set(obj, '一些数据');
console.log(weakMap.get(obj));  // "一些数据"

// weakMap.set('string', 'value');  // 报错:键必须是对象

// 没有 size 属性,不能迭代(弱引用的原因)
// console.log(weakMap.size);  // undefined
// for (let item of weakMap) {}  // 报错

WeakSet

WeakSet 只能存储对象,且是弱引用。

let weakSet = new WeakSet();
let obj1 = { id: 1 };
let obj2 = { id: 2 };

weakSet.add(obj1);
weakSet.add(obj2);
console.log(weakSet.has(obj1));  // true

// weakSet.add(123);  // 报错:只能添加对象

WeakMap/WeakSet 的使用场景

// 使用 WeakMap 存储私有数据
let privateData = new WeakMap();

function User(name) {
  let data = { name };
  privateData.set(this, data);
}

User.prototype.getName = function() {
  return privateData.get(this).name;
};

let user = new User('Alice');
console.log(user.getName());  // "Alice"
// 当 user 被垃圾回收时,privateData 中的对应数据也会被回收

Symbol(ES6)

Symbol 是唯一的、不可变的值,通常用作对象属性的键。

创建 Symbol

// 创建 Symbol(可选描述符)
let sym1 = Symbol();
let sym2 = Symbol('description');
let sym3 = Symbol('description');

console.log(sym1 === sym2);  // false(每个 Symbol 都是唯一的)
console.log(sym2 === sym3);  // false(即使是相同描述符)

// Symbol.for() — 全局 Symbol 注册表
let sym4 = Symbol.for('app.id');
let sym5 = Symbol.for('app.id');
console.log(sym4 === sym5);  // true(从注册表获取)

// Symbol.keyFor() — 获取全局 Symbol 的键
console.log(Symbol.keyFor(sym4));  // "app.id"

使用 Symbol 作为属性键

let id = Symbol('id');

let user = {
  name: 'Alice',
  [id]: 12345  // Symbol 作为键
};

console.log(user[id]);  // 12345
console.log(Object.keys(user));  // ["name"](Symbol 键不会被遍历)

// Symbol 不会被 for...in、Object.keys() 等遍历到
// 获取 Symbol 键:Object.getOwnPropertySymbols()
console.log(Object.getOwnPropertySymbols(user));  // [Symbol(id)]

内置 Symbol

JavaScript 内置了一些 Symbol,用于自定义对象行为:

// Symbol.iterator — 定义迭代器
let obj = {
  data: [1, 2, 3],
  [Symbol.iterator]() {
    let index = 0;
    return {
      next: () => {
        if (index < this.data.length) {
          return { value: this.data[index++], done: false };
        }
        return { done: true };
      }
    };
  }
};

for (let value of obj) {
  console.log(value);  // 1 2 3
}

// 其他内置 Symbol(了解即可)
// Symbol.toPrimitive — 对象转原始值
// Symbol.toStringTag — Object.prototype.toString 的标签
// Symbol.hasInstance — instanceof 操作符的行为

BigInt(ES2020)

BigInt 用于表示任意精度的整数,解决 Number 精度限制问题。

创建 BigInt

// 方式1:在数字后加 n
let big1 = 12345678901234567890n;
console.log(big1);  // 12345678901234567890n

// 方式2:使用 BigInt() 函数
let big2 = BigInt(123);
let big3 = BigInt('456');
console.log(big2);  // 123n
console.log(big3);  // 456n

// 注意:BigInt 和 Number 不可以直接混合运算
// console.log(big1 + 123);  // TypeError
console.log(big1 + BigInt(123));  // 12345678901234568013n

BigInt 运算

let a = 10n;
let b = 3n;

console.log(a + b);  // 13n
console.log(a - b);  // 7n
console.log(a * b);  // 30n
console.log(a / b);  // 3n(整数除法,没有小数!)
console.log(a % b);  // 1n
console.log(a ** 3n); // 1000n

// 比较(可以和 Number 比较)
console.log(10n === 10);   // false(类型不同)
console.log(10n == 10);    // true(宽松相等会转换)
console.log(10n > 5);      // true

Number 的精度限制

// Number 的最大安全整数
console.log(Number.MAX_SAFE_INTEGER);  // 9007199254740991
console.log(Number.MAX_SAFE_INTEGER + 1 === Number.MAX_SAFE_INTEGER + 2);  // true(精度丢失!)

// BigInt 没有这个限制
let big = BigInt(Number.MAX_SAFE_INTEGER);
console.log(big + 1n === big + 2n);  // false(正确)

Promise 对象(ES6)

Promise 用于处理异步操作。

创建 Promise

let promise = new Promise((resolve, reject) => {
  // 异步操作
  setTimeout(() => {
    let success = true;
    if (success) {
      resolve('操作成功');  // 兑现(fulfilled)
    } else {
      reject(new Error('操作失败'));  // 拒绝(rejected)
    }
  }, 1000);
});

promise
  .then(result => console.log('成功:', result))
  .catch(error => console.log('失败:', error.message));

Promise 静态方法

// Promise.resolve() — 创建已兑现的 Promise
Promise.resolve('done').then(console.log);  // "done"

// Promise.reject() — 创建已拒绝的 Promise
Promise.reject(new Error('fail')).catch(console.error);

// Promise.all() — 所有 Promise 都成功时才成功
let p1 = Promise.resolve(1);
let p2 = Promise.resolve(2);
let p3 = Promise.resolve(3);
Promise.all([p1, p2, p3]).then(values => console.log(values));  // [1, 2, 3]

// Promise.allSettled() — 等待所有 Promise 完成(无论成功失败)
Promise.allSettled([p1, Promise.reject('error')]).then(results => {
  console.log(results);
  // [{status: "fulfilled", value: 1}, {status: "rejected", reason: "error"}]
});

// Promise.race() — 返回最先完成的 Promise(无论成功失败)
Promise.race([
  new Promise((resolve) => setTimeout(() => resolve('fast'), 100)),
  new Promise((resolve) => setTimeout(() => resolve('slow'), 500))
]).then(console.log);  // "fast"

// Promise.any() — 返回最先成功的 Promise(ES2021)
Promise.any([
  Promise.reject('error1'),
  Promise.resolve('success'),
  Promise.reject('error2')
]).then(console.log);  // "success"

async/await(ES2017)

// async 函数返回 Promise
async function fetchData() {
  // await 等待 Promise
  let result = await new Promise(resolve => {
    setTimeout(() => resolve('data'), 1000);
  });
  return result;
}

fetchData().then(console.log);  // "data"(1秒后)

注意:Promise 和 async/await 是异步编程的核心,这里仅作简要介绍。


Proxy 和 Reflect(ES6)

Proxy — 创建对象的代理,拦截操作

let target = { name: 'Alice', age: 25 };

let proxy = new Proxy(target, {
  // 拦截属性读取
  get(target, prop, receiver) {
    console.log(`读取属性: ${prop}`);
    return Reflect.get(target, prop, receiver);
  },
  // 拦截属性设置
  set(target, prop, value, receiver) {
    console.log(`设置属性: ${prop} = ${value}`);
    return Reflect.set(target, prop, value, receiver);
  },
  // 拦截属性删除
  deleteProperty(target, prop) {
    console.log(`删除属性: ${prop}`);
    return Reflect.deleteProperty(target, prop);
  }
});

proxy.name;          // 输出:读取属性: name
proxy.age = 26;     // 输出:设置属性: age = 26
delete proxy.age;    // 输出:删除属性: age

实用示例:属性验证

function createValidatedObject(obj, validators) {
  return new Proxy(obj, {
    set(target, prop, value) {
      if (validators[prop]) {
        let error = validators[prop](value);
        if (error) {
          console.log(`验证失败 [${prop}]: ${error}`);
          return false;
        }
      }
      target[prop] = value;
      return true;
    }
  });
}

let user = createValidatedObject({}, {
  age: (value) => value < 0 ? '年龄不能为负数' : null,
  name: (value) => value.length < 2 ? '姓名至少2个字符' : null
});

user.name = 'A';  // 验证失败 [name]: 姓名至少2个字符
user.name = 'Alice';  // 设置成功
user.age = -5;     // 验证失败 [age]: 年龄不能为负数
user.age = 25;     // 设置成功

Reflect — 提供操作对象的反射 API

let obj = { name: 'Alice' };

// Reflect 的方法与 Proxy 的处理器方法一一对应
console.log(Reflect.get(obj, 'name'));  // "Alice"
console.log(Reflect.has(obj, 'name')); // true(相当于 'name' in obj)
console.log(Reflect.deleteProperty(obj, 'name')); // true
console.log(Reflect.ownKeys(obj));  // ["name"]

Proxy 可拦截的操作

拦截器 触发操作
get 读取属性
set 设置属性
has in 操作符
deleteProperty delete 操作符
ownKeys Object.keys()Object.getOwnPropertyNames()
getPrototypeOf Object.getPrototypeOf()
setPrototypeOf Object.setPrototypeOf()
isExtensible Object.isExtensible()
preventExtensions Object.preventExtensions()
getOwnPropertyDescriptor Object.getOwnPropertyDescriptor()
defineProperty Object.defineProperty()
apply 函数调用
construct new 操作符

其他内置对象(简要)

Intl — 国际化(ES6)

// 数字格式化
let number = 1234567.89;
console.log(new Intl.NumberFormat('zh-CN').format(number));  // "1,234,567.89"

// 日期格式化
let date = new Date();
console.log(new Intl.DateTimeFormat('zh-CN').format(date));  // "2024/5/15"

// 字符串比较(排序)
let items = ['中', '文', '排', '序'];
items.sort(new Intl.Collator('zh-CN').compare);
console.log(items);  // ["排", "序", "文", "中"](按拼音排序)

WeakRef(ES2021)

// WeakRef 允许创建对对象的弱引用(高级特性,了解即可)
let obj = { data: 'hello' };
let weakRef = new WeakRef(obj);

console.log(weakRef.deref());  // { data: 'hello' }(如果对象还在)
// 如果 obj 被垃圾回收,weakRef.deref() 返回 undefined

FinalizationRegistry(ES2021)

// 对象被垃圾回收时收到通知(高级特性,了解即可)
let registry = new FinalizationRegistry((heldValue) => {
  console.log(`对象 ${heldValue} 被回收了`);
});

let obj = { id: 1 };
registry.register(obj, 'id=1');
// 当 obj 被回收时,会打印 "对象 id=1 被回收了"

内置对象速查总表

对象 类别 说明 详见
Object 基础 所有对象的基础 js-data-types.md
Function 函数 函数构造器和原型 js-function.md
Array 数据结构 数组 js-data-types.md
String 基础类型包装 字符串 js-data-types.md
Number 基础类型包装 数字 js-data-types.md
Boolean 基础类型包装 布尔值 js-data-types.md
Math 数学 数学常数和函数 本文
Date 日期时间 日期和时间处理 本文
RegExp 文本处理 正则表达式 本文
JSON 数据格式 JSON 解析和序列化 本文
Map 数据结构(ES6) 键值对集合 本文
Set 数据结构(ES6) 唯一值集合 本文
WeakMap 数据结构(ES6) 弱引用键值对 本文
WeakSet 数据结构(ES6) 弱引用集合 本文
Symbol 原始类型(ES6) 唯一标识符 本文
BigInt 原始类型(ES2020) 大整数 本文
Promise 异步(ES6) 异步操作 本文
Proxy 元编程(ES6) 对象代理 本文
Reflect 元编程(ES6) 反射 API 本文
Error 错误 错误对象及子类 js-exception.md
Intl 国际化(ES6) 国际化 API 本文
globalThis 全局(ES2020) 统一全局对象 本文

综合示例

示例 1:数据验证和格式化

function processUserData(jsonString) {
  try {
    // 解析 JSON
    let user = JSON.parse(jsonString);

    // 验证数据
    let errors = [];
    if (!user.name || user.name.trim() === '') {
      errors.push('姓名不能为空');
    }
    if (!Number.isInteger(user.age) || user.age < 0) {
      errors.push('年龄必须是非负整数');
    }

    if (errors.length > 0) {
      return { success: false, errors };
    }

    // 格式化输出
    return {
      success: true,
      data: {
        name: user.name.trim(),
        age: user.age,
        registeredAt: new Date().toISOString()
      }
    };
  } catch (e) {
    return { success: false, errors: ['JSON 解析失败: ' + e.message] };
  }
}

let result = processUserData('{"name":"Alice","age":25}');
console.log(JSON.stringify(result, null, 2));

示例 2:简单的事件系统(使用 Map)

class EventSystem {
  constructor() {
    this.events = new Map();
  }

  on(event, callback) {
    if (!this.events.has(event)) {
      this.events.set(event, []);
    }
    this.events.get(event).push(callback);
  }

  emit(event, data) {
    let callbacks = this.events.get(event);
    if (callbacks) {
      callbacks.forEach(cb => cb(data));
    }
  }

  off(event, callback) {
    let callbacks = this.events.get(event);
    if (callbacks) {
      this.events.set(event, callbacks.filter(cb => cb !== callback));
    }
  }
}

let bus = new EventSystem();
bus.on('message', data => console.log('收到:', data));
bus.emit('message', 'Hello!');  // 收到: Hello!

示例 3:使用 Proxy 实现数据绑定(简化版)

function createReactiveObject(obj, callback) {
  return new Proxy(obj, {
    set(target, prop, value) {
      let oldValue = target[prop];
      target[prop] = value;
      callback(prop, oldValue, value);
      return true;
    }
  });
}

let state = createReactiveObject({ count: 0 }, (prop, oldVal, newVal) => {
  console.log(`状态变化: ${prop} ${oldVal} → ${newVal}`);
});

state.count = 1;  // 状态变化: count 0 → 1
state.count = 2;  // 状态变化: count 1 → 2

示例 4:随机数和数学应用

// 生成随机颜色
function randomColor() {
  let r = Math.floor(Math.random() * 256);
  let g = Math.floor(Math.random() * 256);
  let b = Math.floor(Math.random() * 256);
  return `rgb(${r}, ${g}, ${b})`;
}
console.log(randomColor());  // 如 "rgb(123, 45, 67)"

// 计算两点距离
function distance(x1, y1, x2, y2) {
  return Math.hypot(x2 - x1, y2 - y1);
}
console.log(distance(0, 0, 3, 4));  // 5

// 角度转弧度 / 弧度转角度
function degToRad(deg) { return deg * Math.PI / 180; }
function radToDeg(rad) { return rad * 180 / Math.PI; }
console.log(degToRad(180));  // 3.141592653589793(π)

总结

类别 主要对象
全局函数 parseIntparseFloatisNaNisFiniteeval
数学 Math(floor、ceil、round、random、max、min 等)
日期时间 Date(get/set 方法、格式化)
正则 RegExp(test、exec)
JSON JSON.parseJSON.stringify
ES6 数据结构 MapSetWeakMapWeakSet
ES6 原始类型 SymbolBigInt
ES6 异步 Promise(all、race、allSettled、any)
ES6 元编程 ProxyReflect
国际化 Intl
全局对象 globalThis(ES2020)