早已忘却的面试题,需要在隆冬忆起
一、Vue
Vue 自定义指令
通过自定义指令,我们可以扩展 Vue 的行为,让它在渲染 DOM 元素时添加额外的特性和事件,从而更好地完成业务需求
vue 自定义指令分为两种类型:全局指令和局部指令(组件内指令)
全局指令会注册到 Vue.directive 上,可以全局使用,局部指令则只能在组件内使用
下面是一个全局自定义指令的示例:注册一个名为 v-focus 的全局自定义指令注册了一个名为 v-focus 的全局自定义指令,并实现了 inserted 钩子函数,当该指令所绑定的元素插入到 DOM 中时,该钩子函数会被调用,从而实现元素的聚焦功能
下面是一个局部自定义指令的示例:在组件内定义一个名为 v-highlight 的局部自定义指令
Vue 中 hash 路由与 history 路由的区别
自定义指令在权限控制方面的应用
可以根据用户的角色信息来控制某些按钮或者表格中的行列是否可见,可编辑,可删除,这个时候就可以通过自定义指令来实现这样的权限控制.
定义一个名为 v-permission 的全局自定义指令,并实现了 bind 钩子函数,在该函数中通过当前用户的角色信息,判断该用户是否具有该元素的权限,如果没有,则将该元素隐藏
下面是一个示例代码:
Vue 的动态路由
Vue 的 key 的作用
key 是用来唯一标识一个节点的属性。当 Vue 渲染 Dom 时,它会根据节点的 key 来判断是否需要重新渲染当 Vue 发现节点的 key 发生变化时。它会将该节点从 DOM 树中移出,然后重新创建一个新的节点插入到合适的位置,这样可以减少 DOM 操作次数,提高渲染性能。
Router 路由守卫
Router 中的一项重要功能,它允许开发者在导航到某个路由或离开当前路由时执行一些控制和验证逻辑。Vue Router 提供了全局的、路由级别的和组件级别的三种不同类型的路由守卫,包括:
全局前置守卫 beforeEach 用于验证用户是否登录等全局控制
全局解析守卫 beforeResolve 用于在全局前置守卫之后在组件渲染之前被调用
全局后置钩子 afterEach 用于在路由完成后进行清理
路由独享的守卫 beforeEnter 用于在特定路由进入之前进行验证
组件内部的守卫 beforeRouteEnter、beforeRouteUpdate 和 beforeRouteLeave 用于处理页面内部控制逻辑
二、Javascript
Event Loop
事件循环(Event Loop)是一种用于处理异步任务的机制,它是 js 运行时的一部分,用于管理和调度任务的执行顺序。在 js 中,任务可以分为两种类型:1.同步任务:按照代码的顺序依次执行,直到执行完成 2.异步任务:不会立即执行,而是在将来的某个时间执行。异步任务通常涉及网络请求、定时器、事件监听等。事件循环的工作原理如下:
在每个事件循环中,会先执行所有的微任务,然后执行一个宏任务。这样的机制保证了异步任务的执行顺序,并且能够及时响应用户的交互。常见的宏任务包括 setTimeout, setInterval,网络请求等,而微任务包括 Promise、MutationObserver 等。理解实际那循环对于编写高效的异步代码非常重要,它能够帮助我们合理地处理任务并避免阻塞主线程。
作用域链:
在 js 中每个函数都有自己的作用域,
当在一个函数内部引用一个变量,js 会按照代码中出现的顺序,从当前作用域开始依次向上查找
直到找到第一个包含这个变量的作用域为止,这个过程被称为作用域链的查找
如果整个作用域链都没有找到,就会报错抛出 ReferenceError 异常
js 在转时间时时分秒不满 10 补 0 的几种方式
当我们在浏览器地址栏中输入一个网址时,发生了什么
1.DNS 解析: 浏览器会检查自己有无缓存,如果有该域名对应的 IP 地址就直接使用,否则则向 DNS 发起请求
2.发起 Http 请求,浏览器会根据 URL 的协议头向服务器发起相应的网络请求,同时浏览器也会发送一些请求头和请求参数
3.建立 TCP 连接:在 HTTP 请求建立之前,浏览器需要和服务器建立 TCP 连接,TCP 是一种面向连接的、可靠的、基于字节流的传输协议,通过三次握手来确保数据能够准确可靠的发送到服务端,而不会出现数据丢失或乱序的情况
4.发送 HTTP 请求,在建立了 TCP 连接之后,浏览器就能够向服务器发送 HTTP 请求报文。HTTP 请求报文包括请求头,请求行,和请求体
5.接受服务器相响应报文:当服务器收到请求报文后,会解析请求,然后返回相应的响应报文给客户端。HTTP 响应报文包括状态行、响应头和响应体三个部分,其中状态行包含了该请求的结果状态码。
6.解析渲染页面:当浏览器接收到服务器返回的响应报文之后,会根据相应报文中的内容(如 HTML,CSS、javascript 等资源),解析出对应的 DOM 树、CSS 规则树和 javascript 代码并且根据它们构建出一个渲染树。最后将这些内容交给浏览器的渲染引擎进行渲染,生成我们最终看到的页面。
7.断开 TCP 连接,当浏览器接收到服务器返回的响应报文后,会关闭该连接,释放资源。如果浏览器需要请求更多的资源,则需要重新建立新的 TCP 连接
如何减少重排和重绘
重排和重绘是浏览器渲染过程中的两个关键步骤重排是指浏览器计算元素的位置和大小属性,并重新布局页面的过程。重绘是指根据元素的样式属性,重新绘制元素的外观重排和重绘是耗费性能的操作,因此减少重排和重绘可以提高页面的性能和响应速度
import 和 require 是 js 两种不同的模块化规范
1、用法不同
import 时 ES6 中新增的模块化语法,用于在代码中引入其他 ES6 模块的导出对象。它是一个顶级声明
只能出现在 js 代码最外层或其他类似的顶级位置,不能在其他代码块中使用 import {debounce} from "lodash"
require 是 CommonJS 规范中的模块化语法,用于在代码中引入 CommonJS 模块的导出对象,它可以在任何位置使用,包括函数内部或代码内部 const debounce = require("lodash/debounce")
2、加载时机不同
import 在代码编辑时就会被处理,因此在代码执行前就已经加载了相应的模块。这使得 import 可以在代码运行之前进行静态分析,从而在构建时进行优化
require 是在运行时才会被加载,这意味着当代码中使用 require 时,它会在代码被执行的到的时候加载模块,并将其导出对象作为结果返回
3、语法不同
import 的语法相对简洁,并且可以进行模块的命名空间分离和解构。同时,它也支持异步加载模块
require 的语法相对复杂,特别是在需要进行多层路径嵌套时更为明显,它不能进行命名空间分离,也不支持 ES6 中的解构语法。同时也不能异步加载模块,需要额外的库或者手动编写异步加载逻辑
总之,如果需要使用 Es6 中的新特性或者异步加载模块,使用 import, 如果需要兼容 node 或者 CommonJS 环境,可以使用 require
WebSocket 的使用
WebSocket 是一种在 Web 浏览器和服务器之间进行全双工通信的协议。它提供了更强大的实时数据传输能力,相对于传统的 HTTP 请求-响应模式,WebSocket 允许服务器主动向客户端推送数据,实现了真正的双向通信。
WebSocket 连接需要服务器支持,服务器需要实现相应的 WebSocket 协议来处理连接和消息的传输。在实际使用中,可以使用诸如 Node.js 的 ws 模块或者 Websocket 框架来实现服务器端的功能
微任务和宏任务以及使用场景
微任务和宏任务是用来管理 js 异步任务执行顺序的机制。它们决定了任务在事件循环中的执行顺序。微任务是由 js 引擎提供的任务队列,它的执行优先级高于宏任务,常见的微任务有 Promise 的回调函数,MutationObserver 和 progress.nextTick 宏任务是由浏览器提供的任务队列,它的执行优先级较低,常见的宏任务有定时器 setTimeout,setinterval, DOM 事件回调和 Ajax 请求等
使用场景:
微任务的使用场景:
1 需要在当前事件循环的末尾执行的任务,可以使用微任务,例如 Promise 的回调函数。
2 需要立即执行的任务,可以使用微任务,例如 MutationObserver 监听 DOM 变化并立即做出相应
宏任务的使用场景:
1 需要延迟执行的任务,可以使用宏任务,例如定时器的回调函数。
2 需要在事件循环中的下一个循环中执行的任务,可以使用宏任务,例如 DOM 时间回调和 Ajax 请求
在一个事件循环中,当所有的宏任务执行完毕后,会先执行所有的微任务,然后再进行下一个宏任务的执行,这样可以保证微任务的优先级高于宏任务,确保及时响应和更新总结起来,微任务和宏任务是用来管理异步任务执行顺序的机制,微任务的执行优先级高于宏任务,适合处理需要立即执行或在当前循环末尾执行的任务。宏任务适合处理需要延迟执行或在下一个循环中执行的任务
ES6 中一些常用的特性和语法
let 和 const 关键字
箭头函数
解构赋值
扩展运算符
类和继承
模版字符串
promise 和 async/await
模块化:Symbol、Map、Set、Proxy、Reflect
三、React
Vue 和 React 的区别
分五个方面来说:
1、模版语法:
Vue 使用了 HTML 的模版语法来编写组件模版,比较易于理解和学习,使得开发者可以快速的编写出页面。这样做的优点在于,将 HTML 和 JavaScript 代码分离开来,有利于代码的维护性和阅读性。Vue 的模版语法也提供了一些强大的功能,如条件渲染,循环渲染,事件处理等.
React 则推崇:一切都是 javascript,它采用了 jsx 语法,即 Javascript 和 Xml 的混合语法,使用 jsx 可以轻松地创建复杂的 UI,并提高了应用程序的性能,
不过使用 jsx 的同事,你需要学习更多的语法和编程范式
2、数据绑定
Vue 提供了双向数据绑定的功能,可以实现视图和数据的自动同步,极大方便了数据管理和操作。双向绑定包括两个部分:数据模型和视图模型。在 Vue 中,数据模型即组件实例中的数据;视图模型则负责数据模型中的数据绑定到视图中去。
React 的数据流是则是单向的,采用了组件间 props 和 State 的传递和管理数据,通过 props 向组件传递属性值,并监听这个属性的更改事件来更新 UI
从而实现数据的单向流动;而 state 则是保存组件内部状态的地方,是可变的数据,推荐在合适的情况下尽量使用不可变数据。
3、组件分类
Vue 将组件分为有状态组件和无状态组件 functional 两种,有状态组件包含了应用程序中的逻辑和数据,可以实现更复杂的操作和交互;无状态组件只提供了一个对应的 UI 界面,没有数据和逻辑的处理,通常用于小组件或纯展示类组件。Vue 的组件具有生命周期函数,可以在组件的不同阶段执行不同的处理逻辑。
React 没有严格的组件分类,但通常会将组件分为函数式组件和 Class 组件两种。函数式组件是一种纯 javascript 函数,接受 props 对象作为参数,返回一个 React 元素,不支持状态和生命周期函数;class 组件则是使用面向对象编程的方式来构建组件,支持状态和生命周期函数。所以 React 组件也具有生命周期,可以在组件的不同阶段执行相关操作。
4、生命周期
Vue 和 React 都拥有各自的生命周期函数,并分别在不同的组件阶段调用这些函数。Vue 的生命周期函数包括了 created、mounted、updated 和 destroyed 等每个函数都有特定的用途和功能
React 的生命周期函数包含了 componentWillMount、componentDidMount、shouldComponentUpdate、componentWillUnmount 等也都有各自的特点和用途。
生命周期函数可以用于解决组件挂载、更新、销毁等过程的一系列问题和逻辑
5、渲染效率
Vue 采用了虚拟 DOM 和异步渲染等技术来提高程序的性能,虚拟 DOM 是将真实的 DOM 抽象成 js 对象,可以快速的进行对比和计算,从而减少 DOM 操作带来的性能损耗;异步渲染则是让浏览器在空闲时间渲染组件,从而提高渲染效率。React 则使用了一种名为 reconciliation 的算法在不重新渲染整个组件数的情况下更新 UI,这也使得 React 具有较高的渲染效率。在组件更新时,React 会通过对比虚拟 DOM 的变化来更新 UI,从而避免大量的 DOM 操作
Vue 和 React 都是非常优秀的前端框架,采用不同的实现方式,适用于不同的开发场景。Vue 更加注重开发体验和易用性,适合快速开发小型和中型的应用;React 更加注重应用程序的可维护性和性能,适合大型应用或需要更好的可扩展性的应用。选择哪个框架取决于项目的需求和团队的偏好
四、Webpack
webpack 的摇树
npm run dev 时,webpack 做了什么
总的就是:webpack 在运行 npm run dev 时,会根据配置文件对项目进行构建和打包,并提供开发服务器以及自动编译的功能,方便开发人员进行实时调试和开发
webpack 缓存
Webpack 提供了缓存机制,可以通过缓存来提高投建性能。webpack 的缓存机制有两个方面:
Loader 缓存:在 webpack 构建过程中,Loader 可以使用缓存来提高性能 Loader 缓存可以避免对于同一个文件的重复处理,从而加快构建速度。通过设置 cache:true 来开启 Loader 缓存,例如:
2、Module 缓存:
在 webpack 构建过程中,Webpack 会根据模块的内容生成一个唯一的标识符(hash).
如果模块内的内容没有发生变化,Webpack 会复用之前的构建结果,避免重新构建该模块,从而提高构建速度。
Module 缓存是基于文件的,只有在文件内容发生变化时才会重新构建
Module 缓存是默认开启的,可以通过设置 cache:true 来显示启用缓存。
通过使用 Loader 缓存和 Module 缓存,Webpack 可以避免重复处理和构建不变的模块,从而提高构建的性能和速度。
需要注意的是,缓存机制只有在构建过程找那个文件内容没有发生变化时才会生效,如果文件内容发生变化时,Webpack 会重新构建整个模块和依赖树。
五、TypeScript
ts 中如何新增一个类型
在 ts 中有几种方式可以创建新类型:
any 与 unkown 的区别
在 Typescript 中,any 和 unkown 都是用来表示不确定类型的,都是表示任意类型,但是它们之间有一些区别:
版权声明: 本文为 InfoQ 作者【这我可不懂】的原创文章。
原文链接:【http://xie.infoq.cn/article/0cd0b4d890ffa1b2afb5039ea】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
评论