面试总结

9/11/2019 面试

2019年9月面试记录

# 2019-9-9

# 常见的6种数据类型

  • string 字符串
  • number 数值
  • object 对象
  • array 数组
  • null 空
  • undefined 未定义

# ajax和promise的区别

  • ajax的数据是在回调函数里面返回的
  • promise是在then函数里面返回
  • promise是为了解决ajax回调地狱的问题
  • promise是链式写法
  • es7新增async await函数也可以解决ajax回调地狱和promise重复嵌套的问题

# 怎么解决0.1+0.2=0.33333的问题,只想要小数部分

  • 利用(0.1+0.2).toFixed(1)
  • 可以先分别乘以10,然后再除以10

# promise有几种状态

  • pending:进行中
  • fulfilled:已成功
  • rejected:已失败

# 为什么不建议在原型上拓展方法

  • 容易造成全局污染,和其他库冲突
  • 出了Bug不太好定位问题
  • 有可能出现代码向上不兼容的情况

# array的some、every、filter、find有什么区别

  • some只要数组中有一个满足条件,就返回true
  • every只有数组中所有的项满足条件,才返回true
  • filter返回一个满足条件的新数组
  • find返回数组中满足条件的第一个元素的值

# es6都用过哪些新增的特性

参考:阮一封 es6 (opens new window)

  • let和const声明变量
  • 对象解构、数组解构、参数解构
  • 拓展运算符...
  • async await 函数
  • Promise 对象
  • Class类
  • Set和Map数据结构
  • for of 循环迭代 String、Array、Map、Set、
  • 字符串的拓展
    • 字符串模板 ``
    • string.includes()
  • 数值的拓展
    • Number.isNaN()
    • Number.isFinite()
    • Number.isInteger()
    • Math.trunc() 去除一个数的小数部分,返回整数部分
    • 指数运算符 2 ** 2 = 4
  • 函数的拓展
    • 函数参数的默认值
    • 箭头函数
    • rest参数...rest
    • 函数的name属性,返回该函数的函数名
  • 数组的拓展
    • Array.from转换伪数组或 Set 和 Map 数据结构为真数组
    • Array.of方法用于将一组值,转换为数组
    • copyWithin() 将指定位置的成员复制到其他位置
    • find()与findIndex(),find返回符合条件的成员,findIndex返回符合条件的索引值
    • fill()方法使用给定值,填充一个数组
    • 数组实例的 entries(),keys() 和 values()
    • 数组实例的 includes()
    • 数组实例的 flat() 将二维数组转换成一维数组,返回一个新数组
  • 对象的拓展
    • Object.keys(),Object.values(),Object.entries()
    • Object.is()比较两个值是否相等,与===基本一致
    • Object.assign方法用于对象的合并,只是一级属性复制,比浅拷贝多深拷贝了一层而已

# reduce的常见用法

  • 数组求和
  • 数组求最大值
// 数组求和
const arr = [12, 34, 23];
const sum = arr.reduce((total, num) => total + num);

// 数组最大值
const a = [23,123,342,12];
const max = a.reduce(function(pre,cur,index,arr){return pre>cur?pre:cur;}); 

// 将二维数组转为一维数组
const arr = [[1, 2, 8], [3, 4, 9], [5, 6, 10]];
const res = arr.reduce((x, y) => x.concat(y), []);

# Map和Set数据结构有什么区别

  • Set是没有重复元素的集合
  • Map是键值对的形式

# 箭头函数和普通函数有什么区别

  • 箭头函数的this指向当前的执行环境,而普通函数指向自己
  • 箭头函数不可以当作构造函数,不能使用new命令
  • 箭头函数可以使用rest获取参数对象,普通函数可以用arguments获取参数对象
  • 箭头函数没有prototype(原型),所以箭头函数本身没有this
  • 不能直接修改箭头函数的this指向

# 命令式编程与声明式编程有什么区别

  • 命令式编程:详细的告诉计算怎么一步一步的达到结果
  • 声明式编程:只告诉计算机需要做什么,计算机自己执行达到结果
// 命令式编程
let result;
for (var i = 0; i < user.length; i++) {
  if (user[i] === "Ben") {
    result = user[i];
    break;
  }
}

// 声明式编程
const result = user.find(item => item === "Ben");

# 为什么{} + [] === 0为true

{} 认定是语法块,这个放在前面,只有混淆作用,并不参与运算。
+[] 类型转换 0 ,0===0

# 什么是变量提升

参考:深入理解 js 变量提升 (opens new window)
JavaScript引擎的工作方式是,先解析代码,获取所有被声明的变量,然后再一行一行地运行。这造成的结果,就是所有的变量的声明语句,都会被提升到代码的头部,这就叫做变量提升(hoisting)

