前端面试

前端面试题

前端性能优化的方案

  • 请求与相应

    • 缓存控制

      可以在请求头中 询问服务端请求内容是否更新,如果没更新可以使用浏览器的缓存,避免资源的重新下载

    • 复用TCP

      当要跳转到打开过的页面时,可以通过keep-alive复用之前使用过的TCP

    • 合理使用cookie

      可以在加载静态资源的时候不发送多余的cookie,同时合理设置cookie,如子站避免来着父站不必要的cookie

    • 尽量避免重定向与404

      重定向和404会浪费很多加载请求,使用尽量避免

  • HTML

    • 减少不必要的DOM

      太多的DOM会影响页面的渲染加载。所以除了设计合理的结构外,还有避免创建不必要的DOM,或者可以使用懒加载,当用到该DOM的时候在进行渲染

    • CSS和JS的放置位置尽量合理

      css文件放在head中,js放在body闭标签前,将两个文件放在合适的位置会提高渲染的效率

    • 合理使用脚本延迟

      使用defer和async,async是停下文档解析立即实行脚本,defer是直至文档解析完毕再执行脚本,这样可以提供渲染效率

  • CSS

    • 尽量避免使用后代选择器,因为后代选择器的执行效率比id和class选择器低
    • 可以使用一些transform等属性,利用GPU的运算功能,提高效率
  • JavaScript

    • 避免重排

      可以修改类名从而修改样式,尽量不要直接修改属性

  • 资源

    • 可以压缩资源或者使用懒加载,让页面需要用到该资源的时候再进行加载
  • 缓存

    • 可以使用locastorage或者sessionstorage存储一些静态数据,避免请求过多,消耗资源

对缓存的理解

​ 当用户发送请求后,会先查看浏览器是否有对应的缓存,如果有再查看是否过期,如果没过期则从缓存中取出数据进行呈现,如果过期了或者没有对应缓存会向服务器发送请求,获取资源,然后将资源放入缓存后最后呈现。

CDN的原理

​ CDN是内容分发网络, CDN的基本原理是广泛采用各种缓存服务器,将这些缓存服务器分布到用户访问相对集中的地区或网络中,在用户访问网站时,利用全局负载技术将用户的访问指向距离最近的工作正常的缓存服务器上,由缓存服务器直接响应

闭包是什么,以及应用场景

  • 闭包是指可以有权访问其他函数作用域里的变量的函数,当形成闭包后,局部变量不会被释放,可以理解为闭包的变量存放在堆中
  • 应用场景:当一个函数只需要执行一次,不需要维护其变量,可使用闭包;当一个函数需要用到上一次的变量时可以使用闭包,将上一次的变量值保存下来(即模仿块级作用域、保护外部变量、封装私有变量)

同源策略

当url的协议、端口、主机相同时才为同源

同源策略是浏览器的一个安全机制,即在没有明确授权情况下,不能获取非同源的资源

  • 跨域方法 jsonp、cors

解释一下promise

  • promise是个对象。保存未来要结束的事件
  • promise的状态不受外部的影响,其状态为pending(进行时)、fullfilled(已完成)、rejected(失败),只有异步操作的结果才能决定其状态
  • promise只有两种情况,一种是pending到fullfill,即resolve,一种是pendding到rejected,即reject
  • 常见用法是then.catch.finally

promise.all和promise.race的区别

​ 只有当all里所有的promise对象都返回成功,该promise才成功,不然返回错误,

​ race相当于竞争,当列表中对象有一个返回成功则成功,返回成功的值

暂停性死区

​ 暂停性死区是指他在代码块内,一个变量未经let、const声明前,该变量不可用

什么是内存泄漏

​ 内存泄漏是指程序进行动态内存分配的时候因某种原因导致内存未被及时释放造成系统内存的浪费

