Day01_ES6+ 专业指南:从基础到实战的现代JavaScript开发(下)

4.2.5 字符串方法的应用场景

场景一:数据验证

javascript 复制代码
// 【代码注释】Validator 组合 `includes`、`startsWith` 与 `RegExp.test`:注意 `includes` 不接受正则,密码强度需用 `/[A-Z]/.test()`。手机号先 `replaceAll` 去分隔符再匹配大陆 11 位规则。
class Validator {
    static isEmail(email) {
        const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
        return emailRegex.test(email) && email.includes('.') && email.includes('@');
    }
    
    static isPhoneNumber(phone) {
        const cleanPhone = phone.replaceAll(/[\s-()]/g, '');
        return /^1[3-9]\d{9}$/.test(cleanPhone);
    }
    
    static isIdNumber(id) {
        return /^\d{15}$|^\d{17}[\dXx]$/.test(id);
    }
    
    static isUrl(url) {
        return url.startsWith('http://') || 
               url.startsWith('https://') || 
               url.startsWith('ftp://');
    }
    
    static isStrongPassword(password) {
        if (password.length < 8) return false;
        if (!/[A-Z]/.test(password)) return false;  // includes() 不接受正则,必须用 RegExp.test()
        if (!/[a-z]/.test(password)) return false;
        if (!/[0-9]/.test(password)) return false;
        return true;
    }
}

// 使用示例
console.log(Validator.isEmail('test@example.com')); // true
console.log(Validator.isPhoneNumber('138 1234 5678')); // true

【代码注释】Validator 组合 includesstartsWithRegExp.test:注意 includes 不接受正则,密码强度需用 /[A-Z]/.test()。手机号先 replaceAll 去分隔符再匹配大陆 11 位规则。

场景二:文本处理

javascript 复制代码
// 【代码注释】静态方法封装 truncate/capitalize/camelCase/slug/highlightKeywords:展示字符串 API 组合成业务工具链。`highlightKeywords` 对用户关键词应转义再入 RegExp,防 ReDoS 与 XSS。
class TextProcessor {
    // 截断文本
    static truncate(text, maxLength, suffix = '...') {
        if (text.length <= maxLength) return text;
        return text.slice(0, maxLength - suffix.length) + suffix;
    }
    
    // 首字母大写
    static capitalize(text) {
        return text.charAt(0).toUpperCase() + text.slice(1).toLowerCase();
    }
    
    // 驼峰命名转换
    static toCamelCase(text) {
        return text
            .split(/[\s_-]+/)
            .map((word, index) => {
                if (index === 0) return word.toLowerCase();
                return this.capitalize(word);
            })
            .join('');
    }
    
    // 生成slug
    static generateSlug(text) {
        return text
            .toLowerCase()
            .trim()
            .replace(/[\s_]+/g, '-')
            .replace(/[^\w\-]+/g, '')
            .replace(/\-\-+/g, '-')
            .replace(/^-+/, '')
            .replace(/-+$/, '');
    }
    
    // 高亮关键词
    static highlightKeywords(text, keywords, className = 'highlight') {
        let result = text;
        
        keywords.forEach(keyword => {
            const regex = new RegExp(`(${keyword})`, 'gi');
            result = result.replace(regex, `<span class="${className}">$1</span>`);
        });
        
        return result;
    }
}

// 使用示例
console.log(TextProcessor.truncate('这是一段很长的文本,需要被截断', 10));
console.log(TextProcessor.toCamelCase('hello_world_example'));
console.log(TextProcessor.generateSlug('Hello World! This is a Test'));

【代码注释】静态方法封装 truncate/capitalize/camelCase/slug/highlightKeywords:展示字符串 API 组合成业务工具链。highlightKeywords 对用户关键词应转义再入 RegExp,防 ReDoS 与 XSS。

4.3 完整可运行示例:模板字符串与字符串方法

4.3.1 模板字符串:换行、插值与列表 DOM 渲染
html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>模板字符串演示</title>
</head>
<body>
  <ul id="box">
    <li><span>1</span><a href="#">占位</a></li>
  </ul>
  <script>
    // 【代码注释】反引号 `` 创建模板字符串,类型仍为 string
    const msg = `Hello World`;
    console.log(typeof msg, msg);

    // 【代码注释】多行文本:换行与缩进会原样保留,无需 \n 与 + 拼接
    const content = `
    锄禾日当午
    汗滴禾下土
    谁知盘中餐
    粒粒皆辛苦
    `;
    console.log(content);

    const name = '高小乐';
    const gender = '男';
    const hometown = '山西';
    const hobby = '醋';
    const money = 0.25;

    // 【代码注释】${} 内可为任意表达式(算术、变量引用等),先求值再转为字符串插入
    const message = `
    我的名字叫${name},
    性别${gender},
    我来自${hometown},
    我的业余爱好是${hobby},
    我会进行运算 ${money + 78 * 2}
    我学习后的期望薪资是 ${money} K;`;
    console.log(message);

    // 【代码注释】map + 模板字符串:列表渲染经典模式(注意 XSS:用户数据需转义)
    const data = ['刘姥姥', '马姥姥', '司马姥姥', '欧阳姥姥', '宇文姥姥'];
    const html = data.map(function (item, index) {
      return `
      <li>
        <span>${index + 1}</span>
        <a href="#">${item}</a>
      </li>`;
    }).join(''); // join('') 拼成无分隔符的 HTML 片段
    document.querySelector('#box').innerHTML = html;
  </script>
</body>
</html>

【代码注释】本页演示模板字符串三要素:多行保留换行 (古诗示例)、${} 表达式插值 (含算术 money + 78 * 2)、map 生成 HTML 列表join('') 拼片段后写 innerHTML)。注意:用户输入插入 DOM 前须转义防 XSS,或使用框架自动转义。与 Vue {``{ }}、React JSX { } 同属「数据驱动视图」思想,是 Day01 最接近真实业务的 HTML 实验页。

业界应用:

  • Vue{``{ message }} 与指令本质是模板引擎
  • React :JSX 中 {user.name}${} 同属插值思想
  • 邮件/日志 :多行模板 + 变量拼接,可读性远高于 + 连接
4.3.2 字符串实例方法:repeat、includes、pad、trim、replaceAll
html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>字符串新方法演示</title>
</head>
<body>
  <script>
    // 【代码注释】repeat(n):将字符串重复 n 次,n 须为非负整数
    console.log('高小乐'.repeat(10));

    const msg = 'Hello World';
    // 【代码注释】includes(search, fromIndex?):返回 boolean;第二参数为起始搜索下标
    console.log(msg.includes('l'), msg.includes('World'), msg.includes('H', 5));

    // 【代码注释】startsWith:判前缀;第二参数为开始匹配的位置
    console.log(msg.startsWith('Hello'), msg.startsWith('Hello', 1));
    // 【代码注释】endsWith:判后缀;第二参数为「结束位置」前的子串
    console.log(msg.endsWith('d'), msg.endsWith('d', 5));

    // 【代码注释】padStart/padEnd:填充到目标长度,常用于补零、对齐
    console.log(msg.padStart(20), msg.padStart(20, '@'));
    console.log(msg.padEnd(30), msg.padEnd(30, '0'));

    const content = '    Hello World             ';
    // 【代码注释】trim 系列:去除 Unicode 空白;不改变原串,返回新串
    console.log(`#${content}#`, `#${content.trim()}#`);
    console.log(`#${content.trimStart()}#`, `#${content.trimEnd()}#`);

    // 【代码注释】replace 只换首个;replaceAll(ES2021)全局替换
    console.log(content.replace('l', 'L'));
    console.log(content.replaceAll('l', 'L'));
  </script>
</body>
</html>

【代码注释】本页逐行演示 ES6+ 字符串实例方法:repeat 生成分隔线;includes/startsWith/endsWith 做路由、扩展名、关键字检测;padStart 左补零(订单号);trim* 表单清洗;replace vs replaceAll 区分「首个」与「全部」。注意:所有方法均 不修改原字符串 ,返回新串;includes 区分大小写,忽略大小写需先 toLowerCase()

方法 返回值 经典场景
repeat(n) 新字符串 生成分隔线、占位块
includes/search, pos?) boolean 搜索框过滤、权限关键字检测
startsWith/endsWith boolean URL/路由前缀、文件扩展名
padStart/padEnd 新字符串 账单编号、控制台对齐
trim/trimStart/trimEnd 新字符串 表单校验前清洗空格
replaceAll 新字符串 批量替换敏感词、模板占位符

5. 数值新增特性:更精确的数字计算

5.1 新增的二进制和八进制表示方式

5.1.1 新的数值字面量语法

名词解析:

  • 二进制字面量(Binary Literal):使用0b或0B前缀表示二进制数
  • 八进制字面量(Octal Literal):使用0o或0O前缀表示八进制数
  • 十六进制字面量(Hexadecimal Literal):使用0x或0X前缀表示十六进制数
javascript 复制代码
// 【代码注释】`0b`/`0B` 二进制、`0o`/`0O` 八进制字面量,避免 ES5 无前缀八进制 `012` 的歧义。权限位、颜色 `0xFF` 与位运算 `& | <<` 配合;`rgbToHex` 用移位拼 24 位色值。
// 二进制表示
const binary1 = 0b1010; // 10
const binary2 = 0B1111; // 15

// 八进制表示
const octal1 = 0o17; // 15
const octal2 = 0O10; // 8

// 十六进制表示(ES5就支持)
const hex1 = 0xFF; // 255
const hex2 = 0x10; // 16

console.log(binary1, binary2, octal1, octal2, hex1, hex2); // 10 15 15 8 255 16

// 实际应用:位操作
const permissions = 0b10101010; // 文件权限
const readPermission = 0b10000000;
const writePermission = 0b01000000;

const hasRead = (permissions & readPermission) !== 0;
const hasWrite = (permissions & writePermission) !== 0;

console.log('可读:', hasRead); // true
console.log('可写:', hasWrite); // true

// 颜色值处理
const colorRed = 0xFF0000; // 红色
const colorGreen = 0x00FF00; // 绿色
const colorBlue = 0x0000FF; // 蓝色

function rgbToHex(r, g, b) {
    return (r << 16) + (g << 8) + b;
}

const purple = rgbToHex(0xFF, 0x00, 0xFF); // 0xFF00FF
console.log(purple.toString(16)); // ff00ff

【代码注释】0b/0B 二进制、0o/0O 八进制字面量,避免 ES5 无前缀八进制 012 的歧义。权限位、颜色 0xFF 与位运算 & | << 配合;rgbToHex 用移位拼 24 位色值。

5.2 Number构造函数新增方法和属性

5.2.1 静态方法

#mermaid-svg-VH512DzB8zwmbaC0{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-VH512DzB8zwmbaC0 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-VH512DzB8zwmbaC0 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-VH512DzB8zwmbaC0 .error-icon{fill:#552222;}#mermaid-svg-VH512DzB8zwmbaC0 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-VH512DzB8zwmbaC0 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-VH512DzB8zwmbaC0 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-VH512DzB8zwmbaC0 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-VH512DzB8zwmbaC0 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-VH512DzB8zwmbaC0 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-VH512DzB8zwmbaC0 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-VH512DzB8zwmbaC0 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-VH512DzB8zwmbaC0 .marker.cross{stroke:#333333;}#mermaid-svg-VH512DzB8zwmbaC0 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-VH512DzB8zwmbaC0 p{margin:0;}#mermaid-svg-VH512DzB8zwmbaC0 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-VH512DzB8zwmbaC0 .cluster-label text{fill:#333;}#mermaid-svg-VH512DzB8zwmbaC0 .cluster-label span{color:#333;}#mermaid-svg-VH512DzB8zwmbaC0 .cluster-label span p{background-color:transparent;}#mermaid-svg-VH512DzB8zwmbaC0 .label text,#mermaid-svg-VH512DzB8zwmbaC0 span{fill:#333;color:#333;}#mermaid-svg-VH512DzB8zwmbaC0 .node rect,#mermaid-svg-VH512DzB8zwmbaC0 .node circle,#mermaid-svg-VH512DzB8zwmbaC0 .node ellipse,#mermaid-svg-VH512DzB8zwmbaC0 .node polygon,#mermaid-svg-VH512DzB8zwmbaC0 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-VH512DzB8zwmbaC0 .rough-node .label text,#mermaid-svg-VH512DzB8zwmbaC0 .node .label text,#mermaid-svg-VH512DzB8zwmbaC0 .image-shape .label,#mermaid-svg-VH512DzB8zwmbaC0 .icon-shape .label{text-anchor:middle;}#mermaid-svg-VH512DzB8zwmbaC0 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-VH512DzB8zwmbaC0 .rough-node .label,#mermaid-svg-VH512DzB8zwmbaC0 .node .label,#mermaid-svg-VH512DzB8zwmbaC0 .image-shape .label,#mermaid-svg-VH512DzB8zwmbaC0 .icon-shape .label{text-align:center;}#mermaid-svg-VH512DzB8zwmbaC0 .node.clickable{cursor:pointer;}#mermaid-svg-VH512DzB8zwmbaC0 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-VH512DzB8zwmbaC0 .arrowheadPath{fill:#333333;}#mermaid-svg-VH512DzB8zwmbaC0 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-VH512DzB8zwmbaC0 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-VH512DzB8zwmbaC0 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-VH512DzB8zwmbaC0 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-VH512DzB8zwmbaC0 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-VH512DzB8zwmbaC0 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-VH512DzB8zwmbaC0 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-VH512DzB8zwmbaC0 .cluster text{fill:#333;}#mermaid-svg-VH512DzB8zwmbaC0 .cluster span{color:#333;}#mermaid-svg-VH512DzB8zwmbaC0 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-VH512DzB8zwmbaC0 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-VH512DzB8zwmbaC0 rect.text{fill:none;stroke-width:0;}#mermaid-svg-VH512DzB8zwmbaC0 .icon-shape,#mermaid-svg-VH512DzB8zwmbaC0 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-VH512DzB8zwmbaC0 .icon-shape p,#mermaid-svg-VH512DzB8zwmbaC0 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-VH512DzB8zwmbaC0 .icon-shape .label rect,#mermaid-svg-VH512DzB8zwmbaC0 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-VH512DzB8zwmbaC0 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-VH512DzB8zwmbaC0 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-VH512DzB8zwmbaC0 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Number新增方法
类型检查
类型转换
Number.isFinite
Number.isNaN
Number.isInteger
Number.isSafeInteger
Number.parseFloat
Number.parseInt

