成功拿到offer 20+,2022年前端面试题整理

215 阅读5分钟

本文仅仅分享一下面试中常问,答案本人仅提供一下思路,还是需要自己去深入研究,形成自己的知识框架。本人通过半个月面试6家拿到4家offer ,希望大家成功上岸。2022加油!

call apply bind 作用和区别?

相同

  • 都能够解决this 的指向问题
  • call 和 apply 能够调用函数 不同
  • call 和 apply 传参不同,call(obj,arg1,aeg2) ,apply(obj,[arg1,arg2])
  • bind 传的参数和call 一样,但是会返回一个新的对象

说说你对post 和get 的区别?

  • get 是url传参,post 是request body 传参
  • get 没有 post 安全,get参数直接暴露在地址栏中,post 请求 不是绝对安全,通过抓包也能拿到
  • get 有数据大小的限制,这个限制主要是由浏览器决定的,一般是2k 的大小,post则没有限制
  • get 传输是阿斯托马值类型的数据,post 没有数据类型的限制
  • get 访问能够在浏览器进行缓存,post 不能缓存

对象有几种命名方式?

命名方式:

  • 创建对象 New Object
  • 对象字面量 var a = {};
  • 通过构造函数来创建对象

数组中有那些方法?

map、some 、filter、 every 、splice 、slice、sort 、find、findinex 、include、reduce

鉴权方式有哪几种?

  • HTTPBasicAuthentication(HTTP基本认证);
  • session-cookie;
  • Token验证(包括JWT,SSO);
  • OAuth(开放授权);

实现浅拷贝和深拷贝

浅拷贝 只拷贝对象第一层,简单的数据类型直接拷贝,引用类型的数据仅仅拷贝了地址

  let oldObj ={
      name:'Tom',
      age:10,
      job:['student','manong'],
      class:{
        banji : '101',
        teacher:'Mis Wang'
      }
    }

    let newObj ={}



    //  赋值  是引用拷贝 不是浅拷贝
    newObj =  oldObj
    newObj.name = 'Som'
    console.log(oldObj.name)  // 'Som'


    // 方案二 遍历
    function shallowClone(newObj,oldObj){
      for(item in oldObj){
        newObj[item] = oldObj[item]
      }  
    }

    shallowClone(newObj,oldObj)

    console.log(newObj.class === oldObj.class)  //true


    // 方案三 assign
    Object.assign(newObj,oldObj)
    newObj.name = 'Som'
    console.log(oldObj.name)
    console.log(newObj.class === oldObj.class)  //true
    newObj.name = 'Som'
    newObj.job[0] = 'waimai' 
    newObj.class.banji = '505'
    console.log(oldObj)

实现深拷贝

 //  

    let oldObj = {
      name: 'Tom',
      age: 10,
      job: ['student', 'manong'],
      class: {
        banji: '101',
        teacher: 'Mis Wang'
      }
    }



    function deepClone(oldObj) {
      //拷贝后的新对象
      let newObj = Array.isArray(oldObj) ? [] : {}

      for (item in oldObj) {
        if (oldObj.hasOwnProperty(item)) {
          if (oldObj[item] instanceof Object) {
            newObj[item] = deepClone(oldObj[item])
          } else {
            newObj[item] = oldObj[item]
          }
        }

      }

      return newObj


    }

    const resObj = deepClone(oldObj)

    console.log("新对象", resObj)
    resObj.job[0] = 'waimai'
    resObj.class.banji = '505'

    console.log("旧对象", oldObj)

事件循环机制有了解吗?说说微任务和宏任务

宏任务:setTimeOut,setInterval 、DOM事件、I\O、setImmediate(node环境)

微任务:promise、ansyc\await、new promise().then(回调)、MutationObserver(html5新特新)、Object.observe(已废弃;Proxy 对象替代)

、process.nextTick(node环境)

微前端有了解吗?

继承有几种方法,分别是怎么实现的?

2022-05-09

