2022面试笔记,每天记录一点

256 阅读10分钟

相关面经

01. Vue的Diff算法?详细谈谈。

相关文章:

回答要点

Diff算法是一种对比算法。对比两者是旧虚拟DOM和新虚拟DOM,对比出是哪个虚拟节点更改了,找出这个虚拟节点,并只更新这个虚拟节点所对应的真实节点,而不用更新其他数据没发生改变的节点,实现精准地更新真实DOM,进而提高效率

02. 手写Call/Apply/Bind函数

相关文章

Call

Function.prototype.myCall = function(context,...args){
    let cxt = context || window;
    //将当前被调用的方法定义在cxt.func上.(为了能以对象调用形式绑定this)
    //新建一个唯一的Symbol变量避免重复
    let func = Symbol() 
    cxt[func] = this;
    args = args ? args : []
    //以对象调用形式调用func,此时this指向cxt 也就是传入的需要绑定的this指向
    const res = args.length > 0 ? cxt[func](...args) : cxt[func]();
    //删除该方法,不然会对传入对象造成污染(添加该方法)
    delete cxt[func];
    return res;
}

Apply

Function.prototype.myApply = function(context,args = []){
    let cxt = context || window;
    //将当前被调用的方法定义在cxt.func上.(为了能以对象调用形式绑定this)
    //新建一个唯一的Symbol变量避免重复
    let func = Symbol()
    cxt[func] = this;
    //以对象调用形式调用func,此时this指向cxt 也就是传入的需要绑定的this指向
    const res = args.length > 0 ? cxt[func](...args) : cxt[func]();
    delete cxt[func];
    return res;
}
// 1. 用 `apply` 将数组各项添加到另一个数组
var array = ['a', 'b'];
var elements = [0, 1, 2];
array.push.apply(array, elements);
console.info(array); // ["a", "b", 0, 1, 2]

// 2. 使用apply和内置函数
/* 找出数组中最大/小的数字 */
var numbers = [5, 6, 2, 3, 7];
var max = Math.max.apply(null, numbers); 
var min = Math.min.apply(null, numbers);
/* 基本等同于 Math.max(numbers[0], ...) 或 Math.max(5, 6, ..) */

Bind

Function.prototype.myBind = function (context, ...args) {
    //新建一个变量赋值为this,表示当前函数
    const fn = this
    //判断有没有传参进来,若为空则赋值[]
    args = args ? args : []
    //返回一个newFn函数,在里面调用fn
    return function newFn(...newFnArgs) {
        if (this instanceof newFn) {
            return new fn(...args, ...newFnArgs)
        }
        return fn.apply(context, [...args,...newFnArgs])
    }
}

03. 前端路由了解吗?有什么区别?

相关文章

你好,谈谈你对前端路由的理解
面试官: 你了解前端路由吗?

回答要点:

1、为什么会出现前端路由。

2、前端路由解决了什么问题。

3、前端路由实现的原理是什么。

04. Babel的原理是什么

相关文章

面试官(7): 聊一聊 Babel?
webpack系列之:babel的原理

回答要点:

  • 解析Parse: 将代码(其实就是字符串)转换成 AST( 抽象语法树)
  • 转换Transform: 访问 AST 的节点进行变换操作生成新的 AST
  • 生成Generate: 以新的 AST 为基础生成代码

词法分析和语法分析的作用?

  • a=1;会进行词法分析吗?
  • 怎么进行词法分析的?(关键字)
  • 词法和语法谁先执行?
  • 哪些算是词法哪些算是语法?
  • const const a=1;词法分析能通过吗?是到语法分析才报错吗?

05. 实现一个发布订阅模式,手写EventEmmiter

相关文章

interface SubscribeEvent {
  fn: Function;
  once: boolean;
}

type CacheArgs = Array<any>;

class EventEmmiter {
  subscribes: Map<string, Array<SubscribeEvent>>;
  _cacheQueue: Map<string, Array<CacheArgs>>;

  constructor() {
    this.subscribes = new Map();
    this._cacheQueue = new Map();
  }

  addEvent(type: string, callback: Function, once: boolean = false) {
    const cache = this._cacheQueue.get(type) || [];
    if(cache.length !== 0) {
      cache.forEach(args => {
        callback(...args);
      })
      this._cacheQueue.delete(type);
    }
    const sub = this.subscribes.get(type) || [];
    sub.push({ fn: callback, once });
    this.subscribes.set(type, sub);
  }