【代码注释】Number 静态方法分为「类型检查」(isFinite/isNaN/isInteger 等)与「解析转换」(parseInt/parseFloat),比全局函数更严格、不隐式转型。

5.2.2 类型检查方法

方法一:Number.isFinite()

javascript 复制代码
// 【代码注释】`Number.isFinite` 仅对 **number 类型**且非 ±Infinity/NaN 为 true;`isFinite('100')` 会先 ToNumber 再判断。表单校验:`const n = Number(v); Number.isFinite(n)` 比全局 `isFinite` 更严。
console.log(Number.isFinite(100)); // true
console.log(Number.isFinite(100.5)); // true
console.log(Number.isFinite('100')); // false
console.log(Number.isFinite(Infinity)); // false
console.log(Number.isFinite(NaN)); // false

// 与全局isFinite()的区别
console.log(isFinite('100')); // true(会自动转换)
console.log(Number.isFinite('100')); // false(不转换)

// 实际应用:数值验证
function validateNumberInput(input) {
    if (!Number.isFinite(input)) {
        throw new Error('输入必须是有效的数字');
    }
    
    if (input < 0 || input > 100) {
        throw new Error('输入必须在0-100之间');
    }
    
    return input;
}

try {
    const result = validateNumberInput(50);
    console.log('有效输入:', result);
} catch (error) {
    console.error(error.message);
}

【代码注释】Number.isFinite 仅对 number 类型 且非 ±Infinity/NaN 为 true;isFinite('100') 会先 ToNumber 再判断。表单校验:const n = Number(v); Number.isFinite(n) 比全局 isFinite 更严。

方法二:Number.isNaN()

javascript 复制代码
// 【代码注释】仅 `Number.isNaN(NaN)` 为 true,`Number.isNaN('NaN')` 为 false;全局 `isNaN('NaN')` 为 true。判断运算结果是否无效时用 `Number.isNaN(result)`,不要用 `result === NaN`(恒 false)。
console.log(Number.isNaN(NaN)); // true
console.log(Number.isNaN('NaN')); // false
console.log(Number.isNaN(undefined)); // false

// 与全局isNaN()的区别
console.log(isNaN('NaN')); // true(会尝试转换)
console.log(Number.isNaN('NaN')); // false(严格检查)

// 实际应用:计算结果验证
function safeDivide(a, b) {
    const result = a / b;
    
    if (Number.isNaN(result)) {
        return { success: false, error: '计算结果无效' };
    }
    
    if (!Number.isFinite(result)) {
        return { success: false, error: '计算结果超出范围' };
    }
    
    return { success: true, result };
}

console.log(safeDivide(10, 2)); // { success: true, result: 5 }
console.log(safeDivide(10, 0)); // { success: false, error: '计算结果超出范围' }

【代码注释】仅 Number.isNaN(NaN) 为 true,Number.isNaN('NaN') 为 false;全局 isNaN('NaN') 为 true。判断运算结果是否无效时用 Number.isNaN(result),不要用 result === NaN(恒 false)。

方法三:Number.isInteger()

javascript 复制代码
// 【代码注释】`Number.isInteger` 要求值为 number 且小数部分为 0;`100.0` 为 true。数量、数组下标校验用;字符串 `"100"` 需先 `Number()` 再判。与 `parseInt` 不同,不解析字符串。
console.log(Number.isInteger(100)); // true
console.log(Number.isInteger(100.5)); // false
console.log(Number.isInteger('100')); // false

// 实际应用:整数验证
function processQuantity(quantity) {
    if (!Number.isInteger(quantity) || quantity < 1) {
        throw new Error('数量必须是正整数');
    }
    
    // 处理逻辑
    return `处理 ${quantity} 件商品`;
}

// 数组索引验证
function getArrayItem(arr, index) {
    if (!Number.isInteger(index) || index < 0) {
        throw new Error('索引必须是非负整数');
    }
    
    if (index >= arr.length) {
        throw new Error('索引超出范围');
    }
    
    return arr[index];
}

const fruits = ['苹果', '香蕉', '橙子'];
console.log(getArrayItem(fruits, 1)); // 香蕉

【代码注释】Number.isInteger 要求值为 number 且小数部分为 0;100.0 为 true。数量、数组下标校验用;字符串 "100" 需先 Number() 再判。与 parseInt 不同,不解析字符串。

方法四:Number.isSafeInteger()

javascript 复制代码
// 【代码注释】安全整数范围 ±(2^53−1);超出后 `a±1` 可能相等(精度丢失)。ID、计数器在 JSON/API 传递前用 `isSafeInteger`;更大整数用 BigInt。`safeAdd` 在运算后再检结果是否仍安全。
console.log(Number.isSafeInteger(100)); // true
console.log(Number.isSafeInteger(Math.pow(2, 53) - 1)); // true
console.log(Number.isSafeInteger(Math.pow(2, 53))); // false

// 安全整数范围:-(2^53 - 1) 到 2^53 - 1
const MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER; // 9007199254740991
const MIN_SAFE_INTEGER = Number.MIN_SAFE_INTEGER; // -9007199254740991

// 实际应用:精确计算验证
function safeAdd(a, b) {
    if (!Number.isSafeInteger(a) || !Number.isSafeInteger(b)) {
        throw new Error('操作数超出安全整数范围');
    }
    
    const result = a + b;
    if (!Number.isSafeInteger(result)) {
        throw new Error('计算结果超出安全整数范围');
    }
    
    return result;
}

// ID验证
function validateUserId(id) {
    if (!Number.isSafeInteger(id) || id < 1) {
        return { valid: false, error: '无效的用户ID' };
    }
    return { valid: true };
}

【代码注释】安全整数范围 ±(2^53−1);超出后 a±1 可能相等(精度丢失)。ID、计数器在 JSON/API 传递前用 isSafeInteger;更大整数用 BigInt。safeAdd 在运算后再检结果是否仍安全。

5.2.2.1 Number.EPSILON 与浮点精度陷阱

理论背景:IEEE 754 双精度浮点数

JavaScript 的 Number 类型基于 IEEE 754 双精度浮点数(64位) ,用二进制近似表示十进制小数,导致某些小数运算结果不精确。Number.EPSILON(ES6)是可表示的最小误差精度(约 2.22e-16),用于安全比较浮点数。

javascript 复制代码
// 【代码注释】IEEE 754 双精度无法精确表示部分十进制小数,运算会产生舍入误差
console.log(0.1 + 0.2);          // 0.30000000000000004(肉眼期望 0.3,实际略大)
console.log(0.1 + 0.2 === 0.3);  // false ------ 禁止用 === 直接比较金额/坐标等浮点结果

// 【代码注释】Number.EPSILON ≈ 2.22e-16:相邻两个可区分浮点数的最小间距,用作默认容差
console.log(Number.EPSILON);     // 2.220446049250313e-16

// 【代码注释】floatEqual:|a-b| < epsilon 视为相等;业务可按精度改用 1e-9、0.001 等
function floatEqual(a, b, epsilon = Number.EPSILON) {
    return Math.abs(a - b) < epsilon;
}

console.log(floatEqual(0.1 + 0.2, 0.3)); // true ✅

// 【代码注释】价格比较:按业务约定小数位设容差(此处 1e-9 适合「元」级两位小数场景)
function priceEqual(priceA, priceB) {
    return Math.abs(priceA - priceB) < 1e-9;
}

console.log(priceEqual(19.99 * 3, 59.97)); // true(直接 === 可能为 false)

// 【代码注释】方案一「转分运算」:先乘 100 取整到分,整数相加再除回元------收银、订单合计首选
function addMoney(a, b) {
    const factor = 100;
    return (Math.round(a * factor) + Math.round(b * factor)) / factor;
}
console.log(addMoney(0.1, 0.2)); // 0.3 ✅

// 【代码注释】方案二 toFixed:仅用于展示,返回字符串,参与运算前需 Number()
console.log((0.1 + 0.2).toFixed(1)); // "0.3"

// 【代码注释】方案三 BigInt:以「分」为单位存 BigInt,避免 number 超过 2^53 或浮点误差(见 5.5 节)
const price1 = BigInt(Math.round(0.1 * 100)); // 10n
const price2 = BigInt(Math.round(0.2 * 100)); // 20n
console.log(Number(price1 + price2) / 100);   // 0.3 ✅

// 【代码注释】Number 静态常量:边界判断、除零、无效运算时使用
console.log(Number.MAX_VALUE);         // 约 1.8e+308
console.log(Number.MIN_VALUE);         // 最小正数(非最小负数)
console.log(Number.POSITIVE_INFINITY); // 1/0 等
console.log(Number.NEGATIVE_INFINITY);
console.log(Number.NaN);               // 0/0、无效 parse;NaN !== NaN

【代码注释】0.1 + 0.2 !== 0.3 源于 IEEE 754 二进制浮点 的表示限制,不是引擎 Bug。生产实践:比较Math.abs(a-b) < 容差Number.EPSILON金额 用「转分整数」或 BigInt展示toFixed/Intl.NumberFormat,勿把 toFixed 结果再当 number 精确运算。与 Number.isFinite/isNaN 配合可过滤 Infinity/NaN 污染。

5.2.3 类型转换方法

方法:Number.parseInt()和Number.parseFloat()

javascript 复制代码
// 【代码注释】`Number.parseInt`/`parseFloat` 与全局同名函数相同,便于 `import { parseInt } from 'number-polyfill'` 式模块化。`parseInt('100px')` 从左解析;`0x` 前缀识别十六进制。不要用它代替严格的 `Number()` 校验。
console.log(Number.parseInt('123')); // 123
console.log(Number.parseFloat('123.45')); // 123.45
console.log(Number.parseInt('123px')); // 123
console.log(Number.parseFloat('123.45px')); // 123.45

// 与全局方法相同
console.log(Number.parseInt === parseInt); // true
console.log(Number.parseFloat === parseFloat); // true

// 实际应用:解析CSS值
function parseCssValue(value) {
    const number = parseFloat(value);
    const unit = value.slice(String(number).length);
    
    return { number, unit };
}

console.log(parseCssValue('100px')); // { number: 100, unit: 'px' }
console.log(parseCssValue('1.5em')); // { number: 1.5, unit: 'em' }

// 解析文件大小
function parseFileSize(size) {
    const number = parseFloat(size);
    const unit = size.slice(String(number).length).toUpperCase();
    
    const multipliers = {
        'B': 1,
        'KB': 1024,
        'MB': 1024 * 1024,
        'GB': 1024 * 1024 * 1024
    };
    
    return number * (multipliers[unit] || 1);
}

console.log(parseFileSize('100KB')); // 102400
console.log(parseFileSize('1.5MB')); // 1572864

【代码注释】Number.parseInt/parseFloat 与全局同名函数相同,便于 import { parseInt } from 'number-polyfill' 式模块化。parseInt('100px') 从左解析;0x 前缀识别十六进制。不要用它代替严格的 Number() 校验。

5.3 Math新增方法

5.3.1 Math对象扩展概览

#mermaid-svg-0YPuLdftpp1TSM9C{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-0YPuLdftpp1TSM9C .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-0YPuLdftpp1TSM9C .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-0YPuLdftpp1TSM9C .error-icon{fill:#552222;}#mermaid-svg-0YPuLdftpp1TSM9C .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-0YPuLdftpp1TSM9C .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-0YPuLdftpp1TSM9C .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-0YPuLdftpp1TSM9C .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-0YPuLdftpp1TSM9C .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-0YPuLdftpp1TSM9C .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-0YPuLdftpp1TSM9C .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-0YPuLdftpp1TSM9C .marker{fill:#333333;stroke:#333333;}#mermaid-svg-0YPuLdftpp1TSM9C .marker.cross{stroke:#333333;}#mermaid-svg-0YPuLdftpp1TSM9C svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-0YPuLdftpp1TSM9C p{margin:0;}#mermaid-svg-0YPuLdftpp1TSM9C .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-0YPuLdftpp1TSM9C .cluster-label text{fill:#333;}#mermaid-svg-0YPuLdftpp1TSM9C .cluster-label span{color:#333;}#mermaid-svg-0YPuLdftpp1TSM9C .cluster-label span p{background-color:transparent;}#mermaid-svg-0YPuLdftpp1TSM9C .label text,#mermaid-svg-0YPuLdftpp1TSM9C span{fill:#333;color:#333;}#mermaid-svg-0YPuLdftpp1TSM9C .node rect,#mermaid-svg-0YPuLdftpp1TSM9C .node circle,#mermaid-svg-0YPuLdftpp1TSM9C .node ellipse,#mermaid-svg-0YPuLdftpp1TSM9C .node polygon,#mermaid-svg-0YPuLdftpp1TSM9C .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-0YPuLdftpp1TSM9C .rough-node .label text,#mermaid-svg-0YPuLdftpp1TSM9C .node .label text,#mermaid-svg-0YPuLdftpp1TSM9C .image-shape .label,#mermaid-svg-0YPuLdftpp1TSM9C .icon-shape .label{text-anchor:middle;}#mermaid-svg-0YPuLdftpp1TSM9C .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-0YPuLdftpp1TSM9C .rough-node .label,#mermaid-svg-0YPuLdftpp1TSM9C .node .label,#mermaid-svg-0YPuLdftpp1TSM9C .image-shape .label,#mermaid-svg-0YPuLdftpp1TSM9C .icon-shape .label{text-align:center;}#mermaid-svg-0YPuLdftpp1TSM9C .node.clickable{cursor:pointer;}#mermaid-svg-0YPuLdftpp1TSM9C .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-0YPuLdftpp1TSM9C .arrowheadPath{fill:#333333;}#mermaid-svg-0YPuLdftpp1TSM9C .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-0YPuLdftpp1TSM9C .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-0YPuLdftpp1TSM9C .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-0YPuLdftpp1TSM9C .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-0YPuLdftpp1TSM9C .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-0YPuLdftpp1TSM9C .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-0YPuLdftpp1TSM9C .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-0YPuLdftpp1TSM9C .cluster text{fill:#333;}#mermaid-svg-0YPuLdftpp1TSM9C .cluster span{color:#333;}#mermaid-svg-0YPuLdftpp1TSM9C div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-0YPuLdftpp1TSM9C .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-0YPuLdftpp1TSM9C rect.text{fill:none;stroke-width:0;}#mermaid-svg-0YPuLdftpp1TSM9C .icon-shape,#mermaid-svg-0YPuLdftpp1TSM9C .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-0YPuLdftpp1TSM9C .icon-shape p,#mermaid-svg-0YPuLdftpp1TSM9C .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-0YPuLdftpp1TSM9C .icon-shape .label rect,#mermaid-svg-0YPuLdftpp1TSM9C .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-0YPuLdftpp1TSM9C .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-0YPuLdftpp1TSM9C .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-0YPuLdftpp1TSM9C :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Math新增方法
数值处理
数学运算
trunc
sign
cbrt
对数函数
双曲函数
位运算