# 2019-9-11

# socket怎么检测客户端长时间没有连接

这里面会有一个心跳机制,服务端定时向客户端发送一个数据包,然后启动一个低级别的线程,该线程中不断检测客户端的回应, 如果在一定时间内没有收到客户端的回应,即认为客户端已经掉线,同样,如果客户端在一定时间内没 有收到服务器的心跳包,则认为连接不可用。

# 路由的hash模式和history模式有什么区别

参考:hash 和 history的区别 (opens new window)

  1. 原理不一样
    • hash模式是通过在 window 对象 onhashchange 事件监听的地址栏的hash部分实现路由跳转
    • history模式则是通过在window对象上监听popState()事件,history api 提供 pushState、replaceState、go、back、forward,等方法实现路由跳转
  2. 路由跳转表现不一样
  • pushState() 设置的新 URL 可以是与当前 URL 同源的任意 URL;而 hash 只可修改 # 后面的部分,因此只能设置与当前 URL 同文档的 URL
  • pushState() 设置的新 URL 可以与当前 URL 一模一样,这样也会把记录添加到栈中;而 hash 设置的新值必须与原来不一样才会触发动作将记录添加到栈中
  1. 发送 http 请求的时表现不一样
    • hash对地址栏的变化不会发送到后端,准确说只会发送#前半部分到后端,例如:https://yixiu.com
    • history则会将地址发送到后端,一旦后端没有对应的路由处理,会返回404错误,所以需要后台配置:如果 URL 匹配不到任何静态资源,则应该返回同一个 index.html 页面,这个页面就是你 app 依赖的页面

# 谈谈高阶组件在实际项目的运用

参考:如何理解 React 高阶组件(HOC)? (opens new window)

  • 高阶组件就是接受组件为参数返回一个加强组件的函数
  • withRouter、connect这些都是高阶组件的应用
  • 用高阶组件做增加loading效果
  • 复用组件逻辑

# 深拷贝和浅拷贝

参考:浅拷贝与深拷贝 (opens new window)

  • 浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存
  • 深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改变原对象
/ 和原数据是否指向同一对象 第一层数据为基本数据类型 原数据包含子对象
赋值 改变会使原数据一同改变 改变会使原数据一同改变
浅拷贝 改变不会使原数据一同改变 改变会使原数据一同改变
深拷贝 改变不会使原数据一同改变 改变不会使原数据一同改变

浅拷贝的实现方式

  • 使用Object.assign()
  • 使用es6的扩展运算符...
  • Array.prototype.concat()
  • Array.prototype.slice()

深拷贝的实现方式

  • JSON.parse(JSON.stringify()),这种方法虽然可以实现数组或对象深拷贝,但不能处理函数
  • 手写递归方法
  • 函数库lodash提供_.cloneDeep用来做 Deep Copy
//定义检测数据类型的功能函数
function checkedType(target) {
  return Object.prototype.toString.call(target).slice(8, -1)
}
//实现深度克隆---对象/数组
function clone(target) {
  //判断拷贝的数据类型
  //初始化变量result 成为最终克隆的数据
  let result, targetType = checkedType(target)
  if (targetType === 'Object') {
    result = {}
  } else if (targetType === 'Array') {
    result = []
  } else {
    return target
  }
  //遍历目标数据
  for (let i in target) {
    //获取遍历数据结构的每一项值。
    let value = target[i]
    //判断目标结构里的每一值是否存在对象/数组
    if (checkedType(value) === 'Object' ||
      checkedType(value) === 'Array') { //对象/数组里嵌套了对象/数组
      //继续遍历获取到value值
      result[i] = clone(value)
    } else { //获取到value值是基本的数据类型或者是函数。
      result[i] = value;
    }
  }
  return result
}

# 为什么react和vue里面循环产生html时要绑定key

key的作用是为了在diff算法执行时更快的找到对应的节点,提高diff速度

# 怎么控制video视频的宽高

设置width和height

# 为什么要发送一个option请求

浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段。只有得到肯定答复,浏览器才会发出正式的XMLHttpRequest请求,否则就报错

这和浏览器的 CORS 跨域机制有关,客户端将请求分为了两种:简单请求和非简单请求;当请求为非简单请求时,就会触发浏览器发送预检请求。

预检请求一般包括 request header

# 在项目中做过哪些优化

# 前端部署

# 2019-9-12

# 为何要在componentDidMount里面发送请求?

参考:为何要在componentDidMount里面发送请求? (opens new window)

  • componentDidmount 是在组件完全挂载后才会执行,在此方法中调用setState 会触发重新渲染,最重要的是,这是官方推荐的!
  • componentWillMount、constructor 里进行网络请求会阻碍组件的渲染,会阻碍组件的实例化
  • 从React 16.3(2018年3月)开始componentWillMount会被弃用

