面试题整理

179 阅读27分钟

HTML

1.H5新特性有哪些?

  • 语义化标签
    • nav header footer aside section
  • audio 、video、canvas、内联svg
  • Web存储:LocalStorage、SessionStorage
  • 表单
    • 新的input类型:email、number、url、search、color、tel、date
    • 新的表单属性:
      • form新属性:autocomplete、novalidate
      • input新属性:placeholder、required、min与max、height与width、autofocus等

2.对HTML语义化的理解

  • 语义化是指根据内容的类型,在指定的地方用指定的标签,头部用herader,尾部用footer,导航用nav
  • HTML语义化让页面的结构更清晰,有助于浏览器和搜索引擎解析对内容的抓取
  • 语义化的HTML在没有CSS的情况下也能保持很清晰的内容结构与代码结构
  • 更利于SEO

3.Doctype有什么作用?

  • DOCTYPE是一种标准通用标记语言的文档类型声明
  • 作用:告诉浏览器的解析器(标准通用标记语言解析器),应该是用什么文档类型定义解析文档
  • 影响:DOCTYPE不存在或格式不正确,会导致文档以兼容模式呈现

CSS

1.C3新特性有哪些?

  • 圆角、边框背景、盒子阴影、字体阴影
  • 渐变、过渡、旋转、帧动画
  • 弹性布局

2.垂直居中的办法有哪些?

  • 弹性布局 align-items:center
  • Line-height 等于height (行高等于高度,一般用于文字垂直居中)
  • Position:absolute (绝对定位+偏移值 top:50% margin-top:-50%)
  • Position:absolute(绝对定位+偏移值0 + margin:0 auto)
  • transform:translate(-50%,-50%)

3.清除浮动的方法有哪些,使用原因?

  • 原因:解决父元素因为子元素浮动引起的内部高度为0的问题

  • 方法:

    • 父级div定义height

      • 原理:父级div手动定义height,解决父级div无法自动获取高度问题
      • 缺点:只适合高度固定的布局
    • 结尾处加空div标签,clear:both

      • 原理:在浮动元素后面添加一个空的div兄弟元素,利用css提高的clear:both清除浮动,让父级div能自动获取到高度
      • 缺点:如果页面浮动布局多,则需添加很多空div
    • 父级div定义 伪类:after和zoom

      /*清除浮动代码*/ 
      .clearfix:after{
      content:"";
      display:block;
      visibility:hidden;
      height:0;//必设,否则该元素会比实际高出若干像素
      line-height:0;
      clear:both;
      } 
      .clearfix{zoom:1}
      
      • 兼容性:IE8以上和非IE浏览器才支持:after
      • 原理:与clear:both的类似,zoom(IE私有属性)可解决ie6、7的浮动问题
      • 推荐使用,建议定义公共类,减少css代码
    • 父级div定义 overflow:hidden或auto

      • 超出盒子部分会被隐藏,不推荐使用
    • 双伪元素法

      .clearfix:before,.clearfix:after {/*伪元素是行内元素 正常浏览器清除浮动方法*/
        content:"";
        display: block;
        clear: both;
      }
      .clearfix {
        zoom: 1;/*ie6清除浮动的方式 *号只有IE6-IE7执行,其他浏览器不执行*/
      }
      

4.如何理解盒子模型

  • 每个HTML元素都是一个盒子,这个盒子中可能又包裹着其他的盒子,这就是盒子模型
  • 分类:
    • 标准盒模型:外边距+边框+内边距+内容(宽高)
    • IE盒模型:外边距+内容(宽高+内边距+边框)
  • 设置:
    • 标准盒模型:box-sizing:content-box(默认)
    • IE盒模型:box-sizing:border-box

5.BFC是什么,触发的情况

  • 定义:块级格式上下文,规定内部的Block Box如何布局
  • 触发的情况:
    • 根元素,为html
    • float的值不为none(默认)
    • overflow的值不为visible(默认)
    • display的值为inline-block、table-cell、table-caption时
    • position的值为absolute或fixed

6.CSS选择器有哪些?

  • id选择器
  • class类选择器
  • 标签选择器
  • 属性选择器
  • 后代选择器
  • 子代选择器
  • 并集选择器
  • 伪类选择器
  • 伪元素选择器

7. CSS样式权重优先级是怎么计算的?

!important>行内样式>id>class=伪类=属性>标签>*>继承

8. position几个属性的作用

9. 移动端的边框0.5px,怎么实现?

  • 伪类缩放:【 :after 1px 然后 transform:scale(0.5)】

10. flex有哪些属性?以及值

  • flex-direction:决定主轴的方向

    • row(默认值):主轴为水平方向,起点在左端。
    • row-reverse:主轴为水平方向,起点在右端。
    • column:主轴为垂直方向,起点在上沿。
    • column-reverse:主轴为垂直方向,起点在下沿。
  • flex-wrap:如果一条轴线排不下,如何换行。默认情况下,项目都排在一条线(又称"轴线")上。

    • nowrap(默认):不换行。
    • wrap:换行,第一行在上方。
    • wrap-reverse:换行,第一行在下方。
  • flex-flow:是flex-direction属性和flex-wrap属性的简写形式,默认值为row nowrap

    • flex-flow: <flex-direction> || <flex-wrap>;
      
  • justify-content:定义了项目在主轴上的对齐方式

    • flex-start(默认值):左对齐
    • flex-end:右对齐
    • center: 居中
    • space-between:两端对齐,项目之间的间隔都相等。
    • space-around:每个项目两侧的间隔相等。所以,项目之间的间隔比项目与边框的间隔大一倍。
  • align-items:定义项目在交叉轴上的对齐方式

    • flex-start:交叉轴的起点对齐。
    • flex-end:交叉轴的终点对齐。
    • center:交叉轴的中点对齐。
    • baseline: 项目的第一行文字的基线对齐。
    • stretch(默认值):如果项目未设置高度或设为auto,将占满整个容器的高度。
  • align-content:定义了多根轴线的对齐方式。如果项目只有一根轴线,该属性不起作用

    • flex-start:与交叉轴的起点对齐。
    • flex-end:与交叉轴的终点对齐。
    • center:与交叉轴的中点对齐。
    • space-between:与交叉轴两端对齐,轴线之间的间隔平均分布。
    • space-around:每根轴线两侧的间隔都相等。所以,轴线之间的间隔比轴线与边框的间隔大一倍。
    • stretch(默认值):轴线占满整个交叉轴。

11. flex:1

那三个属性设置的什么值

  • flexflex-growflex-shrinkflex-basis的缩写,默认值为0 1 auto。后两个属性可选

    • 该属性有两个快捷值:auto (1 1 auto) 和 none (0 0 auto)。

      flex: none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]
      
    • flex-grow:定义项目的放大比例,默认为0。即如果存在剩余空间,也不放大

      • flex-grow: <number>; /* default 0 */
        
    • flex-shrink:定义项目的缩小比例,默认为1。即如果空间不足,该项目将缩小

      • 负值无效

      • flex-shrink: <number>; /* default 1 */
        
    • flex-basis:定义了在分配多余空间之前,项目占据的主轴空间(main size)

      • 浏览器根据这个属性,计算主轴是否有多余空间。它的默认值为auto,即项目的本来大小

      • flex-basis: <length> | auto; /* default auto */
        