【代码注释】Math 新增方法覆盖取整(trunc)、符号(sign)、立方根(cbrt)等,常与位运算、科学计算、图形坐标处理配合使用。

5.3.2 常用Math方法详解

方法一:Math.trunc()

javascript 复制代码
// 【代码注释】`Math.trunc` 向零截断,`-3.7` → `-3`;`Math.floor` 向负无穷。正数时 trunc 与 floor 同,负数不同。展示整数部分、分页计算用 trunc 更贴近「去掉小数」语义。
console.log(Math.trunc(4.9)); // 4
console.log(Math.trunc(-4.9)); // -4
console.log(Math.trunc(0.123)); // 0

// 与其他方法的区别
console.log(Math.floor(4.9)); // 4(向下取整)
console.log(Math.ceil(4.1)); // 5(向上取整)
console.log(Math.round(4.5)); // 5(四舍五入)

// 实际应用:处理价格
function calculateDiscount(price, discountPercent) {
    const discount = price * (discountPercent / 100);
    const finalPrice = price - Math.trunc(discount * 100) / 100;
    return finalPrice;
}

console.log(calculateDiscount(99.99, 15)); // 86.99

【代码注释】Math.trunc 向零截断,-3.7-3Math.floor 向负无穷。正数时 trunc 与 floor 同,负数不同。展示整数部分、分页计算用 trunc 更贴近「去掉小数」语义。

方法二:Math.sign()

javascript 复制代码
// 【代码注释】`Math.sign` 返回 -1/0/1 或 -0/+0 区分;`NaN` 返回 NaN。比 `x>0?1:x<0?-1:0` 简洁。注意 `sign(-0)` 为 -0,极少场景需 `Object.is` 判 -0。
console.log(Math.sign(100)); // 1(正数)
console.log(Math.sign(-100)); // -1(负数)
console.log(Math.sign(0)); // 0
console.log(Math.sign(-0)); // -0

// 实际应用:排序和比较
function compareNumbers(a, b) {
    const diff = a - b;
    if (Math.abs(diff) < 0.0001) return 0; // 近似相等
    return Math.sign(diff);
}

// 符号函数的应用
function formatNumber(num) {
    const sign = Math.sign(num);
    const absNum = Math.abs(num);
    
    return `${sign === -1 ? '-' : '+'}${absNum.toFixed(2)}`;
}

console.log(formatNumber(123.456)); // +123.46
console.log(formatNumber(-78.9)); // -78.90

【代码注释】Math.sign 返回 -1/0/1 或 -0/+0 区分;NaN 返回 NaN。比 x>0?1:x<0?-1:0 简洁。注意 sign(-0) 为 -0,极少场景需 Object.is 判 -0。

方法三:Math.cbrt()

javascript 复制代码
// 【代码注释】`Math.cbrt` 可处理负数(与 `Math.pow(x,1/3)` 对负数行为不同)。体积、三维缩放因子开立方根时用;大数注意仍受 number 精度限制。
console.log(Math.cbrt(8)); // 2
console.log(Math.cbrt(27)); // 3
console.log(Math.cbrt(-8)); // -2

// 实际应用:体积计算
function calculateCubeVolume(side) {
    return Math.pow(side, 3);
}

function calculateSideFromVolume(volume) {
    return Math.cbrt(volume);
}

const volume = 125;
const side = calculateSideFromVolume(volume);
console.log(`体积为${volume}的立方体边长为${side}`); // 边长为5

// 几何计算
function calculateSphereDiameter(volume) {
    // V = (4/3) * π * r³
    const radius = Math.cbrt((3 * volume) / (4 * Math.PI));
    return radius * 2;
}

【代码注释】Math.cbrt 可处理负数(与 Math.pow(x,1/3) 对负数行为不同)。体积、三维缩放因子开立方根时用;大数注意仍受 number 精度限制。

5.3.3 Math方法的实际应用

场景一:统计和数据分析

javascript 复制代码
// 【代码注释】示例对数组 `reduce` 求和/极值,配合 `Math.min`/`Math.max`  spread。大数据集应用单次遍历求 min/max 避免展开栈溢出;统计方差、标准差可在此基础上扩展。
class Statistics {
    static mean(numbers) {
        const sum = numbers.reduce((acc, num) => acc + num, 0);
        return sum / numbers.length;
    }
    
    static standardDeviation(numbers) {
        const avg = this.mean(numbers);
        const squareDiffs = numbers.map(num => Math.pow(num - avg, 2));
        const avgSquareDiff = this.mean(squareDiffs);
        return Math.sqrt(avgSquareDiff);
    }
    
    static clamp(number, min, max) {
        return Math.min(Math.max(number, min), max);
    }
    
    static normalize(value, min, max) {
        return (value - min) / (max - min);
    }
    
    static lerp(start, end, t) {
        return start + (end - start) * this.clamp(t, 0, 1);
    }
}

// 使用示例
const data = [1, 2, 3, 4, 5];
console.log('平均值:', Statistics.mean(data));
console.log('标准差:', Statistics.standardDeviation(data));

// 动画插值
function animateValue(start, end, duration) {
    const startTime = performance.now();
    
    function update(currentTime) {
        const elapsed = currentTime - startTime;
        const progress = Math.min(elapsed / duration, 1);
        
        const value = Statistics.lerp(start, end, progress);
        console.log('当前值:', value);
        
        if (progress < 1) {
            requestAnimationFrame(update);
        }
    }
    
    requestAnimationFrame(update);
}

【代码注释】示例对数组 reduce 求和/极值,配合 Math.min/Math.max spread。大数据集应用单次遍历求 min/max 避免展开栈溢出;统计方差、标准差可在此基础上扩展。

场景二:游戏开发

javascript 复制代码
// 【代码注释】向量长度、距离、角度换算展示 Math 与 ES6 解构/模板字符串组合。实际游戏引擎多用专用库(gl-matrix);此处理解 `hypot`、`atan2` 用途即可。
class GameMath {
    // 计算两点距离
    static distance(x1, y1, x2, y2) {
        const dx = x2 - x1;
        const dy = y2 - y1;
        return Math.sqrt(dx * dx + dy * dy);
    }
    
    // 角度转换
    static degreesToRadians(degrees) {
        return degrees * (Math.PI / 180);
    }
    
    static radiansToDegrees(radians) {
        return radians * (180 / Math.PI);
    }
    
    // 随机数生成
    static randomRange(min, max) {
        return Math.random() * (max - min) + min;
    }
    
    static randomInt(min, max) {
        return Math.floor(this.randomRange(min, max + 1));
    }
    
    // 弹性碰撞
    static elasticCollision(m1, v1, m2, v2) {
        const newV1 = ((m1 - m2) * v1 + 2 * m2 * v2) / (m1 + m2);
        const newV2 = ((m2 - m1) * v2 + 2 * m1 * v1) / (m1 + m2);
        return { v1: newV1, v2: newV2 };
    }
}

// 游戏循环
class GameObject {
    constructor(x, y, vx, vy) {
        this.x = x;
        this.y = y;
        this.vx = vx;
        this.vy = vy;
        this.mass = 1;
    }
    
    update(deltaTime) {
        this.x += this.vx * deltaTime;
        this.y += this.vy * deltaTime;
    }
    
    checkBoundary(width, height) {
        if (this.x < 0 || this.x > width) {
            this.vx *= -1;
        }
        if (this.y < 0 || this.y > height) {
            this.vy *= -1;
        }
    }
}

【代码注释】向量长度、距离、角度换算展示 Math 与 ES6 解构/模板字符串组合。实际游戏引擎多用专用库(gl-matrix);此处理解 hypotatan2 用途即可。

5.4 指数运算符 **

5.4.1 指数运算符基本用法
javascript 复制代码
// 【代码注释】`**` 右结合:`2**3**2` 即 `2**(3**2)`。`Math.pow` 对 BigInt 不适用;BigInt 用 `**n` 同类。负数底数非整数指数可能产生 NaN(复数不在实数域)。
console.log(2 ** 3); // 8
console.log(3 ** 2); // 9
console.log(4 ** 0.5); // 2(平方根)
console.log(8 ** (1/3)); // 2(立方根)

// 与Math.pow()的比较
console.log(2 ** 3 === Math.pow(2, 3)); // true

// 右结合性
console.log(2 ** 3 ** 2); // 512(等于 2 ** (3 ** 2))
console.log((2 ** 3) ** 2); // 64

// 实际应用:科学计算
function calculateCompoundInterest(principal, rate, time) {
    return principal * (1 + rate) ** time;
}

console.log(calculateCompoundInterest(1000, 0.05, 10)); // 1628.89

// 单位转换
function convertBytesToKB(bytes) {
    return bytes / (1024 ** 1);
}

function convertBytesToMB(bytes) {
    return bytes / (1024 ** 2);
}

function convertBytesToGB(bytes) {
    return bytes / (1024 ** 3);
}

console.log(convertBytesToMB(1048576)); // 1
console.log(convertBytesToGB(1073741824)); // 1

【代码注释】** 右结合:2**3**22**(3**2)Math.pow 对 BigInt 不适用;BigInt 用 **n 同类。负数底数非整数指数可能产生 NaN(复数不在实数域)。

5.5 新增原始数据类型BigInt

5.5.1 BigInt的基本概念

名词解析:

  • BigInt:ES2020新增的原始数据类型,用于表示任意大小的整数
  • 安全整数范围 :Number类型的安全范围是-(253-1)到253-1
  • 精度丢失:超出安全整数范围的计算可能不精确
javascript 复制代码
// 【代码注释】字面量后缀 `n` 或 `BigInt(123)`;typeof 为 `bigint`。不能与 number 混算(抛 TypeError),比较可先转同类型。用于超 2^53 的 ID、链上整数。
// 创建BigInt的方式
const bigInt1 = 9007199254740993n; // 使用n后缀
const bigInt2 = BigInt(9007199254740993); // 使用BigInt()函数
const bigInt3 = BigInt('9007199254740993'); // 从字符串创建

console.log(bigInt1 === bigInt2); // true
console.log(bigInt2 === bigInt3); // true

// BigInt vs Number的安全范围
const maxSafe = Number.MAX_SAFE_INTEGER; // 9007199254740991
console.log(maxSafe + 1); // 9007199254740992(正确)
console.log(maxSafe + 2); // 9007199254740992(错误,精度丢失)

const bigIntMax = BigInt(maxSafe);
console.log(bigIntMax + 1n); // 9007199254740992n(正确)
console.log(bigIntMax + 2n); // 9007199254740993n(正确)

【代码注释】字面量后缀 nBigInt(123);typeof 为 bigint。不能与 number 混算(抛 TypeError),比较可先转同类型。用于超 2^53 的 ID、链上整数。

5.5.2 BigInt的运算和限制
javascript 复制代码
// 【代码注释】支持 `+ - * ** %`;除法向零取整。混合 `1n + 1` 报错,需显式 `BigInt(1)` 或 `Number(1n)`(大数可能丢精度)。JSON.stringify 默认不支持 BigInt,需自定义 replacer。
const a = 100n;
const b = 50n;

// 基本运算
console.log(a + b); // 150n
console.log(a - b); // 50n
console.log(a * b); // 5000n
console.log(a / b); // 2n(除法取整)
console.log(a % b); // 0n
console.log(a ** 2n); // 10000n

// 比较运算
console.log(100n > 50n); // true
console.log(100n === 100); // false(类型不同)
console.log(100n == 100); // true(类型转换)

// 位运算
console.log(0b1010n & 0b1100n); // 8n (1000)
console.log(0b1010n | 0b1100n); // 14n (1110)
console.log(0b1010n ^ 0b1100n); // 6n (0110)

// 限制演示
// console.log(100n + 50); // TypeError
console.log(100n + BigInt(50)); // 150n

// console.log(Math.max(100n, 50n)); // TypeError

【代码注释】支持 + - * ** %;除法向零取整。混合 1n + 1 报错,需显式 BigInt(1)Number(1n)(大数可能丢精度)。JSON.stringify 默认不支持 BigInt,需自定义 replacer。

5.5.3 BigInt的实际应用场景

场景一:处理大整数ID

javascript 复制代码
// 【代码注释】雪花 ID 等超过 MAX_SAFE_INTEGER 时 API 常以字符串传输;前端存 BigInt 或字符串,展示再格式化。与后端约定类型,避免 `Number(id)` 静默舍入。
class IdHandler {
    // 处理Twitter Snowflake ID
    static parseSnowflakeId(id) {
        const snowflake = BigInt(id);
        
        // 提取时间戳(41位)
        const timestamp = (snowflake >> 22n) + 1288834974657n;
        
        // 提取数据中心ID(5位)
        const datacenterId = (snowflake >> 17n) & 0x1Fn;
        
        // 提取工作机器ID(5位)
        const workerId = (snowflake >> 12n) & 0x1Fn;
        
        // 提取序列号(12位)
        const sequence = snowflake & 0xFFFn;
        
        return {
            timestamp: new Date(Number(timestamp)),
            datacenterId: Number(datacenterId),
            workerId: Number(workerId),
            sequence: Number(sequence)
        };
    }
    