# 你用过哪些react相关的UI框架

  • Zent有赞
  • ant-design和ant-mobile
  • element-react
  • React Suite

# 怎么用css写出三角形

.trangle {
  width: 0;
  height: 0;
  border: 40px solid;  
  border-color: transparent transparent transparent red;
}

# react和vue有什么区别

区别:https://juejin.im/post/5b8b56e3f265da434c1f5f76 数据流动原理:https://recallhyx.github.io/2018/03/18/%E5%89%8D%E7%AB%AF%E4%B8%89%E5%A4%A7%E6%A1%86%E6%9E%B6%E6%95%B0%E6%8D%AE%E6%B5%81%E5%8A%A8%E5%92%8C%E5%8E%9F%E7%90%86/

  • 数据流向不一样:vue支持双向数据绑定,react是单向数据流
  • 监听数据变化的原理不一样:vue使用Object.defineProperty()实现数据劫持,组件能自动响应数据变化,react通过onChange/setState的方式

# MVVM的原理

参考: MVC,MVP 和 MVVM 的图示 (opens new window)
浅析 web 前端 MVVM (opens new window)

  • View:视图
  • ViewModel:视图模型
  • Model:数据模型

它采用双向绑定(data-binding):View的变动,自动反映在 ViewModel,反之亦然

Vue 的 MVVM
View:单文件里 <template> 标签的内容,展现给用户的内容,与 ViewModel 双向绑定,可以在其中插入 ViewModel 提供的数据。
ViewModel:Vue 实例整个都是 ViewModel,与 View 双向绑定,用户在 View 修改数据或发出 ajax 等指令时, ViewModel 会及时相应,接着向下修改 Model——至此可以看出 Model 和 View 是没有直接关系的。
Model:这一层或者有歧义。为了更好理解 Model 需要引入 Vuex,在有 Vuex 的情况下,Vuex 提供的数据就是 Model,这符合后端架构中 Model 包含业务逻辑的情况。但是在无 Vuex 的情况下,Model 应该就是 Vue 实例的 data 属性,也就是 JavaScript 数据对象本身。

# 实现垂直居中的方式有哪些

# 在项目中怎么做移动端适配

# react组件通信

# react导入组件的方式有哪些

  • 通过传统import方式导入
  • 通过require引入

# HTTP请求头

  • General 一般头
    • Request URL 请求地址
    • Request Method 请求方式
    • Status Code 请求状态
    • Remote Address 远端地址
  • Request Header 请求头
    • Accept 用户代理期望的 MIME(媒体类型) 类型列表
    • Origin 远端信息
    • User-Agent 用户代理信息
    • Content-Type 示服务器文档的MIME 类型
    • Host 域名
    • Authorization 用户凭证
  • Response Header 响应头
    • Access-Control-Allow-Headers 允许请求头
    • Access-Control-Allow-Methods 允许的请求方式
    • Access-Control-Allow-Origin 是否允许跨域
    • Content-Type 示服务器文档的MIME 类型
    • Cache-Control 是否开启缓存
    • Expires 过期时间
    • Date 时间

# 按需引入

参考:

const OtherComponent = React.lazy(() => import('./OtherComponent'));

# 对于redux的理解

用来做全局状态管理,组件可以共享到状态

  • state:是一个js对象,存放应用状态
  • action:是一个包含typepayload的普通obj,我们通常使用一个函数(action creator)返回action
  • reducer:是一个纯函数,描述state是如何改变的,它有两个参数state和action,我们在函数体内使用switch语句匹配到action的type,拿到payload然后对状态作出更改

数据流向
数据流向是这样的,组件dispath一个action,reducer匹配到actions的type对state作出修改,view接收到数据变化,视图响应变化。视图是怎么接收到变化到呢,当我们没有使用react-redux时,我们是通过store.subscrib()订阅了state到变化,从而响应到视图上,而在使用react-redux时,我们借助connect方法,它自动订阅了state到变化,并映射到视图上,组件可以使用connect到前提是,我们必须在根组件外层包裹Provider组件。

异步操作
异步操作需要借助redux-thunk这个中间件,它可以使我们可以在action中拿到dispatch对象,我们使用action creator函数返回一个promise对象,在then函数内再dispath一个action通知reducer对state做出改变,也就是说异步操作发起了2次dispatch。

# 同事对你的评价

热情、乐于助人、自律、做事认真、有潜力

# 什么是http协议

# CSS选择器

Last Updated: 3/20/2024, 8:15:43 AM
강남역 4번 출구
Plastic / Fallin` Dild