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
实际应用场景
-
数据私有化
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 -
事件处理封装
function setupButton(buttonId) { let clickCount = 0; const btn = document.getElementById(buttonId); btn.addEventListener(\'click\', () => { clickCount++; btn.textContent = `点击了 ${clickCount} 次`; });}setupButton(\'myBtn\');
⚠️ 注意事项
-
闭包会导致外部函数变量无法被GC回收
-
过度使用可能导致内存泄漏
-
在循环中创建闭包需谨慎
二、变量提升
核心机制
var声明的变量会被提升到当前作用域顶部
只提升声明,不提升赋值
代码示例
console.log(name); // undefined(不会报错)var name = \'小明\';console.log(name); // \'小明\'// 实际执行顺序:// var name; // 声明提升// console.log(name); // undefined// name = \'小明\'; // 赋值// console.log(name); // \'小明\'
不同声明方式对比
varletconst❗ 最佳实践
-
始终使用
let和const -
避免使用
var -
声明放在作用域顶部
三、函数提升
函数声明 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!\');}
⚠️ 注意事项
-
函数声明整体提升(包括函数体)
-
函数表达式仅提升变量声明(类似var)
-
避免在块内使用函数声明(行为不一致)
四、函数参数
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 }
⚠️ 注意事项
-
展开运算符实现的是浅拷贝
-
对象展开是ES2018新增特性
-
字符串也可展开:
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)
✅ 高级特性核心要点总结

📝 高频面试题速答
-
Q:什么是闭包?有什么作用?
A:闭包是内层函数+外层变量,用于数据封装和私有化
-
Q:let/const 和 var 的主要区别?
A:let/const有块作用域且不提升,var有函数作用域且会提升
-
Q:剩余参数和 arguments 的区别?
A:剩余参数是真数组,arguments是伪数组
-
Q:展开运算符的主要用途?
A:展开数组/对象,用于函数传参、数组合并、对象合并等
-
Q:函数声明和函数表达式的区别?
A:函数声明会提升,函数表达式不会提升
🧠 记忆口诀
\"闭包封数据,提升要小心,三点神通广\"
闭包:封装数据实现私有化
提升:var和函数声明会提升
三点:
...既是剩余参数也是展开运算符