    static generateSnowflakeId(datacenterId, workerId, sequence) {
        const timestamp = BigInt(Date.now()) - 1288834974657n;
        
        return (timestamp << 22n) |
               (BigInt(datacenterId) << 17n) |
               (BigInt(workerId) << 12n) |
               BigInt(sequence);
    }
}

// 使用示例
const snowflakeId = '13958471234567890123';
const parsed = IdHandler.parseSnowflakeId(snowflakeId);
console.log(parsed);

const newId = IdHandler.generateSnowflakeId(1, 1, 0);
console.log(newId.toString());

【代码注释】雪花 ID 等超过 MAX_SAFE_INTEGER 时 API 常以字符串传输;前端存 BigInt 或字符串,展示再格式化。与后端约定类型,避免 Number(id) 静默舍入。

场景二:金融计算

javascript 复制代码
// 【代码注释】以分为单位的 BigInt 相加无浮点误差;展示时 `/100n` 或格式化为元。汇率、利率若需小数,仍可能要用 decimal 库,BigInt 适合整数最小货币单位。
class FinancialCalculator {
    // 使用最小单位(分)进行计算
    static calculateTotal(prices) {
        const total = prices.reduce((sum, price) => {
            const cents = BigInt(Math.round(price * 100));
            return sum + cents;
        }, 0n);
        
        return Number(total) / 100;
    }
    
    // 高精度除法
    static divide(a, b, precision = 2) {
        const multiplier = 10n ** BigInt(precision);
        const result = (a * multiplier) / b;
        return Number(result) / Math.pow(10, precision);
    }
    
    // 复利计算
    static compoundInterest(principal, rate, periods) {
        const p = BigInt(Math.round(principal * 100));
        const r = BigInt(Math.round(rate * 100));
        
        // 使用二项式近似计算
        const amount = p * (100n + r) ** BigInt(periods) / (100n ** BigInt(periods));
        
        return Number(amount) / 100;
    }
}

// 使用示例
const prices = [10.99, 25.50, 99.95, 4.99];
console.log('总计:', FinancialCalculator.calculateTotal(prices));

// 精确除法
const a = BigInt(100); // 1.00元
const b = BigInt(3);   // 3份
console.log('每份:', FinancialCalculator.divide(a, b, 2)); // 0.33元

【代码注释】以分为单位的 BigInt 相加无浮点误差;展示时 /100n 或格式化为元。汇率、利率若需小数,仍可能要用 decimal 库,BigInt 适合整数最小货币单位。

场景三:加密算法

javascript 复制代码
// 【代码注释】示例用 BigInt 模幂等说明大整数运算;**非生产加密**,真实场景用 Web Crypto API 与标准库。理解 BigInt 取模 `%` 与 number 的差异即可。
class SimpleCrypto {
    // RSA相关的大数运算
    static modExp(base, exponent, modulus) {
        let result = 1n;
        base = base % modulus;
        
        while (exponent > 0n) {
            if (exponent % 2n === 1n) {
                result = (result * base) % modulus;
            }
            exponent = exponent / 2n;
            base = (base * base) % modulus;
        }
        
        return result;
    }
    
    // 生成大素数(简化版)
    static generateLargePrime(bits) {
        const getRandomBigint = (bitLength) => {
            const bytes = Math.ceil(bitLength / 8);
            const array = new Uint8Array(bytes);
            crypto.getRandomValues(array);
            
            let result = 0n;
            for (const byte of array) {
                result = (result << 8n) + BigInt(byte);
            }
            return result;
        };
        
        let candidate = getRandomBigint(bits);
        // 实际应用中需要更复杂的素数检测
        return candidate | 1n; // 确保是奇数
    }
    
    // 简化的哈希函数
    static hash(input) {
        let hash = 0n;
        const str = String(input);
        
        for (let i = 0; i < str.length; i++) {
            const char = str.charCodeAt(i);
            hash = ((hash << 5n) - hash) + BigInt(char);
            hash = hash & 0x7FFFFFFFFFFFFFFFn; // 保持在63位有符号整数范围内
        }
        
        return hash;
    }
}

// 使用示例
const message = "Hello, World!";
const hashed = SimpleCrypto.hash(message);
console.log('哈希值:', hashed.toString(16));

【代码注释】示例用 BigInt 模幂等说明大整数运算;非生产加密 ,真实场景用 Web Crypto API 与标准库。理解 BigInt 取模 % 与 number 的差异即可。

5.6 数字分隔符

5.6.1 数字分隔符的基本用法
javascript 复制代码
// 【代码注释】字面量与 `0x`/`0b` 中可用 `_` 分组:`1_000_000`、`0xFF_FF`。仅作视觉分隔,不参与运算。二进制/十六进制按字节/半字节分组更易读。
// 整数分隔
const billion = 1_000_000_000;
const million = 1_000_000;
const thousand = 1_000;

console.log(billion); // 1000000000

// 小数分隔
const pi = 3.141_592_653_589_793;
const avogadro = 6.022_140_76e23;

// 特殊格式的数字
const creditCard = 1234_5678_9012_3456;
const phoneNumber = 138_1234_5678;
const socialSecurity = 123_45_6789;

// 不同进制数字的分隔
const binary = 0b1010_0001_1000_0101;
const octal = 0o123_456;
const hex = 0xA1_B2_C3_D4;

// BigInt的分隔
const largeBigInt = 1_000_000_000_000_000_000_000n;

// 实际应用:常量定义
const CONSTANTS = {
    // 物理常数
    SPEED_OF_LIGHT: 299_792_458,        // m/s
    GRAVITATIONAL_CONSTANT: 6.674e-11,  // m³/(kg·s²)
    
    // 网络相关
    MAX_PORT: 65_535,
    LOCALHOST: 127_0_0_1,
    
    // 数据存储
    KB: 1_024,
    MB: 1_048_576,
    GB: 1_073_741_824,
    TB: 1_099_511_627_776
};

【代码注释】字面量与 0x/0b 中可用 _ 分组:1_000_0000xFF_FF。仅作视觉分隔,不参与运算。二进制/十六进制按字节/半字节分组更易读。

5.6.2 数字分隔符的应用场景

场景一:配置文件

javascript 复制代码
// 【代码注释】大数常量、版本掩码、位标志用分隔符降低抄错位风险;构建工具需支持 ES2021 语法。与注释配合说明每一位含义更佳。
const config = {
    // 服务器配置
    server: {
        port: 8_000,
        timeout: 30_000,        // 30秒
        maxConnections: 1_000
    },
    
    // 分页配置
    pagination: {
        defaultPageSize: 20,
        maxPageSize: 100,
        totalItems: 10_000
    },
    
    // 限流配置
    rateLimit: {
        requestsPerMinute: 60,
        requestsPerHour: 1_000,
        banDuration: 3_600_000  // 1小时(毫秒)
    },
    
    // 文件上传
    upload: {
        maxFileSize: 10_485_760,    // 10MB
        maxTotalSize: 104_857_600,  // 100MB
        chunkSize: 524_288          // 512KB
    }
};

【代码注释】大数常量、版本掩码、位标志用分隔符降低抄错位风险;构建工具需支持 ES2021 语法。与注释配合说明每一位含义更佳。

场景二:数据验证

javascript 复制代码
// 【代码注释】可用正则允许数字间下划线再 `Number()` 解析,或解析前 `replaceAll('_','')`。银行卡号、许可证号展示常用分隔,存储仍建议规范化无下划线字符串。
class NumberValidator {
    // 验证手机号
    static validatePhoneNumber(phone) {
        const cleanPhone = phone.replaceAll(/[-\s]/g, '');
        return /^1[3-9]\d{9}$/.test(cleanPhone);
    }
    
    // 验证信用卡号(简化版)
    static validateCreditCard(cardNumber) {
        const cleanNumber = cardNumber.replaceAll(/[-\s]/g, '');
        if (!/^\d{13,19}$/.test(cleanNumber)) {
            return false;
        }
        
        // Luhn算法验证
        let sum = 0;
        let isEven = false;
        
        for (let i = cleanNumber.length - 1; i >= 0; i--) {
            let digit = parseInt(cleanNumber[i], 10);
            
            if (isEven) {
                digit *= 2;
                if (digit > 9) {
                    digit -= 9;
                }
            }
            
            sum += digit;
            isEven = !isEven;
        }
        
        return sum % 10 === 0;
    }
    
    // 验证IP地址
    static validateIPAddress(ip) {
        const parts = ip.split('.');
        if (parts.length !== 4) return false;
        
        return parts.every(part => {
            const num = parseInt(part, 10);
            return num >= 0 && num <= 255;
        });
    }
}

// 使用示例
console.log(NumberValidator.validatePhoneNumber('138-1234-5678')); // true
console.log(NumberValidator.validateCreditCard('1234-5678-9012-3456')); // 根据Luhn算法验证

【代码注释】可用正则允许数字间下划线再 Number() 解析,或解析前 replaceAll('_','')。银行卡号、许可证号展示常用分隔,存储仍建议规范化无下划线字符串。


5.7 可选链 ?. 与 空值合并 ??(ES2020)

这两个运算符在 ES2020 引入,与解构赋值高度互补,是现代前端代码中使用频率极高的特性。

5.7.1 可选链运算符 ?.

名词解析:

  • 可选链(Optional Chaining) :在访问链式属性时,若某个中间值为 nullundefined,直接短路返回 undefined,而不是抛出 TypeError
javascript 复制代码
// 【代码注释】传统写法:每层用 && 短路,冗长且易漏判 null(0、'' 也会被 && 吃掉,语义与 ?. 不同)
const city = user && user.address && user.address.city;

// 【代码注释】?. 仅当左侧为 null/undefined 时短路返回 undefined,不抛 TypeError
const city = user?.address?.city;

// 【代码注释】?.[index]:可选下标访问,tags 不存在时不报错
const firstTag = post?.tags?.[0];

// 【代码注释】?.():仅当左侧存在且为函数时才调用,避免 "x is not a function"
const name = user?.getName?.();

// 【代码注释】深层 API:?. 安全取值 + ?? 提供展示默认值(见下一节)
function renderUserCard(apiData) {
    const avatarUrl   = apiData?.data?.user?.profile?.avatar?.url ?? '/default-avatar.png';
    const displayName = apiData?.data?.user?.name ?? '匿名用户';
    const followerCnt = apiData?.data?.user?.stats?.followers ?? 0;

    return `
        <div class="user-card">
            <img src="${avatarUrl}" alt="${displayName}">
            <p>${displayName} · ${followerCnt} 粉丝</p>
        </div>
    `;
}

// 实际应用:事件处理中安全访问目标元素
document.addEventListener('click', (e) => {
    // 安全访问 dataset 属性
    const userId = e.target?.closest('[data-user-id]')?.dataset?.userId;
    if (userId) fetchUserInfo(userId);
});

// 实际应用:配置对象可选字段
function initPlugin(config) {
    const timeout    = config?.network?.timeout ?? 5000;
    const retries    = config?.network?.retries ?? 3;
    const debugMode  = config?.debug ?? false;

    console.log(`超时:${timeout}ms 重试:${retries}次 调试:${debugMode}`);
}

【代码注释】?. 短路规则 :左侧为 null/undefined 时立即返回 undefined,不再求值右侧(不访问属性、不调用函数、不取下标)。支持 obj?.propobj?.[expr]fn?.() 三种形式。与 && 区别:0?.x 仍会继续(0 不是 nullish),而 0 && x 会短路。渲染/API/事件委托中常与 ?? 组合:api?.user?.name ?? '访客'

5.7.2 空值合并运算符 ??

名词解析:

  • 空值合并(Nullish Coalescing)?? 仅在左侧为 nullundefined 时才使用右侧的默认值,0''false 这类 falsy 值不会触发默认值
javascript 复制代码
// 【代码注释】?? vs || 的关键差异
// || 逻辑或:任何 falsy 值都会使用右侧(包括 0、''、false)
const port1 = 0 || 3000;       // 3000(错误:0 是合法端口,不该被替换)
const name1 = '' || '匿名';    // '匿名'(错误:空字符串可能是用户有意清空)
const flag1 = false || true;   // true(错误:false 是有意义的布尔值)

// ?? 空值合并:只有 null/undefined 才使用默认值
const port2 = 0 ?? 3000;      // 0     ✅ 保留合法的 0
const name2 = '' ?? '匿名';   // ''    ✅ 保留空字符串
const flag2 = false ?? true;  // false ✅ 保留 false

// 实际应用:表单字段默认值处理
function processFormField(value) {
    const displayValue = value ?? '(未填写)'; // 只对 null/undefined 使用默认值
    return displayValue;
}

console.log(processFormField(0));         // 0(数量0是有效值)
console.log(processFormField(''));        // ''(空字符串是有效值)
console.log(processFormField(null));      // '(未填写)'
console.log(processFormField(undefined)); // '(未填写)'

// 实际应用:配置项合并(与解构默认值的对比)
function createConfig(options) {
    return {
        // ?? 与解构默认值等效,但 ?? 可用于运行时动态合并
        host:     options.host     ?? 'localhost',
        port:     options.port     ?? 8080,    // port=0 也能正确保留
        debug:    options.debug    ?? false,   // debug=false 也能正确保留
        maxConn:  options.maxConn  ?? 100
    };
}

console.log(createConfig({ port: 0, debug: false }));
// { host: 'localhost', port: 0, debug: false, maxConn: 100 }

// 【代码注释】?.  与 ?? 的黄金组合:安全读取 + 优雅回退
class UserService {
    getDisplayInfo(user) {
        return {
            name:     user?.profile?.displayName   ?? user?.name ?? '匿名',
            avatar:   user?.profile?.avatarUrl     ?? '/assets/default-avatar.png',
            bio:      user?.profile?.bio           ?? '',
            verified: user?.verification?.isVerified ?? false
        };
    }
}

