web前端面试攻略[vue,js,css,html,webpack,安全,性能,浏览器,手撕代码](一)

266 阅读37分钟

面试自我介绍

  • 一句话概括说明自己的经历和优势
  • 一句话简要描述之前做过的工作
  • 一句话简要描述最近一份工作以及重点的业绩
  • 一句话简要描述对目标岗位的理解和想法
  • 一句话表明应聘的意愿
  • 是否擅长你的专业
  • 是否热爱你的专业
  • 如果你不擅长,那你是否有能力提高
  • 你做过让你受益的项目,项目中遇到最大的困难你是如果考虑问题和解决问题的
  • 是否有明确的职业规划

业务方面

最爱听:做过什么项目。说清楚:为项目做过什么。得高分:对项目的思考。

技术方面

最爱听:使用什么技术。说清楚:这个技术的价值。得高分:对技术的思考

目标

  • 目标是什么:在业务上成为专家,在技术上成为行业大牛
  • 近阶段的目标:不断学习,积累,以学习为主
  • 长期目标:做几件有价值的事情,如开源作品,技术框架

规划

  • 你准备在我们这家单位做多久?

这不是自己单方面决定的,还要看公司,但是可以肯定的是,如果公司跟自己的职业发展一致,我是会一直干下去的。 以我对公司和现有职位的了解,如果能应聘上的话,目前来看至少可以稳定三年。

  • 未来五年的规划是怎样的?

首先是踏实的做好自己的本职工作,然后在空闲之余,研究一下新技术,拓展知识,提高自己的技术水平,往多方面去发展,比如前端框架,架构设计,构建工具,网络安全浏览器优化等,然后会多写一些技术博客,总结自己的错点难点,分享自己的成果,我对前端兴趣很大,个人目前还是偏向于技术职位的,希望在这个领域更上一层楼

离职原因

我在目前这家公司做的还可以,也有一些成绩,学到了很多经验和知识,但职业上遇到了瓶颈,也很难有机会去接触新的技术,我个人比较希望去接触一些别的行业,了解一些新的知识,让自己有更好的发展空间

优点

喜欢学习的知识,喜欢钻研新的技术,并且会很投入进去做这件事,如果学到新的东西,把事情做成功了,会带给我很大的成就感

缺点

性格比较急,然后顾虑也比较多,比如领导给我一个任务,那我就想很尽快的去完成,可是呢,另一个任务也需要尽快完成,然后我心里可能就会有一点焦躁,肯定是希望能把两个任务都很好的完成

你的优势

如果不了解面试公司,可以问

我对前端的基础知识非常扎实,到目前为止,也有两三年的Vue的经验,对于解决不同的技术问题有一定的方法,另外,我喜欢学习钻研新的技术,擅于写笔记,总结错点难题,乐于分享

我看过贵公司的招聘条件,我有信心能胜任这个职位

面试例子

您好,我叫xx,来自XXX,XXX大学毕业,今天来是想面试贵公司的前端岗位

从17年至今,我一直在xx公司担任web前端职务,接触前端也有三年了,最先刚毕业的时候,是用jquery和html写一些静态页面,后来慢慢的接触了前端各种各样的框架,就开始用框架去搭建项目,vue是我比较常用且非常熟悉的一个框架,目前正在做的项目,是一个商城平台,也是用的vue框架,在这个项目中,前期我主要做的是整合代码,重构页面,优化一些功能,让整个项目结构清晰,代码可维护,可复用,后面的话,就是开发一些比如编辑收货地址,图片裁剪,国际化等一些新需求新功能

我对前端这个职业,一直都有很大的热情和兴趣,虽然我做前端这个行业不是很久,技术相对来说还有些欠缺,但如果能面试成功,我有信心也有决心能做好这份工作

以上是我的自我介绍,谢谢

面试技巧

原理题的回答

  • 如果是英文简写就说一下英文全称。
  • 一句话概括该技术的核心用途
  • 描述该技术的核心概念
  • 口述代码书写思路
  • 该技术的优点
  • 该技术的缺点
  • 如何弥补缺点

例子

  • 请问ajax的原理是什么?
    • ajax是JavaScript 和 xml对象的缩写
    • 主要是用在不刷新页面的情况下向服务器发送数据,然后局部更新页面
    • 该技术的核心是xmlHttpRequest对象,该对象可发起请求,并监听获得数据响应
    • 描述代码思路。。。。
    • 优点是无刷新更新页面,
    • 缺点是不支持back后退

前端

  • 说说你对前端架构师的理解?
    • 负责前端管理团队的协调工作,提升团队成员能力和整体效率;
    • 带领团队完成研发工具及前端部分的设计、研发和维护;
    • 带领团队进行前端领域前沿技术研究及新技术调研,保证团队的技术领先
    • 负责前端开发规范制定、功能模块化设计、公共组件搭建等工作,并组织培训。

  • 说说你对前端的理解?
    • 技术选型
    • 搭建架构
    • 设计性能
    • 安全考虑
    • 代码规范
    • 后期维护

    简单来说,就是展现给用户浏览的网页

  • 你觉得前端工程的价值体现在哪?
    • 用户交互,展示数据
    • 浏览器兼容
    • 优化浏览器性能
    • 响应式设计
    • 开发组件库

  • 有了解最近半年的前端相关动态吗?
    • Web组件化:考虑组件开发时代的未来,以及模块化,可重用性,封装和标准化的原理,Web组件就是答案。
    • 微前端:它将前端应用拆分成一个个更小的更简单的能够独立开发、测试、部署的小块,在用户看来它依旧是一个独立的产品。前端业务在发展到一定规模后,需要一种能将业务化繁为简的架构。常用的微前端解决方案有single-spa、qiankun。
    • TypeScript接管前端
    • vue3

  • 微前端?
    • 微前端是一种多个团队通过独立发布功能的方式来共同构建现代化 web 应用的技术手段及方法策略。
    • 微前端借鉴了微服务的架构理念,将一个庞大的前端应用拆分为多个独立灵活的小型应用,每个应用都可以独立开发、独立运行、独立部署。

  • 你最擅长什么技术?
    • 如果是框架,比较擅长用vue开发
    • JavaScript

  • 做过最满意的项目是什么?
  • 在项目中遇到过什么技术问题?如何解决的?
  • 你觉得项目有什么需要改善的?

  • 为什么要学前端?
    • 我大学专业是xx,跟计算机相关,在选择就业方向的时候就选择了前端,这是一个前景非常好的职业,而我本身也对这方面感兴趣。

  • 是怎么入门学习的?
    • 最开始认识前端,是学校有关于web前端的讲座,导师用了几个标签实现了几个功能,让人能直观的感受到,觉得这是个很神奇的事情,很想尝试,实习的时候选择了前端。最开始学习,有年长的大佬带,边学边写,我自己平常也会上论坛和技术网站,把html+css+js这三样自学完成。

  • 平时是怎么学习前端开发的?
    • 论坛、技术网站CSDN,掘金,牛客网