  on(type: string, callback: Function) {
    this.addEvent(type, callback);
  }

  emit(type: string, ...args: Array<any>) {
    const sub = this.subscribes.get(type) || [];
    
    if(sub.length === 0) {
      const cache = this._cacheQueue.get(type) || [];
      cache.push(args)
      this._cacheQueue.set(type, cache);
    } else {
      const context = this;
      
      sub.forEach(({ fn }) => {
        fn.call(context, ...args);
      });
  
      const newSub = sub.filter(item => !item.once);
      this.subscribes.set(type, newSub);
    }
  }

  off(type: string, callback: Function) {
    const sub = this.subscribes.get(type);
    
    if(sub) {
      const newSub = sub.filter(({ fn }) => fn !== callback);
      this.subscribes.set(type, newSub);
    }
  }

  once(type: string, callback: Function) {
    this.addEvent(type, callback, true);
  }
}

const eventEmmiter = new EventEmmiter();

eventEmmiter.emit('test_cache', 1, 2);

eventEmmiter.emit('test_cache', 1, 3);

eventEmmiter.on('test_cache', (a: number, b: number) => {
  console.log("事件发布后才订阅的, 计算的值为",a + b);
});
eventEmmiter.on('test_cache', (a: number, b: number) => {
  console.log("已没有发布事件的缓存了, 不会触发",a + b);
});

06. 说一说Proxy

相关文章

Proxy 对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)。

const p = new Proxy(target, handler)
- `target`: 要使用 `Proxy` 包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)。
- `handler`:  一个通常以函数作为属性的对象,各属性中的函数分别定义了在执行各种操作时代理 `p` 的行为。

07. Webpack的工作原理

基本概念

  • Entry 入口,webpack执行构建的第一步将从Entry开始,可抽象成输入
  • Module 模块,在webpack里一切皆模块,一个模块对应着一个文件。webpack会从配置的Entry开始递归找出所有依赖的模块。
  • Chunk 代码块,一个Chunk由多个模块组合而成,用于代码合并与分割。
  • Loader 模块转换器,用于把模块原内容按照需求转换成新内容。
  • Plugin 扩展插件,在webpack构建流程中特定时机会广播出对应的事件,插件可以监听这些事件的发生,在特定时机做对应的事情。

运行流程:

  1. 初始化参数:从配置文件和Shell语句中读取与合并参数,得出最终的参数;
  2. 开始编译: 用上一步得到的参数初始化Complier对象,加载所有配置的插件,执行对象的run方法开始执行编译;
  3. 确定入口: 根据配置中的entry找出所有入口文件;
  4. 编译模块:从入口文件出发,调用所有配置的Loader对模块进行翻译,再找出该模块依赖的模块,再递归本步骤知道所有入口依赖的文件都经过了本步骤的处理;
  5. 完成模块编译: 在经过第4步使用Loader翻译完所有模块后,得到了每个模块被翻译后的最终内容以及他们之间的依赖关系;
  6. 输出资源:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的Chunk,再把每个Chunk转换成一个单独的文件加入到输出列表,这步是可以修改输出内容的最后机会;
  7. 输出完成: 在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统。

Loader

一个Loader其实就是一个Node.js模块,这个模块需要导出一个函数。这个导出函数的工作就是获得处理前的原内容,对原内容执行处理后,返回处理后的内容。

module.exports = function(source) {
      // source为compiler传递给Loader的一个文件的原内容
      // 该函数需要返回处理后的内容,这里简单起见,直接把原内容返回了,相当于该Loader没有做任何转换
      return source
}
// 由于Loader运行在Node.js中,你可以调用任何Node.js自带的API,或者安装第三方模块进行调用:
const sass = require('node-sass')
module.exports = function(source) {
    return sass(source)
}

08. 前端性能监控有了解吗?

相关文章

09. 怎么防止重复请求

let count = 1;
// 模拟请求
let promiseFunction = () =>
  new Promise(rs =>
    setTimeout(() => {
      rs(count++);
    })
  );

// 如果发了多个请求,只执行
function firstPromise (promiseFn) {
    let p = null
    return function (...args) {
        return p
            ? p
            : (p = promiseFn.apply(this, args)).finally(() => (p = null))
    }
}

