2019年前端面试题总结

HTML

1. 重绘与回流

一个页面从加载到完成,首先生成DOM树,而后根据DOM节点的几何属性生成render树(渲染树),当渲染树构建完成,页面开始根据DOM树布局,渲染树也会根据设置的样式渲染节点javascript

回流: 当咱们删除或修改元素高度时,页面会从新布局,DOM树发生变化,引发渲染树从新渲染,这个过程叫作回流(回流必定形成重绘css

重绘: 当修改元素的颜色,渲染树会根据新规则从新渲染,这个过程叫作重绘(重绘不必定形成回流html

如何减小回流前端

  1. 对DOM进行屡次添加删除操做时,使用documentfragment对象(在该对象中对DOM进行操做,完成后append到文档中,便可只进行一次回流)
    function addDivs(element) {
      var div;
      // Creates a new empty DocumentFragment.
      var fragment = document.createDocumentFragment();
      for (var i = 0; i < 20; i ++) {
        div = document.createElement('a');
        div.innerHTML = 'Heya!';
        fragment.appendChild(div);
      }
      element.appendChild(fragment);
    }
    复制代码
  2. 使用定位脱离文档流改变位置
  3. 避免逐项更改样式,将样式列表定义为class并一次性更改class属性
  4. 避免循环读取offsetLeft等属性,在循环以前把它们缓存起来。

2. 获取点击元素的下标

------ html-------
<ul>
    <li>Coffee</li>
    <li>Milk</li>
    <li>Soda</li>
</ul>
复制代码
  1. 原生js
let lis = document.getElementsByTagName('li')
for (let i=0; i<lis.length; i++) {
  lis[i].index = i
}
document.getElementsByTagName('ul')[0].addEventListener('click', handle, false)
function handle (event) {
  if (event.target.tagName === 'LI') {
    console.log(event.target.index)
  }
}
复制代码
  1. jquery的index()方法
$('li').click(function () {
  console.log($(this).index())
})
复制代码

CSS

1. css布局,实现顶部高固定,左侧导航宽固定,右侧自适应

点我ԅ(¯﹃¯ԅ)vue

2. 三大定位,相对定位放在固定定位产生什么影响?

fixed、relative、absolutejava

相对定位和固定定位,都会使块级元素产生BFC,下面经过步骤检测一下node

  1. 设置父元素为固定定位,不设置高度,内部box设置高度和宽度,根据BFC内部box垂直排列的特征,效果以下jquery

    <div class="sj">
        <div>1</div>
    </div>
    复制代码
    .sj{
        position: fixed;
        top: 0;
        left: 0;
        width: 200px;
        background-color: #ccc;
      }
      .sj>div{
        height: 20px;
        width: 100px;
        background-color: #2db7f5;
      }
    复制代码
    1. 若将内部box设为绝对定位,即内部box会产生BFC,根据BFC与外部互不影响的特征,内部box将没法撑起父元素高度,以下

    .sj>div{
        height: 20px;
        width: 100px;
        position: absolute;
        background-color: #2db7f5;
    }
    复制代码

3. 伪类和伪元素

伪类:向某些选择器设置特殊效果,用于选择器选择不到的元素webpack

伪元素:向某些选择器添加特殊效果web

  • 伪类本质为了弥补选择器的不足,以此获取更多信息
  • 伪元素建立一个新的虚拟容器,该容器内不包含dom节点,但能够添加内容,而且可对伪元素追加样式
  • 伪类“:”,伪元素“::”
  • 能够同时使用多个伪类,但同时只能使用一个伪元素

4. 纯css画三角形

点我ԅ(¯﹃¯ԅ)

5. CSS BFC是什么?

BFC是一个独立的块级渲染容器,拥有本身的渲染规则,不受外部影响,不影响外部

特征

  1. 内部box垂直往下排列
  2. 内部块元素受maigin特征的影响,上下外边距会塌陷
  3. BFC区域不会遮盖浮动元素区域
  4. 计算BFC高度时,浮动元素高度也计算在内
  5. BFC是独立渲染容器,外部元素不影响内部,反之亦然

产生条件

  1. 固定定位和绝对定位
  2. float除了none外
  3. overflow除了visible外(hidden、auto、scroll)
  4. display为如下其一(inline-block、table-cell、table-caption)

做用

  1. 清除浮动
  2. 消除margin重叠
  3. 布局(左浮动,右BFC自适应)

6. 清除浮动的方式

1. 父元素设置伪类:clear:both + zoom:1

设置zomm为了兼容IE

<div class="parent1 clearFloat">
    <div class="left"></div>
</div>
<div class="parent2"></div>

.parent1{
    border: 1px solid red;
}
.parent2{
    height: 100px;
    border: 1px solid blue;
}
.left{
    width: 200px;
    height: 200px;
    background-color: #5cadff;
    float: left;
}
.clearfloat::after{
    display: block;
    clear: both;
    content: '';
    visibility: hidden;
    height: 0;
}
.clearfloat {
    zoom: 1
}
复制代码

2. 结尾处添加空白标签:claer:both

<div class="parent1">
    <div class="left"></div>
    <div class="clearfloat"></div>
</div>
<div class="parent2"></div>

.clearfloat{
    clear: both;
}
复制代码

3. 父元素产生BFC

BFC内浮动元素高度计算在内

7. 水平垂直居中的实现方式,尽量多

方法1、定位 + transform

.parent{
    height: 500px;
    width: 500px;
    border: 1px solid red;
    position: relative;
 }
 .child{
    height: 80px;
    width: 80px;
    background-color: #515A6E;
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
 }
复制代码

方法2、margin + transform

.parent{
    height: 500px;
    width: 500px;
    border: 1px solid red;
 }
 .child{
    height: 80px;
    width: 80px;
    background-color: #515A6E;
    margin: 50% 0 0 50%;
    transform: translate(-50%, -50%);
 }
复制代码

方法3、定位 + 负margin

.parent{
    height: 500px;
    width: 500px;
    border: 1px solid red;
    position: relative;
 }
 .child{
    height: 80px;
    width: 80px;
    background-color: #515A6E;
    position: absolute;
    top: 50%;
    left: 50%;
    margin: -40px 0 0 -40px;
 }
复制代码

方法4、flex

.parent{
    height: 500px;
    width: 500px;
    border: 1px solid red;
    display: flex;
    align-items: center;
    justify-content: center;
 }
 .child{
    height: 80px;
    width: 80px;
    background-color: #515A6E;
 }
复制代码

方法5、table-cell

.parent{
    height: 500px;
    width: 500px;
    border: 1px solid red;
    display: table-cell;
    text-align: center;
    vertical-align: middle;
 }
 .child{
    display: inline-block;
    height: 80px;
    width: 80px;
    background-color: #515A6E;
 }
复制代码

8. 盒子模型

标准盒子模型

width = content

IE盒子模型

width = border + padding + content

9. 块级元素和行内元素的区别?img可设置宽高吗?

块级元素

  • 独占一行,在默认状况下,其宽度自动填满其父元素的宽度
  • 块级元素能够设置width、height属性
  • 块级元素即便设置了宽度也是独占一行,块级元素能够设置margin、padding属性

行内元素

  • 行内元素不会独占一行,相邻的行内元素会排列在同一行里,直到行排不下,就自动换行,其宽度随内容而变化
  • 行内元素的width、height属性则无效
  • 水平方向的padding、margin会产生边距效果,竖直方向的padding、margin不会产生边距效果

行内置换元素

浏览器依据元素的标签和属性来决定元素的具体显示内容

img、input、textarea、select、object属于行内置换元素, 具备块级元素的特征(除宽度外)

10. absolute定位 不设置top、right、bottom、left有什么效果?

元素脱离文档流,但由于没有设置属性致使没法具体定位,紧跟在上个元素以后,但下个元素排列时会忽略此元素

11. css权重

<div id="a">
  <span class="b">222</span> // 红色
</div>

div span{
  color: blue;
}
#a {
  color: red;
}
复制代码

!important(10000) > 内联样式(1000) > id(100) > class|伪类|属性选择(10) > 标签|伪元素(1) > 通配符(0) > 继承(无)

JavaScript

1. js输出数组中出现最多的元素和次数

点我ԅ(¯﹃¯ԅ)

2. 100阶台阶一次走1步或2步有多少种走法

假设只走一个台阶,有1种走法;两个台阶,2中走法,三个台阶,3种走法;四个台阶,5种走法...

1->1; 2->2; 3->3; 4->5...能够看出此问题是斐波那契数列,即下个值是前两个值的和

公式为:f(n) = f(n-1) + f(n-2)

方法1、遍历相加

function test (num) {
    let num1 = 1, num2 = 2, res = 0
      for (let i=2; i<num; i++) {
        res = num1 + num2
        num1 = num2
        num2 = res
      }
    return res
}
复制代码

方法2、递归 (不推荐)

function test (num) {
    if (num === 1)
        return 1
    else if (num === 2)
        return 2
    else 
        return test(num-1) + test(num-2)
}
复制代码

3. 如何实现抽奖转盘

4. 闭包及使用场景

  • 闭包

    1. 外部函数可以访问内部函数的变量
    2. 闭包所在的函数变量不能被垃圾回收机制回收
    3. 常驻内存,占用内存使用量
  • 使用场景

    1. 给对象设置私有变量而且利用特权方法去访问私有属性
    2. 采用函数引用方式的setTimeout调用
    3. 封装相关功能集

    👉传送门

5. 什么是原型、原型链?

  • 原型对象也是普通的对象,是对象一个自带隐式的__proto__属性,原型也有可能有本身的原型,若是一个原型对象的原型不为null的话,咱们就称之为原型链。
  • 原型链是由一些用来继承和共享属性的对象组成的(有限的)对象链。

6. 类的建立与继承

  • 建立:new 一个Function,在prototype中添加属性和方法
  • 继承:
    1. 原型链继承,基于原型链,是父类和子类的实例,没法实现多继承
    function Cat(){}
    Cat.prototype = new Animal();
    Cat.prototype.name = 'cat';
    //&emsp;Test Code
    var cat = new Cat();
    复制代码
    1. 构造函数继承:复制父类的实例给子类,只继承父类实例的属性与方法,不继承原型上的,可实现多继承
    function Cat(name){
        Animal.call(this)
        this.name = name || 'Tom';
    }
    var cat = new Cat()
    复制代码
    1. 组合继承(原型链继承+构造函数继承)

7. new作了什么事

  • 建立一个空对象
  • 将该对象的原型指向建立该对象的构造函数的prototype上

8.建立对象的方式

  1. 工厂模式
  2. 构造函数模式
  3. 原型模式
  4. 混合构造函数与原型模式

9. 深拷贝

  • 数组的深拷贝
let newArr = JSON.Parse(JSON.Stringify(oldArr))
复制代码
扩展运算符
<!-- 仅对包含基本数据类型的数组有效 -->
let newArr = [...oldArr]
复制代码
  • 对象的深拷贝
function deepClone (obj) {
    let newObj = obj instanceof Array ? [] : {}
    for(var i in obj){
        newObj[i] = typeof obj[i] == 'object' ? deepClone(obj[i]) : obj[i]
    }
    return newObj
}
复制代码

10. 数组操做

传送门👉 JavaScript 数组

11. 写一个js函数,实现对一个数字每3位加一个逗号

function test (num) {
    let arr1 = [], arr2 = [],arr = [] // arr1保存小数前, arr2保存小数后
    arr = num.toString().split('.')
    arr2 = arr[1] ? [...arr[1]] : [] // 判断是否存在小数,并将每项转为数组元素
    arr1 = [...arr[0]]
    let newArr1 = arr1.map((item, index) => arr1.length === (index+1) && (index+1)%3 === 0 ? item : (index+1)%3 === 0 ? item+',' : item)
    let newArr2 = arr2.map((item, index) => arr2.length === (index+1) && (index+1)%3 === 0 ? item : (index+1)%3 === 0 ? item+',' : item)  // 数组为空则map()不检测
    newArr2.unshift('.')
    console.log(newArr1.concat(newArr2).join(''))
  }
  test(123456789.123)
复制代码

12. 手写快速排序

快速排序采用分治法的思想,将一个复杂问题分为两个或多个子问题,直到子问题简单到能够直接求解,那么子问题的解的组合即是原问题的解

function quickSort (arr) {
    if (arr.length <= 1) return arr;
    //取中间位置的数据做为基准值,并从原数组中删除该基准值
    let jzIndex = Math.floor(arr.length/2) // 获取基准值下标
    let jzNum = arr.splice(jzIndex, 1) // 删除并获取基准值

    let leftArr = [], rightArr = [] // 分别保存小于和大于基准值的数据
    arr.forEach(item => {
      if (item < jzNum[0]) {
        leftArr.push(item)
      }
      if (item >= jzNum[0]) {
        rightArr.push(item)
      }
    })
    //concat()链接两个数组
    return quickSort(leftArr).concat(jzNum, quickSort(rightArr))
  }
  console.log(quickSort([10,5,15,2,4]))
复制代码

13. 函数的防抖与节流

防抖: 任务频繁触发状况下,只有两次任务间隔超过指定时间,才会执行。若还未超过却又一次触发,则时间从新开始计算

// 防抖函数
  function debounce (fn, time) {
    // 新建一个变量保存定时器
    let timeout = null;
    return function () {
      // 每次用户点击、输入时,清空上一个定时器
      clearTimeout(timeout)
      timeout = setTimeout(() => {
        fn.call(this, arguments)
      }, time)
    }
  }
  // 处理函数
  function handler () {
    console.log('防抖成功!')
  }
  // 触发
  debounce(handler, 1000)
复制代码

节流: 频繁触发任务,任务按照必定时间间隔进行执行

// 节流函数
  function throttle (fn, time) {
    // 利用闭包保存是否可执行的变量
    let canRun = true
    return function () {
      // 若是为false,则终止函数执行
      if (!canRun) return;
      // 执行前将变量设为false
      canRun = false
      setTimeout(() => {
        fn.call(this, arguments)
        canRun = true
      }, time)
    }
  }
  // 处理函数
  function handler () {
    console.log('节流成功!')
  }
  // 触发
  throttle(throttle, 1000)
复制代码

14. 随机生成指定范围内的随机数

在指定范围内生成随机数

ES6

1. Promise相关问题

1. 什么是Promise?

  • promise是异步编程的解决方案,比起传统的异步解决方案“回调函数”、“事件”更合理强大,已被ES6归入规范
  • 具备三种状态:pending 过渡态、fulfilled 完成态、rejected 失败态,状态一旦肯定不可修改

2. Promise优缺点?

优势:

  • 解决回调地域
  • 可读性高,便于维护

缺点:

  • 没法中止,一旦建立Promise当即执行
  • 必须指定回调,不然内部抛出异常
  • 当处于pending状态时,没法肯定此时进行到哪一阶段(刚开始仍是即将完成)

3. Promise的方法有哪些?做用都是什么?

  • Promise.prototype.then()

    Promise 实例添加状态改变时的回调函数,then方法的第一个参数是resolved状态的回调函数,第二个参数(可选)是rejected状态的回调函数

    then方法返回的是一个新的Promise实例(注意,不是原来那个Promise实例)。所以能够采用链式写法,即then方法后面再调用另外一个then方法。

  • Promise.prototype.catch()

    .then(null, rejection)或.then(undefined, rejection)的别名,用于指定发生错误时的回调函数。

  • Promise.prototype.finally()

    不管Promise最后状态如何,都会执行finally内的函数,ES2018引入

  • Promise.all()

    多个Promise同时执行,若所有成功,则以数组形式返回执行结果;如有一个是rejected,则只返回rejected的结果

  • Promise.race()

    多个Promise同时执行,返回最早结束Promise执行任务的结果,不管成功或失败

  • Promise.resolve()

    返回一个新的 Promise 实例,该实例的状态为resolve

    1. 若参数为Promise实例,则返回该实例
    2. 参数是一个thenable对象,(thenable为具备then方法的对象),将此对象转换为Promise并当即执行then方法
    3. 参数不是具备then方法的对象,或根本就不是对象,则Promise.resolve方法返回一个新的 Promise 对象,状态为resolved
    4. 若不带任何参数,直接返回一个resolved状态的 Promise 对象
  • Promise.reject()

    返回一个新的 Promise 实例,该实例的状态为rejected

4. promise如何使用?

  • Promise是构造函数,须要new一个Promise的实例
  • Promise构造函数的参数为一个函数,函数内的参数为resolved和rejected
  • 实例后用then方法分别指定resolved状态和rejected状态的回调函数
  • then方法接受两个参数,rejected非必须;then返回Promise对象,则可链式调用

5. 手写一个promise

// 定义Promise构造函数
  function Promise (exector) {
    let self = this;
    this.value = undefined;
    this.reason = undefined;
    // 定义Promise的状态
    this.status = 'pending'
    // 存储then中成功的回调函数
    this.onResolvedCallbacks = [];
    // 存储then中失败的回调函数
    this.onRejectedCallbacks = [];

    function resolve (value) {
      if (self.status === 'pending') {
        self.value = value
        self.status = 'resolved'
        self.onResolvedCallbacks.forEach(fn => fn())
      }
    }

    function reject (reason) {
      if (self.status === 'pending') {
        self.reason = reason
        self.status = 'rejected'
        self.onRejectedCallbacks.forEach(fn => fn())
      }
    }
    // 异常处理
    try{
      exector(resolve, reject)
    }catch (e) {
      reject(e)
    }
  }

  // 在Promise原型上定义then方法,参数为成功和失败的回调
  Promise.prototype.then = function (onFulfilled, onRejected) {
    let self = this;
    if (this.status === 'resolved') {
      onFulfilled(self.value)
    }
    if (this.status === 'rejected') {
      onRejected(self.reason);
    }
    if (this.status === 'pending') {
      this.onResolvedCallbacks.push(() => {
        onFulfilled(self.value)
      })

      this.onRejectedCallbacks.push(() => {
        onRejected(self.reason)
      })
    }
  }

  let promise = new Promise((resolve, reject)=> {
    setTimeout(() => {
      resolve('success')
    }, 1000)
  })

  promise.then(data => {
    console.log(data)
  }, err => {
    console.log(err)
  })
复制代码

webpack

webpack是模块打包工具,对js模块和扩展语言进行打包供浏览器识别运行

  • webpack只能处理js代码,其余格式须要经过loader进行转换
  • 可对浏览器不能识别的规范和静态文件进行分析、压缩、合并、打包成可供浏览器支持的代码

1. webpack和Grunt以及Gulp相比有什么区别

2. webpack 的 loader 和 plugin 区别,举几个经常使用的 loader 和 plugin 并说出做用

  • loader用于对模块代码进行转换,可将不一样格式语言转换为JavaScript,或将图像转换为Data Url,因为webpack只可以识别JavaScript,因此不一样类型的模块须要对应的loader进行转换
  • plugin是webpack的扩展插件,可完成loader没法完成的复杂功能,可控制webpack每一个打包环节的流程,极大丰富了webpack的扩展性

3. webpack打包过程

  • 读取文件,分析模块的依赖
  • 对模块进行解析执行(深度遍历)
  • 针对不一样的模块使用不一样的 loader
  • 编译模块,生成抽象语法树(AST)
  • 遍历 AST,输出 JS

4. webpack打包优化

  • 使用compression-webpack-plugin压缩代码
  • 使用cdn引入第三方库
  • 按需引入第三方库里不一样组件

Vue

1. 兄弟组件如何通讯,无嵌套,回调触发

方法1、经过父组件通讯

此方法须要保证兄弟组件A、B都在同一个父组件下;

父组件经过接受子组件A传递过来的事件消息,并调用子组件B

子组件A
this.$emit('transmit', 'msg')
复制代码
父组件
<ChildA @transmit="transmit"></ChildA>
<ChildB :msg="msg"></ChildB>

transmit (data) => {
    this.msg = data 
}
复制代码
子组件B、须要使用watch来监听父组件props穿过来的数据变化
watch (new, old) {
    数据操做... 
}
复制代码

方法2、eventBus

经过建立Bus.js注册一个全局实例,通信组件经过调用实例的方法达到通信目的

  1. 建立Bus.js
// eventBus 共享vue实例,用于兄弟组件数据传递
import Vue from 'vue'
const Bus = new Vue({})
export {Bus}
复制代码
  1. 组件A导入Bus.js 并emit消息
import {Bus} from './Bus.js'

Bus.$emit('transmit', 'msg')
复制代码
  1. 组件B导入Bus.js并在mounted中检测数据变化
import {Bus} from './Bus.js'

mounted () {
    Bus.$on('transmit', (data) => {
        操做...
    })
}

因为$on事件没法主动销毁,因此须要根据业务手动进行销毁

在组件销毁前方法中销毁
beforeDestory () {
    Bus.$off('transmit')
}

或者在使用前进行销毁
mounted () {
    Bus.$off('transmit')
    Bus.$on('transmit', (data) => {
        操做...
    })
}
复制代码

2. vueRouter的工做原理

Vue Router 是路由管理器,能够改变url而不向服务器发送请求,页面无需刷新

有hash和history两种路由模式

hash模式

  • #后的hash值改变,会触发onhashchange事件
  • hash的变化会被浏览器记录(历史访问栈)下来,能够前进、后退、刷新而不向服务器发送请求
  • 经过匹配#后面的hash,与vueRouter配置文件里的path对应作路由跳转

history模式

  • 基于浏览器history的pushState()、replaceState()、popState()来实现,能够读取、修改浏览器历史记录栈
  • 能够前进、后退不发往服务器发送请求,但刷新会向服务器发送请求
  • 若匹配不到资源,则返回404,所以须要后台支持,重定向到根目录主页

动态路由匹配中会复用同一组件,这就致使再次访问组件不被从新渲染,声明周期钩子不会执行,这就须要咱们用watch去监听路由的变化

watch: {
    $route(to, from) {
        ······
    }
}
复制代码

vue Router 详解

3. Vuex的理解

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式

Vuex包含五个属性:state、getter、mutation、action、module

  • state:存储数据,存储状态;注册了Store实例后,可经过this.$store.XX来访问;对应组件内的data,数据为响应式,组件经过store来读取vuex的数据,若数据改变,则组件的数据也会改变
  • getter:store的计算属性,它的返回值会被依赖缓存起来,当依赖值发生变化时才会被从新计算
  • mutation:更改Vuex的store中状态的惟一方法是提交mutation
  • action:包含任意异步操做,经过提交 mutation 间接更变状态
  • module:将 store 分割成模块,每一个模块都具备state、mutation、action、getter、甚至是嵌套子模块

当组件进行数据修改的时候,经过调用dispatch来触发actions里面的方法,actions里每一个方法都有commit方法,经过执行commit方法来触发mutation里的方法进行数据修改,因为mutation里每一个函数都有一个state参数,进而可对state进行修改,当数据修改完毕后,会传导给页面。页面的数据也会发生改变。

4. vue Dom渲染的过程和原理

  • new Vue 初始化Vue实例
  • 经过三种渲染模式 Render、el、template 生成Render函数
  • 经过Watcher监测数据变化
  • 当数据变化时,经过Render函数生成VNode
  • 经过patchVnode对比先后变化,经过diff进行更新、添加、删除等操做生成真实Dom节点

5. watch用法

watch用来监听并响应数据的变化

  • 能够直接监听基本数据类型数据
  • 如果监听对象,则须要开启deep(深度监听)
  • 如果监听数组,则不须要开启deep监听
  • immediate 初始化绑定值时即执行监听
  • watch首次初始化绑定不执行,但监听的值发生变化时则执行监听
data () {
    return {
        age: 20,
        obj: {
            age: 24
        },
        arr: [1,2,3]
    }
}
复制代码
1. 监听基本类型
watch: {
    age (newd, oldd) {
        ...
    }
}

复制代码
2. 监听对象
watch: {
    obj: {
        handler (newd, oldd) {
            ...
        },
        deep: true, // 开启深度监听
        immediate: true // 首次即执行
    }
}
复制代码
3. 监听对象某个属性

*** 采用字符串
watch: {
    'obj.age': {
        handler (newd, oldd) {
            ...
        }
    }
}

*** 利用computed计算属性
computed: {
    age () {
        return this.obj.age
    }
}
watch: {
    age (newd, oldd) {
        ...
    }
    // 也可写为
    age: {
        handler (newd, oldd) {
            ...
        }
    }
}
复制代码

6. vue nextTick

异步更新队列

Vue 异步执行 DOM 更新。只要观察到数据变化,Vue将开启一个队列,并缓冲在同一事件循环中发生的全部数据改变。若是同一个 watcher被屡次触发,只会被推入到队列中一次。这种在缓冲时去除重复数据对于避免没必要要的计算和 DOM 操做是很是重要的。而后,在下一个的事件循环“tick”中,Vue刷新队列并执行实际 (已去重的) 工做。Vue 在内部尝试对异步队列使用原生的Promise.then和MessageChannel,若是执行环境不支持,会采用 setTimeout(fn, 0) 代替。

例如,当你设置 vm.someData='newvalue',该组件不会当即从新渲染。当刷新队列时,组件会在事件循环队列清空时的下一个“tick”更新

nextTick

因为DOM是异步执行更新的,有时咱们修改完数据等待DOM更新后进行操做,则此刻可以使用Vue.nextTick(callback)

Vue.component('example', {
  template: '<span>{{ message }}</span>',
  data: function () {
    return {
      message: '没有更新'
    }
  },
  methods: {
    updateMessage: function () {
      this.message = '更新完成'
      console.log(this.$el.textContent) // => '没有更新'
      this.$nextTick(function () {
        console.log(this.$el.textContent) // => '更新完成'
      })
    }
  }
})
复制代码

由于 $nextTick() 返回一个 Promise 对象,因此你可使用新的ES2016async/await语法完成相同的事情:

methods: {
  updateMessage: async function () {
    this.message = 'updated'
    console.log(this.$el.textContent) // => '未更新'
    await this.$nextTick()
    console.log(this.$el.textContent) // => '已更新'
  }
}
复制代码

7. vue 生命周期有哪些?

  • beforeCreate ----建立前
  • created ---- 成功建立
  • beforeMount ---- 挂载前
  • mounted ---- 成功挂载
  • beforeUpdate ---- 更新前
  • updated ---- 成功更新
  • beforeDestroy ---- 销毁前
  • destroyed ---- 成功销毁

👉传送门,Vue声明周期详解

8. vue 响应式数据是如何实现的?

  1. 遍历实例中的data的全部属性,并经过Object.defineProperty将其转换为setter、getter
  2. 每一个实例都有一个Watcher、并经过Dep去关联data中的setter、getter的依赖
  3. 当data改变时,setter会触发Dep依赖,并触发Watcher.update
  • 因为Object.observe的废除,致使没法检测对象的变化
  • 没法检测根级对象的属性变化,可经过Vue.set(this.obj, key, value)来向对象动态添加响应式属性

网络

1. 浏览器输入地址后发生什么

  1. 解析URL
  2. DNS解析、监测缓存
  3. 客户端与服务端创建TCP链接(三次握手)
  4. 请求与传输数据
  5. 进行数据渲染
  6. 解析HTML、生成DOM树、解析CSS代码、将数据渲染到网页上

2. 轮询、长轮询、长链接、websocket区别

  • 轮询:定时向服务器发送ajax请求,无需等待响应
  • 长轮询:客户端向服务器发送请求,服务器保持链接,当有更新消息当即返回客户端,链接关闭。
  • 长链接:客户端向服务器发送请求,服务器保持链接,当有更新消息当即返回客户端,链接保持。
  • websocket:h5提供的基于TCP的双向通信协议,服务器主动推送消息到客户端,只需一次握手链接,便可创建持久链接

3. 三次握手、四次分手

  • 三次握手
客户端      ->(创建链接)->          服务器
    客户端   <-(确认接受,创建链接)<-   服务器
    客户端      ->(确认接受)->          服务器
复制代码
  • 四次分手
客户端      ->(关闭链接)->      服务器
    客户端      <-(确认关闭)<-      服务器
    客户端      <-(关闭链接)<-      服务器
    客户端      ->(确认关闭)->      服务器
复制代码

4. 请求状态码

2XX 请求成功

  • 200 请求成功
  • 204 请求成功,但未有任何资源返回
  • 206 服务器成功处理部分get请求)

