前端面试题含答案(近期面试中被问到的)

一、JS相关

1、常用的es6语法有哪些?
let、const定义变量;解构赋值;模板字符串;箭头函数;函数参数默认值

2、var、let、const的区别
var 存在变量提升,能在声明之前使用。let、const 因为暂时性死区的原因,不能在声明 前使用;var 在全局作用域下声明变量会导致变量挂载在 window 上,其他两者不会;let 和 const 作用基本一致,但是后者声明的变量不能再次赋值。

3、箭头函数和普通函数的区别
1)this的指向。普通函数的this指向window,可以通过bind、call、apply改变this指向。箭头函数的this指向的是父级作用域的this,如果外层有普通函数,指向普通函数,没有就指向window。node环境没有window,它的this指向{}空对象。
2)箭头函数不可以被当作构造函数。通过new命令来作为构造函数会报错,不存在prototype这个属性,也不能通过super访问原型的属性。
3)不可以使用arguments对象,该对象在函数体内不存在,如果要用就用rest参数替代。

4、简述一下原型和原型链
原型:每个函数都有 prototype 属性,该属性指向原型对象;使用原型对象的好处是所有对象实例共享它所包含的属性和方法。
原型链:主要解决了继承的问题;每个对象都拥有一个原型对象,通过__proto__ 指针指向其原型对象,并从中继承方法和属性,同时原型对象也可能拥有原型,这样一层一层,最终指向 null。

5、实现继承的几种方法
1)原型链继承。将父类的实例作为子类的原型。
2)组合继承。通过调用父类构造,继承父类的属性并保留传参的优点,然后通过将父类实例作为子类原型,实现函数复用。
3)寄生组合继承。通过寄生方式,砍掉父类的实例属性,这样,在调用两次父类的构造的时候,就不会初始化两次实例方法/属性,避免的组合继承的缺点。
参见继承的6种方式

6、堆和栈的区别
1)堆。动态分配内存,内存大小不一,也不会自动释放。
2)栈。自动分配相对固定大小的内存空间,并由系统自动释放。
3)基本类型都是存储在栈中,每种类型的数据占用的空间的大小是确定的,并由系统自动分配和释放。内存可以及时回收。
4)引用类型的数据都是存储在堆中。准确说是栈中会存储这些数据的地址指针,并指向堆中的具体数据。

7、数组去重的方法有哪些
1)利用es6的Set数据结构。它类似于数组,其成员的值都是唯一的。
2)filter过滤函数去重。indexOf查找函数中如果存在该项会返回它的index,不存在返回-1

let arr = [1,2,3,3,2]
let res = arr.filter((v, i) => {
    arr.indexOf(v) === i
})

3)遍历数组法。新建一个数组,遍历传入的数组,值不在新数组中就加入到该新数组.

    function unique(array) {
      let arr = []
      for(var i=0; i < array.length;i++){
       if(arr.indexOf(array[i]) === -1) {
         arr.push(array[i})
       }
      }
      return arr
    }

8、浏览器输入url后发生了什么
1)浏览器向DNS服务器发送请求解析url中域名对应的ip地址
2)解析出ip地址后,根据该ip地址和默认端口80,和服务器建立tcp连接
3)浏览器发出读取文件的htpp请求,该请求报文作为tcp三次握手的第三个报文的数据发送给服务器
4)服务器对浏览器的请求作出相应,并把对应的html文本发送给浏览器
5)释放tcp连接
6)浏览器解析html文本并显示内容

9、浏览器怎么渲染dom的
1)解析HTML结构。
2)加载外部脚本和样式表文件
3)解析并执行脚本代码。
4)DOM树构建完成。
5)加载图片等外部资源。
6)页面加载完毕。

10、js的宏任务和微任务
(1)js是单线程的,但是分同步异步
(2)微任务和宏任务皆为异步任务,它们都属于一个队列
(3)宏任务一般是:script,setTimeout,setInterval、setImmediate
(4)微任务:原生Promise
(5)遇到微任务,先执行微任务,执行完后如果没有微任务,就执行下一个宏任务,如果有微任务,就按顺序一个一个执行微任务

