面试题集锦

说明:刚经历过面试不久,以前老是不总结的我,这回总结一下我经常遇到的面试题,留个回忆~
这里只是做个简单的介绍,给自己提个醒,根据面试题延伸出自己需要补哪一块的知识。
下面,开始我的表演

js有哪些内置对象?

本地对象和单体内置对象统称为“内置对象”

  • 本地对象(内置函数):
    Boolean / Number / String / Object / Array / Date / RegExp / Function / Error
  • 单体内置对象:Global/Math/Json(ECMAScript5新增)

js中使用typeof能得到哪些类型?

undefined/number/string/boolean/object/function

  • 值类型能详细的区分出来
  • 引用类型区分不出来这么详细,只能区分出function
typeof undefined  // undefined
typeof 'abc'  // string
typeof 123  // number
typeof true  //  Boolean
typeof {}  // object
typeof []  // object
typeof null  // object
typeof console.log  // function

何时使用=== 何时使用==?

if (obj.a == null) {
	// 这里相当于obj.a === null || obj.a === undefined的简写形式
	// jquery源码推荐写法
}

除了这个,其他一律使用全等.

JS变量按照存储方式区分为哪些类型,并描述其特点?

  • 值类型
    把数值分块存储在内存中,存储在栈内存中

  • 引用类型
    存储在堆内存,变量只存了变量名和指针(用于找到堆内存的位置)

如何理解JSON?

JSON只不过是一个JS对象,也是一种数据格式

JSON.stringify({a: 10, b: 20})
JSON.parse("{"a": 10, "b": 20}")

数据格式:简单值,对象,数组

JSON跟对象字面量的写法很像,JSON属性必须加双引号。

如何准确判断一个变量是数组类型?

简单判断:

var arr = [];
arr instanceof Array  // true
typeof arr  // object。  typeof 是无法判断是否是数组

更准确的判断:

function isArray(value) {
  return Object.prototype.toString.call(value) === '[object Array]';
}
isArray([1, 2, 3]);

描述new一个对象的过程?

  • 创建一个新对象
  • this指向这个新对象
  • 执行代码,即对this赋值
  • 返回this

实战中原型使用实例?

function Elem(id) {
  this.elem = document.getElementById(id)
}
Elem.prototype.html = function(val) {
  var elem = this.elem;
  if (val) {
    elem.innerHtml = val;
    return this; // 链式调用
  } else {
    return elem.innerHtml;
  }
}
Elem.prototype.on = function(type, fn){
  var elem = this.elem;
  elem.addEventListener(type, fn);
  return this;
}
var div1 = new Elem('div1');
div1.html('<p>显示出来了</p>').on('click', function() {
  console.log('ok');
  }).html('<p>kaopu</p>')

说一下对变量提升的理解?

变量定义和函数声明(函数表达式)都会被提到前面,即变量提升。

什么是单线程,和异步有什么关系?

单线程:只有一个线程,同一时间只能做一件事,两段JS不能同时执行
原因:避免DOM渲染的冲突
解决方案:异步算是一种“无奈”的解决方案,虽然有很多问题
异步是单线程的解决方案

避免DOM渲染的冲突:

  • 浏览器需要渲染DOM
  • JS可以修改DOM结构
  • JS执行的时候,浏览器DOM渲染会暂停
  • 两段JS也不能同时执行(都修改DOM就冲突了)
  • webworker支持多线程,但是不能访问DOM

异步存在的两个问题:

  1. 没有按照书写方式执行,可读性差
  2. callback中不容易模块化

实现方式:event loop

  • 事件轮询,JS实现异步的具体解决方案
  • 同步代码,直接执行
  • 异步函数先放在异步队列中
  • 待同步函数执行完毕,轮询执行 异步队列 的函数
  • 注意:立即放入,指定时间内放入,请求完成后放入

使用异步的场景

  • 定时任务:setTimeout,setInterval
  • 网络请求:ajax请求,动态加载
  • 事件绑定

总结当前异步的解决方案

  • jQuery Deferred
  • Promise
  • Async/Await
  • Generator

同步和异步的区别
同步会阻塞代码执行,而异步不会
alert是同步,setTimeout是异步

DOM节点的Attribute和property有什么区别?