let firstFn = firstPromise(promiseFunction);
firstFn().then(console.log); // 1
firstFn().then(console.log); // 1
firstFn().then(console.log); // 1

10. 求两数之和

/**
 * 求一个数组种和等于target的2个元素的下标
 * 把遍历过的值用一个对象存起来,
 * 遍历过程中看看临时对象是否存在`当前值的差值`,有直接返回即结束。
 */

 let nums = [2, 7, 11, 15]
 let target = 9
 
 function getIndexes(arr, tgt) {
     let temp = {}
     for (let i = 0; i < arr.length; i++) {
         let value = arr[i]
         let diff = target - value
         if (temp[diff] === 0 || temp[diff]) {
             return [temp[diff], i]
         } else {
             temp[value] = i
         }
     }
 }

 console.log('age', getIndexes(nums,target));

11. 白屏优化方案

当前很多无线页面都使用前端模板进行数据渲染,那么在糟糕的网速情况下,一进去页面,看到的不是白屏就是 loading,这成为白屏问题。

此问题发生的原因基本可以归结为网速跟静态资源,根本原因是客户端渲染的无力

  • 1、css文件加载需要一些时间,在加载的过程中页面是空白的。 解决:可以考虑将css代码前置和内联。
  • 2、首屏无实际的数据内容,等待异步加载数据再渲染页面导致白屏。 解决:在首屏直接同步渲染html,后续的滚屏等再采用异步请求数据和渲染html。
  • 3、首屏内联js的执行会阻塞页面的渲染。 解决:尽量不在首屏html代码中放置内联脚本。(来自翔歌)

解决方案

  • 因此最简单的方法是在服务器端,使用模板引擎渲染所有页面。同时
  • 减少文件加载体积,如html压缩,js压缩
  • 加快js执行速度 比如常见的无限滚动的页面,可以使用js先渲染一个屏幕范围内的东西
  • 提供一些友好的交互,比如提供一些假的滚动条
  • 使用本地存储处理静态文件。

12. 手写防抖,节流

  • 连续触发在最后一次执行方法,场景:输入框匹配
// 防抖
let debounce = (fn, time = 1000) => {
    let timeLock = null
    return function (...args){
        clearTimeout(timeLock)
        timeLock = setTimeout(()=>{
            fn(...args)
        }, time)
    }
}

13. 说说浏览器的消息循环机制

14. transition和animation的区别

15. 说说requestAnimationFrame的作用,并实现获取每秒的帧数

16. 浏览器的控制台是怎么渲染的?说说在浏览器控制台输出console到输出显示的过程?

17. DNS相关

  • DNS解析是去哪找的缓存?
  • 怎么找到DNS服务器?
  • DNS怎么解析出IP的?
  • 解析出ip地址后怎么找到对方?
  • 握手为什么要三次?万一第三次没有发出去呢?

18. 算法-复原IP地址

19. CSS实现一个正三角形

20. 说说header常见的字段有哪些?作用分别是什么?

Access-Control-Request-Method

21. Cookie有哪些字段?分别什么作用

22. CSRF怎么防范?

23. 单页和多页应用怎么通讯

24. 说说HTTP和HTTPS的区别?

  • 主要从HTTPS解决了什么问题出发分点描述

25. 一个扫码支付的功能你会怎么实现

26. 说说new的过程吧

27. 说说原型链

28. this相关的几道题目

29. 如何防范iframe被钓鱼网站嵌套导致的安全问题?iframe如何判断是否被嵌套?

30. 实现一个深拷贝你会考虑到哪些点?

31. 实现两个有序链表的合并

32. 聊聊你知道的设计模式有哪些?

33. 讲讲函数式编程的特点

34. 给你一段template,写出编译成render函数后的代码

35. 说说Vue的依赖收集过程吧,当数据发生变化后,依赖会重新收集吗

36. 讲讲webpack的原理吧,你掌握到哪种程度?

优化插件、打包原理和热更新原理,看过核心源码

loader和plugin实现过吗?知道原理吗?

说说module、chunk、bundle、asset的区别

  • chunk一定是通过入口生成的吗?(不一定,import动态加载的模块也会作为一个chunk)
  • css-loader的作用?(处理依赖关系)
  • css中的路径是如何解析的?
  • css-loader和file-loader如何一起工作的?