【代码注释】??nullish 语义:仅当左侧为 nullundefined 才取右侧默认值;0''false 均为合法业务值,不会被替换。对比 ||:会把所有 falsy 都换掉,导致端口 0、开关 false、用户清空的 '' 被误覆盖。解构默认值 function f({ port = 8080 })port ?? 8080 类似,但 ?? 可在运行时对任意表达式使用。UserService.getDisplayInfo 演示多层 ?. 与多级 ?? 回退链。
#mermaid-svg-52A7mFtgTlXKqipK{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-52A7mFtgTlXKqipK .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-52A7mFtgTlXKqipK .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-52A7mFtgTlXKqipK .error-icon{fill:#552222;}#mermaid-svg-52A7mFtgTlXKqipK .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-52A7mFtgTlXKqipK .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-52A7mFtgTlXKqipK .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-52A7mFtgTlXKqipK .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-52A7mFtgTlXKqipK .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-52A7mFtgTlXKqipK .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-52A7mFtgTlXKqipK .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-52A7mFtgTlXKqipK .marker{fill:#333333;stroke:#333333;}#mermaid-svg-52A7mFtgTlXKqipK .marker.cross{stroke:#333333;}#mermaid-svg-52A7mFtgTlXKqipK svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-52A7mFtgTlXKqipK p{margin:0;}#mermaid-svg-52A7mFtgTlXKqipK .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-52A7mFtgTlXKqipK .cluster-label text{fill:#333;}#mermaid-svg-52A7mFtgTlXKqipK .cluster-label span{color:#333;}#mermaid-svg-52A7mFtgTlXKqipK .cluster-label span p{background-color:transparent;}#mermaid-svg-52A7mFtgTlXKqipK .label text,#mermaid-svg-52A7mFtgTlXKqipK span{fill:#333;color:#333;}#mermaid-svg-52A7mFtgTlXKqipK .node rect,#mermaid-svg-52A7mFtgTlXKqipK .node circle,#mermaid-svg-52A7mFtgTlXKqipK .node ellipse,#mermaid-svg-52A7mFtgTlXKqipK .node polygon,#mermaid-svg-52A7mFtgTlXKqipK .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-52A7mFtgTlXKqipK .rough-node .label text,#mermaid-svg-52A7mFtgTlXKqipK .node .label text,#mermaid-svg-52A7mFtgTlXKqipK .image-shape .label,#mermaid-svg-52A7mFtgTlXKqipK .icon-shape .label{text-anchor:middle;}#mermaid-svg-52A7mFtgTlXKqipK .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-52A7mFtgTlXKqipK .rough-node .label,#mermaid-svg-52A7mFtgTlXKqipK .node .label,#mermaid-svg-52A7mFtgTlXKqipK .image-shape .label,#mermaid-svg-52A7mFtgTlXKqipK .icon-shape .label{text-align:center;}#mermaid-svg-52A7mFtgTlXKqipK .node.clickable{cursor:pointer;}#mermaid-svg-52A7mFtgTlXKqipK .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-52A7mFtgTlXKqipK .arrowheadPath{fill:#333333;}#mermaid-svg-52A7mFtgTlXKqipK .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-52A7mFtgTlXKqipK .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-52A7mFtgTlXKqipK .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-52A7mFtgTlXKqipK .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-52A7mFtgTlXKqipK .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-52A7mFtgTlXKqipK .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-52A7mFtgTlXKqipK .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-52A7mFtgTlXKqipK .cluster text{fill:#333;}#mermaid-svg-52A7mFtgTlXKqipK .cluster span{color:#333;}#mermaid-svg-52A7mFtgTlXKqipK div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-52A7mFtgTlXKqipK .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-52A7mFtgTlXKqipK rect.text{fill:none;stroke-width:0;}#mermaid-svg-52A7mFtgTlXKqipK .icon-shape,#mermaid-svg-52A7mFtgTlXKqipK .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-52A7mFtgTlXKqipK .icon-shape p,#mermaid-svg-52A7mFtgTlXKqipK .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-52A7mFtgTlXKqipK .icon-shape .label rect,#mermaid-svg-52A7mFtgTlXKqipK .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-52A7mFtgTlXKqipK .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-52A7mFtgTlXKqipK .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-52A7mFtgTlXKqipK :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 有中间 null/undefined
链路完整

否,含0/false/''
访问深层属性
?.短路返回 undefined
返回目标值
是 null/undefined?
?? 提供默认值
使用原值

【代码注释】决策流:访问深层字段 → 中间层可能为空则用 ?. 短路,避免 Cannot read properties of undefined需要兜底展示/配置 → 在 ?. 结果后用 ?? 补默认值。勿混用 || 做默认值(会误伤 0/false/'')。与解构默认值、逻辑与 && 的分工:解构适合形参/已知结构;?./?? 适合运行时 API 形状不确定的场景。

5.7.3 逻辑赋值运算符(ES2021)

ES2021 引入了三个结合逻辑判断与赋值 的复合运算符:??=||=&&=。它们是 ??/||/&&= 的结合体,在左侧满足条件时才执行赋值(具有短路语义)。

javascript 复制代码
// ──────────────────────────────────────────────────────────
// 【代码注释】??= 空值合并赋值:仅当左侧为 null / undefined 时才赋新值
// 语义等价:a ?? (a = b)  → 只有 nullish 才触发,0 / '' / false 不会被覆盖
// ──────────────────────────────────────────────────────────
let userTheme = null;
userTheme ??= 'light';          // null → 赋值
console.log(userTheme);        // 'light'

let port = 0;
port ??= 3000;                  // 0 不是 nullish → 不赋值,保留合法的 0
console.log(port);             // 0  ✅

// 对比 ||= 的风险:
let port2 = 0;
port2 ||= 3000;                 // 0 是 falsy → 赋值(❗ 覆盖了合法端口 0)
console.log(port2);            // 3000  ← 通常不是期望行为

// ──────────────────────────────────────────────────────────
// 【代码注释】||= 逻辑或赋值:左侧为 falsy(含 0/false/'')时才赋值
// 适合:字符串显示默认值、fallback 文案(不需要区分 null 与 '')
// ──────────────────────────────────────────────────────────
let displayName = '';
displayName ||= '匿名用户';      // '' 是 falsy → 赋值
console.log(displayName);      // '匿名用户'

let retries = undefined;
retries ||= 3;                  // undefined 是 falsy → 赋值
console.log(retries);          // 3

// ──────────────────────────────────────────────────────────
// 【代码注释】&&= 逻辑与赋值:左侧为 truthy 时才赋值(条件性更新)
// 适合:仅当属性存在时才更新它;若属性为 falsy,跳过赋值(不触发 setter)
// ──────────────────────────────────────────────────────────
let user = { name: '张三', isVerified: true };
user.isVerified &&= false;       // isVerified 为 truthy → 执行赋值
console.log(user.isVerified);  // false

let guest = { name: '游客', isVerified: false };
guest.isVerified &&= false;     // isVerified 为 falsy → 不执行赋值(无副作用)
console.log(guest.isVerified); // false(未触发,避免不必要的 setter)

【代码注释】三个运算符的核心差异:??= 仅对 null/undefined (最严格);||= 对所有 falsy (含 0/''/false);&&=truthy 时才赋值。与普通 = 不同的是,三者都具有短路语义------左侧不满足条件时右侧不求值,也不触发 setter,性能和语义均更精确。

javascript 复制代码
// ──────────────────────────────────────────────────────────
// 实际应用场景集合
// ──────────────────────────────────────────────────────────

// 【代码注释】场景一:懒初始化(Lazy Initialization)------??= 是最常见用法
class ComponentState {
    #cache = null;
    #listeners = null;

    // 首次调用时初始化 Map,后续复用同一实例
    getCache() {
        this.#cache ??= new Map();
        return this.#cache;
    }

    // 首次添加监听器时初始化数组
    addListener(fn) {
        this.#listeners ??= [];
        this.#listeners.push(fn);
    }
}

// 【代码注释】场景二:配置项安全合并------??= 保留合法的 0 / false / ''
function withDefaults(options) {
    options.timeout  ??= 5_000;   // 仅补充缺失项,timeout=0 也会被保留
    options.retries  ??= 3;
    options.debug    ??= false;   // debug=false 也会被保留(不被 ||= 误覆盖)
    return options;
}

console.log(withDefaults({ timeout: 0, debug: true }));
// { timeout: 0, retries: 3, debug: true }  ← timeout=0 正确保留

// 【代码注释】场景三:条件性更新对象属性------&&= 不触发不必要的 setter
function updateUserStatus(user, shouldDeactivate) {
    // 仅当 isActive 为 true 且需要停用时才修改(&&= 短路,不触发 Vue/MobX 响应式)
    if (shouldDeactivate) {
        user.isActive &&= false;
    }
}

// 【代码注释】场景四:||= 用于展示层默认文案(不需区分 null 与空字符串时)
function renderUserBio(bio) {
    let displayBio = bio;
    displayBio ||= '这个人很懒,什么都没有写...'; // null / undefined / '' 均使用默认文案
    return displayBio;
}

【代码注释】选型建议:配置/初始化 优先用 ??=(最安全,不误伤 0/false/'');展示文案 可用 ||=(把空字符串也视为"未填写");条件性更新&&=(避免不必要的 setter 触发)。在 Vue 3 响应式对象、MobX observable 上,&&= 的短路特性可避免无意义的派发(dispatch),有利于性能。
渲染错误: Mermaid 渲染失败: Parse error on line 3: ...-->|展示场景,'' 也算空| C\|\|= 展示层 A -->|仅在 -----------------------^ Expecting 'NODE_STRING', got 'PIPE'

【代码注释】??= / ||= / &&= 决策流:优先考虑「0/false/'' 是否是合法值」------ 是则用 ??=;纯展示降级可用 ||=;需要「值存在才更新」用 &&=。三者均支持链式属性 obj.prop ??= default,行为与 obj.prop = obj.prop ?? default 等价但更简洁,且短路时不触发 getter/setter。


6. 实战应用场景与最佳实践

6.1 现代前端开发中的ES6+应用

6.1.1 React组件开发
javascript 复制代码
// 【代码注释】函数组件 + 解构 props/state + 模板字符串 className + const 事件处理;hooks 依赖块级 let/const。对比 class 组件,现代代码默认严格模式与模块作用域。
import React, { useState, useEffect, useCallback } from 'react';

// 使用箭头函数和解构
const UserProfile = ({ userId, onUpdate }) => {
    // 使用解构和默认值
    const [user, setUser] = useState(null);
    const [loading, setLoading] = useState(false);
    const [error, setError] = useState(null);
    
    // 使用async/await和模板字符串
    useEffect(() => {
        const fetchUser = async () => {
            setLoading(true);
            setError(null);
            
            try {
                const response = await fetch(`/api/users/${userId}`);
                if (!response.ok) {
                    throw new Error(`HTTP error! status: ${response.status}`);
                }
                const userData = await response.json();
                setUser(userData);
            } catch (err) {
                setError(err.message);
            } finally {
                setLoading(false);
            }
        };
        
        fetchUser();
    }, [userId]);
    
    // 使用useCallback和模板字符串
    const handleUpdate = useCallback((updates) => {
        const updatedUser = { ...user, ...updates };
        setUser(updatedUser);
        onUpdate(updatedUser);
    }, [user, onUpdate]);
    
    // 使用条件渲染和模板字符串
    if (loading) return <div>Loading...</div>;
    if (error) return <div>Error: {error}</div>;
    if (!user) return null;
    
    return (
        <div className="user-profile">
            {/* 使用模板字符串 */}
            <h1>{`User: ${user.name}`}</h1>
            <p>Email: {user.email}</p>
            <p>Age: {user.age}</p>
            
            {/* 使用解构 */}
            {user.address && (
                <address>
                    {user.address.street}<br />
                    {user.address.city}, {user.address.country}
                </address>
            )}
            
            <button onClick={() => handleUpdate({ name: 'Updated Name' })}>
                Update Name
            </button>
        </div>
    );
};

export default UserProfile;

【代码注释】函数组件 + 解构 props/state + 模板字符串 className + const 事件处理;hooks 依赖块级 let/const。对比 class 组件,现代代码默认严格模式与模块作用域。

6.1.2 Vue3 Composition API
javascript 复制代码
// 【代码注释】`<script setup>` 中 `const props = defineProps`、解构 `toRefs`、模板 `${}` 与计算属性;与 React 同属「声明式 + 块级变量」范式。
import { ref, computed, onMounted, watch } from 'vue';

export default {
    props: {
        userId: {
            type: Number,
            required: true,
            validator: value => value > 0
        }
    },
    
    setup(props, { emit }) {
        // 使用ref解构
        const user = ref(null);
        const loading = ref(false);
        const error = ref(null);
        
        // 使用computed
        const userDisplayName = computed(() => {
            if (!user.value) return '';
            const { firstName, lastName } = user.value;
            return `${firstName} ${lastName}`;
        });
        
        // 使用async/await
        const fetchUser = async () => {
            loading.value = true;
            error.value = null;
            
            try {
                const response = await fetch(`/api/users/${props.userId}`);
                const userData = await response.json();
                user.value = userData;
            } catch (err) {
                error.value = err.message;
            } finally {
                loading.value = false;
            }
        };
        
        // 使用watch
        watch(() => props.userId, (newUserId, oldUserId) => {
            if (newUserId !== oldUserId) {
                fetchUser();
            }
        });
        
        // 使用解构
        const updateUser = (updates) => {
            user.value = { ...user.value, ...updates };
            emit('update:user', user.value);
        };
        
        // 使用onMounted
        onMounted(() => {
            fetchUser();
        });
        
        // 返回解构的对象
        return {
            user,
            loading,
            error,
            userDisplayName,
            updateUser
        };
    }
};

【代码注释】<script setup>const props = defineProps、解构 toRefs、模板 ${} 与计算属性;与 React 同属「声明式 + 块级变量」范式。

