一、闭包

  • 由于作用域的关系,正常情况下函数外部是访问不到函数内部作用域变量的,闭包说的通俗一点就是打通了一条在函数外部访问函数内部作用域的通道。
  • 表象判断是不是闭包: 函数嵌套函数,内部函数被return, 内部函数调用外层函数的局部变量
  • 优点:可以隔离作用域,不造成全局污染。
  • 缺点:由于闭包长期驻留内存,则长期这样会导致内存泄露
  • 如何解决内存泄露:将暴露全外部的闭包变量置为null
  • 适用场景:封装组件,存储变量

    二、原型和原型链

  • 原型:在js中,每个函数都有 prototype 属性,该属性指向原型对象;prototype 里面有一个constructor属性指向函数本身。使用原型对象的好处是所有对象实例共享它所包含的属性和方法。

  • 原型链:js在查找属性的过程中,如果在自有的属性中查不到,就会在原型对象中查找,如果原型对象里面也找不到,就会通过原型链指针—proto—在原型对象的原型上查找,这就是原型链,直到查到原型链的最顶端object。

    三、作用域和作用域链

  • 作用域:一个变量可以生效的范围

    • 局部作用域:只能在函数内部访问它们
    • 全局作用域:网页的所有脚本和函数都能够访问它
  • 作用域链:

    • 当查找变量的时候,会先从当前上下文的变量对象中查找,如果没有找到,就会从父级的变量对象中查找,一直找到全局上下文的变量对象,也就是全局对象。这就是作用域链

      四、继承

  • 原型链继承:让新实例的原型等于父类的实例。

  • 构造函数继承:用.call()和.apply()将父类构造函数引入子类函数(在子类函数中做了父类函数的自执行(复制))
  • 实例继承:
  • 拷贝继承
  • 组合继承
  • 寄生组合继承:就是给原型式继承外面套了个壳子

    五、js原生事件如何绑定

  • html标签事件绑定,就是在html各种标签上直接添加事件,类似于css的行内样式,缺点是不好维护,不建议使用

  • js事件绑定:先获取dom元素,然后直接给dom元素添加事件。将事件设置为null可以移除事件。优点:兼容性好。缺点:只支持冒泡,不支持捕获 ```javascript var btn=document.getElementById(‘id元素’)

btn.onclick=function() { //要处理的事件逻辑 } btn.onclick=null

  1. - 事件监听,`addEventListener`绑定,`removeEventListener`移除。
  2. - 优点:支持给个元素绑定多个相同事件,支持冒泡和捕获事件机制
  3. ```javascript
  4. var btn=document.getElementById(‘id元素’)
  5. //绑定事件
  6. btn.addEventListener(‘click’,绑定的事件处理函数名,false)
  7. //移除事件
  8. btn.removeEventListener(‘click’,要移除的事件处理函数名,false)

