八股记录

43 阅读5分钟

3. 是否了解 typeof?

✅ 3.1 基础数据类型 & 引用数据类型(ES6 前):

  • 基本数据类型string, number, boolean, undefined, null, symbol, bigint
  • 引用数据类型object, array, function, date, regexp,自定义对象等

✅ 3.2 为什么 typeof null === 'object'

  • 历史遗留 Bug,JS 最初的实现是用 低位 type tag 来标识数据类型:

    • object 的 type tag 是 0
    • null 被表示为指针地址 0x00,因此其 tag 也被识别为 object
  • 无法修复,兼容性问题太大,已被写入规范

✅ 3.3 除了 typeof,还有其它获取具体类型的方法吗?

  • 是的,可以用:
Object.prototype.toString.call(value); 

示例:

Object.prototype.toString.call([]); // '[object Array]'
Object.prototype.toString.call(null); // '[object Null]'
Object.prototype.toString.call(() => {}); // '[object Function]'

✅ 3.4 Object.prototype.toString.apply() 可以吗?

  • 可以,和 call 等效,只是参数形式不同:
Object.prototype.toString.call(value);   // call(thisArg, arg1, ...)
Object.prototype.toString.apply(value);  // apply(thisArg, [args])

toString 来说没有参数,因此 call(value)apply(value) 等价。


✅ 3.5 call / apply / bind 区别?

方法含义参数形式是否立即执行
call调用函数,指定 this逗号分隔参数列表
apply调用函数,指定 this参数为数组
bind返回一个 this 被绑定的新函数参数逗号分隔❌(延迟执行)

示例:

fn.call(thisArg, a, b);
fn.apply(thisArg, [a, b]);
const newFn = fn.bind(thisArg, a); // newFn() 才执行

4. 了解事件委托机制吗?

事件委托:通过把事件监听器绑定在父元素上,利用事件冒泡机制,监听子元素的行为。

document.getElementById('parent').addEventListener('click', (e) => {
  if (e.target.matches('.child')) {
    // 只处理子元素点击
  }
});

✅ 4.1 好处:

  • 减少事件绑定次数,节省内存(如列表、表格中绑定大量子元素)
  • 方便处理动态插入的子元素
  • 提升性能、降低耦合

✅ 4.2 targetcurrentTarget 区别:

属性含义举例
event.target实际触发事件的元素点击了某个 <li>
event.currentTarget当前监听事件的元素(绑定 listener 的那个)父元素 <ul>

5. 了解进程和线程吗?

  • 进程(Process) :程序的独立运行单位,有独立内存空间。
  • 线程(Thread) :进程中的最小执行单位,同一进程内线程共享内存空间。

✅ 5.1 什么是多线程?

  • 同一进程中并发运行多个线程。
  • 比如:浏览器中渲染线程、JS 引擎线程、网络线程并发运行。

✅ 5.2 多线程会有哪些问题?怎么解决?

常见问题:

  • 竞争条件(两个线程同时写数据)
  • 死锁(两个线程相互等待)
  • 资源同步(线程之间顺序不一致)

解决方案:

  • 加锁机制(mutex)
  • PV 信号量机制:P(wait)和 V(signal)操作,控制临界区
  • 原子操作:如 CAS(Compare and Swap)

✅ 5.3 为什么 JavaScript 是单线程的?

  • JS 是单线程的,源于浏览器设计初衷:为了避免 DOM 操作混乱。
  • 同一时间只能有一个执行上下文,避免状态混乱。

但浏览器环境通过 事件循环机制 + Web APIs 实现了伪多线程(宏任务、微任务、异步事件、Web Worker 等)来模拟并发。


✅ 1. CSS 动画中 transform 的优势

  • 不会触发布局(reflow)或重绘(repaint)
    transform 改变的是合成层(compositing) ,由 GPU 加速,性能远高于 top/left
  • 触发硬件加速(GPU)
    CSS3 中 transformopacity 被称为 GPU 友好属性
  • transitionanimation 联动良好

面试表达句式

使用 transform 动画相比 top/left 不会引起布局重排,能走合成线程,提升性能。


