Skip to content

经常使用的 ES6 新特性

查看详情
  • let, const
  • 模板字符串
  • 箭头函数
  • 函数参数的默认值
  • 扩展/剩余运算符
  • 解构
  • class
  • promise

深度优先遍历和广度优先遍历

查看详情

以遍历一个 dom 节点为例:

  • 深度优先遍历:深度优先遍历是一种从起始节点出发,尽可能深入到子节点的遍历方式。当一个节点的所有子节点都被访问过后,遍历会回溯到它的父节点继续进行未访问的子节点的遍历。
javascript
let deepTraversal = (node, nodeList = []) => {
  if (node !== null) {
    nodeList.push(node);
    let children = node.children;
    for (let i = 0; i < children.length; i++) {
      deepTraversal1(children[i], nodeList);
    }
  }
  return nodeList;
};
  • 广度优先遍历:广度优先遍历是一种从起始节点出发,按层级逐层向外扩展的遍历方式。每一层的所有节点都被访问后,才开始访问下一层的节点。
javascript
let widthTraversal = (node) => {
  let nodes = [];
  let stack = [];
  if (node) {
    stack.push(node);
    while (stack.length) {
      let item = stack.shift();
      let children = item.children;
      nodes.push(item);
      for (let i = 0; i < children.length; i++) {
        stack.push(children[i]);
      }
    }
  }
  return nodes;
};

setTimeout 倒计时为什么会出现误差

查看详情
  • setTimeout 只是将事件插入了任务队列,必须等到当前代码(执行栈)执行完,才会执行它指定的回调函数。要是当前的代码消耗时间很长, setTimeout 也有可能要等很久,所以并没有办法保证回调函数一定在 setTimeout 指定的时间执行,所以 setTimeout 的第二个参数表示的是最小时间。
  • HTML 标准规定了 setTimeout 的第二个参数的最小值不能小于 4ms,如果低于这个值则默认为 4ms。

为什么需要组件化和模块化?

查看详情
  • 组件化能提高代码的复用性,降低维护的成本
  • 模块化能避免变量污染和命名冲突,提高代码的复用率,降低维护成本,方便进行依赖管理

谈谈你对前端模块化的理解

查看详情

前端模块化是指将前端代码按照功能和职责划分为多个独立且互相依赖的模块,通过模块化的方式组织和管理代码,提升代码的可维护性、可复用性和可读性。模块化不仅适用于JavaScript代码,还可以应用于CSS等前端资源。

简述对 Web Worker 的理解

查看详情
  • Web Worker 的作用就是为 JavaScript 创造多线程环境,在主线程运行的同时允许 Worker 线程在后台运行,两者互不干扰。
  • 遵循同源策略
  • worker 线程无法读取主线程所在网页的 DOM 元素,无法使用 document、window 等对象
  • worker 线程不与主线程在同一个上下文环境,它们仅能通过消息机制完成通信
  • worker 线程可以通过 XMLHttpRequest 对象发出 ajax 请求

ES6 模块和 CommonJS 模块的差异是什么?

查看详情
  • 导出导入的方式不同,ES6 使用 export/import。而 CommonJS 使用 module.export/require
  • ES6 模块自动采用严格模式,无论模块开头是否写了 use strict
  • ES6 模块的顶层 this 指向 undefined。而 CommonJS 模块的顶层 this 指向当前模块。
  • ES6 模块在编译的时候就能确定模块的依赖关系,以及输入输出的变量。而 CommonJS 模块是运行时加载。
  • ES6 模块输出的是值的引用,如果原始的值改变了,import 加载的值也会改变。而 CommonJS 模块一旦输出一个值,模块内部变化就影响不到这个值了。

解决跨域的方法有哪些?

查看详情
  • CORS:只要服务器设置了 Access-Control-Allow-Origin 就可以开启 CORS。该属性表示那些域名可以访问资源。
    • 简单请求,同时满足以下两个条件就属于简单请求
      • 使用以下方法
        • get
        • head
        • post
      • Content-Type 的值为以下三者之一
        • text/plain
        • multipart/form-data
        • application/x-www-form-urlencoded
    • 复杂请求,不符合以上条件的就是复杂请求。复杂请求会在正式通信之前增加一次 option 方法的预检查,通过该请求来知道是否允许跨域请求。

存在的问题:对于 CORS 请求,只能拿到 response header 中的 6 个基本字段(Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma),如果想拿到其他的字段就必须在 Access-Control-Expose-Headers 里指定需要的字段

  • nginx 反向代理
  • jsonp: 只支持 get 请求
  • websocket
  • postMessage
  • node 中间件

堆和栈的区别

查看详情
特性栈(Stack)堆(Heap)
内存分配编译器自动分配和释放程序员手动分配和释放
分配方式连续的内存块不连续的内存块
管理方式通过栈指针管理通过自由链表或其他数据结构管理
生命周期函数调用期间存在,函数返回后销毁由程序员控制,显式释放或垃圾回收
性能分配和释放速度快分配和释放速度较慢
内存使用通常较小,适用于临时存储通常较大,适用于长期或共享数据
安全性自动管理内存,减少内存泄漏风险手动管理内存,容易出现内存泄漏和碎片化

Babel 编译原理

查看详情
  1. 解析(Parsing): 词法分析(Lexical Analysis):将源码字符串转换为标记(tokens),这些标记是源代码的基本组成部分,如关键字、标识符、操作符和字面量。 语法分析(Syntax Analysis):将标记流转换为抽象语法树(AST,Abstract Syntax Tree)。AST 是源代码结构的树状表示,每个节点代表源码中的一个结构部分。

  2. 转换(Transforming): 在这一步骤中,Babel 使用插件来遍历和修改 AST 节点。这些插件负责将新语法转换为等效的旧语法。

  3. 生成(Generating): 最后,Babel 将转换后的 AST 转回为代码字符串。这一步骤称为代码生成(Code Generation),生成的代码可以在旧版本的 JavaScript 环境中运行。

代码复用的方式

查看详情
  • 封装
  • 继承
  • 借用(apply/call)

常见的设计模式有哪些?

查看详情
  • JS 工厂模式
  • JS 构造函数模式
  • JS 原型模式
  • 观察者模式
  • 发布订阅模式