11.22前端面经

281 阅读13分钟

1.react和vue有什么区别

1.vue:vue 会遍历 data 数据对象,使用 Object.definedProperty()将每个属性都转换为 getter 和 setter,每个 Vue 组件实例都有一个对应的 watcher 实例,在组件初次渲染的时候会记录组件用到了那些数据,当数据发生改变的时候,会触发 setter 方法,并通知所有依赖这个数据的 watcher 实例调用 update 方法去触发组件的 compile 渲染方法,进行渲染数据。 react:React 主要是通过 setState()方法来更新状态,状态更新之后,组件也会重新渲染。

2.监听数据变化的实现原理不同 vue:Vue 通过 getter/setter 以及一些函数的劫持,能精确知道数据变化。 react:React 默认是通过比较引用的方式(diff)进行的,如果不优化可能导致大量不必要的 VDOM 的重新渲染。为什么 React 不精确监听数据变化呢?这是因为 Vue 和 React 设计理念上的区别,Vue 使用的是可变数据,而 React 更强调数据的不可变,两者没有好坏之分,Vue 更加简单,而 React 构建大型应用的时候更加鲁棒。

3.组件写法不同 vue:Vue 的组件写法是通过 template 的单文件组件格式。 react:React 的组件写法是 JSX+inline style,也就是吧 HTML 和 CSS 全部写进 JavaScript 中。

4.Diff 算法不同 vue 和 react 的 diff 算法都是进行同层次的比较,主要有以下两点不同: vue 对比节点,如果节点元素类型相同,但是 className 不同,认为是不同类型的元素,会进行删除重建,但是 react 则会认为是同类型的节点,只会修改节点属性。 vue 的列表比对采用的是首尾指针法,而 react 采用的是从左到右依次比对的方式,当一个集合只是把最后一个节点移动到了第一个,react 会把前面的节点依次移动,而 vue 只会把最后一个节点移动到最后一个,从这点上来说 vue 的对比方式更加高效。

5.核心思想不同 vue:Vue 的核心思想是尽可能的降低前端开发的门槛,是一个灵活易用的渐进式双向绑定的 MVVM 框架。 react:React 的核心思想是声明式渲染和组件化、单向数据流,React 既不属于 MVC 也不属于 MVVM 架构。

6.数据流不同 vue:Vue1.0 中可以实现两种双向绑定:父子组件之间,props 可以双向绑定;组件与 DOM 之间可以通过 v-model 双向绑定。Vue2.x 中去掉了第一种,也就是父子组件之间不能双向绑定了(但是提供了一个语法糖自动帮你通过事件的方式修改),并且 Vue2.x 已经不鼓励组件对自己的 props 进行任何修改了。 react:React 一直不支持双向绑定,提倡的是单向数据流,称之为 onChange/setState()模式。不过由于我们一般都会用 Vuex 以及 Redux 等单向数据流的状态管理框架,因此很多时候我们感受不到这一点的区别了。

7.组合不同功能的方式不同 vue:Vue 组合不同功能的方式是通过 mixin,Vue 中组件是一个被包装的函数,并不简单的就是我们定义组件的时候传入的对象或者函数。比如我们定义的模板怎么被编译的?比如声明的 props 怎么接收到的?这些都是 vue 创建组件实例的时候隐式干的事。由于 vue 默默帮我们做了这么多事,所以我们自己如果直接把组件的声明包装一下,返回一个 HoC,那么这个被包装的组件就无法正常工作了。 react:React 组合不同功能的方式是通过 HoC(高阶组件)。React 最早也是使用 mixins 的,不过后来他们觉得这种方式对组件侵入太强会导致很多问题,就弃用了 mixinx 转而使用 HoC。高阶组件本质就是高阶函数,React 的组件是一个纯粹的函数,所以高阶函数对 React 来说非常简单。

8.组件通信方法不同 vue:Vue 中有三种方式可以实现组件通信:父组件通过 props 向子组件传递数据或者回调,虽然可以传递回调,但是我们一般只传数据;子组件通过事件向父组件发送消息;通过 V2.2.0 中新增的 provide/inject 来实现父组件向子组件注入数据,可以跨越多个层级。 react:React 中也有对应的三种方式:父组件通过 props 可以向子组件传递数据或者回调;可以通过 context 进行跨层级的通信,这其实和 provide/inject 起到的作用差不多。React 本身并不支持自定义事件,而 Vue 中子组件向父组件传递消息有两种方式:事件和回调函数,但 Vue 更倾向于使用事件。在 React 中我们都是使用回调函数的,这可能是他们二者最大的区别。