flex 取值为一个非负数字,则该数字为 flex-grow 值,flex-shrink 取 1,flex-basis 取 0%,如下是等同的:

.item {flex: 1;}
.item {
    flex-grow: 1;
    flex-shrink: 1;
    flex-basis: 0%;
}

12. ::before和:after中双冒号和单冒号的区别?这两个伪元素的作用?

  • 区别:
    • 单冒号:伪类的书写
      • 伪类:虚拟类名,有类似选择器的功能
      • :link :hover :active :visited :focus :first-child
      • 为了兼容旧版本样式,:after和::after有一样的作用
    • 双冒号:伪元素的书写
      • 伪元素:虚拟元素,有
      • 类似dom结构的功能
      • ::before ::after
  • 作用:
    • ::before:在当前元素的内容的前面插入一个子元素。插入的元素为内联元素
    • :after:在当前元素的内容的后面插入一个子元素。

JS

1. 闭包是什么,应用场景,优缺点

  • 定义:有权访问一个函数内部变量的函数
  • 优缺点
    • 优点
      • 减少全局变量
      • 减少传递函数的参数量
      • 封装
    • 缺点
      • 会占有内存资源
      • 过多的使用闭包会导致内存溢出
        • 解决内存溢出问题:把不需要的变量,但是垃圾回收又收不走的变量赋值为null,然后让垃圾回收走
  • 应用场景:
    • 函数防抖
    • 函数节流
    • 变量持久化(闭包中的变量不会被回收)

2. Promise是什么?

  • 定义:Promise是一种异步编程的解决方案,是一种容器,保存着某个未来才会结束的事情的结果(通常是异步操作)
  • 作用:解决回调地狱
  • Promise创建后就会立即执行(指new Promise()),.then方法只有2个参数(resolve成功、reject失败)
  • 常用方法:
    • .then .catch .all .finally

3. JS的执行机制是什么?

  • JS是单线程语言,一次只能执行一个任务,所有的任务都需要排队,排队的队列为:事件循环Event Loop,所有Event Loop就是js的执行机制
  • js单线程
    • js作为浏览器脚本语言,主要用来与用户进行交互,需要进行dom操作
    • js是单线程,避免了同时操作DOM的矛盾

4. JS为什么需要异步?

  • js是单线程语言,所以任务都需要排队,一次只能执行一个任务,如果上一个任务执行时间很长,后面的任务就必须一直处于等待状态
  • 如果js不存在异步,只能从上往下执行,如果任务执行时间长,就会造成线程阻塞,导致用户体验很差,所以js需要异步

5. JS任务队列是什么?

  • 任务队列就是一个事件队列,其中最重要的是异步任务事件和定时任务事件
    • 异步任务事件(在某一个时刻才会被触发)
      • 点击事件的回调函数
    • 定时任务事件
      • setInterval setTimeout

6. JS的同步任务和异步任务,理解?

  • 同步任务
    • 在主线程执行栈上排队执行的任务,只有前一个执行完毕,才能执行后一个
  • 异步任务
    • 不进入主线程执行栈,而是进入“任务队列”中的任务,只有在同步任务执行完之后,才会执行异步任务

7. 理解 宏任务和微任务

  • 宏任务与微任务都是异步任务,都是在同一个任务队列中,主要区别在于它们的执行顺序
  • 在异步任务队列下 ,又分为宏任务队列与微任务队列
  • 当一个宏任务执行结束之前,会在微任务队列执行栈中查找是否有微任务,如果有则执行,没有则开启一个新的宏任务,所以微任务总是在宏任务结束之前执行的
  • 宏任务
    • 整体script,setTimeout,setInterval,setImmediate
    • 微任务promise MutationObserver

8. JS组成

  • ECMAScript+DOM+BOM

9. DOM事件流的3个阶段分别是什么?

从上到下再从下到上

  • 捕获阶段->目标阶段->冒泡阶段

10. 面向对象的特征是什么?

  • 封装性
    • 隐藏对象的属性和实现细节,仅对外提供公共访问方式,将变化隔离,便于使用,提高复用性和安全性。
  • 继承性
    • 提高代码复用性;继承是多态的前提。
  • 多态性
    • 提高代码复用性;继承是多态的前提。

11. JS继承方式有哪些

  • 方式:
    • 构造函数继承
    • 原型链继承
    • 寄生继承
    • 组合继承
    • 寄生组合式继承(记住)
  • 一般使用组合继承
    • 通用属性:写在构造函数中
    • 通用方法:写在原型中

12. call,apply,bind的用法以及区别?

  • 用法

    • call

      call 方法第一个参数是要绑定给this的值,后面传入的是一个参数列表。当第一个参数为null、undefined的时候,默认指向window

      • var arr = [1, 2, 3, 89, 46]
        var max = Math.max.call(null, arr[0], arr[1], arr[2], arr[3], arr[4])//89
          
        //理解:
        obj1.fn() 
        obj1.fn.call(obj1);
        
        fn1()
        fn1.call(null)
        
        f1(f2)
        f1.call(null,f2)
        
    • apply

      apply接受两个参数,第一个参数是要绑定给this的值,第二个参数是一个参数数组。当第一个参数为null、undefined的时候,默认指向window。

      • var arr = [1,2,3,89,46]
        var max = Math.max.apply(null,arr)//89
        
        //理解:
        obj1.fn() 
        obj1.fn.apply(obj1);
        
        fn1()
        fn1.apply(null)
        
        f1(f2)
        f1.apply(null,f2)
        
    • bind

      和call很相似,第一个参数是this的指向,从第二个参数开始是接收的参数列表。区别在于bind方法返回值是函数以及bind接收的参数列表的使用。

      bind返回值是函数

      var obj = {
          name: 'Dot'
      }
      
      function printName() {
          console.log(this.name)
      }
      
      var dot = printName.bind(obj)
      console.log(dot) // function () { … }
      dot()  // Dot
      

      bind 方法不会立即执行,而是返回一个改变了上下文 this 后的函数。而原函数 printName 中的 this 并没有被改变,依旧指向全局对象 window。

      //参数的使用:
      function fn(a, b, c) {
          console.log(a, b, c);
      }
      var fn1 = fn.bind(null, 'Dot'); //fn1 方法的实参实则是在 bind 中参数的基础上再往后排
      fn('A', 'B', 'C');            // A B C
      fn1('A', 'B', 'C');           // Dot A B
      fn1('B', 'C');                // Dot B C
      fn.call(null, 'Dot');      // Dot undefined undefined  call 是把第二个及以后的参数作为 fn 方法的实参传进去
      
  • 区别

    • 事实上apply 和 call 的用法几乎相同, 唯一的差别在于:当函数需要传递多个变量时, apply 可以接受一个数组作为参数输入, call 则是接受一系列的单独变量

    • bind返回对应函数, 便于稍后调用; apply, call则是立即调用。

    • 在 ES6 的箭头函数下, call 和 apply 将失效, 对于箭头函数来说:

      箭头函数体内的 this 对象, 就是定义时所在的对象, 而不是使用时所在的对象;所以不需要类似于var _this = this这种丑陋的写法 箭头函数不可以当作构造函数,也就是说不可以使用 new 命令, 否则会抛出一个错误 箭头函数不可以使用 arguments 对象,,该对象在函数体内不存在. 如果要用, 可以用 Rest 参数代替 不可以使用 yield 命令, 因此箭头函数不能用作 Generator 函数,什么是Generator函数可自行查阅资料,推荐阅读阮一峰Generator 函数的含义与用法,Generator 函数的异步应用

  • 实现bind方法

    if (!Function.prototype.bind) {
        Function.prototype.bind = function () {
            var self = this,                        // 保存原函数
                context = [].shift.call(arguments), // 保存需要绑定的this上下文
                args = [].slice.call(arguments);    // 剩余的参数转为数组
            return function () {                    // 返回一个新函数
                self.apply(context, [].concat.call(args, [].slice.call(arguments)));
            }
        }
    }
    

