知识记录
1.Js的数据类型有哪些?他们的区别是什么?
基本数据类型:Number String Boolean Null Undefined Symbol(ES6) (直接存储在内存中的,占用固定的内存空间;赋值是通过将值直接复制给变量来完成的;作为参数传递时,传递的是值的副本)
引用数据类型 :狭义的对象(object)、 数组(array)、函数(function) (引用数据类型的变量实际上存储的是对象在内存中的引用,通过引用访问和操作对象的属性和方法;赋值是将对象的引用赋给变量;作为参数传递时,传递的是引用的副本)
2.判断数据类型有几种方法?
typeof运算符:
无法分辨Array、null和Object
instanceof 运算符:
原理是检查右边构造函数的原型对象(prototype),是否在左边对象的原型链上;
等同于:右边构造函数.prototype.isPrototypeOf(左边对象)
因此同一个实例对象,可能会对多个构造函数都返回true。
var d = new Date();
d instanceof Date // true
d instanceof Object // true
Object.prototype.toString.call方法
不能细分为谁谁的实例
3.作用域和作用域链
作用域:规定变量和函数的可使用范围称作作用域
作用域链:每个函数都有一个作用域,查找变量或者函数时,需要从局部作用域到全局作用域依次查找,这些作用域的集合称作作用域链
4.原型和原型链
原型:原型分为隐式原型和显式原型,每个对象都有一个隐式原型,它指向自己的构造函数的显式原型 原型链:每个对象都拥有一个原型对象,同时原型对象也可能拥有原型,这样一层一层,最终指向 null ,这种关系被称为原型链。
5.什么是闭包?
闭包是什么:JS中内层函数可以访问外层函数的变量,使内部私有变量不受外界干扰,起到保护和保存的作用,我们把这个特性称作闭包。 好处: 隔离作用域,保护私有变量; 让我们可以使用回调,操作其他函数内部; 变量长期驻扎在内存中,不会被内存回收机制回收,即延长变量的生命周期; 坏处:内层函数引用外层函数变量,内层函数占用内存,如果不释放内存,过多时,易引起内存泄露。 引用场景: for循环中的保留i的操作 、防抖(多次触发只执行最后一次)和节流 (规定时间内只触发第一次)
6.内存泄露、垃圾回收机制
内存泄露:指我们无法在通过js访问某个对象,而垃圾回收机制却认为该对象还在被引用,因此垃圾回收机制不会释放该对象,导致该块内存永远无法释放,积少成多,系统会越来越卡以至于崩溃
垃圾回收机制:就是垃圾收集器按照固定的时间间隔,周期性地寻找那些不再使用的变量,然后将其清除或释放内存。(标记清除/引用计数)
7.浅拷贝和深拷贝
浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存。
深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改变原对象。
8.如何改变this指向(call、apply与bind区别)
call、bind、apply 都是 JavaScript 中用于改变函数执行上下文(即 this 指向)的方法。
传参: call、bind可以传递很多个参数,apply只有两个参数,第一个参数要绑定的对象、第二个参数为数组;
返回: call和apply方法是直接调用函数并改变函数上下文,而bind方法则是返回一个新函数,稍后调用时绑定指定的上下文。
9.箭头函数和普通函数的区别
箭头函数是普通函数的简写,但是它不具备普通函数的很多特性;
箭头函数的this指向它定义时所在的对象,而不是调用时所在的对象;
没有arguments对象,不能使用arguments;
不会进行函数提升;
不能作为构造函数。
10.什么是web缓存?
web缓存主要指的是两部分:浏览器缓存和http缓存。
浏览器缓存包括:
localStorage:永久保存,以键值对保存,存储空间5M。 sessionStorage:关闭页签/浏览器时清空,存储空间5M。 cookie:随着请求发送,通过设置过期时间删除(大概4kb)。 localStorage/sessionStorage是window的属性,cookie是document的属性。
http缓存:当Web请求抵达缓存时, 如果本地有“已缓存的”副本,就可以从本地存储设备而不是原始服务器中提取这个文档。
优点:
减少不必要的网络传输,节约宽带(就是省钱)
更快的加载页面(就是加速)
减少服务器负载,避免服务器过载的情况出现。(就是减载)
缺点:占内存(有些缓存会被存到内存中)
http缓存又分为强制缓存和协商缓存。
11.从 URL 输入到页面展现到底发生什么?
首先进行 DNS
域名解析,找到真实 IP
,向服务器发起请求,服务器交给后台处理完成后返回数据,浏览器接收⽂件( HTML
、JS
、CSS
、图象等)并对加载到的资源进⾏语法解析,从而构建DOM树等相应的内部数据结构并渲染页面。
12.setState是同步的还是异步的?
setState在React合成事件和生命周期方法中是异步的,在setTimeout和原生事件处理中是同步的。但是,从React 18开始,所有的setState调用都会自动进行批量处理(异步)。
13.前端性能优化
网络优化:压缩资源、代码拆分(比如拆分成多个小模块按需加载)、CDN加速、优化http请求(比如合并小图标为雪碧图、内联关键 CSS 和 JavaScript 代码等)
页面渲染优化:
懒加载;
防抖和节流;
避免重排与重绘:
直接操作 DOM 元素几何属性、改变布局等会触发重排;修改元素颜色、背景等外观属性引发重绘。减少这类操作,批量修改样式,使用 CSS 过渡动画替代即时 DOM 变动;
优化CSS加载顺序:将关键 CSS (用于首屏渲染的样式)放在文档头部加载,确保页面渲染样式尽早可用;非关键 CSS 放底部异步加载,不阻塞页面渲染。
内存管理优化:
及时清理变量:不再使用的变量、定时器、事件监听,要适时清除,防止内存泄漏;
合理使用闭包。
代码质量优化:
移除冗余代码;
优化算法逻辑;
Tree Shaking(它自动剔除未引入模块代码,打包出更精简的生产包)。
14.前端首屏加载优化
减少入口文件体积,例如使用路由懒加载;
静态资源本地缓存,例如采用http缓存和localStorage;
UI框架按需加载,例如Element UI按需引入要使用的组件;
组件重复打包,例如在webpack
的config
文件中,修改CommonsChunkPlugin
的配置minChunks: 3,表示会把使用3次及以上的包抽离出来,放进公共依赖文件,避免了重复加载组件
图片资源压缩,例如使用雪碧图、使用线字体图标
使用SSR。
15.为什么使用vuex?
组件间数据共享:Vuex可以将数据共享给多个组件共同使用,避免了数据的重复获取和频繁更新,提高了代码的效率和复用性。
复杂状态的管理:当项目中的状态和数据交互变得复杂时,Vuex可以通过集中式存储和管理,将状态的变化和交互逻辑统一管理,提高了代码的可维护性和可读性。
异步操作的处理:Vuex可以将异步操作进行集中处理,使得异步操作的流程更加清晰和易于管理,也可以避免异步操作带来的错误和风险。
用户状态的管理:Vuex可以用于管理用户的登录状态、个人信息等敏感信息,使得应用更加安全和稳定。
代码的组织和模块化:Vuex可以将复杂的业务逻辑和状态管理进行模块化,使得代码更加清晰、易于理解和维护。
可预测性和调试:Vuex提供了一种可预测的状态管理模式,可以清晰地了解状态的变化和流向,方便进行调试和测试。
16.Webpack打包流程。
首先会从配置文件和 Shell 语句中读取与合并参数,并初始化需要使用的插件和配置插件等执行环境所需要的参数;初始化完成后会调用Compiler的run来真正启动webpack编译构建过程,webpack的构建流程包括compilation(开始编译)、make(从入口点分析模块及其依赖的模块,创建这些模块对象 )、build(构建模块)、seal(封装构建结果)、emit阶段,执行完这些阶段就完成了构建过程。
17.Webpack热更新
当代码文件修改并保存之后,webapck通过watch监听到文件发生变化,会对代码文件重新打包生成两个模块补丁文件manifest(js)和一个(或多个)updated chunk(js),将结果存储在内存文件系统中,通过websocket通信机制将重新打包的模块发送到浏览器端,浏览器动态的获取新的模块补丁替换旧的模块。
18.js事件循环机制
JS 主线程不断的循环往复的从任务队列中读取任务,执行任务,这种运行机制称为事件循环(event loop)
浏览器的事件循环(event loop)中分成宏任务和微任务。JS 中任务分成同步任务和异步任务。
-
宏任务(macro task)
JS 中主栈执行的大多数的任务,例如:定时器,事件绑定,ajax,回调函数,node中fs操作模块等就是宏任务
-
微任务(micro task)
promise, async/await, process.nextTick等就是微任务。
JS 中任务的执行顺序优先级是:主栈全局任务(宏任务) > 宏任务中的微任务 > 下一个宏任务。所以 promise(微任务) 的执行顺序优先级高于setTimeout定时器。
19.服务端渲染(SSR)
将组件在服务端直接渲染成 HTML 字符串,作为服务端响应返回给浏览器,最后在浏览器端将静态的 HTML“激活”(hydrate) 为能够交互的客户端应用。
优点:
更快的首屏加载:无需等到所有的 JavaScript 都下载并执行完成之后才显示。数据获取过程在首次访问时在服务端完成,相比于从客户端获取,可能有更快的数据库连接。
统一的心智模型:可以使用相同的语言以及相同的声明式、面向组件的心智模型来开发整个应用,而不需要在后端模板系统和前端框架之间来回切换。
更好的 SEO:搜索引擎爬虫可以直接看到完全渲染的页面。
20.Vue2和Vue3的区别
设计理念上:Vue2是基于Options API而Vue3是基于Composition API
模板编译上:Vue2是直接将模板全部编译成虚拟dom树,每次组件更新时,即使静态内容未发生变化,整个虚拟 DOM 树仍然会重新创建;而Vue3则采用了静态树提升和动态节点追踪机制,将这些静态内容提升到渲染函数的外部,只生成一次,标记动态节点,运行时仅更新这些真正需要变化的部分。
响应式系统上:Vue2是基于Object.defineProperty,通过递归劫持对象的每个属性来实现对数据访问和修改的拦截,但是无法监听新增或删除属性,因此添加了delete作为补充;Vue3是基于ES6的新特性Proxy的捕获器(trap)实现,捕获所有对对象的操作,劫持的是整个对象,而不是单个属性,这使得新增和删除属性、数组操作都能被监控,只有在访问嵌套对象时才会进行代理操作(懒代理)。
组件实现上:Vue2的组件是基于 Vue.extend
创建的,组件本质上是构造函数的实例;Vue3 的组件基于函数式实现,使用 setup
方法初始化逻辑,组件树的更新通过 Fragment
提升性能。
diff算法上:
Vue 2 使用的是基于递归的双指针,Vue 3 使用的是基于数组的动态规划。 Vue 2 会对整个组件树进行完整的遍历和比较; Vue 3的静态节点只会在首次渲染时被处理,后续更新时会跳过静态子树的比较,只对动态节点进行更新。 Vue 2 对于列表渲染(v-for)时的元素重新排序会比较低效,需要通过给每个元素设置唯一的 key 来提高性能;Vue 3在列表渲染时,通过跟踪元素的移动,可以更好地处理元素的重新排序。
生命周期上:Vue 2的beforeCreate和created在Vue 3被setup()替代,beforeDestroy变成了onBeforeUnmount(),destroyed变成了onUnmounted(),其他钩子则是变成了onXxxx的形式。
其他:
使用TS重写,提供了更好的TS支持
支持Tree-shaking
引入了Teleport组件
21.说说你对插槽的理解?
插槽本质上是对子组件的扩展,通过<slot>插槽向子组件内部指定位置传递内容,分为默认插槽、具名插槽和作用域插槽三种。
22.什么是重绘和重排
重排是指重新计算网页布局的过程,而重绘则是根据新的布局信息重新绘制网页的过程。它们的区别在于,重排会导致元素的尺寸、位置、内容等属性的变化,因此需要重新计算布局信息;而重绘则是在元素的位置和尺寸等属性不变的情况下,重新绘制元素的样式。
23.requestIdleCallback和requestAnimationFrame
当每秒绘制的帧数(FPS)达到 60 时,页面是流畅的,小于这个值时,用户会感觉到卡顿。
1s 60帧,所以每一帧分到的时间是 1000/60 ≈ 16 ms。所以我们书写代码时力求不让一帧的工作量超过 16ms。
一帧内需要完成如下六个步骤的任务:处理用户的交互
-
JS 解析执行
-
帧开始。窗口尺寸变更,页面滚去等的处理
-
requestAnimationFrame(rAF)
-
布局
-
绘制
上面六个步骤完成后没超过 16 ms,说明时间有富余,此时就会执行 requestIdleCallback
里注册的任务。
即,requestAnimationFrame每一帧必定会执行,requestIdleCallback是捡浏览器空闲来执行任务。
假如浏览器一直处于非常忙碌的状态,requestIdleCallback 注册的任务有可能永远不会执行。
因为它发生在一帧的最后,此时页面布局已经完成,所以不建议在 requestIdleCallback 里再操作 DOM,这样会导致页面再次重绘。
24.useMemo和useCallback区别和使用场景
useMemo和useCallback都是用来优化性能的Hooks,作用都是通过判断依赖项是否改变来决定是否更新值。
区别是:
useMemo 缓存的结果是回调函数中return回来的值,主要用于缓存计算结果的值,通过减少不必要的复杂计算来优化性能
useCallback缓存的结果是函数,主要用于缓存函数,一般用于给子组件传递回调函数时,减少子组件的渲染次数,从而优化性能。需要注意的是,useCallback应该和React.memo配套使用,缺了一个都可能导致性能不升反而下降。
拓展点:
因为函数式组件每次任何一个state发生变化,会触发整个组件更新,一些函数是没有必要更新的,此时就应该缓存起来,提高性能,减少对资源的浪费。
25.http和https的区别
HTTP 的连接很简单,是无状态的,信息是明文传输;HTTPS 是由 SSL+HTTP 协议构建的可进行加密传输、身份认证的网络协议,比 HTTP 协议安全,但是也更耗费服务器资源,使用 HTTPS 协议需要到 CA申请证书。
HTTP 页面响应速度比 HTTPS 快,主要是因为 HTTP 使用 TCP 三次握手建立连接,客户端和服务器需要交换 3 个包,而 HTTPS除了 TCP 的三个包,还要加上 ssl 握手需要的 9 个包,所以一共是 12 个包。
HTTP 和HTTPS 使用的是完全不同的连接方式,用的端口也不一样,前者是 80,后者是 443。
26.http的特点
工作于客户端/服务端的架构之上;
服务程序规模小而且通信速度很快;
允许传输任意类型的数据对象;
无连接:通信双方都不长久的维持对方的任何信息;
无状态:数据包的发送、传输和接收都是相互独立的。
27.Promise
Promise是异步编程的一种解决方案,比传统的解决方案(回调函数)更加合理和更加强大。
优点:解决了回调地狱的问题、更好地进行错误捕获、更适合处理一次性的结果
缺点:
当处于pending状态时无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)
只能有一个最终值或一个最终错误,无法同时返回多个值
如果不设置回调函数,Promise内部抛出的错误,不会反应到外部
一旦新建它就会立即执行,无法中途取消
28.Vue和React的区别
React 是一个用于构建用户界面的 JavaScript 库,而 Vue 则是一个用于构建 Web 应用程序的 渐进式框架。
React采用的是单向数据流,需要手动setState;Vue是响应式数据驱动的设计思想,可以双向数据绑定,修改数据自动更新视图。
28.RESTful Api的优缺点
优点:
简单直观:RESTful 风格使用标准的 HTTP 方法(GET、POST、PUT、DELETE 等 )来对应资源的读取、创建、更新、删除操作。
可扩展性强
跨平台兼容性好
良好的缓存支持
客户端与服务器之间仅通过资源的表述来交互
缺点:
缺乏统一标准规范
版本管理复杂
安全问题:由于 RESTful 依赖 HTTP 协议,数据传输过程中如果没有额外加密(如 HTTPS),信息易被窃取篡改。而且 RESTful 接口难以直接实现复杂的权限控制与身份验证逻辑,往往要借助外部的鉴权、授权方案来补充。
不适用于实时性要求高的场景
拓展知识点
1.React Hooks
useState - 状态钩子
接收状态的初始值作为参数,返回一个数组,分别是状态值和更新该状态值的函数 。
const [text, setText] = useState('Hello, World');
useContext - 共享状态钩子
用于访问 React context 在组件树中传递的数据,而不必通过每个组件传递 props,接收一个Context对象,返回该给Context对象提供的状态。
// 父组件
// 使用 React Context API,在组件外部建立一个 Context。
const AppContext = React.createContext({});
// 父组件组件封装代码
// 通过AppContext.Provider将状态提供给子组件共享
<AppContext.Provider value={{
username: 'superasome'
}}>
<div className="App">
<Navbar/>
<Message/>
</div>
</AppContext.Provide>
// 子组件中获取共享的状态 - 以Navbar组件为例
const Navbar = () => {
const {username} = useContext(AppContext);
return (
<div className="navbar">
<p>AwesomeSite</p>
<p>{username}</p>
</div>
);
}
useReducer - action钩子
接受 Reducer 函数和状态的初始值作为参数,返回一个数组,分别是当前状态值和发送action的dispatch函数。
const [state, dispatch] = useReducer(reducer, initialState);
useEffect - 副作用钩子
用于执行副作用操作。第一个参数是一个回调函数;第二个参数是一个数组,用于给出Effect的依赖项。当第二个参数被省略时,每次组件渲染就会执行Effect。
useEffect(() => {
// Async Action
}, [dependencies])
useCallback
用于返回一个 memoized 版本的回调函数,防止不必要的渲染。第一个参数是回调函数,第二个参数是依赖数组。
const memoizedCallback = useCallback(
() => {
// 回调函数体
},
[dependencies] // 依赖数组
);
useMemo
用于对计算结果进行记忆,避免在每次渲染时重复计算。第一个参数是回调函数,第二个参数是依赖数组。
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
useRef
useRef可以接受一个默认值,并返回一个含有current属性的可变对象; 使用场景: 1、获取子组件的实例(子组件需为react类继承组件); 2、获取组件中某个DOM元素; 3、用做组件的全局变量,useRef返回对象中含有一个current属性,该属性可以在整个组件色生命周期内不变,不会因为重复render而重复申明,类似于react类继承组件的属性this.xxx一样。原因:由于useState保存的变量会触发组件render,而使用useRef定义全局变量不会触发组件render;
const refContainer = useRef(initialValue);
useImperativeHandle
用于使用 ref 时暴露 DOM 元素的方法。
useImperativeHandle(ref, () => ({
// 暴露的方法
}));
useLayoutEffect
与 useEffect 类似,但它在所有的 DOM 变更之后同步执行。这在需要读取 DOM 布局并同步触发重渲染时非常有用。
useLayoutEffect(() => {
// 副作用操作
}, [dependencies]);
useDebugValue
用于在 React 开发者工具中显示自定义 hook 的标签。
useDebugValue(value);
本文作者:何以之
本文链接:https://www.cnblogs.com/serendipity-echo/p/18668591
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步