3XX 重定向

  • 301 url已更新
  • 302 url重定向
  • 303 是否访问新的url
  • 304 访问缓存资源,服务器无数据返回

4XX 客户端错误

  • 401 须要验证
  • 403 不容许访问

5XX 服务器错误

5. 安全问题

XSS(跨站脚本攻击)是在网页中注入非法的js脚本,获取cookie达到控制浏览器的目的

  • DOM xss : 使用DOM能够容许程序和脚本动态的访问和更新文档的内容、结构和样式
  • 反射性 xss:发出请求时,XSS代码出如今URL中,最后输入提交到服务器,服务器解析后在响应内容中出现这段XSS代码,最后浏览器解析执行。
  • 存储型 xss:当攻击者提交一段XSS代码后,被服务器端接收并存储,当全部浏览者访问某个页面时都会被XSS,其中最典型的例子就是留言板。

危害:

  • 利用虚拟输入表单获取用户信息
  • 获取cookie,可代替用户进行危险操做

防范方法:

  • httpOnly: 在 cookie 中设置 HttpOnly 属性,使js脚本没法读取到 cookie 信息
  • 先后端校验输入表单格式,过滤不合理字符

CSRF 跨站点请求伪造,冒充用户发起请求,完成一些违背用户意愿的事情(如修改用户信息等)