13. JS的设计模式有哪些?

  • 设计模式的目的
    • 为了更好的代码重用性,可读性,可靠性,可维护性
  • 9种模式:学习
    • 工厂模式*
    • 单例模式*
    • 适配器模式
    • 装饰器模式
    • 代理模式
    • 外观模式
    • 观察者模式*
    • 迭代模式
    • 状态模式

14. JS是高级语言吗?

  • js是脚本语言,主要是作用于浏览器,与用户进行交互

15. JS的理解,优缺点

  • js是一门跨平台脚本语言,主要作用于浏览器上,进行用户交互
  • 优点
    • 既可以面向过程又可以面向对象
    • 是一门弱类型语言,编程更加随性
  • 缺点
    • 隐式类型转换混乱
    • ==双等运算符自动转换数据类型的隐患

16. JS有哪些内置对象

  • Object,Array,Boolean,Number,String
  • Symbol,Map,Set,Promise,Proxy(ES6新增)

17. 使用JS时,遇到过的坑?

  • 1· 获取DOM的时候提示无法获取
    • 原因是:我把JS文件放在了head标签中,而HTML是从上到下顺序执行,所以就拿不到DOM
    • 解决办法是:在script标签中添加defer=‘true’属性,延迟加载,或者把JS放到body之后
  • 2· 在使用new Data设置日期格式的时候,发现无论怎么设置月份都会+1
    • 原因是:JS中的月份从0开始
    • 解决办法:把月份-1

18. 实现对象的深拷贝

  • 使用JSON.parse(JSON.stringify(obj))
  • 递归遍历 ,判断是否是Object

19. js解决异步的方案

  • Promise
  • async await

20. 作用域链

  • 定义:内部环境可以通过作用域链来访问外部环境的属性和方法,但是,外部环境不能访问内部环境的任何属性和方法。注意,只能通过定义函数来延长作用域链条。
  • 作用:查找标识符。当作用域需要查询变量的时候会沿着作用域链依次查找,如果找到标识符就会停止搜索,否则将会沿着作用域链依次向后查找,直到作用域链的结尾

21. 原型链

  • 原型:所有的函数都有一个特殊的属性prototype(原型)prototype属性是一个指针,指向的是一个对象(原型对象),原型对象中的方法和属性都可以被函数的实例所共享。所谓的函数实例是指以函数作为构造函数创建的对象,这些对象实例都可以共享构造函数的原型的方法。
  • 原型链:
    • 定义:每一个对象都有一个原型,原型也是对象,那原型也有原型,这样就形成了一个链式结构,成为原型链。
    • 作用:查找引用类型的熟悉,查找属性会沿着原型链依次进行,如果找到该属性会停止搜索并做相应的操作,否则将会沿着原型链依次查找直到结尾。
    • 对象访问成员的访问规则: 如果对象访问某个成员,先看自己有没有,自己有就访问自己的,自己没有就访问原型的。如果原型也没有,就沿着原型链一直往上查找,直到找到为止,如果找到头了还没有找到,就返回undefined或者报错.

完整的原型链

22. ES5实现Object.assign

23. 在JS中什么是伪数组?如何将伪数组转化为标准数组?

  • 伪数组的特点
    • 按索引方式存储数据
    • 具有length属性
    • 没有数组的push、pop、shift、unshift等方法
  • 分类
    • function的arguments对象
    • getElementsByTagName、ele.childNodes等返回的NodeList对象
    • 自定义的某些对象
  • 转化方法:
    • 使用Array.prototype.slice.call()或[].slice.call()
    • 使用ES6中Array.from()方法

24. 一个function,清除字符串前后的空格(兼容所有浏览器)

function trim(str){
	if(str && typeof str === "string"){
		return str.replace(/(^\s*)|(\s*)$/g/,"")//取出前后空白符
	}
}

25. undefined与null的区别

  • undefined:一个表示“无”的原始值
  • null:表示尚未存在的对象

26. 如何实现浏览器的前进后退功能?

  • 要求:当我们点开一系列页面例如a-b-c时,到c页面后退可以查看b、a页面,在b、a页面前进可以查看c页面,但是当在b页面重新进入一个新的页面时,此时再也不能通过前进或者后退进入c页面了,这是怎么实现的呢?

  • 提供两个栈:Stack1、Stack2

    1. 进入一系列页面a、b、c:将a、b、c依次压入栈Stack1,此时在页面c
    2. 后退两步:将c、b依次弹出再压入栈Stack2
    3. 前进一步:将b从Stack2弹出压入Stack1
    4. 打开新的页面d:将d压入栈Stack1
    5. 清空Stack2,此时就不能通过前进或者后退进入c页面

27. 描述 new 一个对象的过程

  • 代码

    function Foo(name,age){
        this.name = name;
        this.age = age;
        this.class = 'class-1';
        // return this //默认有这一行
    }
    var f = new Foo('张三',20)
    
  • 过程:

    1. 创建一个新对象
    2. this指向这个新对象
    3. 执行代码,即对this赋值
    4. 返回this