前端框架 - VUE面试点

  • MVVM开发模式的理解?
    • MVVM分为Model、View、ViewModel三者。
    • Model 代表数据模型,数据和业务逻辑都在Model层中定义;
    • View 代表UI视图,负责数据的展示;
    • ViewModel 负责监听 Model 中数据的改变并且控制视图的更新,处理用户交互操作;
    • Model 和 View 并无直接关联,而是通过 ViewModel 来进行联系的,Model 和 ViewModel 之间有着双向数据绑定的联系。因此当 Model 中的数据改变时会触发 View 层的刷新,View 中由于用户交互操作而改变的数据也会在 Model 中同步。
    • 这种模式实现了 Model 和 View 的数据自动同步,因此开发者只需要专注对数据的维护操作即可,而不需要自己操作 dom。

  • 说说你对 SPA 单页面的理解?
    • SPA仅在 Web 页面初始化时加载相应的 HTML、JavaScript 和 CSS,页面加载完成,SPA 不会因为用户的操作而进行页面的重新加载或跳转;取而代之的是利用路由机制实现HTML 内容的变换

  • SPA的优缺点分别是什么?
    • 优点
      • 用户体验好、快,内容的改变不需要重新加载整个页面,避免了不必要的跳转和重复渲染;
      • 基于上面一点,SPA 相对对服务器压力小;
      • 前后端职责分离,架构清晰,前端进行交互逻辑,后端负责数据处理;
    • 缺点
      • 初次加载耗时多
      • 前进后退路由管理需要建立自己的堆栈
      • SEO 难度较大:由于所有的内容都在一个页面中动态替换显示,所以在 SEO 上其有着天然的弱势。

  • 浅谈vue是什么?为什么选择vue,解决了什么问题?
    • 一套构建用户界面的渐进式框架(所谓渐进式框架,就是按需、逐渐集成功能,vue逐步集成了vue-cli、vueRouter、vuex等功能,形成了vue全家桶)
    • vue把数据和视图分离,它只关注视图层
    • vue有响应式的数据绑定
    • vue可组件化开发,拆分页面交互和结构,容易快速上手

  • vue.js的两个核心是什么?
    • 数据驱动(双向数据绑定):ViewModel,保证数据和视图的⼀致性
    • 组件系统:UI可以看做全部是由组件树构成的

  • 谈谈对 vue 组件化的理解?
    • 组件是独立和可复用的代码组织单元,组价系统是 vue 核心特性之一,它使开发者使用小型、独立和通常可复用的组件构建大型应用。
    • 通俗的讲,把一些用户在程序中一些独立的功能和模块单独提取出来,然后切分为更小的块,这些块有独立的逻辑,有更好的复用性。
    • 常见的组件化技术有:prop 属性、自定义事件、插槽等,这些主要用于组件之间的通信
    • 组件化的开发能大幅提高开发效率、测试性和复用性,合理的划分组件能够大幅提升应用性能

  • vue有哪些内置组件?
    • keep-live
    • compoments

  • vue组件的通讯方式?
    • props/ $emit 适用于父子通讯
    • ref/ $parent/ $children 适用于父子通讯
    • 通过Bus公共组件,$emit/$on 适用于父子、隔代、兄弟通信
    • $attrs/ $listeners 适用于 隔代组件通信
    • provide / inject 适用于 隔代组件通信
    • Vuex 适用于 父子、隔代、兄弟组件通信
    • v-model 父子组件通信

  • 子组件可以直接改变父组件的数据吗?
    • 不可以。这样做主要是为了维护父子组件的单向数据流
    • 只能通过 $emit 派发一个自定义事件,父组件接收到后,由父组件修改。

  • vue的单向数据流?
    • 父子之间有一个单向下行绑定:父级数据的更新会向下流动到子组件中,但是反过来则不行。

  • vue2响应式绑定的原理?【点击查看详细分析
    • 采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发给订阅者,触发相应的监听回调
    • Object.defineProperty()缺点:无法检测对象属性的新增或删除,不能监听数组的变化。
    • Object.defineProperty()解决方法:
      • 提供Vue.$set动态给对象添加属性。
      • 重写数组的方法,检测数组变更

  • vue3 实现数据双向绑定的方法?
    • vue3.0 实现数据双向绑定是通过Proxy
    • Proxy是 ES6 中新增的一个特性,用来“代理”某些操作

  • vue3使用proxy实现双向数据绑定,相比vue2Object.defineProperty优势?
    • 可以劫持整个对象,并返回一个新对象
    • 有13种劫持操作

  • proxy的优缺点?
    • 优点:可以检测到代理对象属性的动态新增和删除。可以监测到数组的下标和length属性的变化。
    • 缺点:es6的proxy不支持低版本浏览器(IE11)

  • vue3的新特性?
    • 数据响应重新实现(ES6的proxy代替ES5的Object.defineProperty)。
    • 源码使用ts重写,更好的类型推导。
    • 虚拟DOM新算法(更快、更小)。

  • Vue2的生命周期?【点击查看详细分析
    • beforeCreate:创建前(可以加loading事件,路由判断控制)
    • created:创建后(结束loading事件,处理数据)
    • beforeMount:挂载前
    • mounted:挂载后(DOM渲染完成,获取dom节点)
    • beforeUpdate:更新前
    • updated:更新后
    • activated():keep-alive 组件激活时调用
    • deactivated(); keep-alive 组件停用时调用
    • beforeDestroy:销毁前(停止事件)
    • destroyed:销毁后
    • errorCaptured(2.5.0+ 新增)

  • 第一次页面加载会触发哪几个钩子?
    • 第一次页面加载时会触发 beforeCreate, created, beforeMount, mounted 这几个钩子

  • vue生命周期中异步加载在mouted还是create里实现?
    • created
    • 能更快获取到服务端数据,减少页面 loading 时间
    • 放在 created 中有助于一致性,因为ssr 不支持 beforeMount 、mounted 钩子函数

  • keep-alive 的作用是什么?
    • 包裹动态组件时,会缓存不活动的组件实例,主要用于保留组件状态或避免重新渲染。

  • 如果加入 keep-alive,第一次进入组件会执行哪些生命周期函数?
    • 会执行的钩子函数以及它们的顺序分别为:beforeCreat、created、beforeMount、mounted、activated

  • 如何封装一个组件
    • 创建一个组件,如果需要全局使用,可在vue.install方法注册。
    • 如果子组件需要接收数据,可以在props中定义
    • 要传值给父组件时,可用emit发送数据。
    • 设计原则:组件设计的时候,需要考虑后续的拓展性,以便于增加新的功能,数据结构要清晰明了,尽量一个组件只做一件事。

  • Vue的指令有哪些?
    • v-if:根据表达式的值的真假条件渲染元素。在切换时元素及它的数据绑定 / 组件被销毁并重建。
    • v-show:根据表达式之真假值,切换元素的 display CSS 属性。
    • v-for:循环指令,基于一个数组或者对象渲染一个列表,vue 2.0以上必须需配合 key值 使用。
    • v-bind:动态地绑定一个或多个特性,或一个组件 prop 到表达式。
    • v-on:用于监听指定元素的DOM事件,比如点击事件。绑定事件监听器。
    • v-model:实现表单输入和应用状态之间的双向绑定
    • v-pre:跳过这个元素和它的子元素的编译过程。可以用来显示原始 Mustache 标签。跳过大量没有指令的节点会加快编译。
    • v-once:只渲染元素和组件一次。随后的重新渲染,元素/组件及其所有的子节点将被视为静态内容并跳过。这可以用于优化更新性能
    • v-html:用来更新元素的 innerHTML,v-html会将里面的内容当html标签解析后输出,v-html 指令应尽量避免使用,否则会带来危险(XSS攻击 跨站脚本攻击),一般只在可信任内容上使用 v-html,永不用在用户提交的内容上;
    • v-text:innerText,只输出文本。

  • v-model的作用?实现原理?
    • 作用: 创建双向绑定
    • 原理:
      • value绑定响应式数据
      • input事件传递数据

  • v-if 和 v-for 的优先级哪个高?
    • v-for 的优先级更高。
    • 如果 v-if 和 v-for 同时出现,每次渲染都会先执行循环,再判断条件,无论如何循环都不可避免,浪费了性能。
    • 可在外层加template嵌套

  • v-if 和 v-show 的区别?
    • 相同点:都是动态显示DOM元素
    • v-if 是真正的条件渲染,有更高的切换消耗,v-if适合运行时条件很少改变时使用
    • v-show 只是简单地切换元素的 CSS 属性display。有更高的初始消耗,v-show适合频繁切换

  • vue常用的修饰符?
    • .stop - 调用 event.stopPropagation(),禁止事件冒泡。
    • .prevent - 调用 event.preventDefault(),阻止事件默认行为。
    • .capture - 添加事件侦听器时使用 capture 模式。(与事件冒泡的⽅向相反,事件捕获由外到内)
    • .self - 只当事件是从侦听器绑定的元素本身触发时才触发回调(只会触发⾃⼰范围内的事件,不包含⼦元素)
    • .{keyCode | keyAlias} - 只当事件是从特定键触发时才触发回调。
    • .native - 监听组件根元素的原生事件。
    • .once - 只触发一次回调。
    • .left - (2.2.0) 只当点击鼠标左键时触发。
    • .right - (2.2.0) 只当点击鼠标右键时触发。
    • .middle - (2.2.0) 只当点击鼠标中键时触发。
    • .passive - (2.3.0) 以 { passive: true } 模式添加侦听器
    • .sync - 当一个子组件改变了一个 prop 的值时,这个变化也会同步到父组件中所绑定

  • v-model 和.sync 区别?
    • 相同点:都是语法糖,都可以实现父子组件中的数据通信。
    • 不同点:格式不同,使用的方法不一样
      • v-model="num" 类似 v-model:@input+value
      • :num.sync="num" 类似 :num.sync:@update:num
      • v-model只能使用一次,.sync可以使用多个。

  • key 的作用和工作原理?
    • key是虚拟DOM对象的标识,具有唯一性,用于管理可复用的元素
    • key 的作用主要是为了高效地更新虚拟DOM
    • 其原理是,通过key可以精准判断两个节点是否是同一个,从而避免频繁更新不同元素,使得整个渲染过程更加高效,减少DOM操作量,提高性能。

  • 用index作为key可能会引发的问题?
    • 若对数据进行:逆序添加、逆序删除等破坏顺序操作:会产生没有必要的真实DOM更新 ===> 界面效果没问底,但效率低
    • 如果结构中还包含输入类的DOM:会产生错误DOM更新 ===> 界面有问题

  • Vue 组件中 data 为什么必须是函数?
    • vue 组件可能存在多个实例,如果使用对象形式定义 data ,则会导致所有实例公用一个 data 对象,那么状态变更将会影响所有组件实例。
    • 如果采用函数的形式,在实例化组件时,data 会被当做工厂函数返回一个全新的 data 对象,有效规避多实例之间状态污染问题。
    • 所以在组件中的 data 必须是函数,不能使用对象形式。

  • 为什么 data 在组件内必须是函数,而 vue 的根实例则没有此限制?
    • 在 vue 中根实例只能有一个,不需要担心多实例的问题,所以根实例中的 data 可以是函数也可以是对象。

  • computed 与 methods、watch 的区别?【点击查看详细分析
    • 相同点:computed vs watch都是侦听数据并处理
    • computed:计算属性方法,有缓存。
      • 支持缓存: 被计算的属性本质上是一个观察者,具有缓存行,只有当依赖发生变化后,才会计算新的值
      • 不支持异步:当computed内有异步操作时无效,无法监听数据的变化
      • 计算一个新的属性,并将该属性挂载到实例上
      • 适用于一个属性依赖于其他多个属性的计算
    • watch:监听方法,无缓存。
      • 不支持缓存,数据改变,立即响应
      • 支持异步
      • 监听一个存在并且已经挂载到实例上的数据(watch可监听computed计算属性的变化)
      • 适用于一个属性变化时,需要执行对应操作。
      • 接收两个参数,新值和旧值
      • immediate:是否立即触发回调函数执行
      • deep:是否深度监听(deep无法监听到数组的变动和对象的新增,新增需用set才可被监听到)
    • methods:内部方法,无缓存。
      • Methods是挂载到vue实例所有方法的集合

  • computed的缓存是如何控制的【点击查看详细分析
    • 控制缓存最重要的一点是标志位dirty,简称脏值。
    • dirty是订阅者的一个属性
      • dirtytrue,读取computed会重新计算
      • dirtyfalse,读取computed会使用缓存

  • computed中可以使用new Date()持续获取时间吗?
    • 不能

  • watch实现原理?
    • 基于watcher,订阅者发布者模式实现
      • 首先,进行watch数据初始化,循环遍历watch属性,生成订阅者user watcher实例。
      • user watcher初始化的时候,就会将自己加入到被监听的属性的订阅器中。
      • 被监听的属性值改变,通知user watcher,触发回调,执行用户自定义的回调函数。

  • data,props,computed,watch,methods的初始化顺序?
    • props -> methods -> data -> computed -> watch

  • props 和 data 的优先级谁高?
    • props -> methods -> data -> computed -> watch

  • Vue中set的作用?
    • 给对象添加新的属性
    • Vue无法监听普通的数组新增属性的变化,需要用$set进行视图更新

  • 直接赋值不能检测到,为什么数组push等函数能被检测到?
    • 数组push等重新拦截了一遍getter,setter。

  • 什么是$nextTick?
    • $nextTick是一个用于在DOM更新完成后执行回调函数的方法
    • Vue的数据更新是异步更新,数据更新后不会立刻更新,而是开启一个队列,缓存同一轮事件循环中的所有数据改变,在缓存时会除去重复的操作,等到下一轮事件循环时,才开始更新,这个时候,通过DOM操作获取的数据仍然是没有更新的数据,所以为了正确的获取dom数据,vue提供了nextTick方法

  • nextTick中的waiting是什么时候变为true的呢?
    • 当队列中的所有订阅者的回调都执行完毕后,waiting会变为true

  • Vue-router路由的两种模式?【点击查看详细分析
    • hash模式
      • 使用hash模拟一个完整的url,当hash改变时,url不会刷新重新加载
      • 使用hashChange事件监听,用 window.location.hash 读取
      • 本质上锚点改变,单页面控制页面组件显示隐藏
      • hash模式不会请求服务器
    • history模式
      • 基于HTML5新增的两个API,pushState,replaceState和popstate事件实现。
      • 需要自定义触发popstate事件
      • pushState,replaceState改变URL的路径,不会引起页面刷新。
      • history路由模式没有#号,是真实的URL,刷新页面,这种模式会被服务器识别,服务器会对URL的文件路径进行资源查找,找不到就会报404问题,所以,在我们使用history路由模式时,需要与后端进行沟通,在nginx中配置。

  • vue-router初始化是在什么时候?
    • 路由初始化的时机是在组件初始化的阶段,执行到beforeCreate钩子函数时候会执行router.init方法

  • Vue-router跳转和location.href有什么区别?
    • 使⽤location.href=/url 来跳转,简单⽅便,但是刷新了页⾯
    • Vue-router⽆刷新页⾯,静态跳转,可按需加载,减少dom消耗

  • params和query的区别?
    • query在url中显示,params不显示
    • query刷新不会丢失,params会丢失

  • 导航守卫的作用?
    • 主要用来通过跳转或取消的方式守卫导航。
    • 简单的说,导航守卫就是路由跳转过程中的一些钩子函数。路由跳转是一个大的过程,这个大的过程分为跳转前中后等等细小的过程,在每一个过程中都有一函数,这个函数能让你操作一些其他的事儿的时机,这就是导航守卫。

  • 路由守卫有哪些?
    • 全局守卫
      • beforeEach 全局前置守卫(用于验证登录)
      • beforeResolve 全局解析守卫
      • afterEach 全局后置守卫(路由跳转完成后触发)
    • 路由独享守卫
      • beforeEnter 路由独享守卫 (路由配置文件中设置)
    • 组件守卫
      • beforeRouteEnter 无法获取组件实例this,执行时,组件实例还没创建

      • beforeRouteUpdate 该组件为复用时调用

      • beforeRouteLeave

  • 路由导航全过程?
    • 导航被触发。
    • 在准备离开的组件里调用 beforeRouteLeave 守卫。
    • 调用全局的 beforeEach 守卫。
    • 在重用的组件里调用 beforeRouteUpdate 守卫 (2.2+)。(如果你的组件是重用的)
    • 在路由配置里调用 beforeEnter。
    • 解析即将抵达的组件。
    • 在即将抵达的组件里调用 beforeRouteEnter。
    • 调用全局的 beforeResolve 守卫 (2.5+)。
    • 导航被确认。
    • 调用全局的 afterEach 钩子。
    • 触发 DOM 更新。
    • 用创建好的实例调用 beforeRouteEnter 守卫中传给 next 的回调函数。

  • 路由实现权限管理?
    • 前端控制不用后端帮助,路由表维护在前端逻辑相对比较简单,比较容易上手
      • 在全局守卫阶段进行拦截
      • 根据meta.role字段和用户权限信息,判断用户是否能跳转页面。
    • 后端控制相对更安全一点,路由表维护在数据库(下一个问题解答)

  • 动态路由怎么做?
    • 动态路由是一个常用的功能,根据后台返回的路由json表,前端动态显示可跳转的路由项
    • 实现过程
      • 定义静态路由,动态路由,vue初始化只挂在静态路由
      • 用户登录请求接口,根据用户权限,拿到该用户的路由表信息,前端处理数据,将路由信息存储在vuex或者localstore下,防止刷新找不到页面。
      • 在全局路由守卫进行拦截。
      • 使用router.addRoute方法,将动态路由加入前端的路由数组里。

  • 权限信息的级别分为?
    • 页面级(菜单权限):用户可访问的页面
    • 行为级(控件级):用户可执行的权限
    • 接口级:用户可访问的接口权限

  • vue角色权限管理如何设计?
    • 页面级
      • 通过路由守卫进行控制
    • 行为级(控件级):用户可执行的权限
      • 通过指令来实现,控制控件的显示和隐藏
    • 接口级:用户可访问的接口权限
      • 由后端实现

  • ref,$refs,$el区别?
    • ref :是元素的属性,用于设置在元素上
    • $refs :页面中所有含有ref属性的DOM元素
    • $el :Vue实例关联的DOM元素

  • 浅谈Vuex?
    • 是一个状态管理仓库,用于管理所有组件的数据状态,提供统一数据操作。
    • 常用于大型项目,适用于多个组件依赖于同一状态,不同组件的行为需要变更同一状态

  • vuex刷新怎么存储数据?
    • 将 vuex 中的数据存放到 localStorage 或者 sessionStroage 中。
    • 在页面刷新的时候,再重新初始化赋值。

  • Vuex和localstorage的区别?
    • vuex存的是状态,存储在内存;localStorage是浏览器提供的接口,存储到本地
    • vuex用于组件之间的传值,localStorage则主要用于页面之间的传值
    • 当刷新页面时,vuex存储的值会丢失,localStorage不会
    • 对于不变的数据,localStorage可以代替vuex,但是当两个组件共同用于数据源,如果其中一个组件中的数据源改变,希望另一个组件响应变化,这时候就要选择用vuex。vuex是vue的状态管理机制,是方便组件之间通信的。一个组件的数据变化是会映射到使用这个数据的其他组件。而localStorage是本地存储,是将数据存储到浏览器的方法,一般在跨页面时使用。

  • Vuex的五种对象?
    • state 存储基本数据
    • gettters 是state的计算属性,可以对state进行过滤和加工。
    • mutations 提交更改数据,通过commit方法更改state存储的状态。(mutations是同步函数)
    • actions: 与mutations功能相同
      • actions提交的是 mutations,而不是直接变更状态
      • actions可包含异步操作
      • actions先执行异步,再去调mutation,再更新state
    • modules 项目特别复杂的时候,可以让每一个模块拥有自己的state、mutation、action、getters,使得结构非常清晰,方便管理
    • 辅助函数:mapState、MapGetters、MapActions、mapMutations等辅助函数,方便快速使用属性。

  • dispatch与commit区别?
    • dispatch 是跟action一块用的,含有异步操作,例如向后台提交数据
    • commit 是跟mutation一块用的,同步操作

  • 工程量大时,vuex出现同名方法怎么处理?
    • 在模块中引入namespace,调用方法时,加上定义的namespace

  • 你了解哪些 vue 性能优化的方法?
    • 路由懒加载。使用路由懒加载,项目打包的时候体积会大幅减小,访问项目时,这些组件也会按需进行加载,大大提升了项目性能。
    • keep-alive 缓存页面。第一次加载之后,关闭再次打开,页面不会重新渲染。
    • v-for遍历避免同时使用 v-if
    • 长列表性能优化。如果是大数据长列表,可采用虚拟滚动,只渲染少部分区域的内容
    • 事件的销毁。
    • 图片懒加载。对于图片过多的页面,为了加快页面的加载速度,需要把未出现在可视区域的图片暂不进行加载,滚动到可视区域之后再开始加载。
    • 第三方插件按需引用。如element-ui组件按需加载。

