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特性!

相关推荐
To_OC5 小时前
别再串行写 await 了,Promise.all 才是并行请求的正确打开方式
前端·javascript·promise
To_OC5 小时前
LC 17 电话号码的字母组合:我的回溯算法,就是从这道题开窍的
javascript·算法·leetcode
vipbic5 小时前
中后台越做越乱后,我用插件化把它救回来了
前端·vue.js
Hyyy5 小时前
Computer Use 适合做什么,不适合做什么——一次真实使用后的思考
前端
小和尚同志6 小时前
前端 AI 单元测试思考与落地
前端·人工智能·aigc
invicinble7 小时前
c端系统,其实更像一个信息展示平台
前端
你怎么知道我是队长7 小时前
JavaScript的变量和数据类型介绍
开发语言·javascript·ecmascript
李姆斯7 小时前
管理是否可以被完全量化
前端·产品经理·团队管理
名字还没想好☜8 小时前
Next.js 中间件实战:鉴权、重定向与 A/B 分流
开发语言·前端·javascript·中间件·react·next.js
广州灵眸科技有限公司8 小时前
瑞芯微RV1126B开发板(EASY-EAI-PI2) INI文件操作
java·前端·javascript·网络·人工智能