危害:

  • 利用已认证过的用户对商品信息、我的信息进行违法操做等

防范方法:

  • 验证码: 强制用户与应用进行交互
  • 减小get请求
  • token验证CSRF防护机制是公认最合适的方案

token使用原理

  • 后端随机生成一个token,并将此token携带在cookie中,而后将此token传递给前端页面
  • 前端获取此token后,每次请求都携带token
  • 后端验证token是否一致,若一致则请求合法

6. ajax请求过程

  1. 建立XMLHttpRequest对象,
  2. 建立http请求,并指明请求的url,方式和参数
  3. 设置http请求状态变化的函数
  4. 发送http请求
  5. 经过回调获取返回的数据
  6. 渲染

7. 跨域的方式

同源策略: 具备相同的协议(http/https)、域名、端口即为同源,不存在跨域,反之亦然

  • 跨域资源共享(CORS)

    需后端设置

  • 服务器转发代理

    请求同源地址的代理接口,服务器访问跨域接口并返回数据

  • jsonp

    利用script标签不受同源策略限制的特征,在src内写入请求地址,末尾回调处理数据

    <script type="text/javascript" src="http://localhost/Service.ashx?callback=jsonpCallback" />
    复制代码

8. cookie、sessionStorage、localStorage

cookie

  • 存储大小最大为4k
  • 老是携带于http请求中
  • 需设置max-age,超过期间则被销毁