6.1.3 Node.js后端开发
javascript 复制代码
// 【代码注释】路由处理函数参数解构 `req.body`、默认配置 const、模板字符串拼错误信息。Node 模块默认严格模式(ESM)或 CommonJS 中手动 strict。
import express from 'express';
import { body, validationResult, param } from 'express-validator';

const router = express.Router();

// 使用解构和async/await
router.get('/users/:id', 
    param('id').isInt({ min: 1 }),
    async (req, res, next) => {
        try {
            const errors = validationResult(req);
            if (!errors.isEmpty()) {
                return res.status(400).json({ errors: errors.array() });
            }
            
            const { id } = req.params;
            const { include, fields } = req.query;
            
            // 使用解构和模板字符串
            const user = await User.findById(id);
            
            if (!user) {
                return res.status(404).json({ 
                    error: `User with id ${id} not found` 
                });
            }
            
            // 使用可选链和空值合并
            const response = {
                id: user.id,
                name: user.name,
                email: user.email,
                profile: user.profile ?? null
            };
            
            // 处理include参数
            if (include) {
                const includes = include.split(',');
                if (includes.includes('posts')) {
                    response.posts = await user.getPosts();
                }
                if (includes.includes('comments')) {
                    response.comments = await user.getComments();
                }
            }
            
            res.json(response);
        } catch (error) {
            next(error);
        }
    }
);

// 使用解构和验证
router.post('/users',
    [
        body('name').trim().isLength({ min: 2, max: 50 }),
        body('email').isEmail().normalizeEmail(),
        body('age').optional().isInt({ min: 18, max: 120 })
    ],
    async (req, res, next) => {
        try {
            const errors = validationResult(req);
            if (!errors.isEmpty()) {
                return res.status(400).json({ errors: errors.array() });
            }
            
            const { name, email, age } = req.body;
            
            // 使用展开运算符
            const user = await User.create({
                name,
                email,
                age: age ?? 18,
                createdAt: new Date(),
                updatedAt: new Date()
            });
            
            res.status(201).json(user);
        } catch (error) {
            next(error);
        }
    }
);

export default router;

【代码注释】路由处理函数参数解构 req.body、默认配置 const、模板字符串拼错误信息。Node 模块默认严格模式(ESM)或 CommonJS 中手动 strict。

6.2 工具函数库开发

6.2.1 字符串处理工具
javascript 复制代码
// 【代码注释】封装校验、格式化、slug 生成等纯函数,便于单测。结合 `includes`/`replaceAll`/`padStart` 覆盖常见表单与展示需求。
class StringUtils {
    // 驼峰命名转换
    static toCamelCase(str) {
        return str
            .replace(/[-_\s]+(.)?/g, (_, char) => char ? char.toUpperCase() : '')
            .replace(/^(.)/, (char) => char.toLowerCase());
    }
    
    // 短横线命名转换
    static toKebabCase(str) {
        return str
            .replace(/([a-z])([A-Z])/g, '$1-$2')
            .replace(/[\s_]+/g, '-')
            .toLowerCase();
    }
    
    // 蛇形命名转换
    static toSnakeCase(str) {
        return str
            .replace(/([a-z])([A-Z])/g, '$1_$2')
            .replace(/[\s-]+/g, '_')
            .toLowerCase();
    }
    
    // 生成唯一ID
    static generateId(prefix = 'id') {
        const timestamp = Date.now().toString(36);
        const randomStr = Math.random().toString(36).substring(2, 8);
        return `${prefix}_${timestamp}_${randomStr}`;
    }
    
    // 截断文本
    static truncate(str, maxLength, suffix = '...') {
        if (str.length <= maxLength) return str;
        return str.substring(0, maxLength - suffix.length) + suffix;
    }
    
    // 移除HTML标签
    static stripHtml(html) {
        const tmp = document.createElement('div');
        tmp.innerHTML = html;
        return tmp.textContent || tmp.innerText || '';
    }
    
    // 高亮关键词
    static highlightKeywords(text, keywords, className = 'highlight') {
        let result = text;
        keywords.forEach(keyword => {
            const regex = new RegExp(`(${keyword})`, 'gi');
            result = result.replace(regex, `<span class="${className}">$1</span>`);
        });
        return result;
    }
}

// 使用示例
console.log(StringUtils.toCamelCase('hello-world-example')); // helloWorldExample
console.log(StringUtils.toKebabCase('helloWorldExample')); // hello-world-example
console.log(StringUtils.generateId('user')); // user_xxxxx_xxxxxx

【代码注释】封装校验、格式化、slug 生成等纯函数,便于单测。结合 includes/replaceAll/padStart 覆盖常见表单与展示需求。

6.2.2 数组处理工具
javascript 复制代码
// 【代码注释】解构、`...spread`、 `Array.from` 处理类数组与 immutable 更新模式。注意浅拷贝:嵌套对象仍需深拷贝或 Immer。
class ArrayUtils {
    // 数组去重
    static unique(arr, key = null) {
        if (key) {
            const seen = new Set();
            return arr.filter(item => {
                const keyValue = item[key];
                if (seen.has(keyValue)) {
                    return false;
                }
                seen.add(keyValue);
                return true;
            });
        }
        return [...new Set(arr)];
    }
    
    // 数组分组
    static groupBy(arr, key) {
        return arr.reduce((result, item) => {
            const groupKey = item[key];
            if (!result[groupKey]) {
                result[groupKey] = [];
            }
            result[groupKey].push(item);
            return result;
        }, {});
    }
    
    // 数组分块
    static chunk(arr, size) {
        const chunks = [];
        for (let i = 0; i < arr.length; i += size) {
            chunks.push(arr.slice(i, i + size));
        }
        return chunks;
    }
    
    // 数组排序
    static sortBy(arr, key, order = 'asc') {
        return [...arr].sort((a, b) => {
            const aVal = a[key];
            const bVal = b[key];
            
            if (aVal < bVal) return order === 'asc' ? -1 : 1;
            if (aVal > bVal) return order === 'asc' ? 1 : -1;
            return 0;
        });
    }
    
    // 数组随机
    static shuffle(arr) {
        const result = [...arr];
        for (let i = result.length - 1; i > 0; i--) {
            const j = Math.floor(Math.random() * (i + 1));
            [result[i], result[j]] = [result[j], result[i]];
        }
        return result;
    }
    
    // 数组差集
    static difference(arr1, arr2) {
        const set2 = new Set(arr2);
        return arr1.filter(item => !set2.has(item));
    }
    
    // 数组交集
    static intersection(arr1, arr2) {
        const set2 = new Set(arr2);
        return arr1.filter(item => set2.has(item));
    }
}

// 使用示例
const users = [
    { id: 1, name: '张三', age: 25 },
    { id: 2, name: '李四', age: 30 },
    { id: 3, name: '王五', age: 25 },
    { id: 4, name: '赵六', age: 30 }
];

console.log(ArrayUtils.groupBy(users, 'age'));
console.log(ArrayUtils.chunk([1, 2, 3, 4, 5], 2));
console.log(ArrayUtils.sortBy(users, 'age'));

【代码注释】解构、...spreadArray.from 处理类数组与 immutable 更新模式。注意浅拷贝:嵌套对象仍需深拷贝或 Immer。

6.3 性能优化技巧

6.3.1 内存优化
javascript 复制代码
// 【代码注释】块级变量及时失效利于 GC;避免闭包长期持有大对象。`const` 引用不变但对象过大时仍占内存;列表渲染用 key 与虚拟滚动而非全局 var。
class MemoryOptimizer {
    // 使用WeakMap避免内存泄漏
    static createCache() {
        const cache = new WeakMap();
        
        return {
            get(key) {
                return cache.get(key);
            },
            
            set(key, value) {
                cache.set(key, value);
                return this;
            },
            
            has(key) {
                return cache.has(key);
            },
            
            delete(key) {
                return cache.delete(key);
            }
        };
    }
    
    // 使用WeakRef处理大对象
    static processLargeObject(obj) {
        const weakRef = new WeakRef(obj);
        
        // 模拟异步处理
        setTimeout(() => {
            const result = weakRef.deref();
            if (result) {
                console.log('处理结果:', result);
            } else {
                console.log('对象已被回收');
            }
        }, 1000);
    }
    
    // 使用FinalizationRegistry清理资源
    static createResourceRegistry() {
        const registry = new FinalizationRegistry((heldValue) => {
            console.log('清理资源:', heldValue);
            // 清理逻辑
        });
        
        return {
            register(obj, resource) {
                registry.register(obj, resource, obj);
            },
            
            unregister(obj) {
                registry.unregister(obj);
            }
        };
    }
}

// 使用示例
const cache = MemoryOptimizer.createCache();
const key = { id: 1 };
cache.set(key, { data: '重要数据' });

【代码注释】块级变量及时失效利于 GC;避免闭包长期持有大对象。const 引用不变但对象过大时仍占内存;列表渲染用 key 与虚拟滚动而非全局 var。

6.3.2 异步操作优化
javascript 复制代码
// 【代码注释】Promise.all 与 let 块级绑定、解构取结果项组合;避免在循环里 `await` 串行除非必要。错误处理用 try/catch 或 `.catch`,解构 `{ success, result }` 统一返回形状。
class AsyncOptimizer {
    // 并发控制
    static async concurrentLimit(tasks, limit = 3) {
        const results = [];
        const executing = [];
        
        for (const task of tasks) {
            const promise = task().then(result => {
                executing.splice(executing.indexOf(promise), 1);
                return result;
            });
            
            results.push(promise);
            executing.push(promise);
            
            if (executing.length >= limit) {
                await Promise.race(executing);
            }
        }
        
        return Promise.all(results);
    }
    
    // 重试机制
    static async retry(fn, options = {}) {
        const {
            times = 3,
            delay = 1000,
            backoff = 2,
            condition = () => true
        } = options;
        
        let lastError;
        
        for (let i = 0; i < times; i++) {
            try {
                return await fn();
            } catch (error) {
                lastError = error;
                
                if (i < times - 1 && condition(error)) {
                    const waitTime = delay * Math.pow(backoff, i);
                    await new Promise(resolve => setTimeout(resolve, waitTime));
                }
            }
        }
        
        throw lastError;
    }
    
    // 超时控制
    static async timeout(promise, ms, message = '操作超时') {
        const timer = new Promise((_, reject) => {
            setTimeout(() => reject(new Error(message)), ms);
        });
        
        return Promise.race([promise, timer]);
    }
}

// 使用示例
const tasks = [
    () => fetch('/api/data1'),
    () => fetch('/api/data2'),
    () => fetch('/api/data3'),
    () => fetch('/api/data4'),
    () => fetch('/api/data5')
];

AsyncOptimizer.concurrentLimit(tasks, 2).then(results => {
    console.log('所有任务完成:', results);
});

【代码注释】Promise.all 与 let 块级绑定、解构取结果项组合;避免在循环里 await 串行除非必要。错误处理用 try/catch 或 .catch,解构 { success, result } 统一返回形状。

7. 知识点总结与对比

7.1 ES5 vs ES6+ 特性对比表

特性分类 ES5 ES6+ 优势
变量声明 var let, const 块级作用域、TDZ 强制先声明
字符串 单引号/双引号 模板字符串、String.raw 支持换行、变量插值、原始字符串
字符串访问 str[str.length-1] str.at(-1) 支持负索引,更简洁
函数 function关键字 箭头函数 简洁语法、this绑定
参数 默认参数缺失 默认参数、剩余参数 更灵活的参数处理
对象 对象字面量 解构、展开运算符 简化对象操作
数组 Array方法 解构、展开运算符 简化数组操作
属性访问 a && a.b && a.b.c a?.b?.c 可选链防 TypeError
默认值 `val default`
赋值默认值 `a = a b`(误伤 falsy)
对象不可变 Object.freeze(obj) const + deepFreeze 深度冻结配置/枚举常量
异步 回调函数 Promise、async/await 更优雅的异步处理
原型链 class关键字 更直观的面向对象编程
模块 无模块系统 import/export 原生模块支持
数据类型 5种基本类型 Symbol、BigInt 更丰富的数据类型
浮点精度 手动误差判断 Number.EPSILON 标准化误差常量

7.2 使用场景对比

