前端数据结构与算法 |青训营笔记

73 阅读3分钟

这是我参与「第五届青训营 」笔记创作活动的第10天

本堂课重点内容

前端中数据结构,算法的重要性

实战案例分享

重点知识点介绍

1. 遍历所有文件

遍历所有文件的场景是很基础且常见的,比如生成页面侧边栏、生成文件树等场景。这里使用Node.js实现递归的DFS算法

// 使用Node.js实现递归的DFS算法
const fs = require('fs');
const path = require('path');
function scanDiretory(path){
    let allFiles = [];
    function readDiretory(path){
        let files = fs.readdirSync(path);
    files.forEach((file)=>{
        let curPath = path + '/' + file;
        let stat = fs.statSync(curPath);
        if(stat.isDirectory()){
            scanDiretory(curPath);
        }else{
            allFiles.push(curPath);
        }
    });
    }
}

readDiretory(path);
return allFiles;

2. AST解析器

抽象语法树AST可以将代码解析为一颗对象树的结构,每个语法都对应对象树中的节点。借助对象树我们可以方便地进行语法分析和转换,其最主要的两个步骤是tokenize词法分析parse语法分析

这用到了编译原理中的知识,编译器的前端部分主要是scannerparser,我按照自己的理解编写了如下JavaScript代码

// 1. 首先,JavaScript引擎会将这段代码分成两个阶段:分词/词法分析和解析/语法分析。
// 2. 分词/词法分析阶段,JavaScript引擎会将代码分解成有意义的代码块,这些代码块被称为词法单元。
function scanner(input) {
  let current = 0;
  let tokens = [];
  while (current < input.length) {
    let char = input[current];
    if (char === "(") {
      tokens.push({
        type: "paren",
        value: "(",
      });
      current++;
      continue;
    }
    if (char === ")") {
      tokens.push({
        type: "paren",
        value: ")",
      });
      current++;
      continue;
    }
    let WHITESPACE = /\s/;
    if (WHITESPACE.test(char)) {
      current++;
      continue;
    }
    let NUMBERS = /[0-9]/;
    if (NUMBERS.test(char)) {
      let value = "";
      while (NUMBERS.test(char)) {
        value += char;
        char = input[++current];
      }
      tokens.push({ type: "number", value });
      continue;
    }
    if (char === '"') {
      let value = "";
      char = input[++current];
      while (char !== '"') {
        value += char;
        char = input[++current];
      }
      char = input[++current];
      tokens.push({ type: "string", value });
      continue;
    }
    let LETTERS = /[a-z]/i;
    if (LETTERS.test(char)) {
      let value = "";
      while (LETTERS.test(char)) {
        value += char;
        char = input[++current];
      }
      tokens.push({ type: "name", value });
      continue;
    }
    throw new TypeError("I dont know what this character is: " + char);
  }
  return tokens;
}
// 3. 解析/语法分析阶段,JavaScript引擎会将词法单元流(数组)转换成一个由元素逐级嵌套所组成的代表了程序语法结构的树。这个树被称为“抽象语法树”(Abstract Syntax Tree,AST)。
function parser(tokens) {
  let current = 0;
  function walk() {
    let token = tokens[current];
    if (token.type === "number") {
      current++;
      return {
        type: "NumberLiteral",
        value: token.value,
      };
    }
    if (token.type === "string") {
      current++;
      return {
        type: "StringLiteral",
        value: token.value,
      };
    }
    if (token.type === "paren" && token.value === "(") {
      token = tokens[++current];
      let node = {
        type: "CallExpression",
        name: token.value,
        params: [],
      };
      token = tokens[++current];
      while (
        token.type !== "paren" ||
        (token.type === "paren" && token.value !== ")")
      ) {
        node.params.push(walk());
        token = tokens[current];
      }
      current++;
      return node;
    }
    throw new TypeError(token.type);
  }
  let ast = {
    type: "Program",
    body: [],
  };
  while (current < tokens.length) {
    ast.body.push(walk());
  }
  return ast;
}

3. 相似命令提示

在使用命令行时我们难免会输入错误的命令,此时命令行会提示我们最接近的命令(例如git),这个功能是基于最小距离算法实现的

参考:autocorrect(github.com)

// 命令行提示功能:使用最小距离算法实现最接近的命令
var fs = require("fs");
var leven = require("leven");
var wordListPath = require("word-list");

var readDictionary = function (path) {
  path || (path = wordListPath);
  return fs.readFileSync(path).toString().trim().split("\n");
};

var autocorrect = function (options) {
  options || (options = {});
  var dictionary = options.words || readDictionary(options.dictionary);
  var len = dictionary.length;

  return function (str) {
    var distance, bestWord, i, word, min;

    for (i = 0; i < len; i++) {
      word = dictionary[i];
      distance = leven(str, word);

      if (distance === 0) {
        return word;
      } else if (min === undefined || distance < min) {
        min = distance;
        bestWord = word;
      }
    }

    return bestWord;
  };
};

module.exports = autocorrect;

课后个人总结

老师介绍了前端中一些要用到算法的场景,提到了DFS算法,最小距离算法等。前端不仅仅只有UI和交互开发,还有工程化的工具链、可视化、跨段等需要用到各自不同的算法。所以呢,前端学习还是有数据结构和算法的能力,持续地积累和思考这方面的知识才能更加有效地提高自己的水平。

引用参考

‌⁢⁢⁡⁢⁡⁤‌⁤‬‍⁡‌⁡⁣⁡⁣⁢‌⁤⁣⁢‬‬‬‬‬‌‌⁣‌⁡⁢⁢⁢前端,与数据结构与算法专场(feishu.cn)