sessionStorage

  • 存储大小最大为5M
  • 存储于本地中
  • 当前会话有效,页面或浏览器关闭则销毁
  • 从A跳转到B,B可与A共享sessionStorage;若单独打开B,则获取为null

localStorage

  • 存储大小最大为5M
  • 存储于本地中
  • 若未设置过时时间,则永久保存
  • 页面之间共享

优化

1. 图片优化

图片大体分为png、jpg、gif三种

  • gif体积小,很好的压缩效果,支持动画,支持透明效果;但色彩效果最低
  • png压缩效果好,支持透明效果,色彩不如jpg,最为通用

优化方案:

  1. 雪碧图
    • 即css sprites, 就是把不少小图片制做成一个大图,而后做为背景图片使用,定位便可
    • 优势: 体积小,引入一张图片便可,减小http请求
  2. 图片压缩
    • 使用canvas的drawImage()进行压缩
    • 上传至七牛云或阿里云进行压缩
  3. base64
    • 利用编码存储图片,减小http请求
  4. 响应式图片
    • 利用srcset 和 sizes 属性作响应式图片
  5. 延迟加载
    • 当图片不少时,所有加载耗时过多也极可能形成卡顿
    • 仅加载可视区域内的图片,非可视区域使用通用图片占位,当页面滚动进入可视区域后,再加载此区域内的图片

当加载图片过大时,会出现局部逐步加载状况,用户体验差;可经过哟图片的onload方法来判断图片是否加载完成,未加载完前先display:none;进行隐藏,当onload后在进行加载。

其余

1. 轮流向圆形桌子放硬币,若是保证能赢,谁先放?

假设桌子小到只能放下一枚硬币,那么先放者赢;若不肯定桌子大小,则首先在圆心处放硬币,而后在对手放完后的关于圆心的对称点处再放硬币,确保先放者赢

2. 随机抽样一致性算法

详解