六、JS原生常用dom操作方法

  • 查找:
    • getElementByid
    • getElementsByTagName
    • querySelector
    • querySelectorAll
  • 插入:
    • appendChild
    • insertBefore
  • 删除:
    • removeChild
  • 克隆:
    • cloneNode
  • 设置和获取属性:

    • setAttribute(“属性名”,”值”),getAttibute(“属性名”)

      七、说一下ES6新增特性

  • let/const

  • 箭头函数
  • 模板字符串
  • 解构赋值
  • 类和继承
  • 函数默认参数
  • 展开运算符
  • 模块化
  • 模块的导入(import)和导出(export default/export),Promise,setsymbol
  • 数组字符串的新方法,其实有很多,我平时常用的就这些

    八、对面向对象的理解

  • 在js里面,万物皆对象。可以将所需要做的功能抽象成一个“对象”,然后反复调用这个对象来完成你想要的功能

    九、说一下JS数组常用方法

  • push:末尾添加

  • pop:末尾删除
  • shift:前面删除
  • unshift:前面删除
  • reverse: 反转数组
  • splice:截取数组
  • join:将数组的元素链接称字符串
  • split:把字符串分割成字符串数组

    十、说一下JS数组内置遍历方法有哪些和区别

  • forEach

  • filter:是一个过滤遍历的方法,将数组中满足条件的数据返回成一个新数组
  • map:操作数组的每一个元素,并返回一个新数组
  • some:这个some方法用于只要数组中至少存在一个满足条件的结果,返回值就为true,否则返回false, 写法和forEach类似
  • every: 这个every方法用于数组中每一项都得满足条件时,才返回true,否则返回false, 写法和forEach类似

    十一、说一下从输入域名URL到页面加载完中间发生了什么?

  • DNS解析

  • TCP连接
  • 发送HTTP请求
  • 服务器处理请求并返回需要的数据
  • 浏览器解析渲染页面
  • 连接结束
  • 输入了一个域名,域名要通过DNS解析找到这个域名对应的服务器地址(ip),通过TCP请求链接服务,发送HTTP请求,通过WEB服务器(apache)返回数据,浏览器根据返回数据构建DOM树,通过css渲染引擎及js解析引擎将页面渲染出来,关闭tcp连接

    十二、说一下JS事件代理(也称事件委托)是什么,及实现原理?

  • JS事件代理或事件委托就是通过给父级元素(例如:ul)绑定事件,不给子级元素(例如:li)绑定事件,然后当点击子级元素时,通过事件冒泡机制在其绑定的父元素上触发事件处理函数,主要目的是为了提升性能,因为我不用给每个子级元素绑定事件,只给父级元素绑定一次就好了,在原生js里面是通过event对象的targe属性实现

    十三、 说一下JS数据类型有哪些?

  • 基本数据类型

    • number
    • string
    • Boolean
    • null
    • undefined
    • symbol(ES6新增)
  • 复合类型

    • Object
    • function

      十四、说一下call,apply,bind区别

  • call和apply的主要区别是在传递参数上不同,call后面传递的参数是以逗号的形式分开的,apply传递的参数是数组形式 call的性能要比apply好。

  • bind返回的是一个函数形式,如果要执行,则后面要再加一个小括号 例如:bind(obj,参数1,参数2,)(),bind参数只能以逗号分隔形式,不能是数组形式

    十五、Ajax相关

  • 说一下你对ajax的同源策略的理解

    • ajax同源策略是因为安全的考虑,ajax不允许访问不同域名下的资源即所谓同源策略的意思。
  • 说一下什么情况下会产生跨域及产生跨域的解决方案和实现原理?
    • 产生跨域的情况有:不同协议,不同域名,不同端口以及域名和ip地址的访问都会产生跨域。
  • 什么是ajax

    • 异步的js和 XML,用于和后端进行交互

      十六、 跨域的解决方案目前有三种主流解决方案。

  • jsonp

    • jsonp实现原理:主要是利用动态创建script标签请求后端接口地址,然后传递callback参数,后端接收callback,后端经过数据处理,返回callback函数调用的形式,callback中的参数就是json
  • 代理(前端代理和后端代理)
    • 前端代理我在vue中主要是通过vue脚手架中的config中的index文件来配置的,其中有个proxyTable来配置跨域的
  • CORS

    • CORS全称叫跨域资源共享,主要是后台工程师设置后端代码来达到前端跨域请求的

      十七、说一下原生ajax的交互过程(即流程)

  • 交互流程:

    • 第一步:先创建XHR对象即XMLHttpRequest()
    • 第二步:然后open准备发送,open中有三个参数一是提交方式get和post,二是接口地址,三是同步和异步
    • 第三步:是用send发送
    • 第四步:再发送的过程中通过onreadystatechange来监听接收的回调函数,可以通过判断readyState==4和status==200来判断是否成功返回,然后通过responseText接收成功返回的数据

      十八、说一下你对同步和异步的理解

  • 同步即sync,形象的说就是代码一行行执行,前面代码和请求没有执行完,后面的代码和请求就不会被执行,

    • 缺点:容易导致代码阻塞
    • 优点:程序员容易理解(因为代码从上往下一行行执行,强调顺序)
  • 异步:即async,形象的说就是代码可以在当前程序没有执行完,也可以执行后面的代码
    • 缺点:程序员不易理解(因为不是按顺序执行的)
    • 优点:可以解决代码阻塞问题,提升代码执行效率和性能
  • 异步解决方案主要有三个:

    • 回调函数
    • promise(重点掌握)
    • generator(了解)
    • async和await(重点掌握)

      十九、浅拷贝和深拷贝

  • 浅拷贝:

    • for···in只循环第一层
    • Object.assign方法
    • 直接用=赋值
  • 深拷贝:
    • JSON.parse(JSON.stringify(对象))
  • 递归

    二十、this的指向问题

  • 全局的 this → 指向的是 Window

  • 对象中的 this → 指向其本身
  • 事件中 this → 指向事件对象
  • 函数:this指向函数的调用者
  • 箭头函数:this指向上下文的this

    二十一、数组去重

  • 双层循环,外层循环元素,内层循环时比较值如果有相同的值则跳过,不相同则push进新数组

  • 利用splice直接在原数组进行操作,双层循环,外层循环元素,内层循环时比较值,值相同时,则删去这个值,删除元素之后,需要将数组的长度也减1.
  • indexOf:新建一个新数组,遍历数组,用indexOf判断值不在新数组中就push进新数组
  • new.set()和Array.from()

    • 使用new.set()将数组去重,然后用Array.from将数据结构转化成数组 —set是一个类似数组的结构,具有唯一性

      二十二、检查数据类型的方法

  • typeof

  • instanceof
  • object.prototype.tostring.call()

    二十三、进程和线程

  • 进程是系统中正在运行的一个程序,程序一旦运行就是进程。

  • 线程是进程的一个实体,是进程的一条执行路径。
  • 一个进程可以拥有多个线程,每个线程使用其所属进程的栈空间。线程与进程的一个主要区别是,同一进程内的多个线程会共享部分状态,多个线程可以读写同一块内存(一个进程无法直接访问另一进程的内存)。

    二十四、promise

  • Promise 是一个构造函数,对回调函数的一种封装,可以解决回调地狱问题。

  • 当我们使用new出来的promise对象时。它有三种状态:pending(进行中),resolved(已完成),rejected(已失败),状态一旦发生,就不能改变。执行new的时候状态就开始变化。
  • promise对象有两个方法:then()和catch()。
    • then()方法有两个参数,resolve和reject第一个参数是状态为已完成时执行的回调函数,第二个参数是状态为已失败时执行的回调函数
    • catch()方法用来捕获错误的,错误时不捕获错误会报错
  • 使用promise的好处是:

    • 代码结构更加扁平且更可读,清晰明了
    • 能解决回调地狱问题。
    • 可将数据请求和业务逻辑分离开来。
    • 便于管理维护。
    • 能更好的捕获错误。

      二十五、重绘和回流是什么

  • 回流:当 render tree 中的一部分或者全部因为元素的规模尺寸,布局, 隐藏等改变而需要重新构建,这就叫回流,每个页面至少需要一次回流, 就是在页面第一次加载的时候,这时候一定会发生回流,因为要构建 render tree

  • 重绘:在回流的时候,浏览器会使渲染树中收到影响的部分失效,并重新构造 这部分渲染树,完成回流后,浏览器会重新绘制受影响的部分到屏幕中, 这就是重绘
  • 当 render tree 中的一些元素需要更新属性,而这些属性只是影响元素的 外观,不会影响布局,就叫重绘

    二十六、race和all

  • Promise.race():

    • race的用法:谁跑的快,以谁为准执行回调。
    • race的使用场景:比如我们可以用race给某个异步请求设置超时时间,并且在超时后执行相应的操作
  • Promise.all():

    • all的用法:谁跑的慢,以谁为准执行回调。
    • all的使用场景:在前端的开发实践中,我们有时会遇到需要发送多个请求并根据请求顺序返回数据的需求

      二十七、var let const的区别

  • var声明的变量会挂载在window上,而let和const声明的变量不会

  • var声明变量存在变量提升,let和const不存在变量提升
  • let和const声明形成块作用域
  • 同一作用域下let和const不能声明同名变量,而var可以
  • const一旦声明必须赋值,不能使用null占位,声明后不能再修改,如果声明的是复合类型数据,可以修改其属性

    二十八、说一下vue最大特点是什么或者说vue核心是什么

  • vue最大特点我感觉就是“组件化“和”数据驱动“

    • 组件化就是可以将页面和页面中可复用的元素都看做成组件,写页面的过程,就是写组件,然后页面是由这些组件“拼接“起来的组件树
    • 数据驱动就是使用了mvvm原理,让我们只关注数据层,只要数据变化,页面(即视图层)会自动更新

      二十九、说一下vue常用基本指令有哪些

  • v-if

  • v-show
  • v-for
  • v-model
  • v-on
  • v-bind
  • v-once

    三十、Vue常用的修饰符

  • .stop - 调用 event.stopPropagation(),禁止事件冒泡。

  • .prevent - 调用 event.preventDefault(),阻止事件默认行为。
  • .capture - 添加事件侦听器时使用 capture 模式。
  • .self - 只当事件是从侦听器绑定的元素本身触发时才触发回调。
  • .native - 监听组件根元素的原生事件。
  • .once - 只触发一次回调。
  • .left - (2.2.0) 只当点击鼠标左键时触发。
  • .right - (2.2.0) 只当点击鼠标右键时触发。
  • .middle - (2.2.0) 只当点击鼠标中键时触发。

    三十一、Vue 组件中 data 为什么必须是函数?为什么data函数里面要return一个对象?

  • 因为如果data是一个对象会导致数据共享,在多次使用该组件时,改变其中一个组件的值会影响到全部组件的值。

  • 而如果是通过函数的形式返回一个对象,在每次使用该组件时返回的对象地址指向都是是不一样的,这样就可以使每个组件数据独立。防止数据污染

    三十二、 说一下v-if和v-show的区别

  • v-if和v-show都可以显示和隐藏一个元素但v-if是控制dom的显示和隐藏,而v-show是控制样式的显示和隐藏。

  • v-if比v-show的性能消耗更大

    三十三、自定义指令v-bind

  • 全局自定义指令:Vue.directive(‘指令名’,{ inserted (el) { bind函数 } })

  • 局部自定义指令:directives:{ ‘指令名’:{ bind函数 } }

    三十四、过滤器

  • vue过滤器主要用于对渲染出来的数据进行格式化处理。

  • 全局过滤器

    1. Vue.filter(‘过滤器名’,function(参数1,参数2,…) {
    2. return 要返回的数据格式
    3. })
  • 局部过滤器:在组件内部添加filters属性来定义过滤器

    1. fitlers:{
    2. 过滤器名(参数1,参数2,,…参数n) {
    3. return 要返回的数据格式
    4. }
    5. }

    三十五、说一下vue生命周期钩子函数有哪些

  • 创建前:beforeCreate, 创建后:created

  • 挂载前:beforeMount, 挂载后:mounted
  • 更新前:beforeUpdate, 更新后:updated
  • 销毁前:beforeDestroy, 销毁后:destroyed
  • created用于获取后台数据,mounted用于dom挂载完后做一些dom操作

    三十六、通过vuex实现兄弟组件通信

  • 具体实现:

    • vuex是一个状态管理工具,主要解决大中型复杂项目的数据共享问题,
    • 主要包括state,actions,mutations,getters和modules 5个属性
  • 主要流程:

    • 组件通过dispatch到 actions,actions是异步操作,再actions中通过commit到mutations,mutations再通过逻辑操作改变state,从而同步到组件,更新其数据状态

      三十七、slot

  • vue的插槽,可以把封装的组件插入页面,给solt定义一个name,就是具名插槽,可以插入指定的组件

    三十八、说一下你对单向数据流的理解

  • 单向数据流主要是vue 组件间传递数据是单向的,即数据总是由父组件传递给子组件,子组件在其内部维护自己的数据,但它无权修改父组件传递给它的数据,当开发者尝试这样做的时候,vue 将会报错。这样做是为了组件间更好的维护。

  • 在开发中可能有多个子组件依赖于父组件的某个数据,假如子组件可以修改父组件数据的话,一个子组件变化会引发所有依赖这个数据的子组件发生变化,所以 vue 不推荐子组件修改父组件的数据

    三十九、双向数据绑定

  • 双向数据绑定利用了数据劫持和订阅者模式,是使用obiect.defineproperty劫持了所有属性的getter和setter,当数据发生变化时,会给订阅者发送消息,执行回调的函数

    四十、hash和history

  • Hash 模式地址栏中有#,history 没有,history 模式下刷新,会 出现 404 情况,需要后台配置

  • hash 方案兼容性好,而H5的history主要针对高级浏览器。

    四十一、vue路由实现底层原理

  • 在Vue中利用数据劫持defineProperty在原型prototype上初始化了一些getter,劫持_route,当_route触发setter方法的时候,则会通知到依赖的组件。

  • 接下来在init中,会挂载判断是路由的模式,是history或者是hash,点击行为按钮,调用hashchange或者popstate的同时更_route,_route的更新会触发route-view的重新渲染。

    四十二、路由钩子

  • 全局钩子:

    • Router.beforeEach
    • Router.afterEach
  • 某个路由独享钩子:
    • beforeEnter
    • beforeLeave
  • 组件内部钩子:

    • beforeRouteEnter
    • beforeRouteLeave
    • beforeRouteUpdate

      四十三、Vue 等单页面应用的优缺点

  • 优点

    • 单页应用的内容的改变不需要重新加载整个页面,web应用更具响应性和更令人着迷。
    • 单页应用没有页面之间的切换,就不会出现“白屏现象”,也不会出现假死并有“闪烁”现象
    • 单页应用相对服务器压力小,服务器只用出数据就可以,不用管展示逻辑和页面合成
    • 良好的前后端分离。后端不再负责模板渲染、输出页面工作,后端API通用化,即同一套后端程序代码,不用修改就可以用于Web界面、手机、平板等多种客户端。
  • 缺点

    • 首次加载耗时比较多。

      四十四、Vue-router 使用params与query传参有什么区别

  • 用法上

    • query要用path来引入,params要用name来引入,接收参数都是类似的,分别是this.前端面试题 - 图1route.params.name。
  • 展示上

    • query更加类似于我们ajax中get传参,params则类似于post,说的再简单一点,前者在浏览器地址栏中显示参数,后者则不显示
    • params是路由的一部分,必须要有。query是拼接在url后面的参数,没有也没关系。
      4:params、query不设置也可以传参,params不设置的时候,刷新页面或者返回参数会丢失

      四十五、vuex

  • 目录下建立一个 store 文件夹,并且在下面建立一个 store.js 文件,先引入 Vue 和 Vuex 并且别忘了 Vue.use(Vuex);

  • main.js 引入 store 文件并且 Vue 实例上得将 挂载 store
  • 在store.js导出 new Vuex.Store({}),里面有一个state
  • 通过 this.$store.state 可以拿到 state里面的数据
  • getters 可以实时监听state值的变化(最新状态)
  • 在methods使用一个事件this.$store.comit(vuex事件名,参数)提交,在store.js文件,添加mutations,在mutations中定义两个函数修改state

    四十六、mock

  • 安装mock依赖:cnpm i mockjs -D

  • 在src下创建mock文件夹,再创建index.js

    1. // (1)引入mock
    2. const Mock = require('mockjs')
    3. // (2)mock一个接口
    4. Mock.Mock('/api/artList', {
    5. code: 200,
    6. msg: 'success',
    7. "data|10-20": [
    8. {
    9. "id|+1": 1,
    10. "title": "@ctitle", // 标题
    11. "desc": "@cparagraph", // 描述
    12. "author": "@cname", // 作者中文名
    13. "thumb": "@image('100x100','@color','牛夫人)", // 随机图片(里面的乘号是 英文小x)
    14. }
    15. ]
    16. })

    四十七、注册组件

  • 使用Vue.component('my-component-name', { /* ... */ })注册组件并导出

  • 在其他页面引入并在components注册

    四十八、生命周期

  • 整个小程序的生命周期 – 在app.js中设置

    • onLaunch 当小程序初始化完成时,会触发 onLaunch(全局只触发一次)。
    • onShow 当小程序启动,或从后台进入前台显示,会触发 onShow
    • onHide 当小程序从前台进入后台,会触发 onHide
    • onError 当小程序发生脚本错误,或者 api 调用失败时,会触发 onError 并带上错误信息
  • 小程序页面的生命周期

    • onLoad 一个页面只会调用一次 可以用来接收页面参数
    • onShow 每次打开页面都会调用一次
    • onReady 一个页面只会调用一次,代表页面已经准备妥当,可以和视图层进行交互
    • onHide 当navigateTo或底部tab切换时调用。
    • onUnload 当redirectTo或navigateBack的时候调用。

      四十九、小程序中的路由跳转

  • wx.navigateTo():保留当前页面,跳转到应用内的某个页面。但是不能跳到 tabbar 页面

  • wx.redirectTo():关闭当前页面,跳转到应用内的某个页面。但是不允许跳转到 tabbar 页面
  • wx.switchTab():跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面
  • wx.navigateBack()关闭当前页面,返回上一页面或多级页面。可通过 getCurrentPages() 获取当前的页面栈,决定需要返回几层
  • wx.reLaunch():关闭所有页面,打开到应用内的某个页面

    五十、小程序和H5的区别

  • 主要区别时运行环境不同,(小程序运行在安卓,ios或开发者工具,H5运行在浏览器)
    ,会导致开发成本不一样,获取权限的方式不同,运行流畅度不同

    五十一、小程序页面间传递数据

  • 使用全局变量实现数据传递

    • app.js 文件中定义全局变量 globalData, 将需要存储的信息存放在里面。使用的时候,直接使用 getApp() 拿到存储的信息
  • 使用 wx.navigateTowx.redirectTo 的时候,可以将部分数据放在 url 里面,并在新页面 onLoad 的时候初始化
  • 使用本地缓存 Storage 相关

    五十二、bindtap 和 catchtap 的区别是什么

  • 相同点:首先他们都是作为点击事件函数,就是点击时触发。在这个作用上他们是一样的,可以不做区分

  • 不同点:他们的不同点主要是bindtap是不会阻止冒泡事件的,catchtap是阻止冒泡的

    五十三、小程序tabbar实现原理

  • 要实现tabbar的导航条其实很简单

    • 全局的tabbar只需要在app.json文件中定义即可
    • 局部的就在局部的tabbar文件中实现。
  • page里设置地址,tabbar对象里设置list,tabbar信息

    五十四、说说小程序中wx:if和hidden的区别

  • wx:if 与 hidden 都用来控制小程序元素的显示

  • 不同点

    • wx:if:
      • 条件为 true 时显示
      • 当元素显示时渲染
      • 元素变为不显示时销毁元素
    • hidden:
      • 条件为 false 时显示
      • 当元素显示时渲染
      • 元素变为不显示时保留元素
      • 相当于使用了dispaly

        五十五、跨站脚本攻击(XSS攻击)

  • 攻击者往Web页面里插入恶意html代码,当用户浏览该页之时,嵌入其中Web里面的html代码会被执行

  • xss常见的攻击方式:
    • 用户提交的数据未经处理,直接住注入到动态页面中
  • 危害:盗取各类用户帐号 ,企业数据,强制发送电子邮件,网站挂马
  • 解决方案:不信赖用户输入,对特殊字符如”<”,”>”转义,或者是替换
  • 小结:

    • 用户提交的时候 ,可能输入代码,存放到数据库
    • 用户读取数据的时候,数据库中代码可能会执行

      五十六、跨站请求伪造(CSRF攻击)

  • 跨站请求伪造(CSRF攻击)

    • 现象:有一个和官网一样的网站,篡改官网的提交的路径,或者cookie一起提交,
    • 导致提交数据流入外部网站 从而泄密
    • 解决方案:
      • 用户必须输入验证码,手机验证码…
      • 添加token 来进行二次校验 增强安全性

        五十七、使用vue-print-nb实现打印功能

  • 安装vue-print-nb依赖

    1. npm install vue-print-nb --save
  • main.js里面全局引入

    1. import Print from 'vue-print-nb'
    2. Vue.use(Print);
  • 页面中使用

    1. <div id="printMe" >
    2. <p>打印内容</p>
    3. </div>
    4. <button v-print="'#printMer'">打印</button>

    五十八、利用h5实现文件导入功能

  • 使用input标签H5新增的type=“file”属性可以上传文件

  • 使用readAsDataURL可以转换为base64编码
    1. const file = this.files[0]
    2. const fr = new FileReader()
    3. fr.readAsDataURL(file) // 将文件转换成 base64进制编码