说说你工作的流程

  • 需求评审
  • 任务分配
  • 工程规范
  • 环境配置
  • 编写代码
  • 单元测试
  • 代码质量控制
  • 合并分支
  • 提交分支
  • 修复bug

你是怎样的控制代码质量的?用过那些自动化的工具?

建立代码规范与Code Review制度。
使用工具(linters)自动检查代码质量。
代码自动化构建
前端自动化测试工具介绍 —— Karma

你来了解 MVVM 吗?分别代表什么?

MVVM 是数据 - 视图 -视图数据模型 ,实现双向数据绑定,数据改变会影响视图层的改变,视图层的改变会影响数据层的更新。不再需要进行DOM 的操作。

都用过那些vue 指令?你用过那些,都是怎么用的?

v-bind v-if v-for v-model v-html v-once

  • v-bind 是属性绑定指令
  • v-if 是条件指令
  • v-for 是循环指令
  • v-model 数据双向绑定 用在表单中,以及组件件的数据双向传输

v-if v-for 能一起使用吗?为什么?怎么解决?

不能, v-for的[优先级]比v-if高,就导致列表会先全部[遍历]出来,在一个一个判断是否显示,就会造成渲染了无用的dom节点,浪费了性能,我们可以使用computed来解决这个问题。

  1. 如果避免出现这种情况,则在外层嵌套template(页面渲染不生成dom节点),在这一层进行v-if判断,然后在内部进行v-for循环。
  2. 如果条件出现在循环内部,可通过计算属性computed提前过滤掉那些不需要显示的项。

自定义指令有用过吗?怎么用?那些场景?

nextTick了解吗?有何作用?

在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM

在更新DOM 之后再一次处理DOM的时候 可以使用Vue.nextTick()

vue data函数中 属性名 和 methods中 函数名能相同吗?

不可以,vue会把methods和data的东西,全部代理到vue生成对象中。 会产生覆盖所以最好不要同名
源码 中的 initData()  方法 if (methods && hasOwn(methods, key)) { warn( Method "${key}" has already been defined as a data property., vm ) } 会取出 methods 中的方法进行判断,也就是 hasOwn(methods, key) 如果此 key 值 在 methods 中存在,会有warn 警告哦****

created和mounted区别?

created 是DOM渲染完成之前调用,通常是初始化某些属性值,然后再渲染成识图。

mounted 是DOM 渲染完成之后,通常初始化页面完成后,再对html的dom节点进行一些需要的操作

比如插件chart.js的使用。如果写入created中,你会发现无法对chart进行一些初始化配置,一定要等到html渲染完成才可以进行,这时候就需要用到mounted。

watch和computed的区别及用法?

watchcomputed 都是在数据发生变化的时候,进行数据的处理工作。自动监听和完成数据的变化和计算工作。

  • watch 是一个数据的变化会影响到多个数据的变化。
  • computed 是多个数据变化,会影响某一个数据的变化。
  • computed 支持缓存,只有依赖数据发生改变,才会重新进行计算。
  • watch 不支持缓存,数据变,直接会触发相应的操作。

watch和change 用哪个好?

input中 使用 watch 更好,select 使用change 更好

说说你对SPA 的理解?

1、单应用页面,通过动态加载渲染页面与用户进行交互,避免页面之间的切换打断用户的连续性体验。
2、html css js 都在当前的页面中进行渲染。会动态的根据当前页面中的需要哪些资源进行加载。
3、他的容器始终是没有改变的,改变的是容器中的内容。只有一个index.html 为入口

你对首屏加载过慢有什么优化方案?

首屏加载过慢原因:

  • 资源的体积过大
  • 资源重复加载
  • 加载资源是,内容渲染堵塞 优化方案
  • 减小入口的体积文件
  • 利用本地缓存,进行静态资源的加载
  • UI 框架按需加载
  • 图片资源进行压缩
  • 组件重复打包
  • 开启压缩模式
  • 使用SSR

2022/05/10

说一下语义化标签有哪些作用?

  • 用正确的标签来标记正确的内容
  • 代码结构更具有整洁性和可读性,方便日后的代码维护

