Skip to content

JavaScript 核心概念深度解析

静态作用域和动态作用域

  • JavaScript 采用词法作用域(静态作用域),函数作用域在定义时就确定
  • 动态作用域中,函数作用域在调用时才确定

执行上下文与变量对象

当执行可执行代码时,会创建对应的执行上下文,包含三个核心属性:

  1. 变量对象(VO)
  2. 作用域链
  3. this

函数上下文

  • 函数上下文中使用活动对象(AO) 表示变量对象
  • AO 在进入函数上下文时创建,通过arguments属性初始化
  • AO 变化过程:
    1. 进入执行上下文:添加形参、函数声明、变量声明
    2. 代码执行阶段:修改变量值
js
function foo(a) {
  var b = 2;
  function c() {}
  var d = function() {};
  b = 3;
}
foo(1);

// 进入执行上下文时AO:
AO = {
  arguments: {0: 1, length: 1},
  a: 1,
  b: undefined,
  c: reference to function c(){},
  d: undefined
}

// 代码执行后AO:
AO = {
  arguments: {0: 1, length: 1},
  a: 1,
  b: 3,
  c: reference to function c(){},
  d: reference to FunctionExpression "d"
}

作用域链

  • 查找变量时从当前上下文的变量对象开始,沿父级执行上下文逐级查找
  • 作用域链是由多个执行上下文的变量对象构成的链表
js
function foo() {
  function bar() {
    // bar作用域链:[bar.AO, foo.AO, global.VO]
  }
}

函数参数传递

  • ECMAScript 中所有函数参数都是按值传递
  • 基本类型:传递值的副本
  • 引用类型:传递引用的副本(共享传递)
js
var obj = { value: 1 };
function foo(o) {
  o = 2; // 修改引用副本
}
foo(obj);
console.log(obj.value); // 1(原对象未改变)

手写核心方法

实现 call

js
Function.prototype.call2 = function (context, ...args) {
  context = context || window;
  context.fn = this;
  const result = context.fn(...args);
  delete context.fn;
  return result;
};

实现 bind

js
Function.prototype.myBind = function (context) {
  const self = this;
  return function (...args) {
    return self.apply(context, args);
  };
};

实现 new

js
function myNew(Fn, ...args) {
  const obj = Object.create(Fn.prototype);
  const result = Fn.apply(obj, args);
  return result instanceof Object ? result : obj;
}

AJAX vs Fetch

特性AJAX (XMLHttpRequest)Fetch
设计回调函数Promise
API 设计集中式模块化(Request/Response/Headers)
数据流不支持分块读取支持 Stream 分块读取
CORS需手动处理默认不发送 cookies

let 底层实现

  1. 编译阶段:扫描函数体,为 let 变量生成初始词法环境
  2. 执行上下文:进入块级作用域创建新词法环境
  3. 绑定变量值:运行时在词法环境中搜索变量
  4. 块级作用域:创建子遮蔽环境实现作用域隔离

垃圾回收机制

引用计数

  • 优点:立即回收垃圾
  • 缺点:循环引用问题,计数器占用空间

标记清除

  1. 标记所有对象为垃圾(0)
  2. 从根对象遍历,标记可达对象(1)
  3. 清除标记为 0 的对象
  • 优点:实现简单
  • 缺点:内存碎片

分代回收

  • 新生代:新创建对象,回收频率高
  • 老生代:长期存活对象,回收频率低

函数式编程核心

  1. 纯函数:相同输入 => 相同输出,无副作用
    js
    function add(a, b) {
      return a + b;
    }
  2. 不可变性:数据创建后不可修改
    js
    const newArr = [...arr, newItem];
  3. 高阶函数:函数作为参数或返回值
    js
    function multiplier(factor) {
      return (num) => num * factor;
    }
  4. 函数组合
    js
    const process = compose(func1, func2, func3);

发布订阅 vs 观察者模式

特性发布订阅观察者
耦合度完全解耦相互耦合
通信方式消息通道直接调用
扩展性高(多发布/订阅者)

精度丢失问题

js
0.1 + 0.2 !== 0.3; // true
9007199254740991 + 1; // 精度丢失

原因:浮点数二进制表示存在近似值

WeakMap vs Map

特性WeakMapMap
Key 类型仅对象任意值
引用类型弱引用强引用
垃圾回收自动回收不回收
可枚举

小程序双线程架构

  • 渲染层:WebView 渲染界面
  • 逻辑层:JsCore 线程运行 JS 脚本 优势:避免 JS 执行阻塞渲染

前端工程化核心

  1. 模块化:代码按功能划分
  2. 规范化:统一代码风格
  3. 自动化:构建/测试/部署
  4. 组件化:高复用 UI 组件

重绘 vs 回流

重绘回流
触发条件外观变化布局变化
性能影响较小较大
优化建议避免频繁样式修改批量 DOM 操作

setTimeout vs requestAnimationFrame

setTimeoutrequestAnimationFrame
执行时机指定时间后下一帧开始前
主线程阻塞不阻塞
后台运行继续执行暂停
适用场景通用定时动画优化

script 加载策略

正常加载asyncdefer
HTML 解析暂停并行并行
执行顺序顺序执行下载完立即执行HTML 解析完后顺序执行
使用建议-独立脚本依赖 DOM 的脚本

内存泄漏场景

  1. 意外全局变量
    js
    function leak() {
      temp = "leak";
    }
  2. 未清除定时器
    js
    setInterval(() => {...}, 1000);
  3. DOM 引用未释放
    js
    const element = document.getElementById("my-element");
    // 未在不需要时解除引用
  4. 闭包滥用
    js
    function outer() {
      const bigData = new Array(1000000);
      return function inner() {
        console.log(bigData.length);
      };
    }

Vite 为何启动快

  • 开发环境:直接使用 ES6 Module,无需打包
  • 按需编译:仅编译当前请求的模块
  • Esbuild 预构建:极速的依赖预构建

Vue vs React 对比

VueReact
模板系统基于 HTML 的模板JSX
更新粒度组件级从根节点调度
响应式Proxy 拦截setState 触发
渲染方式递归可中断循环

模块化概念

术语含义
Module源码文件(webpack 中一切皆模块)
Chunk多个模块合并(entry/import/splitChunk)
Bundle最终输出文件

前端打包必要性

  1. 性能优化:Tree-Shaking/压缩/合并
  2. 语法转换:TS/ES6+/SCSS → 浏览器兼容
  3. 工程能力:Lint/测试/CI/CD 集成

项目构建要素

mermaid
graph TD
A[代码仓库] --> B[框架选择]
B --> C[目录规范]
C --> D[构建工具]
D --> E[代码规范]
E --> F[预提交检查]
F --> G[单元测试]
G --> H[CI/CD]
H --> I[文档系统]

开发环境标识

环境全称用途
DEVDevelopment开发
SITSystem Integration Test系统整合测试
UATUser Acceptance Test用户验收测试
PRODProduction生产环境

循环方法对比

方法可中断遍历内容适用对象
forEachArray
for...inObject/Array
for...ofArray/Map/Set

数据类型细节

  • undefined:变量声明但未初始化
  • null:空对象指针

递减操作符

js
let a = 5;
let b = a-- + 2; // b=7, a=4(先计算后递减)
let c = --a + 2; // a=3, c=5(先递减后计算)