9.模板渲染方式不同 vue:Vue 是在和组件 JS 代码分离的单独的模板中,通过指令来实现的,比如条件语句就需要 v-if 来实现对这一点,这样的做法显得有些独特,会把 HTML 弄得很乱。 react:React 是在组件 JS 代码中,通过原生 JS 实现模板中的常见语法,比如插值,条件,循环等,都是通过 JS 语法实现的,更加纯粹更加原生。

10.渲染过程不同 vue:Vue 可以更快地计算出 Virtual DOM 的差异,这是由于它在渲染过程中,会跟踪每一个组件的依赖关系,不需要重新渲染整个组件树。 react:React 在应用的状态被改变时,全部子组件都会重新渲染。通过 shouldComponentUpdate 这个生命周期方法可以进行控制,但 Vue 将此视为默认的优化。

11.框架本质不同 vue:Vue 本质是 MVVM 框架,由 MVC 发展而来;

react:React 是前端组件化框架,由后端组件化发展而来。

2.react中父子组件数据传递的方式是什么

父组件向子组件传值,调用子组件时通过属性名={}的方式传递,子组件通过 props 接收。子组件向父组件传值在父组件中定义一个方法来,子组件可以通过 this.props.handleData(params)来向父组件传递,在父组件中调用 handleData()方法就可以获取子组件传递过来的值。

3.做一个水平垂直居中的布局

  1. 绝对定位+margin 负值
  2. 使用 css3 属性 transform
  3. flex 布局 justify-content:center;align-items:center
  4. 使用 table-cell

4.后端给到一个对象数组,每个对象中有一个属性为id,id相同代表两条数据重复,如何去重

  1. 使用filter和Map
function uniqueFunc(arr, uniId){
    const res = new Map();
    return arr.filter((item) => !res.has(item[uniId]) && res.set(item[uniId], 1));
}

2.使用 reduce

function uniqueFunc2(arr, uniId){
    let hash = {}
    return arr.reduce((accum,item) => {
        hash[item[uniId]] ? '' : hash[item[uniId]] = true && accum.push(item)
        return accum
    },[])
}

5.ES6中有哪些新增的数组方法

  1. Array.from 方法用于将两类对象转为真正的数组:类似数组的对象(array-like object)和可遍历(iterable)的对象(包括 ES6 新增的数据结构 Set 和 Map)
  2. Array.of 方法用于将一组值,转换为数组。弥补数组构造函数 Array()的不足。因为参数个数的不同,会导致 Array()的行为有差异
  3. find()方法找到第一个符合条件的成员,没有符合的则返回 undefined
  4. findIndex 方法的用法与 find 方法非常类似,返回第一个符合条件的数组成员的位置,如果所有成员都不符合条件,则返回-1
  5. fill()方法使用给定值, 填充一个数组,fill 方法还可以接受第二个和第三个参数,用于指定填充的起始位置和结束位置
  6. entries(),keys()和 values()——用于遍历数组,可以用 for...of 循环进行遍历,唯一的区别是 keys()是对键名的遍历、values()是对键值的遍历,entries()是对键值对的遍历
  7. includes()方法返回一个布尔值
  8. flat()用于将嵌套的数组“拉平”,变成一维的数组。该方法返回一个新数组,对原数据没有影响。传参数代表拉平几层默认是一层
  9. flatMap()只能展开一层数组。方法对原数组的每个成员执行一个函数(相当于执行 Array.prototype.map()),然后对返回值组成的数组执行 flat()方法。该方法返回一个新数组,不改变原数组

6.webpack中常用的配置,说出属性名即可

  1. mini-css-extract-plugin:分离样式文件,CSS 提取为独立文件,支持按需加载,还可以结合 postcss 进行兼容性处理(postcss 配置项放在最后,也就是第一个执行)
  2. html-webpack-plugin:简化了 HTML 文件的创建,以便为你的 webpack 包提供服务。比如例子中,在该插件中就可以实现 html 的压缩后输出
  3. optimize-css-assets-webpack-plugin:压缩 css 代码
  4. HotModulePlugin:热模块更新

7.webpack的构建流程

1、初始化参数:从配置文件和 Shell 语句中读取与合并参数,得出最终的参数

2、开始编译:用上一步得到的参数初始化 Compiler 对象,加载所有配置的插件,执行对象的 run 方法开始执行编译

3、确定入口:根据配置中的 entry 找出所有的入口文件

4、编译模块:从入口文件出发,调用所有配置的 Loader 对模块进行翻译,再找出该模块依赖的模块,再递归本步骤直到所有入口依赖的文件都经过了本步骤的处理

5、完成模块编译:在经过第 4 步使上述 loader 翻译完所有模块后,得到了每个模块被翻译后的最终内容以及它们之间的依赖关系