11、后端用cors解决跨域,为什么会发送两个请求
浏览器将CORS请求分成两类:简单请求和非简单请求。当请求存在跨域并且是非简单请求,浏览器会发送option预请求。
解决办法:可以在后台设置Access-Control-Max-Age来控制浏览器在多长时间内(单位s)无需在请求时发送预检请求,从而减少不必要的预检请求

12、浏览器的强缓存和协商缓存
强缓存:不会向服务器发送请求,直接从缓存中读取资源。状态码是200。
协商缓存:向服务器发送请求,服务器会根据这个请求的request header的一些参数来判断是否命中协商缓存,如果命中,则返回304状态码并带上新的response header通知浏览器从缓存中读取资源;
两者的共同点是,都是从客户端缓存中读取资源;区别是强缓存不会发请求,协商缓存会发请求

13、手写promise

  function myPromise(fn) {
    let self = this
    self.promiseState = 'pending'
    self.promiseResult = null
    function resolve(data) {
      if(self.promiseState != 'pending') return
      self.promiseState = 'fulfilled'
      self.promiseResult = data
    }
    function reject(data) {
      if(self.promiseState != 'pending') return
      self.promiseState = 'rejected'
      self.promiseResult = data
    }
    try {
      fn(resolve,reject)
    }catch(e) {
      reject(e)
    }
  }
  myPromise.prototype.then = function(onFulfilled,onRejected) {
    if(this.promiseState === 'fulfilled') {
      onFulfilled(this.promiseResult)
    }
    if(this.promiseState === 'rejected') {
      onRejected(this.promiseResult)
    }
  }
  let p = new myPromise((resolve,reject) => {
    reject('err')
  })
  p.then(res => {
    console.log(res)
  },err => {
    console.log(err)
  })
    

14、手写深拷贝

function deepClone(obj) {
    if(typeof obj !== 'object' || obj == null) {
      return obj
    }
    let result
    (obj instanceof Array) ? result = [] : result = {}
    for(let key in obj) {
      if(obj.hasOwnProperty(key)) {
        result[key] = deepClone(obj[key])
      }
    }
    return result
  }
  let obj1 = {
    name: 'tom',
    age: 18,
    address: {
      city: 'chengdu'
    }
  }
  let obj2 = deepClone(obj1)
  obj2.address.city = 'beijing'

15、重绘和回流
1)回流:当render tree的一部分或者全部元素因改变了自身的宽高,布局,显示或隐藏,或元素内部的文字结构发生变化,导致需要重新构建页面的时候,回流就产生了。
2)重绘:当一个元素自身的宽高,布局,及显示或隐藏没有改变,而只是改变了元素的外观风格的时候,就产生了重绘。
3)回流必定触发重绘,而重绘不一定触发回流。
4)何时会发生回流:

  • 添加或删除可见的DOM元素
  • 元素的位置发生变化
  • 元素的尺寸发生变化(包括外边距、内边框、边框大小、高度和宽度等)
  • 内容发生变化,比如文本变化或图片被另一个不同尺寸的图片所替代。 页面一开始渲染的时候(这肯定避免不了)
  • 浏览器的窗口尺寸变化(因为回流是根据视口的大小来计算元素的位置和大小的)

16、使用random函数实现,传入两个参数min,max。返回的随机数[min,max]之间

function rand(min,max){
    return Math.ceil((Math.random()*(max-min+1))+min-1);
}

二、VUE相关

1、简述vue响应式原理
一个vue实例被创建,vue会遍历data的所有属性,通过object.defineProporty转换为getter/setter并且在内部追踪相关依赖,在属性被访问或修改时通知变化。
每个组件实例都有相应的watcher程序实例,它会在组件渲染的过程中把属性记录为依赖,当依赖触发setter时,通知watcher重新计算,从而让它相关联的组件更新。

2、vue router路由传参的方式有哪些
1)params传参。使用name传参时必须搭配params。传的参数在url中看不见。刷新页面参数会丢失。对于像path: '/detail/:id’这样的携带参数的动态路由,传参时也应当使用params,动态路由传参是可以再url上看到的。
2)query传参。浏览器url上是可以看得到参数的。
3)props传参。在路由配置时传入props

  {
  name: 'news',
  path: '/news',
  component: () => import('@/views/news'),
  meta: { title: '新闻详情' },
  props: { type: 1 }
}