property只是一个js对象的属性修改,它们会在初始化的时候再DOM对象上创建。
Attribute是对html标签属性的修改,attributes是属于property的一个子集。

  • property能够从attribute中得到同步;
  • attribute不会同步property上的值;
  • attribute和property之间的数据绑定是单向的,attribute->property;
  • 更改property和attribute上的任意值,都会将更新反映到HTML页面中;

cookie: 本身用于客户端和服务器端通信,但是它有本地存储的功能,于是就被“借用”,使用document.cookie = … 获取和修改即可。
缺点:存储量太小,只有4kb,所有http请求都带着,会影响获取资源的效率,API简单,需要封装才能用。

sessionStorage, localStorage:HTML5专门为存储而设计,最大容量5M,API简单易用: localStorage.setItem(key, value) localStorage.getItem(key)
localStorage在IOS safari隐藏模式下,localStorage.getItem会报错

sessionStorage关闭浏览器后数据也会跟着清掉,而localStorage不会。

区别:容量,是否会携带到ajax中,API易用性

AMD和CommonJS的使用场景

  • 需要异步加载JS,使用AMD,CommonJS是同步
  • 使用npm之后建议使用CommonJS

上线流程要点

  1. 将测试完成的代码提交到git版本库的master分支
  2. 将当前服务器的代码全部打包并记录版本号,备份
  3. 将master分支的代码提交覆盖到线上服务器,生成新版本

回滚流程要点

  1. 将当前服务器的代码打包并记录版本号,备份
  2. 将备份的上一个版本号解压,覆盖到线上服务器,并生成新的版本号

加载一个资源的过程

  1. 浏览器根据DNS服务器得到域名的IP地址
  2. 向这个IP的机器发送http/https请求
  3. 服务器收到、处理并返回http/https请求
  4. 浏览器得到返回内容

性能优化

  • 资源合并,减少http请求(通过构建工具合并, webpack或者gulp);
  • 静态资源缓存(通过连接名控制);
  • 使用CDN, 减轻服务器端请求压力;
  • 懒加载;
  • 减少DOM操作(缓存DOM查询,合并DOM插入);
  • 事件节流.

class和js构造函数的区别

  1. Class语法上更加贴合面向对象的写法,java发展方向
  2. Class实现继承更加易读、易理解
  3. 更易于写java等后端语言的使用
  4. 本质还是语法糖,使用prototype

es6常用的功能

  • Class
  • promise
  • import export 模块化
    编译:webpack rollup
  • let/const(常量)
  • 多行字符串/模板变量 ${}
  • 解构赋值 const {a, b} = {a: 10, b: 20, c: 30}
  • 块级作用域
  • 函数默认参数
  • 箭头函数

如何理解MVVM?

首先从名字来看,MVVM即Model, View ViewModel,Model对应的是data数据部分,View对应的是html视图部分,ViewModel对应的是new Vue实例部分,View通过事件绑定的方式影响到Model,Model通过数据绑定影响到View。

对ViewModel的理解:连接器,用于连接View和Model

MVVM不是一个从零开始的创新,是由之前的MVC发展过来的,因为MVC是应用到后端的,并不是前端的,为了适用前端的场景,把C换成了VM

如何实现MVVM

MVVM实现的三要素也是vue的三要素:

  1. 响应式:vue如何监听到data的每个属性变化?
  2. 模板引擎:vue的模板如何被解析,指令如何处理?
  3. 渲染:vue模板如何被渲染成html? 以及渲染过程?

设计模式的六大原则(SOLID)

  • 单一职责原则
  1. 一个程序只做好一件事
  2. 如果功能过于复杂就拆分开,每个部分保持独立
  • 开放封闭原则
  1. 对扩展开放,对修改封闭
  2. 增加需求时,扩展新代码,而非修改已有代码
  3. 这是软件设计的终极目标
  • 李氏置换原则
  1. 子类能覆盖父类
  2. 父类能出现的地方,子类就能出现
  3. JS中使用较少(弱类型&继承使用较少)
  • 接口独立原则
  1. 保持接口的单一独立,避免出现“胖接口”
  2. JS中没有接口(typescript例外),使用较少
  3. 类似于单一职责原则,这里更关注接口
  • 依赖倒置原则
  1. 面向接口变成,依赖于抽象而不依赖于具体
  2. 使用方只关注接口而不关注具体类的实现
  3. JS中使用较少(没有接口&弱类型)
  • 迪米特法则

