> 技术文档 > JavaScript进阶篇——第二章 高级特性核心

JavaScript进阶篇——第二章 高级特性核心

目录

一、闭包

二、变量提升

三、函数提升

四、函数参数

1. 动态参数 (arguments)

2. 剩余参数 (...rest)

五、展开运算符

六、剩余参数 vs 展开运算符


本文摘要:JavaScript核心概念解析,包含闭包、变量/函数提升、函数参数及展开运算符。闭包由内层函数和外层变量组成,用于数据封装;变量提升仅var存在,let/const有块级作用域;函数声明会整体提升。函数参数处理中,剩余参数(...rest)替代arguments更实用。展开运算符(...)用于数组/对象展开、合并等场景。关键区别:let/const无提升,剩余参数是真数组,展开运算符实现浅拷贝。记忆口诀:\"闭包封数据,提升要小心,三点神通广\"概括核心要点。

一、闭包

核心概念

闭包 = 内层函数 + 外层函数的变量
内层函数可以访问外层函数作用域中的变量

基本结构

function outer() { // 外层函数变量 const a = 1; // 内层函数(闭包) function inner() { console.log(a); // 访问外层变量 } return inner;}const closure = outer();closure(); // 输出 1

简约写法

function counter() { let count = 0; return function() { count++; console.log(`调用次数: ${count}`); };}const increment = counter();increment(); // 调用次数: 1increment(); // 调用次数: 2

实际应用场景

  1. 数据私有化

    function createBankAccount(initial) { let balance = initial; // 私有变量 return { deposit: (amount) => balance += amount, withdraw: (amount) => balance -= amount, getBalance: () => balance };}const account = createBankAccount(1000);account.deposit(500);console.log(account.getBalance()); // 1500// 无法直接访问 balance
  2. 事件处理封装

    function setupButton(buttonId) { let clickCount = 0; const btn = document.getElementById(buttonId); btn.addEventListener(\'click\', () => { clickCount++; btn.textContent = `点击了 ${clickCount} 次`; });}setupButton(\'myBtn\');

⚠️ 注意事项

  1. 闭包会导致外部函数变量无法被GC回收

  2. 过度使用可能导致内存泄漏

  3. 在循环中创建闭包需谨慎


二、变量提升

核心机制

var 声明的变量会被提升到当前作用域顶部
只提升声明,不提升赋值

代码示例

console.log(name); // undefined(不会报错)var name = \'小明\';console.log(name); // \'小明\'// 实际执行顺序:// var name; // 声明提升// console.log(name); // undefined// name = \'小明\'; // 赋值// console.log(name); // \'小明\'

不同声明方式对比

声明方式 变量提升 块作用域 重复声明 初始值 var ✅ ❌ ✅ undefined let ❌ ✅ ❌ 未初始化 const ❌ ✅ ❌ 必须赋值

❗ 最佳实践

  1. 始终使用 let 和 const

  2. 避免使用 var

  3. 声明放在作用域顶部


三、函数提升

函数声明 vs 函数表达式

类型 提升 调用时机 示例 函数声明 ✅ 声明前后均可调用 function foo() {} 函数表达式 ❌ 赋值后调用 const bar = function() {}

代码示例

// 函数声明(可提升)sayHello(); // ✅ 正常执行function sayHello() { console.log(\'Hello!\');}// 函数表达式(不提升)try { sayHi(); // ❌ 报错} catch(e) { console.error(e); // TypeError: sayHi is not a function}const sayHi = function() { console.log(\'Hi!\');}

⚠️ 注意事项

  1. 函数声明整体提升(包括函数体)

  2. 函数表达式仅提升变量声明(类似var)

  3. 避免在块内使用函数声明(行为不一致)


四、函数参数

1. 动态参数 (arguments)

函数内部伪数组,包含所有传入的实参

function sum() { let total = 0; for(let i = 0; i < arguments.length; i++) { total += arguments[i]; } return total;}console.log(sum(1, 2, 3)); // 6console.log(sum(10, 20)); // 30
特点:
  • 伪数组(有length,无数组方法)

  • 箭头函数不可用

  • 不推荐使用(被剩余参数替代)

2. 剩余参数 (...rest)

将多余实参收集到真数组

function config(baseURL, ...other) { console.log(\'基础URL:\', baseURL); console.log(\'其他参数:\', other);}config(\'https://api.com\', \'GET\', \'json\', true);/* 输出:基础URL: https://api.com其他参数: [\'GET\', \'json\', true]*/
优势:
  • 真数组(可使用所有数组方法)

  • 清晰区分必需参数和可选参数

  • 箭头函数可用


五、展开运算符

核心功能

将数组展开为逗号分隔的元素序列

应用场景

// 1. 求数组最大/最小值const scores = [95, 89, 72, 100];console.log(Math.max(...scores)); // 100console.log(Math.min(...scores)); // 72// 2. 合并数组const arr1 = [1, 2];const arr2 = [3, 4];const combined = [...arr1, ...arr2, 5];console.log(combined); // [1, 2, 3, 4, 5]// 3. 复制数组const original = [10, 20];const copy = [...original]; // 浅拷贝// 4. 函数参数传递const points = [5, 10, 15];function plot(x, y, z) { console.log(`坐标: (${x},${y},${z})`);}plot(...points); // 坐标: (5,10,15)// 5. 对象展开(ES2018+)const obj1 = { a: 1, b: 2 };const obj2 = { ...obj1, c: 3 }; // { a:1, b:2, c:3 }

⚠️ 注意事项

  1. 展开运算符实现的是浅拷贝

  2. 对象展开是ES2018新增特性

  3. 字符串也可展开:console.log(...\'hello\') // h e l l o


六、剩余参数 vs 展开运算符

对比解析

特性 剩余参数 展开运算符 语法位置 函数参数列表 数组/对象字面量 主要功能 收集多余参数为数组 展开数组/对象为元素序列 符号 ... 在形参前 ... 在数组/对象前 结果类型 数组 逗号分隔序列 典型场景 函数定义中处理不定数量参数 函数调用、数组合并、对象合并

代码示例

// 剩余参数(收集)function collect(a, b, ...rest) { console.log(rest);}collect(1, 2, 3, 4); // [3, 4]// 展开运算符(展开)const nums = [3, 4];collect(1, 2, ...nums); // [3, 4] 等价于 collect(1,2,3,4)

✅ 高级特性核心要点总结

📝 高频面试题速答

  1. Q:什么是闭包?有什么作用?

    A:闭包是内层函数+外层变量,用于数据封装和私有化

  2. Q:let/const 和 var 的主要区别?

    A:let/const有块作用域且不提升,var有函数作用域且会提升

  3. Q:剩余参数和 arguments 的区别?

    A:剩余参数是真数组,arguments是伪数组

  4. Q:展开运算符的主要用途?

    A:展开数组/对象,用于函数传参、数组合并、对象合并等

  5. Q:函数声明和函数表达式的区别?

    A:函数声明会提升,函数表达式不会提升


🧠 记忆口诀

\"闭包封数据,提升要小心,三点神通广\"

  • 闭包:封装数据实现私有化

  • 提升:var和函数声明会提升

  • 三点... 既是剩余参数也是展开运算符