前言学完 HTML、CSS、JS 基础与 DOM/BOM 之后JS 进阶是前端分水岭是原生 JS 内核也是 Vue、React 等框架底层原理。吃透本篇内容才算真正理解 JavaScript 运行机制解决工作中 90% 疑难 BUG面试高频考点全部覆盖。一、作用域与作用域链1.1 什么是作用作用域限定变量的可访问范围用来隔离变量防止全局变量污染不同作用域同名变量互不干扰。 JS 作用分为全局作用域、局部作用函数作用域 块级作用域。1.1.1 全局作用域所有独立.js文件、script标签最外层代码属于全局作用域。全局变量全局任意作用域都能访问生命周期页面打开创建页面关闭销毁。// 全局变量 let globalNum 20; function test() { console.log(globalNum); // 函数内部可访问全局变量 } test();❌ 不规范写法函数内不写 let/var 直接赋值变量自动变为全局变量项目严禁使用。1.1.2 局部作用域分为函数作用域、块级作用域{}① 函数作用域在function(){}内部用 let/const/var 定义的变量仅在函数内生效函数执行完毕局部变量被 GC 回收。函数形参也是局部变量不同函数内部变量互相无法访问。function fn() { let num 10; // 局部变量 } console.log(num); // 报错外部无法访问② 块级作用域{}、for/iflet、const声明变量会产生块作用域var 没有块作用域。for(let i 1; i 5; i) { console.log(i); } console.log(i); // 报错i仅限循环内部1.2 作用域链1.2 原理多层嵌套函数层层向外形成链式结构查找变量规则先在当前作用域查找→找不到逐层向上找父级→直到全局找不到报错。子作用域可以访问父作用域变量父不能访问子内部变量。let a 10; // 全局 function outer() { let b 20; // 外层局部 function inner() { let c 30; console.log(a, b, c); // 逐层向上查找 } inner(); } outer();1.3 垃圾回收机制 GCJS 自动管理内存不需要程序员手动开辟 / 释放内存。1.3.1 内存生命周期内存分配定义变量、对象、函数JS 自动分配堆 / 栈内存内存使用读写变量、调用函数内存回收数据不再使用GC 自动回收释放内存。全局变量页面关闭才回收局部变量函数执行结束自动回收。 内存泄漏内存已经无用但无法被 GC 回收长期占用内存。1.3.2 两种主流 GC 算法引用计数法老 IE 专用规则统计对象被引用次数次数 0 就回收 缺陷循环引用无法回收造成内存泄漏let o1 {}, o2 {}; o1.a o2; o2.a o1; // 互相引用计数永远不为0无法释放标记清除现代 Chrome/Firefox 主流从全局 window 作为根节点遍历能访问到标记存活无法访问直接回收完美解决循环引用问题。二、闭包面试超级重点2.1 闭包定义闭包 内层函数 外层函数的局部变量内层函数引用外层函数变量外层函数执行完毕局部变量不会被 GC 销毁。function outer() { let i 1; // 外层局部变量 function inner() { console.log(i); } return inner; // 返回内层函数 } const fn outer(); fn(); // 外部调用访问外层变量2.2 闭包作用私有化变量变量无法从全局随意修改延长局部变量生命周期弊端滥用闭包容易内存占用过高造成内存泄漏。三、变量提升与函数提升3.1 变量提升仅 var 有效var声明提升到当前作用域顶部先使用后定义值为undefinedlet/const不存在变量提升暂时性死区先使用直接报错。console.log(str); // undefined var str js进阶; // let str; 提前访问直接报错3.2 函数提升函数声明 function fn (){}整体提升调用可以写在定义前面fn(); function fn() {}函数表达式 const fnfunction (){}无提升必须先定义再调用fn(); // 报错 const fn function(){}四、函数进阶用法4.1 arguments 动态参数函数内置伪数组存储所有实参不确定参数个数时用来求和只有普通函数拥有箭头没有。function sum() { let total 0; for(let i 0; i arguments.length; i) { total arguments[i]; } return total; } sum(10,20,30);4.2 剩余参数 ...args形参末尾书写...接收多余实参返回真数组开发优先替代 arguments。function test(base, ...other) { console(base, other) } test(域名, get, json)4.3 展开运算符 ...作用展开数组 / 对象常用数组拼接、Math 最大值let arr [1,5,9]; console.log(Math.max(...arr)); let newArr [...arr, 88];4.4 箭头函数 ES6简写规则无参数(){}单个参数可省略括号x{}单行代码省略 {} 与 return(a,b)ab返回对象必须外层加括号n({name:n})const add (a,b)ab;箭头函数四大特性没有 arguments用剩余参数...args 替代不绑定 this继承上层作用域 thisDOM 绑定事件慎用this 指向 window不能用作构造函数 new不能使用 yield五、解构赋值 ES65.1 数组解构快速批量把数组值赋值给变量//基础解构 const [a,b,c] [10,20,30]; //剩余参数接收后面所有元素 const [x,...rest] [小米,华为,苹果]; //默认值只有对应值为undefined生效 const [m5] []; //变量交换 let n11,n22;[n1,n2][n2,n1]; //跳过元素 const [a,,c] [1,2,3];5.2 对象解构const user {name:张三,age:18}; const {name,age} user; //属性重命名 const {name:uname} user;六、数组高阶 API项目高频6.1 forEach () 遍历数组无返回值单纯循环遍历每个元素const arr [红,绿]; arr.forEach((item,index){ console.log(index,item); })6.2 filter () 筛选数组返回满足条件新数组原数组不变let arr [10,50,33]; let res arr.filter(itemitem30);6.3 reduce 累加器多用于数组求和参数prev 上次结果、curr 当前值let arr [1,2,3,4]; let sum arr.reduce((prev,curr)prevcurr,0);6.4 其他常用数组方法方法功能find返回第一个符合条件元素every全部满足返回 truesome任意一个满足返回 trueconcat数组合并join数组转字符串splice删除 / 替换元素Array.from伪数组转真数组七、字符串常用 APIsplit(分隔符)字符串切割成数组substring(起始,结束)字符串截取includes()判断是否包含字符toUpperCase/toLowerCase大小写转换replace(正则/字符,替换内容)字符替换八、面向对象 OOP8.1 两种编程思想面向过程 POP分步拆解按步骤执行例做蛋炒饭备菜→炒饭→出锅注重过程面向对象 OOP拆分对象对象分工协作盖浇饭米饭 配菜注重事物三大特性封装、继承、多态。8.2 创建对象三种写法对象字面量const obj{name:}new Object()构造函数批量创建同类对象8.3 构造函数规则函数名首字母大写new 关键字实例化对象function Pig(name,age) { this.name name; this.age age; } const peppa new Pig(佩奇,6);new 执行四步在内存开辟空对象绑定构造函数 this 指向新对象执行构造函数内代码给对象添加属性自动返回新对象无需 return。实例成员 静态成员实例成员this.xxx实例对象访问静态成员构造函数.属性只能构造函数访问实例无法访问Pig.eye 2; //静态属性8.4 原型 prototype节省内存核心1. 原型对象每个构造函数自带prototype原型对象存放所有实例共用的方法所有实例共享节省内存function Star(name) { this.name name; } // 原型挂载公共方法 Star.prototype.sing function(){} let s1 new Star(刘德华); let s2 new Star(张学友); console.log(s1.sing s2.sing) // true 共用同一个函数2.proto对象原型所有实例自带__proto__属性指向构造函数的 prototype 原型实例能调用原型方法全靠它。3. constructor 属性原型默认constructor指向原构造函数直接重写原型对象会丢失 constructor需要手动修正Star.prototype { constructor:Star, sing:function(){} }8.5 原型链实例.proto→ 构造函数.prototype → 原型.proto→ Object.prototype → null属性查找规则先在自身找属性找不到去__proto原型找逐级向上找到 Object 原型无则 undefinedinstanceof检测构造函数是否出现在实例原型链上。九、深浅拷贝只针对引用数据类型基本数据赋值直接复制值引用数据默认赋值复制内存地址。9.1 浅拷贝仅拷贝对象第一层嵌套对象拷贝地址修改嵌套内容原对象同步变化常用方法对象{...obj}、Object.assign({},obj)数组[...arr]、concat()let obj {a:1,info:{b:2}} let newObj {...obj}; newObj.info.b 99; //原对象info同步改变9.2 深拷贝完整开辟新内存新老对象完全隔离修改互不影响 三种实现JSON.parse(JSON.stringify(obj))无法处理函数、undefined递归手写深拷贝第三方库 lodash_.cloneDeep(obj)十、this 指向 重中之重10.1 this 分三类普通函数直接调用this window严格模式 undefined对象。方法调用this 当前对象箭头函数无自身 this继承外层上下文 this构造函数this new 出来的实例10.2 三个修改 this 方法方法执行特性传参形式call立即执行函数逐个传参 fn.call (obj,1,2)apply立即执行函数数组传参 fn.apply (obj,[1,2])bind不执行返回新函数永久绑定 this逐个传参function test(a,b){console(this,ab)} test.call({name:小明},1,2) test.apply({name:小明},[1,2]) let fn test.bind({name:小明},1,2) fn();十一、异常处理11.1 throw 主动抛出错误throw new Error(参数非法)抛出后终止后续代码11.2 try/catch 捕获运行错误try { // 可能报错代码 let a undefined 1; } catch(err) { // 捕获错误信息 console.log(err.message) }十二、学习寄语JS 进阶是原生 JS 的分水岭原型、闭包、this、作用域都是抽象概念不要死记多敲代码、打印测试、手绘原型链。坚持每天练习案例吃透本章节后续 Vue、React 学习效率翻倍前端之路稳步进阶日积月累你一定可以成为资深前端工程师