去重 写代码消除 数组 【6 8 9 9 12 13 14 1 3】中重复的元素。

方法一:
let arr = [6, 8, 9, 9, 12, 13, 14, 1, 3];
function removeArr(arr) {
  let arrayResult = [];
  for (let i = 0, len = arr.length; i < len; i++) {
    if (arrayResult.indexOf(arr[i]) === -1) {
      arrayResult.push(arr[i]);
    }
  }
  return arrayResult;
}
removeArr(arr);
方法二:
var arr = [6, 8, 9, 9, 12, 13, 14, 1, 3];
function removeArr(arr) {
  var i = 0,
      len = arr.length,
      j;
  for (i; i < len; i++) {
    for (j= i+1; j < len; j++) {
      if(arr[i] == arr[j]) {
        arr.splice(j, 1);
        j--;
      }
    }
  }
  return arr;
}
removeArr(arr);
方法三:
let arr = [6, 8, 9, 9, 12, 13, 14, 1, 3];
function removeArr(arr) {
  return Array.from(new Set(arr))
}
removeArr(arr);
方法四:
let arr = [6, 8, 9, 9, 12, 13, 14, 1, 3];
function removeArr(arr) {
  let arrayResult = [];
  arr.reduce((s1, s2) => {
    if(s1 !== s2) {
      arrayResult.push(s1);
    }
    return s2
  });
  arrayResult.push(arr[arr.length-1])
  return arrayResult;
}
removeArr(arr);

ajax和axios的区别, fetch

  1. jQuery整个项目太大,单纯使用ajax却要引入整个jQuery非常不合理
  2. axios是Promise的实现版本,符合最新ES规范,支持Promise API
  3. axios客户端支持防止XSRF
  4. axios提供了一些并发的请求接口

fetch:
号称是AJAX的替代品.。

优势:

  • 更加底层,提供的API丰富(request, response)
  • 脱离了XHR,是ES规范里新的实现方式

缺点:

  1. fetch只对网络请求报错,对400,500都当做成功的请求,需要封装去处理
  2. fetch默认不会带cookie,需要添加配置项
  3. fetch不支持abort,不支持超时控制,使用setTimeout及Promise.reject的实现的超时控制并不能阻止请求过程继续在后台运行,造成了流量的浪费
  4. fetch没有办法原生监测请求的进度,而XHR可以

Vue生命周期

  • beforeCreate和created在vue实例化的时候就执行了,此处可请求数据,但是不能进行dom操作,因为拿不到组件对应的dom节点,如下图。
    给实例赋值最早要在created里面操作。

  • beforeMount和mounted这里是把组件生成的html内容挂在到dom上面的一个过程,如果不指定el或者是$mount()的话,数据是不会挂在到页面上的,因为它不知道该挂载到哪里去。所以dom应该在mounted这里才去操作。
    beforeMount()是渲染前的,mounted()是通过render函数渲染后拿到的,mounted之后实例就创建完成了.
    说明:上述4个钩子都是只会被调用一次。beforeMount和mounted在服务端渲染的时候不会被调用。服务端渲染的时候会调用的只有beforeCreate和created。
    在.vue文件里开发的过程中,是都没有template的,在.vue里面写的template都经过vue-loader处理直接变成了render函数放在vue-loader解析过的文件里面。

  • beforeUpdate和updated是有数据更新的时候才会去执行的。

  • beforeDestroy和destroyed组件被销毁的时候才会去执行。
    $destroy() // 组件销毁的一个方法,解除所有的事件监听和所有的watch。

  • activated和deactivated和keep-alive有关系,该钩子在服务器端渲染期间不被调用。activated是在keep-alive 组件激活时调用。
    deactivated在keep-alive 组件停用时调用。

  • render(h)和renderError(),有render的时候就不需要template了,因为template处理后最终也是变成render函数的返回vnode的,renderError是在render报错之后才会触发,报错之后渲染出来的就是报错的信息,只有在本组件的render函数出现错误的时候才会被调用,只关心自己有没有渲染成功,不管子组件。

  • errorCaptured() 正式环境可以使用,收集线上环境的一些错误。所有子组件的错误都可以捕捉到,除非子组件把冒泡事件停止掉。

原文地址:https://www.cnblogs.com/arissy/p/9903141.html