Javascript面试点

  • 说一下EventLoop机制?
    • 起因:
      • js是单线程的,后面任务必须等待前面任务完成才能开始执行,如果前面任务一直不完成,就会造成阻塞。
    • 轮询机制的执行过程
      • 所有任务都在主线程上,形成一个执行栈
      • 主线程查看是否有异步任务,宏任务放入宏任务队列,微任务放入微任务队列
      • 如果执行栈中的同步任务都已完成,执行微任务
      • 微任务执行完成,执行宏任务
      • 重复以上步骤,称为一个事件循环。
    • 详细解释:
      • 所有任务分为两种,同步任务和异步任务,同步任务指的是在主线程上排队执行的任务,只有前一个任务执行完毕才能执行后一个任务;异步任务指的是,不进入主线程而进入“任务队列“的任务,只有任务队列通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。异步执行的运行机制如下:所有同步任务都在主线程上执行,形成一个执行栈,主线程之外,还存在一个“任务队列”,只要异步任务有了运行结果,就在“任务队列”种放置一个事件,一旦“执行栈”中同步任务执行完毕,系统就会读取"任务队列“,看里面有什么事件,哪些对应的异步任务,于是结束等待状态,进入执行栈,开始执行,主线程重复以上步骤。

  • 宏任务和微任务有哪些?
    • 宏任务由宿主发起,而微任务由js自身发起
    • 宏任务
      • setTimeout
      • setInterval
      • setImmediate(用于中断长时间运行的操作,并在浏览器完成其他操作(如事件和显示更新)后立即运行回调函数。)
      • postMessage(是html5新引进的一个可跨源通信api)
      • MessageChannel(前端api,一个消息通道)
    • 微任务
      • promise
      • process.nextTick(当前循环结束之后,下一轮循环开始之前)
      • mutationObserver(H5新增,是一个可以监听DOM结构变化的接口)

  • setImmediate和process.nextTick对比?
    • process.nextTick在当前tick同一个阶段立即执行
    • setImmediate在事件循环的下一次迭代或tick时触发

    在事件循环中,每进行一次循环操作称为tick

  • 微任务为什么先于宏任务执行?
    • 这是js的事件循环机制规定。
    • 任务的执行过程:执行一个宏任务,过程中遇到微任务时,将其放到将其放到微任务的事件队列里,当前宏任务执行完成后,会查看微任务的事件队列,依次执行里面的微任务,如果还有宏任务的话,再重新开始宏任务轮询。
    • 在js中,script本身就是一个宏任务,所以执行异步队列的时候,优先执行script里的所有微任务,再去执行下一个宏任务。

  • 什么是事件?
    • 按下键盘、点击鼠标
    • web浏览器中发生的事情,如某个web页面加载完成,或者是用户滚动窗口或改变窗口大小;
    • UI事件:load,unload,error,select,resize,scroll。

  • js事件流/事件传播是怎么样体现的?
    • 事件流描述的是从页面中接收事件的顺序,有两种方式
    • 事件冒泡是逐级向上传导的过程,从内往外
    • 事件捕获从最外层开始,然后一层一层接收事件并响应

    最终由w3c统一了最后标准,先捕获在冒泡,现代的浏览器都遵循此标准。

  • 描述一下事件传播的三个阶段?
    • 捕获阶段:事件捕获会从window开始触发,一级一级往下传递,依次触发,直到真正事件目标为止。
    • 目标过程
    • 冒泡阶段:事件冒泡会从当前触发的事件目标一级一级往上传递,依次触发,直到window为止。

  • 如何阻止冒泡?
    • 加入event.stopPropagation()终止事件广播(IE下是event.cancelBubble=true)
    • 只处理自己产生的事件,event.target == event.currentTarget

  • 所有事件都有冒泡吗?
    • onblur,onfocus,onmouseenter,onmouseleave没有冒泡

  • e.target和e.currentTarget的区别?
    • target:是发生事件的元素或触发事件的元素,是指真正发生事件的DOM元素。
    • currentTarget:是指当前事件发生在哪个DOM元素上,是我们在其上显式附加事件处理程序的元素。简单来说,目标元素并未绑定点击事件,但点击目标元素时,发生冒泡和捕获,在冒泡和捕获过程中,其他元素绑定了点击事件,由此而触发了该元素的事件,当事件执行的时候,e.currentTarget指的就是该元素。

  • e.target 和 this 的区别
    • 常情况下terget 和 this是一致的
    • 但有一种情况不同,那就是在事件冒泡时(父子元素有相同事件,单击子元素,父元素的事件处理函数也会被触发执行),这时候this指向的是父元素,因为它是绑定事件的元素对象,而target指向的是子元素,因为他是触发事件的那个具体元素对象。

  • 简单说一下事件委托?
    • 利用冒泡的原理,把事件加到父级上,让它的父级来完成事件的监听,来触发子元素的执行效果。
    • 优点:减少监听次数,从而提升性能

  • 如何创建自定义事件?触发自定义事件?
    • 创建
      • new Event(‘thing’)
      • new CustomEvent('thing',{detail:{}})
    • 触发
      • window.dispatchEvent('thing)

  • 什么是作用域?js有哪些作用域?
    • JavaScript 中的作用域是我们可以有效访问变量或函数的区域。
    • 作用域相当于是一个独立的地盘,让变量不会外泄、暴露出去。也就是说作用域最大的用处就是隔离变量,不同作用域下同名变量不会有冲突。
    • 块级作用域:ES6新增,let/const
    • 全局作用域:全局可使用
    • 函数作用域:
      • 函数内部可以使用全局变量
      • 函数外部不可以使用函数内部的局部变量
      • 函数执行完毕,函数作用域内的变量会销毁

  • 什么是作用域链?
    • 如果变量在当前作用域中不存在,它将向外部作用域中查找并搜索,如果该变量不存在,它将再次查找直到到达全局作用域,如果找到,则可以使用它,否则引发错误,这种查找过程也称为作用域链

  • 谈一下闭包?
    • 闭包是一个函数,这个函数可以访问一个函数内部变量。
    • 作用:就是为了设置私有变量和方法。
    • 优点和好处:
      • 延伸了变量使用范围
      • 让这些变量的值始终保持在内存中。
      • 总结来说,实现封装和缓存
    • 缺点:造成内存泄漏,闭包函数使用后,函数内部的变量不会销毁
    • 使用场景:节流和防抖,setTimeou调用
    • 如何销毁:return的函数重新赋值为null

  • 谈一下节流?
    • 概念:间隔执行,每隔一段时间执行函数,在规定时间内只执行一次,减少调用频率。(一个函数执行一次后,只有大于设定的执行周期后才会执行第二次。)
    • 节流场景:DOM拖拽功能,搜索联想,监听滚动事件

  • 谈一下防抖?
    • 概念:延迟执行,一段时间内,如果再次被触发,就会再延迟。对于连续的事件响应,只需要执行一次。(一个需要频繁触发的函数,在规定时间内,只让最后一次生效,前面的不生效。)
    • 场景:文本框的连续输入

  • js的存储方式有哪些?它们有什么区别?
    • cookie
      • 客户端存储
      • 有大小限制4kb
      • 有存储期限
      • 存在安全性问题
      • 只能保存字符串类型
    • session
      • 服务器存储
      • 没有大小限制
      • 存储期限很短
      • 相对cookie更安全
      • 支持多种保存类型
    • localStorage
      • 本地存储,不和服务器交互
      • 有大小限制5M
      • 没有存储期限
      • 只能保存字符串类型
    • sessionStorage
      • 本地存储,不和服务器交互
      • 有大小限制5M
      • 有存储期限,随着网页关闭而销毁
      • 只能保存字符串类型

  • cookie有哪些安全问题?如何预防?
    • 跨站脚本攻击(XSS)
    • 安全属性HttpOnly未设置

  • let const var 区别?
    • var
      • 全局作用域
      • 变量提升
      • 可重复定义
      • 可修改值
    • let
      • 块级作用域
      • 在使用前声明才可用,不可提升
      • 不可重复定义
      • 可修改
    • const
      • 常量声明方式
      • 不可修改值(并不是变量的值不得改动,而是变量指向的那个内存地址不得改动,如是引用类型,对象的属性值可以改变)
      • 不可重复定义

  • let/const中提到的暂时性死区是什么?var为什么没有死区?
    • 在一个块级区域内,let一旦声明了一个变量,该变量就会绑定这个区域,凡是在声明之前使用该变量,就会报错。在let没有声明该变量之前,都属于该变量的死区。
    • var有变量提升,var定义的变量,会将该变量提升到作用域的顶部。

  • 什么是提升?let/const/var/function提升的区别?
    • 提升是用来描述变量和函数移动到其(全局或函数)作用域顶部的术语
    • let/const的创建被提升,初始化和赋值不提升
    • var的创建和初始化被提升,赋值不提升
    • function的创建、初始化、赋值都被提升

  • js数据类型?
    • 基本数据类型
      • Number,String,Boolean,null,undefined
      • ES6新增:symbol,bigint
    • 引用数据类型
      • object(包含:array,Expre,date, Math等),function

  • null、undefined的区别?
    • 相同点:都是基本类型
    • null
      • 是一个空对象,它不指向任何空间地址,简单来说,是一个不代表任何值的值
      • 一般用来释放变量的引用链接(虽然赋值为null,但不会主动释放空间,需要垃圾机制回收没有任何引用的空间)
    • undefined
      • 是未指定特定值的变量的默认值,代表初始化变量时的一个原始状态
      • 变量被定义和声明,但是没有被赋值

  • js数据类型的存储方式及区别?
    • 基本数据类型
      • 值直接存储在栈中
      • 占据空间小、大小固定。
    • 引用数据类型
      • 值储在堆中
      • 占据空间大、大小不固定。
      • 引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址
    • 区别
      • 比栈空间大,栈比堆运行速度快。
      • 堆内存是无序存储,可以根据引用直接获取。
      • 基础数据类型比较稳定,而且相对来说占用的内存小。
      • 引用数据类型大小是动态的,而且是无限的。

  • 堆和栈的区别?
    • 栈内存:存储的都是局部变量,后进先出,栈内存的更新速度很快,因为局部变量的生命周期都很短。
    • 堆内存:存储的都是数组和对象,堆里面的实体不会被释放,但是会被当成垃圾,java有垃圾回收机制不定时地收取。

  • == 和 === 的区别?
    • == 是一般比较,只比较值
    • === 是严格比较,比较值和类型

  • 数据类型判断的方式有哪些?【点击查看详情
    • typeof
      • 基础类型:除null之外,全部可判(null判断为object,null是一个特殊的object)
      • 引用类型:除function, 全部返回object
    • instanceof:判断检测对象是否是某个对象的实例,检测的是原型,适用于引用类型的判断
    • constructor: 判断对象的构造函数
      • 缺点:constructor 在类继承时会出错,null 和 undefined 是无效的对象,没有 constructor 存在
    • Object.prototype.toString():基本上所有类型都可判断

  • 谈谈js的原型?
    • 简单来说,js的原型分为显示原型和隐式原型。
    • 显示原型prototype属性,这个属性是每一个函数都有,而这个prototype 属性,它指向是一个对象,这个对象里面的所有属性和方法都会被构造函数所拥有。
    • 隐式原型说的是__proto__,除了null和undefinded之外,所有的对象都有proto属性,则这个对象的隐式原型指向的是:构造该对象的构造函数的原型。
    • 没有原型的对象为数不多, Object.prototype就是其中之一。

  • 谈谈js的原型链?
    • 对象原型往上一直寻找,直到没有为止,由此形成原型链
    • 原型链的最顶端是:Object.prototype

  • 谈谈js的继承?【点击查看详情
    • 第一种,原型链继承,比如说有一个父函数和子函数,子函数想要继承父函数上的属性和方法,可以把子函数的原型指向父函数的实例。缺点就是,子函数的实例会共享父函数上的属性,并且其中一个实例改变属性,另一个实例的属性也会变化。
    • 第二种是构造函数继承,这种继承方式就是直接在子函数内调用父函数,但缺点是,父函数原型属性上的不能被共享,继承不到。
    • 第三种是组合继承(构造函数+原型链继承)
    • 第四种是原型式继承,使用object.create()方法收两个参数:一是用作新对象原型的对象、二是为新对象定义额外属性的对象(可选参数)。
    • 第五种是寄生式继承,是在原型式继承的基础上,添加一些方法
    • 第六种是寄生组合方式,相当于原型链继承,构造函数继承,原型式继承的这三类的优点缺点改造。

    ES6 的 extends 关键字实现逻辑,是用的寄生组合继承方式。

  • 简短描述一下this?
    • this是指向当前上下文的一个对象
    • this 指的是当前正在执行或调用该函数的对象的值,this 值的变化取决于使用它的上下文环境。

  • this指向问题?
    • 普通函数调用指向window
    • 构造函数调用指向实例对象,原型里面的方法也指向实例
    • 对象方法调用指向这个方法的对象
    • 事件绑定方法调用指向事件对象

  • 改变函数内部this指向的方法?
    • call: obj1.fun.call(obj2, a, b, c) obj2是obj1.fun需要重新指向的对象。后面参数正常,用于继承
    • apply: obj1.fun.call(obj2, [a, b, c]) 后面arr是obj1.fun需要的参数。call和apply二者而言,作用完全一样,只是接受参数的方式不太一样,常用于数组
    • bind:语法和call一模一样,区别在于call立即执行,bind等待执行,不调用函数

  • new 关键字的执行过程
    • 创建一个空对象
    • 将新对象的原型链指向构造函数的原型
    • 执行构造函数,并将构造函数中的this指向新对象
    • 返回新对象

  • 什么是拷贝?
    • 针对引用类型的一个复制

  • 什么是深拷贝?
    • 概念:复制对象本身,创造出一个一模一样的对象,新旧对象的值互相不影响。(新增指针指向新增内存地址)
    • 思路:利用递归和构造函数,创建一个该构造函数类型的对象
    • 拷贝方法:JSON.parse(JSON.stringify())(对function类型无用,拷贝后为null)

  • 什么是浅拷贝?
    • 概念:只复制指向某个对象的指针,并不复制对象本身,新旧对象仍旧共享同一个内存,当新对象改变值时,原对象的值也会改变。
    • 缺点:无法拷贝引用类型,因为共享内存,改变会引起其他对象的变化
    • 拷贝方法:Object.assign({},obj) (对象第一层是深拷贝,对象的属性如果仍是引用数据类型,将会被浅拷贝。)

  • 什么是形参和实参?
    • 形参:是指定义函数的时候,函数定义的参数。
    • 实参:调用函数的时候,实际传入的值

  • 函数传参的机制?
    • 函数接受参数之前,会先在函数作用域内创建一个形参,并把传入的实参赋值给创建的形参。

  • JavaScript函数传参是传递是值还是引用?
    • 事实上,在js中,不管对于值类型还是引用类型,都是按值传递
    • 区别在于
      • 对于值类型(基本类型),直接赋值,形参的改变不会影响实参。
      • 对于引用类型,形参只是复制了实参的存储指针,形参和实参会指向同一个堆地址,修改形参对象下的属性会影响实参。

  • arguments是什么?
    • 函数 arguments 对象是所有(非箭头)函数中都可用的局部变量, 是一个类似数组的对象。

  • 什么是内存泄露?
    • 就是没有使用,或已经使用完的变量,没有及时回收。

  • JS哪些操作会造成内存泄露?
    • 闭包引起的内存泄露。
    • 没有清理的DOM元素引用。
    • 意外的全局变量,初始化未经声明的变量。
    • 由this创建的全局变量。

  • JS数组和对象的遍历方式和区别?
    • for循环——循环每进行一次,就要检查一下数组的长度,速度比较慢;
    • for in 循环——需要分析出array的每一个属性,这个操作性能开销很大。
    • forEach循环——不能遍历对象,不可以使用continue、break跳出循环,且使用return是跳出本次循环。

  • 说一说JS实现异步的方法?
    • promise
    • 定时器
    • 回调函数
    • async/await

  • 数组去重的方法?
    • ES6新特性new Set()
    • for循环

  • js是怎么解析和执行的?
    • JS程序的解析过程分为编译和执行两个阶段。
    • 编译也叫做JS预处理,编译器将JS脚本代码转换成字节码,执行期间,解释器借助执行期环境将字节码生成机械码并按顺序执行。
    • js边编译边执行

  • js是怎么运行的?
    • 引擎
    • 上下文
    • 预编译
    • 轮询机制

  • js中有哪些数据结构?
    • 栈:后进先出
    • 队列:先进先出
    • 链表:多个元素组成的列表,元素存储不连续,通过指针来链接
    • 集合:一种无序且唯一的数据结构,ES6中有Set类型
    • 字典:与集合类似,以键值对形式存储
    • 树:
    • 图:网络结构的抽象模型,由边连接的点
    • 堆:一种特殊的完全二叉树

  • 快慢指针解决了什么问题?
    • 快慢指针是指定义两个相同类型的指针,只不过移动速率不同,一快一慢,用来解决算法问题
    • 比如数组中间值
    • 单项链表是否有环

  • 产品sku算法是怎么实现的?
    • sku商品的规格组合。
    • 比如说一个手机,有颜色属性,比如红蓝白等多种颜色,还有尺寸属性,比如说6寸,11寸,但是在库存里,可能红色就只有6寸,没有11寸的,蓝色只有11寸的,没有6寸的,所以前端就需要去实现这样的一个功能,一排颜色按钮,一排尺寸按钮,如果点击了某个颜色,其他的属性在库存中存在,就高亮,没有就禁用。
    • 实现方式,就是邻接矩阵,就是说把颜色和尺寸两个属性组成一个矩阵,前端可以用二维数组表示,把颜色和尺寸都放到这个矩阵里,如果某个颜色和尺寸有库存,就取值为1,没有库存就取值为0。
    • 当用户点击某个颜色后,用这个颜色为索引,就去矩阵查找这个属性,并且把该颜色对应的其他属性遍历出来,如果为1,其他就高亮,如果为0,其他属性就禁用不可选。
    • 实现邻接矩阵:把所有颜色和尺寸当做key,初始化二维数组,这个时候数组值都是0。然后通过遍历后端的库存数据,把值填充。

  • 长列表和虚拟表格怎么实现的?
    • 如果列表项数量过多,一般则会采用分页的方式来处理,而分页的形式也有2种:前后翻页,上下滚动
    • 无限滚动的长列表对用户来说体验是很好的,但是这里会有个问题,当用户滚动的屏数过多时,就会出现页面滑动卡顿、数据渲染较慢、白屏的问题,究其原因是列表项过多,渲染了大量dom节点
    • 虚拟列表原理:只对可见区域进行渲染,对非可见区域中的数据不渲染部分渲染的技术,从而达到极高的渲染性能,虚拟列表其实是按需显示的一种实现。
    • 实现:可视区域的容器,列表项的高度占位(把容器撑开形成滚动条),列表项的渲染区域。计算可视区域的高度,计算列表项的高度,计算当前滚动条的位置,列表项的高度乘以列表项的下标在滚动条位置+容器高度里面,该列表项就渲染出来,否则不渲染。

  • 如果长列表高度不固定怎么处理?
    • 拿到要渲染的业务数据,计算总高度。

  • 长列表拉动太快,有白屏怎么处理?
    • 列表项的渲染区需要大于可视区域,相当于要额外的渲染部分缓存区的元素,。
    • 用一个加载的动态骨架屏来代替白屏。

  • Array.reduce方法的作用?
    • 是一个累加器
    • 数组中的每个值都会遍历,然后缩减计算成一个值。
    • 与其他for,filter的不同之处是,它可以设置一个初始值,让代码可方便解读。

  • nextick是微任务还是宏任务?
    • 优先是微任务。

  • map和forEach的区别?
    • 相同点
      • 循环遍历数组中的每一项
      • 只能遍历数组
    • map
      • map()会分配内存空间,创建一个新的存储新数组,并返回
      • map遍历的后的数组通常都是生成一个新的数组,新的数组的值发生变化,当前遍历的数组值不会变化。
    • foreach
      • forEach()不会返回新数据
      • forEach遍历通常都是直接引入当前遍历数组的内存地址,生成的数组的值发生变化,当前遍历的数组对应的值也会发生变化。

  • 有哪些常用调试技巧?
    • 使用Chrome浏览器打断点,可以清楚的看到每走一步页面发生了什么变化。
    • 请求使用mock数据。

下一章

web前端面试攻略[vue,js,css,html,webpack,安全,性能,浏览器,手撕代码](二)