#mermaid-svg-OkC0F2mBylUMvtYT{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-OkC0F2mBylUMvtYT .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-OkC0F2mBylUMvtYT .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-OkC0F2mBylUMvtYT .error-icon{fill:#552222;}#mermaid-svg-OkC0F2mBylUMvtYT .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-OkC0F2mBylUMvtYT .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-OkC0F2mBylUMvtYT .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-OkC0F2mBylUMvtYT .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-OkC0F2mBylUMvtYT .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-OkC0F2mBylUMvtYT .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-OkC0F2mBylUMvtYT .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-OkC0F2mBylUMvtYT .marker{fill:#333333;stroke:#333333;}#mermaid-svg-OkC0F2mBylUMvtYT .marker.cross{stroke:#333333;}#mermaid-svg-OkC0F2mBylUMvtYT svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-OkC0F2mBylUMvtYT p{margin:0;}#mermaid-svg-OkC0F2mBylUMvtYT .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-OkC0F2mBylUMvtYT .cluster-label text{fill:#333;}#mermaid-svg-OkC0F2mBylUMvtYT .cluster-label span{color:#333;}#mermaid-svg-OkC0F2mBylUMvtYT .cluster-label span p{background-color:transparent;}#mermaid-svg-OkC0F2mBylUMvtYT .label text,#mermaid-svg-OkC0F2mBylUMvtYT span{fill:#333;color:#333;}#mermaid-svg-OkC0F2mBylUMvtYT .node rect,#mermaid-svg-OkC0F2mBylUMvtYT .node circle,#mermaid-svg-OkC0F2mBylUMvtYT .node ellipse,#mermaid-svg-OkC0F2mBylUMvtYT .node polygon,#mermaid-svg-OkC0F2mBylUMvtYT .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-OkC0F2mBylUMvtYT .rough-node .label text,#mermaid-svg-OkC0F2mBylUMvtYT .node .label text,#mermaid-svg-OkC0F2mBylUMvtYT .image-shape .label,#mermaid-svg-OkC0F2mBylUMvtYT .icon-shape .label{text-anchor:middle;}#mermaid-svg-OkC0F2mBylUMvtYT .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-OkC0F2mBylUMvtYT .rough-node .label,#mermaid-svg-OkC0F2mBylUMvtYT .node .label,#mermaid-svg-OkC0F2mBylUMvtYT .image-shape .label,#mermaid-svg-OkC0F2mBylUMvtYT .icon-shape .label{text-align:center;}#mermaid-svg-OkC0F2mBylUMvtYT .node.clickable{cursor:pointer;}#mermaid-svg-OkC0F2mBylUMvtYT .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-OkC0F2mBylUMvtYT .arrowheadPath{fill:#333333;}#mermaid-svg-OkC0F2mBylUMvtYT .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-OkC0F2mBylUMvtYT .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-OkC0F2mBylUMvtYT .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-OkC0F2mBylUMvtYT .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-OkC0F2mBylUMvtYT .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-OkC0F2mBylUMvtYT .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-OkC0F2mBylUMvtYT .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-OkC0F2mBylUMvtYT .cluster text{fill:#333;}#mermaid-svg-OkC0F2mBylUMvtYT .cluster span{color:#333;}#mermaid-svg-OkC0F2mBylUMvtYT div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-OkC0F2mBylUMvtYT .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-OkC0F2mBylUMvtYT rect.text{fill:none;stroke-width:0;}#mermaid-svg-OkC0F2mBylUMvtYT .icon-shape,#mermaid-svg-OkC0F2mBylUMvtYT .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-OkC0F2mBylUMvtYT .icon-shape p,#mermaid-svg-OkC0F2mBylUMvtYT .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-OkC0F2mBylUMvtYT .icon-shape .label rect,#mermaid-svg-OkC0F2mBylUMvtYT .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-OkC0F2mBylUMvtYT .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-OkC0F2mBylUMvtYT .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-OkC0F2mBylUMvtYT :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} ES6+特性选择指南
变量声明
函数定义
异步处理
数据操作
const: 配置/常量
let: 可变变量
避免使用var
箭头函数: 回调/短函数
传统函数: 方法/构造函数
Promise: 链式异步
async/await: 顺序异步
解构: 数据提取
展开: 数组合并
模板字符串: 文本拼接

【代码注释】对照表从可读性、安全性、性能、兼容性四维给建议:新代码默认 let/const;多字段提取用解构;拼接用模板字符串;遗留环境走 Babel。决策树比死记语法更有长期价值。

7.3 最佳实践建议

7.3.1 变量声明规范
javascript 复制代码
// 【代码注释】默认 const,需要重新赋值再 let;禁止新代码 var。循环索引、累加器 let;配置与 import const。启用 ESLint `prefer-const`、`no-var`。
// ✅ 推荐:优先使用const
const CONFIG = {
    apiUrl: 'https://api.example.com',
    timeout: 5000
};

// ✅ 推荐:需要在循环中重新赋值时使用let
for (let i = 0; i < 10; i++) {
    console.log(i);
}

// ❌ 避免:不要使用var(除非有特殊需求)
var oldStyle = '避免使用';

// ✅ 推荐:在块级作用域中使用let/const
function processData(data) {
    const result = [];
    
    for (const item of data) {
        let processed = transform(item);
        result.push(processed);
    }
    
    return result;
}

【代码注释】默认 const,需要重新赋值再 let;禁止新代码 var。循环索引、累加器 let;配置与 import const。启用 ESLint prefer-constno-var

7.3.2 函数定义规范
javascript 复制代码
// 【代码注释】优先箭头函数作回调(不绑定 this);方法简写与解构参数减少样板代码。需要 `arguments` 对象或构造函数时用 function 声明。
// ✅ 推荐:简短回调使用箭头函数
const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map(n => n * 2);

// ✅ 推荐:对象方法使用传统函数
const calculator = {
    add(a, b) {
        return a + b;
    },
    
    subtract(a, b) {
        return a - b;
    }
};

// ✅ 推荐:复杂逻辑使用传统函数
function processUserData(userData) {
    // 复杂的处理逻辑
    let result = {};
    
    // 多行处理
    for (const [key, value] of Object.entries(userData)) {
        // ...
    }
    
    return result;
}

// ❌ 避免:不要在需要this上下文的地方使用箭头函数
const button = document.querySelector('button');
button.addEventListener('click', () => {
    console.log(this); // this不会指向button
});

【代码注释】优先箭头函数作回调(不绑定 this);方法简写与解构参数减少样板代码。需要 arguments 对象或构造函数时用 function 声明。

7.3.3 异步处理规范
javascript 复制代码
// 【代码注释】async/await 配合 try/catch;并发用 `Promise.all`/`allSettled`。解构 API 响应固定字段;错误对象 `{ code, message }` 统一解构处理。
// ✅ 推荐:使用async/await处理顺序异步
async function fetchUserData(userId) {
    try {
        const user = await fetch(`/api/users/${userId}`);
        const posts = await fetch(`/api/users/${userId}/posts`);
        const comments = await fetch(`/api/users/${userId}/comments`);
        
        return {
            user: await user.json(),
            posts: await posts.json(),
            comments: await comments.json()
        };
    } catch (error) {
        console.error('获取用户数据失败:', error);
        throw error;
    }
}

// ✅ 推荐:使用Promise.all处理并行异步
async function fetchAllUserIds() {
    try {
        const response = await fetch('/api/users');
        const users = await response.json();
        
        const userDetails = await Promise.all(
            users.map(user => fetch(`/api/users/${user.id}`))
        );
        
        return await Promise.all(userDetails.map(res => res.json()));
    } catch (error) {
        console.error('获取用户详情失败:', error);
        throw error;
    }
}

// ✅ 推荐:错误处理要全面
async function safeApiCall(url, options = {}) {
    try {
        const response = await fetch(url, {
            timeout: 5000,
            ...options
        });
        
        if (!response.ok) {
            throw new Error(`HTTP error! status: ${response.status}`);
        }
        
        return await response.json();
    } catch (error) {
        if (error.name === 'AbortError') {
            console.error('请求超时');
        } else if (error instanceof TypeError) {
            console.error('网络错误');
        } else {
            console.error('未知错误:', error);
        }
        throw error;
    }
}

【代码注释】async/await 配合 try/catch;并发用 Promise.all/allSettled。解构 API 响应固定字段;错误对象 { code, message } 统一解构处理。

7.4 性能对比与优化

7.4.1 性能对比
javascript 复制代码
// 【代码注释】微观基准中模板字符串与 `+` 差异通常可忽略;解构有轻微赋值成本但换来可维护性。热点路径再 profile,勿过早优化。
class PerformanceComparison {
    // 字符串拼接性能
    static stringConcatenation() {
        const iterations = 100000;
        let result = '';
        
        // 传统方式(慢)
        console.time('传统字符串拼接');
        for (let i = 0; i < iterations; i++) {
            result += 'item';
        }
        console.timeEnd('传统字符串拼接');
        
        // 数组join(快)
        console.time('数组join');
        const items = [];
        for (let i = 0; i < iterations; i++) {
            items.push('item');
        }
        result = items.join('');
        console.timeEnd('数组join');
        
        // 模板字符串(中等)
        console.time('模板字符串');
        result = '';
        for (let i = 0; i < iterations; i++) {
            result = `${result}item`;
        }
        console.timeEnd('模板字符串');
    }
    
    // 数组遍历性能
    static arrayIteration() {
        const largeArray = Array.from({ length: 1000000 }, (_, i) => i);
        
        // 传统for循环(最快)
        console.time('传统for循环');
        let sum = 0;
        for (let i = 0; i < largeArray.length; i++) {
            sum += largeArray[i];
        }
        console.timeEnd('传统for循环');
        
        // forEach(中等)
        console.time('forEach');
        sum = 0;
        largeArray.forEach(item => {
            sum += item;
        });
        console.timeEnd('forEach');
        
        // reduce(较慢)
        console.time('reduce');
        sum = largeArray.reduce((acc, item) => acc + item, 0);
        console.timeEnd('reduce');
        
        // for...of(慢)
        console.time('for...of');
        sum = 0;
        for (const item of largeArray) {
            sum += item;
        }
        console.timeEnd('for...of');
    }
}

【代码注释】微观基准中模板字符串与 + 差异通常可忽略;解构有轻微赋值成本但换来可维护性。热点路径再 profile,勿过早优化。

7.5 兼容性处理

7.5.1 转译和Polyfill
javascript 复制代码
// 【代码注释】Babel 转译语法(let/class/解构);core-js 等 polyfill 补 API(Promise、Object.assign)。按 browserslist 决定垫片范围;`<script type="module">` 天然严格模式。
// 使用Babel转译
// 转译前
const arrowFunction = () => {
    console.log('箭头函数');
};

// 转译后
var arrowFunction = function arrowFunction() {
    console.log('箭头函数');
};

// 使用Polyfill
// 检测并添加缺失的方法
if (!String.prototype.includes) {
    String.prototype.includes = function(search, start) {
        if (typeof start !== 'number') {
            start = 0;
        }
        
        if (start + search.length > this.length) {
            return false;
        } else {
            return this.indexOf(search, start) !== -1;
        }
    };
}

// 现代化的兼容性检测
class FeatureDetection {
    static supportsES6() {
        try {
            // 检测箭头函数
            eval('const arrow = () => true');
            
            // 检测let/const
            eval('let x = 1');
            eval('const y = 1');
            
            // 检测解构
            eval('const {a} = {a: 1}');
            eval('const [b] = [1]');
            
            // 检测模板字符串
            eval('const template = `test`');
            
            return true;
        } catch (e) {
            return false;
        }
    }
    
    static getBrowserCompatibility() {
        return {
            arrowFunctions: this.supportsES6(),
            templateLiterals: this.supportsES6(),
            destructuring: this.supportsES6(),
            promises: typeof Promise !== 'undefined',
            map: typeof Map !== 'undefined',
            set: typeof Set !== 'undefined',
            weakMap: typeof WeakMap !== 'undefined',
            weakSet: typeof WeakSet !== 'undefined',
            symbol: typeof Symbol !== 'undefined',
            proxy: typeof Proxy !== 'undefined'
        };
    }
}

【代码注释】Babel 转译语法(let/class/解构);core-js 等 polyfill 补 API(Promise、Object.assign)。按 browserslist 决定垫片范围;<script type="module"> 天然严格模式。

8. Day01 知识点速查与归纳

8.1 一句话记忆卡