给两个盒子左右布局怎么实现?

使用float或者absolute等

让一个盒子水平垂直居中?

方法一

  1. 设置好子绝父相
  2. left:50%;top:50%;
  3. margin-left:子盒子负的自身宽度的一半;margin-top:子盒子负的自身高度的一半;

方法二

  1. 亲父级设置display:flex;属性
  2. 亲父级中设置:justify-content: center; //主轴(此时是水平)居中
  3. align-items:center; // 侧轴(此时是垂直)居中

让一个文本垂直居中?

单行文本

设置line-height与父级元素的height相等*/ text-align: center; /设置文本水平居中/ overflow: hidden; /防止内容超出容器或者产生自动换行/

多行文本垂直居中

- 父级元素高度不固定

设置内填充(padding)的值来使文本看起来垂直居中

- 父级元素高度固定

设置父级div的display属性:display: table;;然后再添加一个div包含文本内容,设置其display:table-cell;和vertical-align:middle。

display: flex 解决方案

display: flex;

text-align: center;

align-items: center;

ES6 你都了解哪些语法

变量声明

letconst 都不会有变量声明提前的作用;
const 定义一个常量,不可以修改,如果赋值的是对象,可以修改对象内部属性值。
let 声明的变量 仅在作用域内有效

箭头函数

()=>{}

  • 箭头函数内的this对象,指向的就是所定义时所在的对象,而不是使用时所在的对象。
  • 箭头函数不可以当做构造函数使用,也就是不能new 一个箭头函数。
  • 不可以使用arguements参数,因为该属性在函数中不存在,可以用rest 代替。
  • 不可以使用yield命令,因此箭头函数不能用作 Generator 函数

promise

异步编程的解决方案,相比较回调函数更加合理强大,解决了回调地狱的问题

式调用 优化代码

有三个状态

  • 进行中
  • 成功 resolve
  • 失败 reject

特点

  • 状态不受外界的影响,只跟异步返回的结果有关系
  • 状态一旦改变就不再更新,永久这个状态

使用

const promise = new Promise(function(resolve, reject) {});

Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolvereject

实例方法

Promise构建出来的实例存在以下方法:

  • then()
  • catch()
  • finally() then是实例状态发生改变时的回调函数,第一个参数是resolved状态的回调函数,第二个参数是rejected状态的回调函数

then方法返回的是一个新的Promise实例,也就是promise能链式书写的原因

数组新增方法

扩展元素符...

能够将数值解析成 用逗号隔开的参数序列

const [first, ...rest] = [1, 2, 3, 4, 5];
first // 1
rest  // [2, 3, 4, 5]

find()、findIndex()

find()用于找出第一个符合条件的数组成员

参数是一个回调函数,接受三个参数依次为当前的值、当前的位置和原数组

对象新增的方法

属性的简写

const baz = {foo:foo}

// 等同于
const baz = {foo}

super关键字

this关键字总是指向函数所在的当前对象,ES6 又新增了另一个类似的关键字super,指向当前对象的原型对象

  const proto = {
      foo: 'hello'
    };

    const obj = {
      foo: 'world',
      find() {
        console.log(super.foo)
        return super.foo;
      }
    };
    Object.setPrototypeOf(obj, proto)

    obj.find()

解构赋值

  • 通过扩展运算符进行解构赋值,在解构赋值中,未被读取的可遍历的属性,分配到指定的对象上面

  • 结构赋值能够实现浅拷贝

let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };
x // 1
y // 2
z // { a: 3, b: 4 }

属性的遍历

  • Object.is() 严格判断两个值是否相等,与严格比较运算符(===)的行为基本一致,Object.is()不同之处只有两个: 一是 +0不等于-0,二是NaN等于自身
  • Object.assign() 方法用于对象的合并
  • Object.setPrototypeOf() 用来设置一个对象的原型对象
  • Object.getPrototypeOf() 用于读取一个对象的原型对象

Set\Map 两个数据结构

不同点:

Set 可以理解为 数据集合 [值,值]