6、输出资源:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的 Chunk,再把每个 Chunk 转换成一个单独的文件加载到输出列表,这步是可以修改输出内容的最后机会

7、输出完成:在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统,在以上过程中,webpack 会在特定的时间点广播出特定的事件,插件在监听到感兴趣的事件后会执行特定的逻辑,并且插件可以调用 Webpack 提供的 API 改变 Webpack 的运行结果

8.Typescript 中的 interface 和 type 到底有什么区别

  1. 相同点: 都可以描述一个对象或者函数 都允许拓展(extends)
  2. 不同点: type 可以声明基本类型别名,联合类型,元组等类型 type 语句中还可以使用 typeof 获取实例的 类型进行赋值 interface 能够声明合并

9.什么情况下会使用ts

10.今年哪一个团队弃用了ts改用js

Turbo

11.MVVM框架

MVVM 其实表示的是 Model-View-ViewModel

Model:模型层,负责处理业务逻辑以及和服务器端进行交互 View:视图层:负责将数据模型转化为 UI 展示出来,可以简单的理解为 HTML 页面 ViewModel:视图模型层,用来连接 Model 和 View,是 Model 和 View 之间的通信桥梁

在 MVVM 的架构下,View 层和 Model 层并没有直接联系,而是通过 ViewModel 层进行交互。 ViewModel 层通过双向数据绑定将 View 层和 Model 层连接了起来,使得 View 层和 Model 层的同步工作完全是自动的。

12.vue的双向绑定

vue 数据双向绑定原理是通过数据劫持+发布订阅者的方式来实现的,首先是通过 ES6 提供的 Object.defineProperty()方法来劫持监听各属性的 getter 和 setter,并在当监听的属性发生变动时通知订阅者,是否需要更新,若更新就会执行对应的更新函数。

常见的数据劫持有两种方式,第一种是 Vue2 中的 object.defineProperty,第二种是 ES2015 中新增的 Proxy,Vue3 中就是通过 Proxy 代替 Object.defineProperty

完成一个数据的双向绑定需要做到如下步骤:

1.利用 Proxy 或 Object.defineProperty 生成的 observer 针对对象/对象的属性进行劫持,在属性发生变化后通知订阅者

2.解析器 complie 解析模板中的 Directive 指令,收集指令所有的方法和数据,等待数据发生变化然后进行渲染。

3.watcher 属于 observer 和 complie 的桥梁,接收到 observer 产生的数据变化并根据 complie 提供的指令进行视图渲染,使得数据变化促使视图变化

13.diff算法中key的作用

key 的特殊 attribute 主要用在 Vue 的虚拟 DOM 算法,在新旧 nodes 对比时辨识 VNodes。如果不使用 key,Vue 会使用一种最大限度减少动态元素并且尽可能的尝试就地修改/复用相同类型元素的算法。而使用 key 时,它会基于 key 的变化重新排列元素顺序,并且会移除 key 不存在的元素。

有相同父元素的子元素必须有独特的 key。重复的 key 会造成渲染错误。

通俗解释:

key 在 diff 算法的作用,就是用来判断是否是同一个节点。

Vue 中使用虚拟 dom 且根据 diff 算法进行新旧 DOM 对比,从而更新真实 dom ,key 是虚拟 DOM 对象的唯一标识, 在 diff 算法中 key 起着极其重要的作用,key 可以管理可复用的元素,减少不必要的元素的重新渲染,也要让必要的元素能够重新渲染。

14.vue中有多少种插槽

默认插槽,具名插槽,作用域插槽

15.作用域插槽如何获取父组件的数据

子组件在作用域上绑定属性来将子组件的信息传给父组件使用,这些属性会被挂在父组件 v-slot 接受的对象上

父组件中在使用时通过 v-slot:(简写:#)获取子组件的信息,在内容中使用

子组件 Child.vue

<template>
<slot name="footer" testProps="子组件的值">
<h3>没传 footer 插槽</h3>
</slot>
</template>

父组件 把v-slot的值指定为作⽤域上下⽂对象

<template v-slot:default="slotProps">
    来⾃⼦组件数据:{{slotProps.testProps}}
</template>

16.父组件向子组件传递额外的参数

attrsattrs和listeners

17.dev1分支已经开发还没有提交,此时发现分支错误,应该提交到dev2中,又不能更改dev1分支,如何处理

git stash
git checkout dev2
git add .
git commit -m 'xxx'
git pull origin dev2
git stash pop

18.dev1和dev2已经开发提交,要把其中一部分功能摘出来作为一个临时版本,放到一个dev3新的分支上如何处理

简选功能,sourceTree,可以将其中的一些提交加到新的分支上,再合并到新的分支或者其他已有分支上。