JavaScript 进阶精讲完整版(面试 + 自学通用)
2026/6/4 20:06:56 网站建设 项目流程

前言

学完 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/if)

let、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 垃圾回收机制 GC

JS 自动管理内存,不需要程序员手动开辟 / 释放内存。

1.3.1 内存生命周期

  1. 内存分配:定义变量、对象、函数,JS 自动分配堆 / 栈内存;
  2. 内存使用:读写变量、调用函数;
  3. 内存回收:数据不再使用,GC 自动回收释放内存。

全局变量:页面关闭才回收;局部变量:函数执行结束自动回收。 内存泄漏:内存已经无用,但无法被 GC 回收,长期占用内存。

1.3.2 两种主流 GC 算法

  1. 引用计数法(老 IE 专用)规则:统计对象被引用次数,次数 = 0 就回收; 缺陷:循环引用无法回收,造成内存泄漏
let o1 = {}, o2 = {}; o1.a = o2; o2.a = o1; // 互相引用,计数永远不为0,无法释放
  1. 标记清除(现代 Chrome/Firefox 主流)从全局 window 作为根节点遍历,能访问到标记存活,无法访问直接回收,完美解决循环引用问题。

二、闭包(面试超级重点)

2.1 闭包定义

闭包 = 内层函数 + 外层函数的局部变量;内层函数引用外层函数变量,外层函数执行完毕,局部变量不会被 GC 销毁。

function outer() { let i = 1; // 外层局部变量 function inner() { console.log(i); } return inner; // 返回内层函数 } const fn = outer(); fn(); // 外部调用,访问外层变量

2.2 闭包作用

  1. 私有化变量,变量无法从全局随意修改;
  2. 延长局部变量生命周期

弊端:滥用闭包容易内存占用过高,造成内存泄漏。

三、变量提升与函数提升

3.1 变量提升(仅 var 有效)

  • var:声明提升到当前作用域顶部,先使用后定义值为undefined
  • let/const:不存在变量提升,暂时性死区,先使用直接报错。
console.log(str); // undefined var str = "js进阶"; // let str; 提前访问直接报错

3.2 函数提升

  1. 函数声明 function fn (){}:整体提升,调用可以写在定义前面
fn(); function fn() {}
  1. 函数表达式 const fn=function (){}:无提升,必须先定义再调用
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(=>)

简写规则

  1. 无参数:()=>{}
  2. 单个参数可省略括号:x=>{}
  3. 单行代码省略 {} 与 return:(a,b)=>a+b
  4. 返回对象必须外层加括号:n=>({name:n})
const add = (a,b)=>a+b;

箭头函数四大特性

  1. 没有 arguments,用剩余参数...args 替代
  2. 不绑定 this,继承上层作用域 this(DOM 绑定事件慎用,this 指向 window)
  3. 不能用作构造函数 new
  4. 不能使用 yield

五、解构赋值 ES6

5.1 数组解构

快速批量把数组值赋值给变量

//基础解构 const [a,b,c] = [10,20,30]; //剩余参数接收后面所有元素 const [x,...rest] = ["小米","华为","苹果"]; //默认值,只有对应值为undefined生效 const [m=5] = []; //变量交换 let n1=1,n2=2;[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(item=>item>30);

6.3 reduce 累加器

多用于数组求和,参数:prev 上次结果、curr 当前值

let arr = [1,2,3,4]; let sum = arr.reduce((prev,curr)=>prev+curr,0);

6.4 其他常用数组方法

方法功能
find返回第一个符合条件元素
every全部满足返回 true
some任意一个满足返回 true
concat数组合并
join数组转字符串
splice删除 / 替换元素
Array.from伪数组转真数组

七、字符串常用 API

split('分隔符'):字符串切割成数组substring(起始,结束):字符串截取includes():判断是否包含字符toUpperCase/toLowerCase:大小写转换replace(正则/字符,替换内容):字符替换

八、面向对象 OOP

8.1 两种编程思想

  1. 面向过程 POP:分步拆解,按步骤执行(例:做蛋炒饭:备菜→炒饭→出锅),注重过程;
  2. 面向对象 OOP:拆分对象,对象分工协作(盖浇饭:米饭 + 配菜),注重事物,三大特性:封装、继承、多态

8.2 创建对象三种写法

  1. 对象字面量const obj={name:""}
  2. new Object()
  3. 构造函数(批量创建同类对象)

8.3 构造函数

规则:函数名首字母大写,new 关键字实例化对象

function Pig(name,age) { this.name = name; this.age = age; } const peppa = new Pig("佩奇",6);

new 执行四步

  1. 在内存开辟空对象;
  2. 绑定构造函数 this 指向新对象;
  3. 执行构造函数内代码,给对象添加属性;
  4. 自动返回新对象(无需 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

属性查找规则

  1. 先在自身找属性;
  2. 找不到去__proto原型找;
  3. 逐级向上找到 Object 原型,无则 undefined;instanceof:检测构造函数是否出现在实例原型链上。

九、深浅拷贝(只针对引用数据类型)

基本数据:赋值直接复制值;引用数据:默认赋值复制内存地址。

9.1 浅拷贝

仅拷贝对象第一层,嵌套对象拷贝地址,修改嵌套内容原对象同步变化常用方法:

  1. 对象:{...obj}Object.assign({},obj)
  2. 数组:[...arr]、concat()
let obj = {a:1,info:{b:2}} let newObj = {...obj}; newObj.info.b = 99; //原对象info同步改变

9.2 深拷贝

完整开辟新内存,新老对象完全隔离,修改互不影响 三种实现:

  1. JSON.parse(JSON.stringify(obj))(无法处理函数、undefined)
  2. 递归手写深拷贝
  3. 第三方库 lodash:_.cloneDeep(obj)

十、this 指向 (重中之重)

10.1 this 分三类

  1. 普通函数
  • 直接调用:this = window(严格模式 undefined)
  • 对象。方法调用:this = 当前对象
  1. 箭头函数:无自身 this,继承外层上下文 this
  2. 构造函数: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,a+b)} 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 学习效率翻倍,前端之路稳步进阶,日积月累,你一定可以成为资深前端工程师!

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询