Map 可以理解为数据字典 键值对 [key,value]

共同点:

没有重复的值

Set Map本身是一个构造函数,用来生成 Set 或者 Map 数据结构

方法有
add() 添加值

delete() 删除某一个值 返回布尔

has() 判断是否存在某一个值 返回布尔

clear()清除所有成员,没有返回值

Set 的遍历

forEach()

Map类型是键值对的有序列表,而键和值都可以是任意类型

Map 有个属性size 属性返回 Map 结构的成员总数。

  • set() 设置键名key对应的键值为value set(key,value)

  • get() get方法读取key对应的键值,如果找不到key,返回undefined

  • has() 方法返回一个布尔值,表示某个键是否在当前 Map 对象之中

  • delete方法删除某个键,返回true。如果删除失败,返回false

  • clear方法清除所有成员,没有返回值

遍历Map

  • forEach():遍历 Map 的所有成员

Proxy

Proxy 用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)

Proxy其功能非常类似于设计模式中的代理模式,常用功能如下:

  • 拦截和监视外部对对象的访问
  • 降低函数或类的复杂度
  • 在复杂操作前对操作进行校验或对所需资源进行管理

数组的遍历有哪些

forEach() map()

every()

some()

filter()

find()

keys,values,entries 都是 ES6 中的新方法

需要配合 for of

for (let index of ['a', 'b'].keys()) {
  console.log(index);
}
// 0
// 1

for (let elem of ['a', 'b'].values()) {
  console.log(elem);
}
// 'a'
// 'b'

for (let [index, elem] of ['a', 'b'].entries()) {
  console.log(index, elem);
}

定义一个 对象

 var a = {

       b:()=>{
          console.log("this",this)    // 指向到哪里
        }

    }

    a.b()

指向 window

js 继承有哪些

原型继承 构造函数继承 类继承

class 继承怎么用?

1)先声明一个父类 
(2)然后用extends 来继承这个父类 
(3super来传递父类声明的值

数值之间的切换 let a = 1 ; let b = 2; 将a 和 b 的值互调 有那些方案?

五种 :

中间值

解构赋值

    let a = 1 ;
    let b = 2;
    [b,a] = [a,b]
    console.log(a,b)

数组

    let a = 1 ;
    let b = 2;
    a = [a,b];
    a = a[1]
    b = a[0]

Set 的用法了解吗?具体怎么用?那 Map 呢?

去重、浅克隆

vue 组件通信有哪些?

props

$on $emit

ref

父组件调用子组件是,设置ref属性值
父组件通过设置子组件ref来获取数据

eventBus

VueX

provide 、inject (静态的) 通过 conputed()方法处理为动态的

$attrs $listeners

$parent$root

兄弟组件

this.$parent.on('add',this.add)

另一个兄弟组件

this.$parent.emit('add')

具体说说VueX

  • state 存放所有需要管理共享的状态数据
  • getter,可以增加一个getter派生状态,(相当于store中的计算属性),用来获得共享变量的值
  • mutations用来存放修改state的方法。
  • actions也是用来存放修改state的方法,不过action是在mutations的基础上进行。常用来做一些异步操作

在mutations 中实现异步方法可以吗?会发生问题?

不可以,不利于开发的调试。因为在开发过程中,我们常常会追踪状态的变化。

Vue3 你了解多少?

组合API setUp definedProperty 改为 proxy 作为拦截

作废了过滤器

webpack 的打包流程,你都做了哪些工作?

数组的去重有哪些方案?

for indexOf
indexOf
Set()
filter()
splice()
silce()
for for splice()组合使用
sort()

怎么判断一个数据是数组

Array.isArray()

instanceof

原型方法 prototype + toString + call

2022年5月11日

web 缓存有哪些了解 ?

了解强缓存 协商缓存吗?

路由怎么调用,权限怎么做的?

有几种守卫?深入说一下怎么使用?

vue 数组有哪些方法

Vue 和 JQuery 做一下比较,为什么选择Vue? 到底有哪些性能优势?

vue data 为什么是函数?