防抖和节流的区别

  • 节流是指一段时间内方法只执行一次,防抖是指当方法调用频繁的时候,停止调用一段时间后才执行方法

  • //节流
    function(func, delay) {
        let flag = true;
        return () => {
            if (!flag) return;
            flag = false;
            setTimeout(() => {
                func.aplly(this, arguments);
                flag = true;
            },delay);
        };
    }
    
  • //防抖
    function(func, delay) {
        let timer = null;
        return () => {
            if (timer) clearTimeout(timer);
            timer = setTimeout(()=> {
                func.aplly(this, arguments);
            }, delay);
        };
    };
    

布局方式

圣杯布局、双飞翼布局(三栏)、多栏布局(栏栅格、多列布局)、弹性布局、瀑布流布局、流式布局、响应式布局

继承方式

  • 原型链继承

    • function person() {
          this.name = "xxx"
      };
      person.prototype = new man();
      
    • 重点:让新实例的原型等于父类的实例

    • 特点:子类可继承实例的构造函数的属性、父类构造函数的属性、父类原型的属性(实例不会继承父类实例的属性)

    • 缺点:

      • 新实例无法向父类构造函数传参
      • 继承单一
      • 所有实例会共享父类实例的属性
  • 构造继承

    • function person() {
          man.apply(this, arguments);
          this.name = 'xxx';
      };
      
    • 重点:用call等将父类的构造函数引入子类

    • 特点:

      • 只继承父类构造函数的属性
      • 解决原型链继承的缺点
      • 可以继承多个父类
    • 缺点:

      • 只继承父类构造函数的属性
      • 无法实现构造函数的复用
      • 每个实例都有父类构造函数的副本
  • 组合继承

    • function person() {
          this.name = "xxx";
          man.apply(this, arguments);
      }
      person.prototype = new man();
      
    • 重点:结合了两种,传参和复用

    • 特点:

      • 可以继承父类原型的属性,传参,复用
      • 每个实例引入的构造函数是私有的
    • 缺点:

      • 调用两次构造函数
      • 子类的构造函数会代替父类构造函数
  • 原型式继承

    • function content(obj) {
          function F() {
          };
          F.prototype = obj;
          return new F();
      }
      const con1 = content(new man())
      
  • 寄生式继承

    • function content(obj) {
          function F() {};
          F.prototype = obj;
          return new F();
      };
      function subobject(obj) {
          let o = content(obj);
          o.name = 'xxx';
          return o;
      }
      let per1 = subobject(new man());
      
  • 寄生组合继承

    • function Person () {
          this.name = "xxx"
      };
      function content(obj) {
          function F(){};
          F.prototype = obj;
          return new F();
      };
      let con = content(Person.prototype);
      function sub () {
      	Person.call(this);
      };
      sub.prototype = con;
      con.constructor = sub;
      

箭头函数的arguments拿什么代替

使用...rest

webpack是什么,作用

​ webpack是一个前端模块化的打包工具,可以将开发中的一些资源图片等,打包成一个个时候部署的前端资源

语义化标签的意思

让编写的人或者看代码的人能更容易理解该标签和属性的用途和作用

宏任务和微任务

  • 宏任务:当前调用栈中执行的任务称为宏任务。(主代码快,定时器等等)
  • 微任务: 当前(此次事件循环中)宏任务执行完,在下一个宏任务开始之前需要执行的任务为微任务。(可以理解为回调事件,promise.then,proness.nextTick等等)。
  • 宏任务中的事件放在callback queue中,由事件触发线程维护;微任务的事件放在微任务队列中,由js引擎线程维护。

http协议无状态

  • 协议对事物处理没有记忆能力。如果后续要处理之前的信息,必须重传

http相应码

  • 1xx临时相应
  • 2xx成功相应
  • 3xx重定向
  • 4xx请求错误
  • 5xx服务器内部错误