模块 核心要点
严格模式 'use strict' 消灭隐式全局、非法字面量等静默错误
let 不提升(TDZ)、不重复声明、块级作用域、非 window 属性
TDZ let/const 提升后标记 <uninitialized>,访问即 ReferenceError
const 同 let 作用域规则 + 绑定不可重新赋值
数组解构 按索引匹配;可交换变量、函数形参、解构伪数组
对象解构 按属性名匹配;可重命名、默认值、嵌套
for...of + 解构 遍历 Map/Object.entries 时同时拆包 [key, value]
模板字符串 反引号 + 换行 + ${表达式};标签模板用于 XSS 防护、i18n
字符串方法 查找用 includes;对齐用 pad;清洗用 trim;新 at(-1) 负索引
String.raw 内置标签函数,返回不处理转义的原始字符串(Windows 路径必备)
数值 0b/0o 字面量、**BigInt、数字分隔符 _
浮点精度 0.1+0.2 ≠ 0.3;用 Number.EPSILON 或"转分运算"解决
可选链 ?. 链式访问中遇 null/undefined 短路返回 undefined,防 TypeError
空值合并 ?? 仅 null/undefined 触发默认值,0/''/false 不受影响
逻辑赋值 ??= 仅 nullish 时才赋值(最安全的懒初始化 / 配置合并方式)
逻辑赋值 `
逻辑赋值 &&= truthy 时才赋值,条件更新对象属性且不触发不必要的 setter
Object.freeze 冻结对象顶层属性;配合 deepFreeze 实现枚举常量/配置深度不可变

8.2 Day01 知识关系总图

#mermaid-svg-3mb4HAxEb9iD3o0W{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-3mb4HAxEb9iD3o0W .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-3mb4HAxEb9iD3o0W .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-3mb4HAxEb9iD3o0W .error-icon{fill:#552222;}#mermaid-svg-3mb4HAxEb9iD3o0W .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-3mb4HAxEb9iD3o0W .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-3mb4HAxEb9iD3o0W .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-3mb4HAxEb9iD3o0W .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-3mb4HAxEb9iD3o0W .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-3mb4HAxEb9iD3o0W .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-3mb4HAxEb9iD3o0W .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-3mb4HAxEb9iD3o0W .marker{fill:#333333;stroke:#333333;}#mermaid-svg-3mb4HAxEb9iD3o0W .marker.cross{stroke:#333333;}#mermaid-svg-3mb4HAxEb9iD3o0W svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-3mb4HAxEb9iD3o0W p{margin:0;}#mermaid-svg-3mb4HAxEb9iD3o0W .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-3mb4HAxEb9iD3o0W .cluster-label text{fill:#333;}#mermaid-svg-3mb4HAxEb9iD3o0W .cluster-label span{color:#333;}#mermaid-svg-3mb4HAxEb9iD3o0W .cluster-label span p{background-color:transparent;}#mermaid-svg-3mb4HAxEb9iD3o0W .label text,#mermaid-svg-3mb4HAxEb9iD3o0W span{fill:#333;color:#333;}#mermaid-svg-3mb4HAxEb9iD3o0W .node rect,#mermaid-svg-3mb4HAxEb9iD3o0W .node circle,#mermaid-svg-3mb4HAxEb9iD3o0W .node ellipse,#mermaid-svg-3mb4HAxEb9iD3o0W .node polygon,#mermaid-svg-3mb4HAxEb9iD3o0W .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-3mb4HAxEb9iD3o0W .rough-node .label text,#mermaid-svg-3mb4HAxEb9iD3o0W .node .label text,#mermaid-svg-3mb4HAxEb9iD3o0W .image-shape .label,#mermaid-svg-3mb4HAxEb9iD3o0W .icon-shape .label{text-anchor:middle;}#mermaid-svg-3mb4HAxEb9iD3o0W .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-3mb4HAxEb9iD3o0W .rough-node .label,#mermaid-svg-3mb4HAxEb9iD3o0W .node .label,#mermaid-svg-3mb4HAxEb9iD3o0W .image-shape .label,#mermaid-svg-3mb4HAxEb9iD3o0W .icon-shape .label{text-align:center;}#mermaid-svg-3mb4HAxEb9iD3o0W .node.clickable{cursor:pointer;}#mermaid-svg-3mb4HAxEb9iD3o0W .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-3mb4HAxEb9iD3o0W .arrowheadPath{fill:#333333;}#mermaid-svg-3mb4HAxEb9iD3o0W .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-3mb4HAxEb9iD3o0W .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-3mb4HAxEb9iD3o0W .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-3mb4HAxEb9iD3o0W .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-3mb4HAxEb9iD3o0W .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-3mb4HAxEb9iD3o0W .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-3mb4HAxEb9iD3o0W .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-3mb4HAxEb9iD3o0W .cluster text{fill:#333;}#mermaid-svg-3mb4HAxEb9iD3o0W .cluster span{color:#333;}#mermaid-svg-3mb4HAxEb9iD3o0W div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-3mb4HAxEb9iD3o0W .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-3mb4HAxEb9iD3o0W rect.text{fill:none;stroke-width:0;}#mermaid-svg-3mb4HAxEb9iD3o0W .icon-shape,#mermaid-svg-3mb4HAxEb9iD3o0W .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-3mb4HAxEb9iD3o0W .icon-shape p,#mermaid-svg-3mb4HAxEb9iD3o0W .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-3mb4HAxEb9iD3o0W .icon-shape .label rect,#mermaid-svg-3mb4HAxEb9iD3o0W .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-3mb4HAxEb9iD3o0W .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-3mb4HAxEb9iD3o0W .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-3mb4HAxEb9iD3o0W :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 文本与数值
数据处理
基础
严格模式
let
const
块级作用域
数组解构
对象解构
模板字符串
字符串新方法
数值扩展

【代码注释】依赖图强调前置关系:不理解 TDZ 则解构默认值中的引用易错;不熟模板字符串则后续框架插值难对应源码。复习时可沿箭头自测每节点能否口述 + 写 5 行示例。

8.3 示例索引(完整可运行 HTML)

主题 章节锚点
ES5 严格模式 [2.0](#主题 章节锚点 ES5 严格模式 2.0 let 关键字 2.4.1 TDZ 底层机制 2.1.2.1 块级作用域与列表点击 2.4.2 const 常量 2.4.3 数组解构 3.3.1 对象解构 3.3.2 for…of + 解构 3.2.3.1 模板字符串与列表渲染 4.3.1 字符串新方法 4.3.2 String.at() / String.raw 4.2.4.1 浮点精度 Number.EPSILON 5.2.2.1 可选链 ?. 与 ?? 5.7 逻辑赋值 ??= /
let 关键字 [2.4.1](#主题 章节锚点 ES5 严格模式 2.0 let 关键字 2.4.1 TDZ 底层机制 2.1.2.1 块级作用域与列表点击 2.4.2 const 常量 2.4.3 数组解构 3.3.1 对象解构 3.3.2 for…of + 解构 3.2.3.1 模板字符串与列表渲染 4.3.1 字符串新方法 4.3.2 String.at() / String.raw 4.2.4.1 浮点精度 Number.EPSILON 5.2.2.1 可选链 ?. 与 ?? 5.7 逻辑赋值 ??= /
TDZ 底层机制 [2.1.2.1](#主题 章节锚点 ES5 严格模式 2.0 let 关键字 2.4.1 TDZ 底层机制 2.1.2.1 块级作用域与列表点击 2.4.2 const 常量 2.4.3 数组解构 3.3.1 对象解构 3.3.2 for…of + 解构 3.2.3.1 模板字符串与列表渲染 4.3.1 字符串新方法 4.3.2 String.at() / String.raw 4.2.4.1 浮点精度 Number.EPSILON 5.2.2.1 可选链 ?. 与 ?? 5.7 逻辑赋值 ??= /
块级作用域与列表点击 [2.4.2](#主题 章节锚点 ES5 严格模式 2.0 let 关键字 2.4.1 TDZ 底层机制 2.1.2.1 块级作用域与列表点击 2.4.2 const 常量 2.4.3 数组解构 3.3.1 对象解构 3.3.2 for…of + 解构 3.2.3.1 模板字符串与列表渲染 4.3.1 字符串新方法 4.3.2 String.at() / String.raw 4.2.4.1 浮点精度 Number.EPSILON 5.2.2.1 可选链 ?. 与 ?? 5.7 逻辑赋值 ??= /
const 常量 [2.4.3](#主题 章节锚点 ES5 严格模式 2.0 let 关键字 2.4.1 TDZ 底层机制 2.1.2.1 块级作用域与列表点击 2.4.2 const 常量 2.4.3 数组解构 3.3.1 对象解构 3.3.2 for…of + 解构 3.2.3.1 模板字符串与列表渲染 4.3.1 字符串新方法 4.3.2 String.at() / String.raw 4.2.4.1 浮点精度 Number.EPSILON 5.2.2.1 可选链 ?. 与 ?? 5.7 逻辑赋值 ??= /
数组解构 [3.3.1](#主题 章节锚点 ES5 严格模式 2.0 let 关键字 2.4.1 TDZ 底层机制 2.1.2.1 块级作用域与列表点击 2.4.2 const 常量 2.4.3 数组解构 3.3.1 对象解构 3.3.2 for…of + 解构 3.2.3.1 模板字符串与列表渲染 4.3.1 字符串新方法 4.3.2 String.at() / String.raw 4.2.4.1 浮点精度 Number.EPSILON 5.2.2.1 可选链 ?. 与 ?? 5.7 逻辑赋值 ??= /
对象解构 [3.3.2](#主题 章节锚点 ES5 严格模式 2.0 let 关键字 2.4.1 TDZ 底层机制 2.1.2.1 块级作用域与列表点击 2.4.2 const 常量 2.4.3 数组解构 3.3.1 对象解构 3.3.2 for…of + 解构 3.2.3.1 模板字符串与列表渲染 4.3.1 字符串新方法 4.3.2 String.at() / String.raw 4.2.4.1 浮点精度 Number.EPSILON 5.2.2.1 可选链 ?. 与 ?? 5.7 逻辑赋值 ??= /
for...of + 解构 [3.2.3.1](#主题 章节锚点 ES5 严格模式 2.0 let 关键字 2.4.1 TDZ 底层机制 2.1.2.1 块级作用域与列表点击 2.4.2 const 常量 2.4.3 数组解构 3.3.1 对象解构 3.3.2 for…of + 解构 3.2.3.1 模板字符串与列表渲染 4.3.1 字符串新方法 4.3.2 String.at() / String.raw 4.2.4.1 浮点精度 Number.EPSILON 5.2.2.1 可选链 ?. 与 ?? 5.7 逻辑赋值 ??= /
模板字符串与列表渲染 [4.3.1](#主题 章节锚点 ES5 严格模式 2.0 let 关键字 2.4.1 TDZ 底层机制 2.1.2.1 块级作用域与列表点击 2.4.2 const 常量 2.4.3 数组解构 3.3.1 对象解构 3.3.2 for…of + 解构 3.2.3.1 模板字符串与列表渲染 4.3.1 字符串新方法 4.3.2 String.at() / String.raw 4.2.4.1 浮点精度 Number.EPSILON 5.2.2.1 可选链 ?. 与 ?? 5.7 逻辑赋值 ??= /
字符串新方法 [4.3.2](#主题 章节锚点 ES5 严格模式 2.0 let 关键字 2.4.1 TDZ 底层机制 2.1.2.1 块级作用域与列表点击 2.4.2 const 常量 2.4.3 数组解构 3.3.1 对象解构 3.3.2 for…of + 解构 3.2.3.1 模板字符串与列表渲染 4.3.1 字符串新方法 4.3.2 String.at() / String.raw 4.2.4.1 浮点精度 Number.EPSILON 5.2.2.1 可选链 ?. 与 ?? 5.7 逻辑赋值 ??= /
String.at() / String.raw [4.2.4.1](#主题 章节锚点 ES5 严格模式 2.0 let 关键字 2.4.1 TDZ 底层机制 2.1.2.1 块级作用域与列表点击 2.4.2 const 常量 2.4.3 数组解构 3.3.1 对象解构 3.3.2 for…of + 解构 3.2.3.1 模板字符串与列表渲染 4.3.1 字符串新方法 4.3.2 String.at() / String.raw 4.2.4.1 浮点精度 Number.EPSILON 5.2.2.1 可选链 ?. 与 ?? 5.7 逻辑赋值 ??= /
浮点精度 Number.EPSILON [5.2.2.1](#主题 章节锚点 ES5 严格模式 2.0 let 关键字 2.4.1 TDZ 底层机制 2.1.2.1 块级作用域与列表点击 2.4.2 const 常量 2.4.3 数组解构 3.3.1 对象解构 3.3.2 for…of + 解构 3.2.3.1 模板字符串与列表渲染 4.3.1 字符串新方法 4.3.2 String.at() / String.raw 4.2.4.1 浮点精度 Number.EPSILON 5.2.2.1 可选链 ?. 与 ?? 5.7 逻辑赋值 ??= /
可选链 ?.?? [5.7](#主题 章节锚点 ES5 严格模式 2.0 let 关键字 2.4.1 TDZ 底层机制 2.1.2.1 块级作用域与列表点击 2.4.2 const 常量 2.4.3 数组解构 3.3.1 对象解构 3.3.2 for…of + 解构 3.2.3.1 模板字符串与列表渲染 4.3.1 字符串新方法 4.3.2 String.at() / String.raw 4.2.4.1 浮点精度 Number.EPSILON 5.2.2.1 可选链 ?. 与 ?? 5.7 逻辑赋值 ??= /
逻辑赋值 ??= / `
const + deepFreeze 不可变对象 [2.2.5](#主题 章节锚点 ES5 严格模式 2.0 let 关键字 2.4.1 TDZ 底层机制 2.1.2.1 块级作用域与列表点击 2.4.2 const 常量 2.4.3 数组解构 3.3.1 对象解构 3.3.2 for…of + 解构 3.2.3.1 模板字符串与列表渲染 4.3.1 字符串新方法 4.3.2 String.at() / String.raw 4.2.4.1 浮点精度 Number.EPSILON 5.2.2.1 可选链 ?. 与 ?? 5.7 逻辑赋值 ??= /
标签模板:styled-components / GraphQL / SQL [4.1.3 用法四](#主题 章节锚点 ES5 严格模式 2.0 let 关键字 2.4.1 TDZ 底层机制 2.1.2.1 块级作用域与列表点击 2.4.2 const 常量 2.4.3 数组解构 3.3.1 对象解构 3.3.2 for…of + 解构 3.2.3.1 模板字符串与列表渲染 4.3.1 字符串新方法 4.3.2 String.at() / String.raw 4.2.4.1 浮点精度 Number.EPSILON 5.2.2.1 可选链 ?. 与 ?? 5.7 逻辑赋值 ??= /

8.4 选型速查:何时用哪一项

渲染错误: Mermaid 渲染失败: Parse error on line 15: ...级,'' 也算空| NCA2逻辑赋值 \|\|= N -->|仅值存在时才更 -----------------------^ Expecting 'SQE', 'TAGEND', 'UNICODE_TEXT', 'TEXT', 'TAGSTART', got 'PIPE'

【代码注释】决策流:可变用 let、固定引用用 const、配置枚举用 deepFreeze;有序数据数组解构、配置对象用对象解构;多行/插值用模板字符串、DSL/XSS 防护用标签模板;深层属性访问用 ?.,设默认值用 ??,赋默认值用 ??=/||=/&&=;浮点比较用 Number.EPSILON

结语

ES6+为JavaScript带来了革命性的变化,不仅提升了语言的表达能力,还大大改善了开发体验。通过掌握这些新特性,开发者可以:

  1. 编写更安全、更可靠的代码:块级作用域、常量、新的数据类型
  2. 提高开发效率:解构赋值、模板字符串、箭头函数
  3. 更好地处理异步操作:Promise、async/await
  4. 构建更复杂的应用:类、模块、新的数据结构

在实际开发中,建议:

  • 优先使用const和let,避免var
  • 合理使用解构赋值,简化代码
  • 充分利用模板字符串,提高可读性
  • 善用异步处理新特性,避免回调地狱
  • 关注性能和兼容性,合理选择转译工具

随着JavaScript生态的不断发展,ES6+特性已成为现代前端开发的基础技能。持续学习和实践这些特性,将帮助开发者构建更加优雅、高效的应用程序。


参考资源:

持续学习资源:

希望这份ES6+专业指南能够帮助您更好地理解和应用现代JavaScript特性!

相关推荐
lichenyang4531 小时前
鸿蒙 MVVM 实战:从 Demo 到工程化,聊聊登录、状态管理与埋点系统设计
前端
IT_陈寒2 小时前
Vite打包时遇到的坑,原来问题出在这里
前端·人工智能·后端
kyriewen2 小时前
AI生成代码快如闪电,但我修了三个小时——它到底帮了谁?
前端·javascript·ai编程
竹林8183 小时前
用 wagmi v2 和 viem 手写 NFT 市场批量上架功能,我踩遍了所有异步坑
javascript
ayqy贾杰3 小时前
基层管理的三板斧,在AI时代行不通了
前端·后端·团队管理
Apifox3 小时前
Apifox 5 月更新|Postman 导入优化、Runner 支持非 root 运行、请求代码自动带鉴权
前端·后端·安全
zithern_juejin3 小时前
数组扁平化
javascript
清溪5493 小时前
n8n表达式沙箱逃逸至RCE漏洞-CVE-2025-68613复现
javascript·安全
miaowmiaow3 小时前
PSD2Code 近期更新与深度解析:从设计稿到生产级代码的完整技术栈
前端·人工智能·ai编程