28. 对象方法

  • Object.keys(对象):将对象里面的键名提取出来返回成一个数组

    • 用途:空对象判断 Object.keys(obj).length==0
    var obj={a:1,b:2}
    Object.keys(obj)   ==== >     [a,b]
    Object.values(obj)   ==>   [1,2]
    Object.entries(obj)     ===>  [[a,1],[b,2]]
    
  • Object.values(对象):将对象里面的键值提取出来返回成一个数组

  • Object.entries(对象):将对象里面的键名与键值提取出来成一个新二维数组

  • for of:循环遍历数组和对象

    let obj={a:1,b:2};
    for(let [key,value] of Object.entries(obj)){
            window.console.log(key,value);
    }
    //输出结果:
    //a 1
    //b 2
    
  • Object.assign(目标对象,需要合并的对象1,需要合并的对象2)`

    • 注:后面的对象的值会覆盖前面对象的值,也就是目标对象的值

    • let obj1 = { a: 1 }
      let obj2 = { b: 2, a: 3 }
      Object.assign(obj1, obj2)
      console.log(obj1);//{a:3,b:2}
      
      let a1={a:1};
      let c1={a:3,b:2};
      let b1={d:1,b:4};
      window.console.log(Object.assign(b1,a1,c1));//{d:1,b:4,a:3}
      

29. 数组常用的方法

forEach、map、filter、

push、pop、shift、unshift

ES6

1.ES6新特性有哪些?

  • 箭头函数 ()=>{}
    • 匿名函数,不能用于构造函数,不能被new
    • this指向上下文
  • 模板字符串``
  • 解构赋值
  • 展开运算符...
  • let const 关键字
  • Promise
  • class类
  • for of
    • 遍历数组中的每一项
    • 与for in的区别
      • 无法遍历对象
      • 输出结果为数组的值,for in为数组的索引
      • 不会遍历自定义属性(用.或[]添加的属性)

jQuery

1. jq中常用的api有哪些

  • $(selector).html():方法返回或者设置被选元素的内容,ps:在一定的程度上可以等同于value

    • 返回(跟value等同):$(selector).html()
    • 设置:$(selector).html("world")
  • $(selector).attr():方法设置或者返回被选元素的属性值

    • 返回:$(selector).attr("属性名")
    • 设置:$(selector).attr("属性名","值")
  • $(selector).addClass():向被选元素添加一个或者多个类,即class属性

    • $(selector).addClass("hello");
  • eval(String):执行括号内的表达式或者是语句必须为字符串

  • $(selector).each(function(index,element){}):遍历jQuery对象集合,在每个对象上执行function函数

    • 一般用法

      $(selector).each(function(key){
      	alert($(selector)[key]);
      })
      
  • $(selector).data():方法向被选元素附加数据或者获取数据

    • 从被选元素中返回数据::$(selector).data(name);
    • 向元素附加元素:
      • $(selector).data(name,value);
      • 对象:$(selector).data(Object);

Ajax

1.Ajax的工作原理是什么?

  • 定义:Ajax是一种异步获取数据的技术
  • 原理:通过XmlHttpRequest对象来向服务器发送异步请求,类似一个中间层,负责请求数据,而不影响浏览器其他事件的执行,等到数据回来之后再通知浏览器,浏览器在进行处理

2.Ajax的使用步骤

  1. 新建一个XMLHttpRequest对象

    let xhr = new XMLHttpRequest()
    
  2. 使用open和send方法发送请求

    xhr.open('方法','url地址')  //设置请求的方法和地址
    xhr.send() //发送请求
    
  3. 使用onload注册回调

    xhr.onload=function(){}
    
  4. 根据服务器返回的结果做响应的处理 xhr.responseText

3.get和post有什么区别?

  • 参数传输方式不同
    • get通过url传输参数
    • post通过请求体传输参数
  • 安全性不同
    • post通过请求体传输参数,安全性比较高
    • get通过url传输参数,在历史记录,浏览器缓存很容易查到数据信息,所以安全性偏低
  • 可传输参数大小不同
    • post可以传输任意格式的参数
    • get因为是在url中传输,有长度限制

4. ajax是怎么上传文件的?

  • 使用FormData对象
    • 1、创建一个FormData对象
      • let fd = new FormData()
    • 2、通过files[0]获取到确认选择的图片信息
      • let imgInfo = document.getElementById('img').files[0]
    • 3、把文件信息添加到FormData对象中
      • fd.append('img',imgInfo)
      • 注:键值对形式
    • 4、在ajax请求的响应体中添加FormData对象
      • $ajax({data:fd})

5. 怎么封装axios?

把axios封装,创建一个新的请求对象,将项目基地址放进去,然后暴露出去,如果其他组件用到了就直接导入封装好的axios文件

Vue

1. Vue的生命周期钩子

  • 所有的生命周期都是一个函数

  • 书写位置:和methods是兄弟关系

  • 特点:自动执行,不用调用

  1. beforeCreate:
    1. 创建前,它还不能访问data与methods
    2. 只自动执行一次
  2. created:
    1. 创建后,可以访问data与methods,但是还不能访问vue渲染后的dom
    2. 只自动执行一次
    3. 用途:进入页面的接口请求
  3. beforeMount:
    1. 渲染前,还没完成data与methods里面渲染到dom,还不能访问vue渲染后的dom
    2. 只会执行一次
  4. mounted:
    1. 渲染后,已完成data与methods的dom渲染,可以访问vue渲染后的dom
    2. 最早可以访问vue渲染后的dom的钩子
    3. 只会执行一次
  5. beforeUpdate:
    1. 更新前,数据(页面中使用的数据)已修改,但还没完成dom渲染
    2. 会执行多次
  6. updated:
    1. 更新后,数据已修改,且dom已完成渲染
    2. 会执行多次
  7. beforeDestroy:
    1. 销毁前,准备销毁当前组件,但是还没有完成销毁
    2. 只会执行一次
  8. destroyed:
    1. 销毁后,切断了页面的渲染,回到了渲染前,还可以访问data属性和methods方法,还可以做一些善后工作,但是不能访问vue渲染后的dom
    2. 只会执行一次
  9. activated:重新激活时调用,需要keep-alive触发
  10. deactivated:取消激活时调用,需要keep-alive触发
  • 语法

    new Vue({
      el: '#app',
      methods: {
      },
      beforeCreate(){//创建前,还不能访问data与methods},
      created(){//创建后,能访问data与methods},
      beforeMounte(){//渲染前,被vue管理的dom还没完成在vue实例内的渲染,所以还不能调用dom},
      mounted(){//渲染后,被vue管理的dom已完成vue实例内的渲染,所以现在可以调用dom},
      beforeUpdate(){//更新前,当数据发生改变,但页面还没完成更新时调用。},
      updated(){//更新后,数据发生改变,且完成了页面更新时调用。}
    })
    

2. Vue中的传值方法有哪些?

  • 父传子

    • props
      • 父组件 :属性名="值/处理值的方法"
      • 子组件 props:['属性名']
    • $children
  • 子传父

    • $parent(在子组件中写)

    • $emit

      • 子组件:$emit('属性名',值)
      • 父组件:@属性名=“处理值的方法”
    • $refs(在父组件中写)

      • 调用子组件的时候调用一个ref

        <v-fgsheader ref="header"></v-fgsheader>
        
      • 在父组件中通过

        this.$refs.header.属性
        this.$refs.header.方法
        
      • 可能出现的问题:子组件很多的时候,不知道传到哪个子组件里面

  • 兄弟

    • $parent 父搭桥通信
    • $root 根组件搭桥通信
  • 祖孙后代

    • provide 提供

      // 祖孙 隔代传值  父级使用provide定义
        provide() {
          return {
            apple: this.food,
            changeApple: this.changeApple
          };
        },
      // 这里的this指向父组件的实例 第二个成员changgeApple是一个可以修改apple的函数
      
    • inject 注入

      inject: ["apple", "changeApple"],
      mounted() {
          //   通过this调用
          this.changeApple("香蕉");
          console.log(this);
      }
      // inject注入的数据会平铺到子组件的实例上,通过this可以调用
      
  • 没有关系

    • $bus(广播传值)

      • 新建一个bus.js文件,暴露vue实例

        // 导入vue
        import Vue from 'vue';
        // 暴露一个vue实例出去
        export default new Vue()
        
      • 在要广播的地方引入刚才定义的实例

        import bus from '../bus.js'
        
      • 传播:bus.$emit('名称','数据')

      • 接收:bus.$on('名称',data=>{})

  • 本地传值

    • localStorage

      • 存:

        localStorage.setItem('属性名',JSON.stringify(值));
        
      • var tolist = JSON.parse(localStorage.getItem('属性名'));
        
    • Vuex

  • 路由传值

    • 动态路由传值

      //1. 配置路由
      routes:[
               //动态路由参数  以冒号开头
               {path:'/user/:id',conponent:User}
             ]
      //2. 传值  
      第一种写法 :  <router-link :to="'/user/'+item.id">传值</router-link>
      第二种写法 : goToUser(id) {
                       //'user' 是路径名称
                       this.$router.push({path:'/user/'+id});
                 }
      //3. 在对应页面取值
      this.$route.params;  //结果:{id:123}
      
    • Get传值(类似HTMLGet传值)

      //1. 配置路由
      const routes = [{path:'/user',component:User},]
      //2. 传值  
      第一种写法 : <router-link :to="'/user/?id='+item.id">传值</router-link>
      第二种写法 : goToUser(id) {
                         //'user' 是路径名称
                         this.$router.push({path:'user',query:{ID:id}});
                   }
      //3. 在对应页面取值
      this.$route.query;  //结果 {id:123}
      

      注:路径传递参数会拼接在URL路径后

    • 命名路由push传值

      //1. 配置路由
      const routes = [{path:'/user',name: 'User',component:User},]
      //2. 传值  
      goToUser(id) {
             //'User' 是路径重命名
             this.$router.push({name:'User',params:{ID:id}});
      }
      //3. 在对应页面取值
      this.$route.params;  //结果:{id:123}
      

      注:命名路由传递参数不在URL路径拼接显示

3. Vue的优缺点有哪些

  • 优点
    • 轻量 双向数据绑定 指令 插件化 渐进式灵活 组件系统 自底向上灵活应用 只关心数据 第三方整合 Vue全家桶
  • 缺点
    • vue应用是单页面应用,不利于seo优化,需要在服务端做seo
    • 前进后退功能需要使用程序进行处理
    • 初次加载耗时比较多,因为第一次加载就需要把所有的html css js加载完成

4. router和route的区别

  • router:路由实例对象
  • route:当前跳转路由信息对象

5. Vuex是什么?

  • vuex是专门为vue开发的状态管理工具,类似于一个仓库,仓库中存储着应用中的状态

  • vuex的状态存储是响应式的

  • 改变状态的唯一方法就是提交commit(mutation),符合vue的单向数据流思想

  • vuex的模块

    • state :保存状态
    • getters:加工state成员给外界,(相当于vue的计算属性,有缓存)
    • mutations:state成员操作。修改状态的方法,必须是同步
    • action:异步操作。用于提交mutation ,不是直接改变状态,而是异步操作,或者一些比较复杂的逻辑都可以使用action提交dispatch ,dispatch就是commit
    • module:模块化状态管理。保存特定的模块,例如用户模块,允许将单一的store拆分为多个并且各自保存
  • 参考https://www.jianshu.com/p/2e5973fe1223

  • 单向数据流:访问state,修改用mutations

6. vue中你常用的指令有哪些?

v-text、v-html、v-model、v-on、v-bind、v-if、v-for

  • 改变标签内容
    • v-text:替换当前标签的文本内容
      • v-text="一句话表达式"{{值}},类似innerText
    • v-html:替换当前标签的内容,并以html形式展示出来
      • v-html="一句话表达式"
  • 改变表单元素值
    • v-model:实现表单元素值的双向绑定
      • v-model="变量"
  • 监听事件
    • v-on:事件的绑定
      • v-on:事件名="需要执行的简单代码或方法"
      • @事件名="需要执行的简单代码或方法"
      • 修饰符
        • .stop:阻止冒泡 @事件名.stop="事件执行代码"
        • .prevent:阻止默认事件@事件名.prevent="事件执行代码"
        • .enter:回车才执行后面的方法或者js
  • 改变标签样式与属性值
    • v-bind
      • v-bind:属性名="属性值"
      • :属性名="属性值"
  • 渲染列表数据
    • v-for
      • 数组:v-for="(item,index) in array"
      • 对象:v-for="(value,key,index) in object"
  • 条件渲染
    • v-if:v-if="boolean值",控制标签是否渲染
    • v-else-if:v-else-if="boolean值"
    • v-else
  • 控制标签是否显示
    • v-show:控制标签的显示和隐藏
      • v-show="boolean值"

7. 你是怎么理解vue的单向数据流的?

  • 单向数据流是指,在父子组件使用prop传值时,父组件的状态变更,数据会流向子组件,但是反过来则不行,不可以直接在子组件直接变更传递的props,这样会导致数据流不清晰,如果子组件可以修改props,那么就可能会出现无法分辨是哪一个子组件修改的这个状态了
  • 如果子组件需要修改,可以在自己的data中定义保存props

8. 谈一谈你对keep-alive的理解

  • keep-alive是vue内置的一个组件

  • 作用:缓存组件,避免在组件重新激活后再次渲染

  • 用法:一般结合动态组件使用

    <keep-alive>
          <login v-if="index == 0" />
    </keep-alive>
    
  • 对应的两个生命钩子:

    • activated:当组件激活时调用
    • deactivated:当组件失活时调用(未激活)
  • 提供include与exclude属性

    • include:匹配名称的组件才会被缓存
    • exclude:匹配名称的组件都不会被缓存
    • 优先级:exclude > include

9. v-model的原理是什么?

  • 本质:一个语法糖

    <son v-model="msg" />翻译为<son :value="msg" @input="msg=$event"/>

  • 原理:input事件与value属性的绑定

    • 当input事件触发,就会修改data中的值,data中的值发生改变就会渲染

    • app.vue

      <template>
      	<div class="app">
              <h3>app.vue</h3>
              <p>msg是:{{msg}}</p>
              <son :value="msg" @input="msg = $event"/>
          </div>
      </template>
      <script>
      import son from './son';
      export default{
          components:{
              son
          },
          data(){
              return {
                  msg:"hello"
              }
          }
      }
      </script>
      
    • son.vue

      <template>
      	<div class="son">
              <input type="text" v-model="selfMsg" @input="toFather">
          </div>
      </template>
      <script>
      export default{
          //父传子
          props:['value'],
          data(){
              return{
                selfMsg:this.value
              }
          },
          watch:{
              //父组件值变了,子组件的值也跟着改变
              value(val){
                  this.selfMsg = this.fatherMsg
              }
          }
          methods:{
              toFather(){
                  //传递值给父组件
                  this.$emit('input',this.selfMsg)
              }
          }
      }
      </script>
      
  • 如果不是input元素(组件上),可以使用model:{}(与data同级)来改变

    • prop:修改绑定的值
    • event:修改事件名
    /*
      外面用我这个组件的时候,如果使用v-model,他会生成:value
      我想外面生成的不再是:value,而是:v1 
      我希望外面用我这个组件的时候,如果使用v-model,默认生成@input就改成@xx
    */
      model:{
        // 告诉外面调用我组件时,如果写了v-model就会生成 :v1="绑定的值"
        prop:"v1",
        // 告诉外面调用我组件时,如果写了v-model就会生成 @xx="绑定值=$event"
        event:"xx"
      },
    
    • 默认情况下v-model生成的是:value 和 @input,如果要改就用上面的model代码来改属性名和事件名(这是加在子组件上)
  • 官方v-model

    • app.vue

      <template>
      	<div class="app">
              <h3>app.vue</h3>
              <p>msg是:{{msg}}</p>
              <!--给子组件传值-->
              <son :value="msg" @input="msg = $event"/>
          </div>
      </template>
      <script>
      import son from './son';
      export default{
          components:{
              son
          },
          data(){
              return {
                  msg:"hello"
              }
          }
      }
      </script>
      
    • son.vue

      <template>
        	<div class="son">
                <!--<input type="text" :value="value" @input="toFather($event)">-->
                <input type="text" :value="value" @input="$emit('input',$event.target.value)">
            </div>
        </template>
        <script>
        export default{
            //父传子
            props:['value'],}
            },
            methods:{
                toFather(e){
                    //e是事件对象(原生事件)
                    //传递值给父组件
                    this.$emit('input',e.target.value)
                }
            }
        }
      </script>
      
    • 修改默认绑定属性和事件

      //app.vue里面
      <son v-model="msg" />
        
      //son.vue里面
      <input type="text" :value="v1" @input="$emit('xx',$event.target.value)">
        
      <script>
      export default{
          //父传子
          props:['v1'],
        	//修改默认绑定属性和事件
        	model:{
        		prop:'v1',
        		event:'xx'
       	}
      }
      </script>
      

10. computed与watch有什么区别?

  • 定义
    • computed:计算属性,依赖于某个值而产生新的值
      • computed有缓存机制,只有当计算值变化才会返回内容,如果依赖的值不发生变化,就不需要重新计算
      • 数值运算时可使用
    • watch:监听器,观察的作用,类似于数据监听的回调函数,一旦这个数据发送改变都会触发监听的回调
      • 在数据发生变化时需要执行异步会开销比较大的操作时,就可以使用watch
  • 实现原理:
    • 都是新增一个watcher
    • computed是惰性求值的,默认没有set

11. vue的父组件和子组件的生命周期钩子的执行顺序?

  • 父加载->子加载->子渲染->父渲染->
    • 父beforeCreate -> 父created -> 父beforeMount -> 子beforCreate -> 子created -> 子beforMount -> 子mouted -> 父mouted
  • 父更新之前 -> 子更新之前 -> 子更新 -> 父更新
    • 父beforUpdate -> 子beforUpdate -> 子updated -> 父updated
  • 父销毁之前 -> 子销毁之前 -> 子销毁 -> 父销毁
    • 父beforDestroy -> 子beforDestroy -> 子destroyed -> 父destroyed

12. vue-router有几种模式?vue-router实现的原理是什么?

  • 模式:3种
    • hash:哈希模式
      • 使用url中的hash值来做路由跳转路径,#号后面的都是哈希值
    • history:历史模式
      • 没有#号,需要后端配合,否则可能会出现静态资源无法加载的情况
    • abstract:抽象模式
      • 后端用的,node环境下使用的
  • hash缺点:#后面的参数后端都无法获取到,服务器无法读取,因为是锚点
  • 实现原理:
    • hashchange监听url的变化,映射指定的组件并渲染
      • window.onhashchange
        • 当hash值(url上 #/xxx)发生改变触发
        • 获取hash值:location.hash
      • 路由切换原理(router-view):监听hash改变事件,在改变事件里获得hash,再根据hash值来找到组件对应的html代码,渲染到路由出口那
    • history:
      • 通过H5提供(的History API来实现路由(push和pop实现的浏览器历史记录栈,.back(),.go())
      • 刷新后页面空白:重新向后台请求当前url需要的静态资源,需要后端做静态资源的定位,进行url匹配,当满足

13. vue-router的导航守卫有哪些?路由的函数钩子?

传送门

  • 全局守卫
    • beforeEach(to,from,next)全局前置守卫,路由跳转之前触发
    • beforeResolve(to,from,next)全局解析守卫,在导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后,解析守卫就被调用
    • afterEach(to,from)全局后置钩子,路由跳转之后调用的回调函数
  • 路由独享的守卫
    • beforeEnter(to,from,next),在路由配置上直接定义
  • 组件内的守卫
    • beforeRouterEnter(to,from,next) 在渲染该组件的对应路由被 confirm 前调用 ,不能使用this 获取组件实例
    • beforeRouterUpdate(to,from,next) 在当前路由改变,但是该组件被复用时调用 , 可以使用this获取组件实例
    • beforeRouterLeave(to,from,next) 导航离开该组件的对应路由时调用,可以使用this获取组件实例

14. vue实现双向绑定的原理?

  • 核心是使用了Object.definProperty() vue3.0改为proxy

  • 在初始化data(initData)时,会将data作为对象传递给监听器Observer,Observer会遍历data中的每一个key,包括深层嵌套的key(对象中的对象),在遍历的过程中会使用Object.definProperty为每一个key做数据拦截,设置get与set,当初次渲染时会触发get , 在get中收集依赖,数据变更时会触发set,set中会调用dep通知依赖(watcher)进行更新(update)

  • 采用的是发布订阅的设计模式

  • vue2.0中object.definePropety遍历递归data对象里每个属性,重写set和get方法, 通过订阅器和订阅者做一个绑定. 重写操作数组的7个方法的原型. vue3.0里面用proxy代替了object.definePropety().不需要递归了

采用的是数据劫持结合发布和-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调

  • 原理:用Object.defineproperty()重新定义(set方法)对象设置属性值和(get方法)获取属性值的操纵来实现的

    • vue2.0:Object.property(对象,属性名,属性描述符(对象))
      • 缺点:一次只能监听一个属性的改变
    • vue3.0:new Proxy(对象,{get(被操作的对象,属性名){},set(被操作的对象,属性名,赋值的值){}})
      • 注意:用了proxy对象代理后,要想触发set方法,必须通过proxy对象进行赋值
  • vue的数据双向绑定是通过数据劫持和发布-订阅者功能来实现的

  • 实现步骤:

    1.实现一个监听者Oberver来劫持并监听所有的属性,一旦有属性发生变化就通知订阅者

    2.实现一个订阅者watcher来接受属性变化的通知并执行相应的方法,从而更新视图

    3.实现一个解析器compile,可以扫描和解析每个节点的相关指令,并根据初始化模板数据以及初始化相对应的订阅者

  • 流程图:

vue双向绑定流程图

15. vue是如何实现对数组的数据监听的?

  • 数组无法使用Object.definProperty, vue的方法是将可改变数组的7个方法进行劫持,并且重写了数组的原型
  • 在每次触发这7个方法时,都会执行重写的原型,进行通知依赖更新
  • push shift unshift pop splice sort reverse

16. proxy对比Object.definProperty的优势是什么?

  • Proxy可以直接监听整个对象,而Object.definProperty需要递归遍历对象中的每一个成员
  • Proxy可以直接监听数组,而Object.definProperty需要劫持数组的7个方法做数据响应和更新通知

17. 路由懒加载

18. v-for中,key的作用,为什么不建议使用index作为key

  • **key的作用:**让vue更高效的进行虚拟DOM的更新
  • **原理:**vue在patch过程中可以通过key精准的对比两个节点是否是同一个节点,从而避免频繁更新不同的元素,使整个patch过程更高效,减少dom的操作,提高性能。
  • 原因:
    • key是唯一的,可以是后端返回的数据中的id,或者其他的唯一数据
    • 如果使用index作为key,那么顺序是不会变化的,即便重排了元素,也是会按照顺序来算,这样就不利于diff算法进行虚拟DOM节点比对

19. v-if与v-for谁的优先级更高?如何正确使用避免性能浪费?

  • v-for的优先级更高,在指令解析源码中v-for优先于v-if编译
  • 可以将v-if条件判断写在template上,先判断条件,再执行循环,这样就解决了性能浪费的问题
  • 如果必须在同一个位置使用v-if v-for ,那么可以使用计算属性过滤掉不需要不符合条件的项,往往for循环中的数据都是可以渲染的

20. 如何实现动态路由的

21. MVC,MVP,MVVM是什么?

  • MVC
    • 传统的MVC是指,用户操作会请求服务端路由,路由会调用对应的控制器来处理,控制器会获取数据,再将结果返回给前端,前端手动进行页面重新进行渲染,通信是单向的
    • M(Model模型【后端数据库】),V(view视图),C(controller控制器)
    • 主要是基于分层目的,让彼此的职责分开
    • View通过controller来联系Model,controller是View和Model的协调者,View和Model不直接联系,所以基本上通信都是单向的
  • MVP
    • M(Model模型),V(view视图),P(Presenter主持?)
    • MVP是从MVC模式演变过来的,都是通过controller / presenter负责逻辑的处理 + Model提供数据 + View负责显示
    • 在MVP中,Presenter完全把Model与View进行了分离,主要的程序逻辑在presenter中实现,并且presenter与view是没有直接关联的,是通过定义好的接口进行交互,从而使得view变更的时候可以保持presenter不变
    • MVP模式的框架
      • Riot.js
  • MVVM
    • 传统的前端会将数据手动渲染到页面上,MVVM模式下不需要用户手动操作DOM元素,而是将数据绑定到ViewModel层上,会自动将数据渲染到页面中,视图变化会通知ViewModel层更新数据,ViewModel就是MVVM模式的桥梁
    • M(Model模型),V(view视图),VM(ViewModel)
    • MVVM是双向的
    • MVVM是把MVC里的Controller和MVP里的Presenter改成了ViewModel。Model+View+ViewModel
    • View的变化会自动更新到ViewModel,ViewModel的变化也会自动同步到View上显示
    • 这种自动同步是因为ViewModel中的属性实现了Observer,当属性变更时都能触发对应的操作。
    • MVVM模式的框架
      • AngularJS
      • Vue
      • React

22. vue页面渲染过程

23. vue中的$set是

浏览器相关

事件机制

跨域

1. 跨域是什么?

跨域是指浏览器为了安全做的同源策略,协议,域名,端口三者其中一种不同都是跨域

2. 为什么浏览器要使用同源策略

  • 防止CSRF攻击(利用用户的登录态发起恶意请求)
  • 跨域,ajax请求会失败(不能完全阻止CSRF)

3. 解决跨域的办法

  • JSONP
    • 利用script标签没有跨域限制的漏洞,并提供一个回调函数callback
    • 缺点:只支持get
  • CORS
    • 需要浏览器和后端同时支持
      • 浏览器端:自动进行CORS通信
      • 服务端:设置Access-Control-Allow-Origin就可以开启CORS
  • document.domain
  • postMessage

4. 了解预检请求

存储

1.登录保持是怎么实现的?

  • 利用localStorage把服务端返回的token保存在本地,在接下来的请求的请求头中都携带上token,并在路由响应中判断,如果响应码为401则token失效,再根据对应的逻辑做处理

2. 说一说cookies,sessionStorage,localStorage的区别?

  • 存储位置不同
    • cookies:发送请求会自动携带cookies
    • sessionStorage和localStorage:会保存在本地
  • 大小不同
    • cookies:数据不能超过4K
    • sessionStorage和localStorage:有大小限制,比cookies大,可以达到5M或者更大
  • 时效不同
    • cookies:在设置的过期时间前一直有效
    • sessionStorage:在浏览器窗口关闭后销毁
    • localStorage:持久保存,只要不手动删除都会一直存在

3. 如何让cookies在浏览器关闭就失效?

  • 不对cookies设置任何过期时间,不是任何正、负或者0的时间即可

4. 如何让localStorage与cookies一样设置失效时间?

  • 在存储数据时,存储一个时间戳,在get获取localStorage中的value时,拿当前时间戳与首次存入的时间戳做比较即可

缓存机制

性能优化

1. 谈一谈你对浏览器缓存机制的理解?

  • 浏览器缓存一般都是针对静态资源,比如js,css,图片等等
  • 缓存是一种简单高效的性能优化方式,可以显著的减少网络传输造成的影响,浏览器缓存一般会在 发起网络请求和浏览响应的时候进行性能优化
    • 发起网络请求时:
      • 浏览器会先查询请求头中对应的缓存数据,如有存在,就会拦截本次网络请求并且返回缓存数据的副本,并且结束本次网络请求
    • 浏览器响应时:
      • 如果命中缓存,但是缓存已经过期了,那么浏览器会继续发送本次请求,但是会在请求头中加上if-none-match字段,让服务端判断请求的数据有没有变化,如果没有变化服务端就会返回304 not modified ,浏览器刷新缓存,然后将缓存的副本返回
  • 缓存策略
    • 强制缓存
      • 强制缓存不需要重新发送请求(浏览器缓存中存在请求的数据)
    • 协商缓存
      • 发送请求验证请求资源是否需要更新(浏览器里有缓存,但是请求过期了,问一下服务器要不要更新数据)
        • 如果没有更新服务器返回304 ,浏览器刷新缓存并返回缓存副本
        • 如果需要更新,服务端直接返回最新的数据给浏览器

1. 缓存位置

2. 缓存策略

3. 实际场景应用缓存策略

渲染原理

兼容性问题

1. 不同浏览器的标签默认的外补丁(margin)和内补丁(padding)不同

解决方案:css里增加通配符*{margin:0;padding:0}

2. IE6双边距问题;在IE6中设置了float,同时又设置margin,就会出现边距问题

解决方案:设置display:inline;

3. 当标签的高度设置小于10px,在IE6、IE7中会超出自己设置的高度

解决方案:超出高度的标签设置overflow:hidden,或者设置line-height的值小于你的设置高度

4. 图片默认有间距

解决方案:使用float为img布局

5. IE9以下浏览器不能使用opacity

解决方案:

opacity:0.5;
filter:alfha(opacity=50);
filter:progid:DXlmageTransform.Microsoft.Alfha(style=0,opacity=50);

6. 边距重叠问题;当相邻两个元素都设置了margin边距时,margin将取最大值,舍弃最小值;

7. cursor:hand显示手型在safari上不支持

解决方案:统一使用cursor:pointer

8. 两个块级元素,父元素设置了overflow:auto;子元素设置了position:relative;且高度大于父元素,在IE6、IE7会被隐藏而不是溢出;

解决方案:父级元素设置position:relative

9. const问题

说明:

  • Firefox下,可以使用const关键字来定义常量;
  • IE下,只能使用var关键字来定义常量。

解决方法:统一使用var关键字来定义常量。

10. event.srcElement问题

问题说明:

  • IE下,event对象有srcElement属性,但是没有target属性;
  • Firefox下,event对象有target属性,但是没有srcElement属性。

解决方法:使用srcObj = event.srcElement?event.srcElement:event.target;

11. 事件绑定

  • IE:dom.attachEvent();
  • 其他浏览器:dom.addEventListener();

标准浏览器采用事件捕获的方式对应IE的事件冒泡机制(即标准由最外元素至最内元素或者IE由最内元素到最外元素)最后标准方亦觉得IE这方面的比较合理,所以便将事件冒泡纳入了标准,这也是addEventListener第三个参数的由来,而且事件冒泡作为了默认值。

12. 操作tr的html

在ie9以下,不能操作tr的innerHTML

13. ajax略有不同

  • IE:ActiveXObject
  • 其他:xmlHttpReuest

14. 对象宽高赋值问题

问题说明:FireFox中类似obj.style.height = imgObj.height的语句无效。

协议

1.Http请求状态码有哪些?

  • 1** 信息,服务器收到请求,需要请求者继续执行操作
  • 2** 成功,操作被成功接收并处理
  • 3** 重定向,需要进一步的操作
  • 4** 客户端错误,请求包含语法错误或无法完成请求
  • 5** 服务器错误,服务器在处理请求的过程中发生错误
  • 常见的如下:
    • 200 请求成功
    • 301 资源或网页等被永久转移到其他的URL
    • 404 请求的资源或网页不存在
    • 401 权限不足
    • 403 服务器拒绝
    • 500 服务器内部错误

2.http请求方式有哪些?

  • get、post、put、delete、head、trace

3.请求报文与响应报文你了解吗?

  • 请求报文:3部分组成
    • 请求行:包含请求方法,请求地址url,协议版本
    • 请求头:包含请求的附加信息,键值对的形式,Authorization
    • 请求体:浏览器发送给服务器的数据(参数)
  • 响应报文:3部分组成
    • 响应行:包含协议版本,状态码,状态描述
    • 响应头:content-type
    • 响应体:服务器返回的数据 xhr.responseText

4.HTTP与HTTPS的区别

  • 概念:
    • HTTP:网络上应用最广泛的一种网络协议,是客户端与服务端通信的标准(TCP),HTTP是明文传输的
    • HTTPS:以安全为目标的HTTP通道,即在HTTP下加入了SSL协议,用于对HTTP协议传输进行加密(HTTPS是HTTP的安全版)
  • 区别:
    • HTTPS需要申请证书,需要收费
    • HTTP是超文本传输协议,信息是明文传输,HTTPS是具有安全性的SSL加密传输协议
    • HTTP使用的端口是80,HTTPS使用的端口是443
    • HTTP是无状态链接的,HTTPS则需要进行身份认证

5.TCP3次握手和4次挥手

优化

1. 你做过哪些性能优化

  • 减少HTTP请求
  • 懒加载:图片、路由、长列表数据
  • 外部资源使用CDN引入
  • 功能相似的组件与逻辑抽离并复用
  • 函数防抖、函数节流
  • 减少js代码的全局变量,html标签语义化

2. 你是怎么做小程序优化的?

  • 避免频繁的操作setData,如果不需要更新视图,直接使用this
  • 分页懒加载,避免使用setData传输大数据
  • 除开tabBar外,其他的图片都从服务器加载
  • 清理没有用到的代码和资源,减少包的大小

场景

1. 网站崩了怎么办?

2. 网页从输入网址到渲染完成经历了哪些过程?

大致可分为七步:

1、输入网址

2、发送到DNS服务器,并获取域名对应的web服务器对应的ip地址

3、与web服务器建立tcp连接

4、浏览器向web服务器发送http请求

5、web服务器响应请求,并返回指定url的数据

6、浏览器下载web服务器返回的数据并解析html源文件

7、生成Dom树,解析js和css,渲染页面

3. 哪些操作会造成内存泄漏?

  • 常见的内存溢出:

    • 不再需要用到一个函数后,它的定时器没有停止clearTimeout()
    • 一个DOM被删除前,没有解绑事件
    • 一个DOM被删除前,对它的引用没有手动清除掉
    • 临时创建的DOM没有被手动清除掉
    • 闭包没有管理好,大量闭包的使用
    • 意外的全局变量引起的内存泄漏
  • 内存泄漏:一段内存用完了,我们已经不需要它了。但是它没有被释放掉(引用),所以这部分内存不能被重新利用,这部分内存就被浪费掉了。就像垃圾堆积占用了空间一样。

  • 垃圾回收机制:JavaScript的垃圾回收机制依据的是引用计数,如果引用计数降为0,它就会被自动回收。

    • 垃圾回收器定期扫描对象,并计算引用了每个对象的其他对象的数量。如果一个对象的引用数量为0(没有其他对象引用过该对象),或对该对象的惟一引用是循环的,那么该对象的内存即可回收。
  • 避免内存泄漏、利用好垃圾回收机制的做法是:如果我们不需要一个东西,就要先把对于它的各种引用都摘除掉

4. 如何实现浏览器内多个标签页之间的通信?

  • 调用localStorage

    • 在一个标签页里面使用 localStorage.setItem(key,value)添加(修改、删除)内容;

    • 在另一个标签页里面监听 storage 事件。

      window.addEventListener("storage", function(event){    
             console.log(event.key + "=" + event.newValue);    
      });     
      
    • 即可得到 localstorge 存储的值,实现不同标签页之间的通信。

  • 调用cookies+setInterval()

    • 将要传递的信息存储在cookie中,每隔一定时间读取cookie信息,即可随时获取要传递的信息。

    • 存储在cookies中:document.cookie="name="+name;

    • 定时读取:

      <script type="text/javascript">  
          $(function(){   
              function getCookie(key) {    
                  return JSON.parse("{\"" + document.cookie.replace(/;\s+/gim,"\",\"").replace(/=/gim, "\":\"") + "\"}")[key];    
              }     
              setInterval(function(){    
                  console.log("name=" + getCookie("name"));    
              }, 10000);    
          });  
      </script>  
      

5. 比如用循环渲染了一堆P标签,但是P标签没更新,怎么办?

$forceUpdate()强更新

6. 如果后台管理系统中 点击侧边栏,右上角出现×怎么解决

7. sourcetree中你跟你同事的代码不兼容怎么办?

  1. 暂存自己的代码,提交到本地仓库
  2. 进行pull操作,从远程仓库拉取,sourceTree会将两个人的相同的文件进行合并
  3. 再次提交到本地仓库,也就是merge
  4. 进行push操作,将合并后的代码推送到远程仓库