Vue

  • 如何理解生命周期

    • new Vue()
    • 首先初始化事件和模板-
    • beforeCreate()函数(数据未获取,未挂载,一般不做操作)
    • 数据代理,挂载数据,绑定事件等
    • created()(可以在该函数中更改数据,不会触发updated函数,一般用作获取数据)
    • 生成虚拟DOM,放入render函数中进行渲染
    • beforeMouted(虚拟DOM已完成,可以进行最后数据的修改,不会触发其他钩子函数,一般用于获取数据)
    • 将render函数挂载到dom树上,进行渲染
    • mounted(dom已创建,可以操作真实的dom)
    • 当数据更改时,会立即执行beforeUpdate函数(),然后虚拟dom机制会重新构建虚拟dom,并与上一次的dom树利用diff算法进行对比。渲染dom树。
    • updated函数(可以操作更新后的dom)
    • 当vue实例即将被销毁时,会立即执行beforedestroy函数,可在该函数内执行一些善后工作,如清除定时器等
    • 当事件、数据等都清除后,会执行destroyed函数,也可以实现善后工作
  • 如何进行非父子组件通信

    • 使用vuex
    • 在main.js中的vue实例中,vue.protoype.$bus = new vue();实现总线。通过bus.$emit()以及bus.$on进行事件响应
  • 浅谈Diff算法

    • 当使用key属性的时候,会开启类似diff的算法,diff算法是根据dom生成一颗虚拟dom树,当节点数据改变后,会进行新旧节点的对比,这样提高了效率
  • nextTick原理以及用途

    • 当数据发生变化时,vue会先将同步任务执行完后再更新视图,那么在同一个事件循环中获取不到变化后的数据,nexttick相当于执行了一个异步操作,等待更新完视图后才执行的回调函数
    • 用途:获取视图更新后的DOM
  • scoped原理

    • vue编译时会通过将dom元素以及样式添加唯一标识实现其私有化
  • vue中自定义指令

    • vue.directive("focus", {...})
  • vue等单页面的优缺点

    • 优点:
      • 良好的交互体验
      • 良好的前后端工作分离模式
      • 减轻服务器压力
    • 缺点:
      • SEO难度较高(搜索引擎优化 )
      • 前进、后退管理困难
      • 初次加载耗时多
  • Vue的响应式原理

    • 不要认为数据发生改变,界面跟着更新,并不是理所当然
    • app.message修改数据,Vue内部是如何监听message数据的改变
      • Object.defineProperty ->监听对象属性的改变
    • 当数据发生改变,Vue是如何知道要通知哪些对象、界面发生刷新
      • 发布订阅者模式
    • 通过发布者-订阅者模式实现
    • 当组件初始化的时候,会先用Object.defineProperty给每个data属性注册getter和setter,然后再new 一个watcher对象,然后watcher会立即调用组件的render函数生成虚拟dom,然后再调用render挂载到页面上,使用render函数会调用data的getter,会将当前watcher注册进sub中。
    • 当data的值发生修改时,会先遍历sub里所有的watcher对象,找到对应的wathcer,然后让其重新渲染组件
    • 数据劫持
      • 使用Object.defineProperty(data, 'message', {set: get}),当设置或定义属性时会生成get和set
  • vue2与vue3区别

    • 默认进行懒观察。不管数据多大,在vue2中一开始会为其创建观察者,当数据量大时,会对性能造成压力,vue3只对用于渲染可见部分的数据创建观察者,且3.x的观察者更高效
    • 变更更精准。对于vue2.x版本来说,通过vue.set为对象创建属性时,这个对象的所有 watcher都会重新运行,vue3中,只有依赖那个属性的watcher才会重新运行
    • vue3新加入了typescript以及对pwa的支持
    • 部分命令发生变化
    • 默认目录结构也发生了变化
  • watch和computed的区别

    • computed
      • 支持缓存,当数据发生变化时才会重新计算
      • 不支持异步,当computed内有异步操作则无效
    • watch
      • 不支持缓存,当数据变化,直接触发相关操作
      • 支持异步
posted @ 2021-04-08 20:22  ghost12137  阅读(101)  评论(0)    收藏  举报