在组件内通过props取值

props: ['type']

3、promise.all 里面只要有一个方法执行失败还会继续执行吗?
假设有三个异步任务,如果都执行成功,那么返回的值是三个异步任务的值。如果有一个任务失败,那么返回这个失败的任务的值。

4、vue中key值的作用
key值是提供给虚拟dom的唯一标识,为了后续的更新能快速找到节点。不能用index作为key值,因为在对数组进行增删时会改变下标。

5、vue中的data为什么是一个函数
data返回的数据会形成闭包,给每个组件提供一个私有的空间,组件之间不会相互影响

6、v-on,click可以绑定多个点击事件吗?
可以,它的底层是addEventListener

7、computed 和 watch 的区别和运用的场景?
computed: 是计算属性,依赖其它属性值,并且 computed 的值有缓存,只有它依赖的属性值发生改变,下一次获取 computed 的值时才会重新计算 computed 的值;
watch: 更多的是「观察」的作用,类似于某些数据的监听回调 ,每当监听的数据变化时都会执行回调进行后续操作;
运用场景:当我们需要进行数值计算,并且依赖于其它数据时,应该使用 computed,因为可以利用 computed 的缓存特性,避免每次获取值时,都要重新计算;当我们需要在数据变化时执行异步或开销较大的操作时,应该使用 watch。

8、谈谈你对 keep-alive 的了解
keep-alive 是 Vue 内置的一个组件,可以使被包含的组件保留状态,避免重新渲染 。
其有以下特性:

  • 一般结合路由和动态组件一起使用,用于缓存组件;
  • 提供 include 和 exclude 属性,两者都支持字符串或正则表达式, include表示只有名称匹配的组件会被缓存,exclude 表示任何名称匹配的组件都不会被缓存 ,其中 exclude 的优先级比 include高;
  • 对应两个钩子函数 activated 和 deactivated ,当组件被激活时,触发钩子函数 activated,当组件被移除时,触发钩子函数 deactivated。

9、vue中v-model实现原理
vue 项目中主要使用 v-model 指令在表单 input、textarea、select 等元素上创建双向数据绑定,我们知道 v-model 本质上不过是语法糖,v-model 在内部为不同的输入元素使用不同的属性并抛出不同的事件:

  • text 和 textarea 元素使用 value 属性和 input 事件;
  • checkbox 和 radio 使用 checked 属性和 change 事件;
  • select 字段将 value 作为 prop 并将 change 作为事件。

10、Proxy 与 Object.defineProperty 优劣对比
1)Proxy 的优势如下:
Proxy 可以直接监听对象而非属性;
Proxy 可以直接监听数组的变化;
Proxy 有多达 13 种拦截方法,不限于 apply、ownKeys、deleteProperty、has 等等是 Object.defineProperty 不具备的;
Proxy 返回的是一个新对象,我们可以只操作新的对象达到目的,而 Object.defineProperty 只能遍历对象属性直接修改;
Proxy 作为新标准将受到浏览器厂商重点持续的性能优化,也就是传说中的新标准的性能红利;
2)Object.defineProperty 的优势如下:
兼容性好,支持 IE9,而 Proxy 的存在浏览器兼容性问题,而且无法用 polyfill 磨平,因此 Vue 的作者才声明需要等到下个大版本( 3.0 )才能用 Proxy 重写。

11、vue中nextick实现原理
1)nextTick就是一个异步方法。nextTick 方法主要是使用了宏任务和微任务(事件循环机制),定义了一个异步方法,多次调用 nextTick 会将方法存入 队列中,通过这个异步方法清空当前队列。
2)使用场景。在Vue生命周期的created()钩子函数进行的DOM操作一定要放在Vue.nextTick()的回调函数中;在数据变化后要执行的某个操作,而这个操作需要使用随数据改变而改变的DOM结构的时候,这个操作都应该放进Vue.nextTick()的回调函数中。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值