✅ 2. 浏览器进程与线程 & Web Worker 是否能加速渲染?

  • 浏览器多进程架构:每个标签页/插件/渲染进程独立

  • 渲染线程负责:HTML 解析 → DOM 构建 → 样式计算 → 布局 → 绘制

  • Web Worker

    • 是 JS 的多线程能力
    • 用于耗时计算、IO,不会阻塞主线程
    • 不能操作 DOM无法加速渲染

✅ 3. HTTP 缓存核心字段

强缓存(不发请求):

  • Cache-Control: max-age=3600
  • Expires: GMT时间

协商缓存(需要服务端确认):

  • ETag / If-None-Match
  • Last-Modified / If-Modified-Since

缓存流程可画一张图或举例说明


✅ 4. 闭包 VS 类 的区别

  • 闭包:函数携带其定义时的词法作用域,保存局部变量

    function makeCounter() {
      let count = 0;
      return function () {
        return ++count;
      }
    }
    
  • :通过 this 保存状态,用 new 实例化

    class Counter {
      constructor() {
        this.count = 0;
      }
      next() {
        return ++this.count;
      }
    }
    

✅ 关键区别:

  • 闭包基于作用域链保存状态;类基于实例化对象(this)
  • 闭包更轻量但可能造成内存泄漏;类更易于扩展和继承

✅ 5. Promise / await 原理(封装递归)

  • awaitPromise.then 的语法糖,本质是将异步代码串行化
  • async 函数返回一个 Promise
  • 实现 await 行为底层可通过递归处理 promise 队列

可手写一个:

function run(generatorFn) {
  const gen = generatorFn();
  function step(val) {
    const result = gen.next(val);
    if (result.done) return;
    Promise.resolve(result.value).then(step);
  }
  step();
}

✅ 6. Vue 对 DOM 的理解

  • Vue2 使用虚拟 DOM,通过 diff 算法最小化真实 DOM 操作
  • Vue3 使用 Proxy 实现响应式系统(替代 Vue2 的 defineProperty)
  • DOM 更新是异步的,封装在 nextTick

✅ 7. 垃圾回收 & WeakMap

  • JS 使用 标记清除引用计数

  • 弱引用(WeakMap)不会阻止垃圾回收

  • 使用场景:

    • 缓存(不影响被缓存对象生命周期)
    • 私有属性封装

✅ 8. AOP 和 IoC

  • AOP(面向切面编程) :关注横切逻辑(如日志、权限),可通过高阶函数封装:

    const withLog = (fn) => (...args) => {
      console.log('before');
      const res = fn(...args);
      console.log('after');
      return res;
    }
    
  • IoC(控制反转) :框架控制对象的创建和注入,开发者只关注逻辑
    常见于依赖注入容器、Spring/Angular 等框架中


✅ 9. Token 和 JWT

  • Token:用于标识用户登录状态,通常由服务器生成
  • JWT(JSON Web Token):结构为 Header.Payload.Signature,是 Token 的一种实现形式

优点:

  • 无需服务器存储状态
  • 前端可解析 payload 中的信息(非敏感)

✅ 10. Webpack Loader

常见 loader:

  • babel-loader:转译 ES6+
  • css-loader:解析 CSS 文件
  • style-loader:将样式插入 DOM
  • file-loader / url-loader:处理图片、字体等资源
  • vue-loader / ts-loader:框架专属

✅ 11. 手写链表(含 add、print、reverse)

class Node {
  constructor(val) {
    this.val = val;
    this.next = null;
  }
}

class LinkedList {
  constructor() {
    this.head = null;
  }

  add(val) {
    const node = new Node(val);
    if (!this.head) {
      this.head = node;
    } else {
      let p = this.head;
      while (p.next) p = p.next;
      p.next = node;
    }
  }

  print() {
    let p = this.head;
    const res = [];
    while (p) {
      res.push(p.val);
      p = p.next;
    }
    console.log(res.join(' -> '));
  }

  reverse() {
    let prev = null, curr = this.head;
    while (curr) {
      const next = curr.next;
      curr.next = prev;
      prev = curr;
      curr = next;
    }
    this.head = prev;
  }
}