在 JavaScript 中如果说 循环 是代码的“重复能力”那 函数和作用域 就是代码的“组织能力”。函数让代码可复用作用域让变量可控。绝大多数 JS 疑难问题、面试题、bug 来源变量污染、变量提升、闭包、全局污染、变量找不到、函数执行顺序混乱根源全部来自函数与作用域。今天这篇文章我从零到一细致拆解函数的所有种类、使用细节、作用域分层、变量查找规则、生命周期、经典坑点一次性彻底学通透。一、什么是 JS 函数核心本质函数就是一段可以重复调用、具备独立功能的代码块。函数的出现就是为了解决一个问题代码重复、冗余、难维护。函数三要素函数名、参数、返回值。函数名标记函数用于调用参数外部传入的数据让函数更灵活返回值 return函数执行完对外输出结果二、JS 函数的 4 种写法细节区别很多新手只会一种函数写法但实际开发中四种写法机制完全不同提升、调用时机、this 指向全部不一样。函数声明最常用、支持提升标准的 function 函数名(){} 写法。function fn() {console.log(‘我是函数声明’)}核心细节支持 变量提升可以 先调用后定义有函数名可递归、可监听堆栈适合封装通用工具函数函数表达式匿名函数赋值把匿名函数赋值给变量。const fn function() {console.log(‘函数表达式’)}核心细节不提升必须先定义、后调用更严谨防止全局函数泛滥开发中使用频率极高箭头函数ES6 最简写法const fn () {console.log(‘箭头函数’)}关键特性面试必考无自己的 this继承上层作用域 this无 arguments不能作为构造函数 new极简语法适合回调、遍历、简单逻辑立即执行函数IIFE(function(){// 立即执行执行完销毁})()作用制造独立作用域防止变量污染全局ES6 之前唯一模块化方案三、函数参数的详细规则超多新手坑形参和实参形参函数定义时的占位变量实参调用函数时传入的真实数据参数个数不匹配规则实参多于形参多余参数自动忽略实参少于形参缺少的形参值为 undefined默认参数function fn(a 10) {console.log(a)}剩余参数 …收集多个参数function fn(…args) {console.log(args) // 数组形式接收所有参数}替代废弃的 arguments开发首选。四、函数返回值 return 细节return 终止函数执行后面代码不再运行没有 return 的函数默认返回 undefinedreturn 可以返回任意类型基本数据、数组、对象、甚至另一个函数闭包基础五、JS 作用域完整详解核心重点作用域变量可以生效、可以被访问的范围。JS 作用域分为三层全局作用域、函数作用域、块级作用域。全局作用域页面打开就存在关闭页面才销毁。所有在 函数外、代码最外层 定义的变量属于全局变量。缺点全局变量过多容易 变量污染、命名冲突。函数作用域函数内部定义的变量外部无法访问。function fn() {let a 10}console.log(a) // 报错a 未定义优点变量私有化不会污染全局块级作用域ES6 核心被 {} 包裹的代码块if、for、while、switch。let / const 才有块级作用域var 没有。if(true){let b 20}console.log(b) // 访问不到六、变量查找规则作用域链重中之重作用域链内层向外层逐层查找变量的机制查找规则一句话就近原则从内向外找到即停找不到报错let num 100function outer() {let num 200function inner() {console.log(num) // 输出 200}inner()}outer()查找流程先在当前作用域找没有就去父作用域一直找到全局作用域全局都没有 → Uncaught ReferenceError七、变量提升机制为什么函数声明可以先调用提升规则var 变量提升声明值为 undefinedfunction 函数声明整体提升可以先调用后定义let / const / 箭头函数表达式不提升存在暂时性死区经典对比fn1() // 正常执行function fn1(){}fn2() // 报错const fn2 function(){}八、作用域生命周期变量什么时候销毁全局变量页面打开存在页面关闭销毁局部/块级变量函数/代码块执行完毕立即销毁释放内存这也是为什么局部变量更省内存、更安全。九、新手最容易踩的 6 个函数/作用域坑点坑1var 没有块级作用域导致变量泄露for(var i0;i3;i){}console.log(i) // 3 泄露到全局坑2箭头函数无 this乱用导致指向错误回调场景优先箭头函数对象方法不要用箭头函数。坑3函数表达式不能先调用只有函数声明支持提升。坑4全局变量随意定义造成污染多人开发极易命名冲突、覆盖变量。坑5return 后面换行导致隐性终止return{ name: “test” } // 不会生效坑6内层变量和外层同名造成变量遮蔽内层变量会遮蔽外层同名变量导致外层无法访问。十、开发最佳实践总结干货禁止使用 var统一 let / const杜绝变量泄露通用工具方法用 函数声明业务逻辑、回调优先 箭头函数、函数表达式尽量少写全局变量多用局部作用域封装利用作用域隔离代码避免全局污染理解作用域链是学习 闭包、this、原型、模块化 的前置基础十一、结尾总结函数决定代码能力作用域决定代码秩序。弄懂函数你会写复用、简洁、规范的代码。弄懂作用域你能解决 90% 的变量报错、作用域污染、查找异常 问题同时为后续 闭包、ES6模块化、this指向 打好地基。