react提供了hooks,因此函数组件也可以用hooks进行状态管理并且也可以用useEffect模拟class组件的生命周期。
useEffect中第一个参数是一个执行函数,当第二个参数依赖项不为空数组时,前一个函数中的return会在再次执行useEffect前执行,可以用于回收之前的计时器等。
useEffect的依赖项是做浅比较
useEffect第一个参数是一个回调函数,在依赖项发生变化的时候,会执行它,也被称为副作用函数。 可以在里面进行相应的生命周期阶段的操作,异步请求,设定计时器等,可以通过副作用函数的return来清除副作用,比如回收计时器。
可以模拟三个生命周期函数,分别是componentDidMount,componentDidUpdate,componentWillUnMpunt
区别
两者的区别如下:
虚拟 DOM 不会进行排版与重绘操作,而真实 DOM 会频繁重排与重绘
虚拟 DOM 的总损耗是“虚拟 DOM 增删改+真实 DOM 差异增删改+排版与重绘”,真实 DOM 的总损耗是“真实 DOM 完全增删改+排版与重绘”
优缺点
真实 DOM 的优势:易用
缺点:
效率低,解析速度慢,内存占用量过高 性能差:频繁操作真实 DOM,易于导致重绘与回流
使用虚拟 DOM 的优势如下:
简单方便:如果使用手动操作真实 DOM 来完成页面,繁琐又容易出错,在大规模应用下维护起来也很困难 性能方面:使用 Virtual DOM,能够有效避免真实 DOM 数频繁更新,减少多次引起重绘与回流,提高性能 跨平台:React 借助虚拟 DOM,带来了跨平台的能力,一套代码多端运行
缺点:在一些性能要求极高的应用中虚拟 DOM 无法进行针对性的极致优化 首次渲染大量 DOM 时,由于多了一层虚拟 DOM 的计算,速度比正常稍慢
setState用于设置状态对象
nextState,将要设置的新状态,该状态会和当前的state合并 callback,可选参数,回调函数。该函数会在setState设置成功,且组件重新渲染后调用。 合并nextState和当前state,并重新渲染组件。setState是React事件处理函数中和请求回调函数中触发UI更新的主要方法。
replaceState
replaceState()方法与setState()类似,但是方法只会保留nextState中状态,原state不在nextState中的状态都会被删除.
nextState,将要设置的新状态,该状态会替换当前的state。
callback,可选参数,回调函数。该函数会在replaceState设置成功,且组件重新渲染后调用。
1. 首先react有自己的事件系统,是遵循w3c的,这个事件系统的名称叫做合成事件(SyntheticEvent),而其自定义事件系统的动机主要包含以下几个方面:
抹平不同浏览器之间的兼容性差异。最主要的动机。
件合成既可以处理兼容性问题
提供一个抽象的跨平台事件机制
可以做更多优化
可以干预事件的分发
2. 当给组件(元素)绑定onClick事件之后
(1. react会对事件先进行注册,将事件统一注册到 document上
(2. 根据组件 唯一的标识key来对事件函数进行存储
3. 统一的指定dispatchEvent回调函数
4. 储存事件回调
react会将click这个事件统一存到一个对象中,回调函数的存储采用键值对(key/value)的方式存储在对象中,key 是组件的唯一标识id,value 对应的就是事件的回调函数,通过组件的key就能回调到相应的函数了
理解:
React Fiber 是 Facebook 花费两年余时间对 React 做出的一个重大改变与优化,是对 React 核心算法的一次重新实现。从Facebook在 React Conf 2017 会议上确认,React Fiber 在React 16 版本发布
在react中,主要做了以下的操作:
为每个增加了优先级,优先级高的任务可以中断低优先级的任务。然后再重新,注意是重新执行优先级低的任务。 增加了异步任务,调用requestIdleCallback api,浏览器空闲的时候执行。 dom diff树变成了链表,一个dom对应两个fiber(一个链表),对应两个队列,这都是为找到被中断的任务,重新执行。 从架构角度来看,Fiber 是对 React核心算法(即调和过程)的重写。
从编码角度来看,Fiber是 React内部所定义的一种数据结构,它是 Fiber树结构的节点单位,也就是 React 16 新架构下的虚拟DOM。
解决问题
1、掉帧 在react 15以及之前,还没有fiber的概念, 当虚拟dom量非常大非常复杂时,react在递归进行渲染时会非常耗时,会一直递归进行,会造成页面卡顿掉帧的现象,严重情况下浏览器还可能失去响应。
fiber有协调与提交两个阶段,协调包含了fiber创建与diff更新,此过程可暂停。而提交必须同步执行,保证渲染不卡顿。
2、并发 fiber实现了并发,为任务赋予不同优先级,保证了一有时间总是做最高优先级的事,而不是先来先占位死板的去执行。
常用的中间件
redux-thunk:用于异步操作
redux-logger:用于日志记录
实现原理
redux-thunk是官网推荐的异步处理中间件
默认情况下的dispatch(action),action需要是一个JavaScript的对象
redux-thunk中间件会判断你当前传进来的数据类型,如果是一个函数,将会给函数传入参数值(dispatch,getState)
dispatch函数用于我们之后再次派发action getState函数考虑到我们之后的一些操作需要依赖原来的状态,用于让我们可以获取之前的一些状态
如果想要实现一个日志功能,则可以使用现成的redux-logger
缓存:
缓存是指浏览器(客户端)在本地磁盘中队访问过的资源保存的副本文件。
强缓存: 强缓存是根据返回头中的 Expires 或者 Cache-Control 两个字段来控制的,都是表示资源的缓存有效时间。
协商缓存: 协商缓存是由服务器来确定缓存资源是否可用。 主要涉及到两对属性字段,都是成对出现的,即第一次请求的响应头带上某个字, Last-Modified 或者 Etag,则后续请求则会带上对应的请求字段 If-Modified-Since或者 If-None-Match,若响应头没有 Last-Modified 或者 Etag 字段,则请求头也不会有对应的字段。
区别:
如果浏览器命中强缓存,则不需要给服务器发请求;而协商缓存最终由服务器来决定是否使用缓存,即客户端与服务器之间存在一次通信。 在 chrome 中强缓存(虽然没有发出真实的 http 请求)的请求状态码返回是 200 (fromcache);而协商缓存如果命中走缓存的话,请求的状态码是 304 (not modified)。 不同浏览器的策略不同,在FireFox中,from cache 状态码是 304.
1 如果数据是对象的话,可以监听对象的里面的值,值是基本类型,如果值改变了,那么可以监听执行 2 在去修改对象和数据的时候,使用参拷贝或者浅拷贝,这样地址发生改变可以监听执行 3 可以转成字符串,通过JSON.stringify0,监听字符串这样的,这样改变也会执行
react-redux react官方推出的redux绑定库,react-redux将所有组件分为两大类:UI组件和容器组件,其中所有容器组件包裹着UI组件,构成父子关系。容器组件负责和redux交互,里面使用redux API函数,UI组件负责页面渲染,不使用任何redux API。容器组件会给UI组件传递redux中保存对的状态和操作状态的方法
@reduxjs/toolkit Redux 官方强烈推荐,开箱即用的一个高效的 Redux 开发工具集。它旨在成为标准的 Redux 逻辑开发模式,使用 Redux Toolkit 都可以优化你的代码,使其更可维护
定义
Portal 提供了一种将子节点渲染到存在于父组件以外的 DOM 节点的优秀的方案
使用场景
一个 portal 的典型用例是当父组件有 overflow: hidden 或 z-index 样式时,但你需要子组件能够在视觉上“跳出”其容器。例如,对话框、悬浮卡以及提示框
style-loader: 将css添加到DOM的内联样式标签style里 css-loader :允许将css文件通过require的方式引入,并返回css代码 less-loader: 处理less sass-loader: 处理sass postcss-loader: 用postcss来处理CSS autoprefixer-loader: 处理CSS3属性前缀,已被弃用,建议直接使用postcss file-loader: 分发文件到output目录并返回相对路径 url-loader: 和file-loader类似,但是当文件小于设定的limit时可以返回一个Data Url html-minify-loader: 压缩HTML babel-loader :用babel来转换ES6文件到ES
压缩代码: 删除多余的代码、注释、简化代码的写法等等方式。可以利用webpack的UglifyJsPlugin和ParallelUhlifyPlugin来压缩JS文件,利用cssnano(css-loader?minim ize)来压缩css
利用CDN加速: 在构建过程中,将引用的静态资源路径修改为CDN上对应的路径。可以利用 webpack对于output参数和各种loader的publicPath参数来修改资源路径
Tree Shaking 消除最终文件中未使用的代码。可以通过在启动webpack时追加参数–optimize-minimize来实现
Code Splitting 将代码按路由维度或者组件分块(chunk),这样做到按需加载,同时可以充分利用浏览器缓存
提供公共第三方库 SplitChunksPlugin插件来进行公共模块抽取,利用浏览器缓存可以长期缓存这些无需频繁变动的公共代码
首先,JavaScript是一门单线程的语言,意味着同一时间内只能做一件事,但是这并不意味着单线程就是阻塞,而实现单线程非阻塞的方法就是事件循环 在JavaScript中,所有的任务都可以分为
同步任务:立即执行的任务,同步任务一般会直接进入大屏主线程中执行 异步任务:异步执行的任务,比如ajax网络请求,setTimeout定时函数等
如果将任务划分为同步任务和异步任务并不是那么的准确
微任务
一个需要异步执行的函数,执行时机是在主函数执行结束之后、当前宏任务结束之前
宏任务
宏任务的时间粒度比较大,执行的时间间隔是不能精确控制的,对一些高实时性的需求就不太符合
mixin是面向对象程序设计语言中的类,提供了方法的实现。其他类可以访问mixin类的方法而不必成为其子类; mixin类通常作为功能模块使用,在需要该功能时“混入”,有利于代码复用又避免了多继承的复杂。 本质就是一个JS对象,可以包含组件中的任意功能选项,如data、components、methods、creaded、computed以及生命周期函数等等。 只需要将共用的功能以对象的方式传入mixins选项中,当组件使用mixins对象时所有mixins对象的对象都将被混入该组件本身的选项中来。
一、什么是websocket WebSocket是HTML5下一种新的协议(websocket协议本质上是一个基于tcp的协议) 它实现了浏览器与服务器全双工通信,能更好的节省服务器资源和带宽并达到实时通讯的目的 Websocket是一个持久化的协议
二、websocket的原理
websocket约定了一个通信的规范,通过一个握手的机制,客户端和服务器之间能建立一个类似tcp的连接,从而方便它们之间的通信 在websocket出现之前,web交互一般是基于http协议的短连接或者长连接 websocket是一种全新的协议,不属于http无状态协议,协议名为"ws"
(1)for in遍历的是数组的索引(即键名),而for of遍历的是数组元素值
(2)for in总是得到对象的key或数组、字符串的下标
(3)for of总是得到对象的value或数组、字符串的值
(4)for in是ES5里的,for…of是ES6里的
cors跨域: 服务端进行接口请求设置,前端直接调用 jsonp: jsonp跨域-前端适配,后端配合, 前后端同时改造 接口代理: 通过修改nginx服务器配置实现代理转发 前端修改,后端不
代码中调用 setState函数之后,React会将传入的参数对象与组件当前的状态合并,然后触发所谓的调和过程(Reconciliation)。
经过调和过程,React会以相对高效的方式根据新的状态构建 React 元素树并且着手重新渲染整个 UI 界面;
在 React 得到元素树之后,React会自动计算出新的树与老树的节点差异,然后根据差异对界面进行最小化重渲染;
在差异计算算法中,React能够相对精确地知道哪些位置发生了改变以及应该如何改变,这就保证了按需更新,而不是全部重新渲染。
书写JSX代码 Babel编译JSX 编译后的JSX执行React.createElement的调用 传入到ReactElement方法中生成虚拟Dom 最终返回给ReactDom.render生成真实Dom
CommonJS CommonJS: nodejs中的模块化机制,模块通过require()引入,exports或modules.exports导出
规范的特点:
当使用require命令加载某个模块时,就会运行整个模块的代码。 对于基本数据类型,属于复制。即会被模块缓存。同时,在另一个模块可以对该模块输出的变量重新赋值。 对于复杂数据类型,属于浅拷贝。由于两个模块引用的对象指向同一个内存空间,因此对该模块的值做修改时会影响另一个模块 循环加载时,属于加载时执行 执行流程:
根据CommonJS规范,一个单独的文件就是一个模块。每一个模块都是一个单独的作用域,也就是说,在该模块内部定义的变量,无法被其他模块读取,除非定义为global对象的属性 模块输出:模块只有一个出口,module.exports对象,我们需要把模块希望输出的内容放入该对象 加载模块:加载模块使用require方法,该方法读取一个文件并执行,返回文件内部的module.exports对象 AMD AMD: 上面的commonjs主要适用于node.js这种后端模块化,其中的require引用是同步的,前端环境中有很多异步的情况,因此commonjs是不够用的,AMD就出现了。
多个js文件可能有依赖关系,被依赖的文件需要早于依赖它的文件加载到浏览器 js加载的时候浏览器会停止页面渲染,加载文件越多,页面失去响应时间越长 CMD CMD: 规范是阿里的玉伯提出来的,实现js库为sea.js。和requirejs非常相似,也是前端异步加载模块化。不同的是它的模块是需要的时候去请求,而不是先加载再使用。RequireJS用的就是AMD,AMD用define定义方法,用require引用模块。
AMD与CMD区别: 最明显的区别就是在模块定义时对依赖的处理不同 AMD推崇依赖前置,在定义模块的时候就要声明其依赖的模块 CMD推崇就近依赖,只有在用到某个模块的时候再去require
什么是koa?
Koa是一个精简的node框架,被认为是第二代Node框架,其最大的特点就是独特的中间件流程控制,是一个典型的洋葱模型,它的核心工作包括下面两个方面:
将node原生的req和res封装成为一个context对象。 基于async/await的中间件洋葱模型机制。
什么是洋葱模型。
Koa的洋葱模型是以next()函数为分割点,先由外到内执行Request的逻辑,然后再由内到外执行Response的逻辑,这里的request的逻辑,我们可以理解为是next之前的内容,response的逻辑是next函数之后的内容,也可以说每一个中间件都有两次处理时机。洋葱模型的核心原理主要是借助compose方法
一、版本的格式
patch:修复bug,兼容老版本
minor:新增功能,兼容老版本
major:新的架构调整,不兼容老版本
二、依赖版本号规则
这三个依赖分别使用了三个符号来表明依赖的版本范围。语义化版本范围规定:
*:升级到最新版本
^:升级次版本号和修订号
~:只升级修订号
三、必须匹配某个版本
version
必须大于某个版本 如:>1.1.2,表示必须大于1.1.2版
=version
可大于或等于某个版本 如:>=1.1.2,表示可以等于1.1.2,也可以大于1.1.2版本
<=version 可以小于或等于某个版本 如:<=1.1.2,表示可以等于1.1.2,也可以小于1.1.2版本
设备像素是设备屏幕上的物理像素,CSS像素是网页上的逻辑像素,设备独立像素是指在不同设备上显示相同大小的像素,dpr是设备像素和CSS像素的比例,ppi是每英寸像素数。设备像素和CSS像素的比例由dpr决定,而设备独立像素则是通过dpr和ppi计算得出的。
TCP需要三次握手是为了建立可靠的连接,第一次握手是客户端向服务器发送一个SYN包,请求建立连接;第二次握手是服务器收到SYN包后,向客户端发送一个SYN+ACK包,表示同意建立连接;第三次握手是客户端收到SYN+ACK包后,向服务器发送一个ACK包,表示连接建立成功。这样可以确保双方都能收到对方的信息,建立可靠的连接。
TCP需要四次挥手是为了断开连接,第一次挥手是客户端向服务器发送一个FIN包,请求断开连接;第二次挥手是服务器收到FIN包后,向客户端发送一个ACK包,表示已经收到请求;第三次挥手是服务器向客户端发送一个FIN包,请求断开连接;第四次挥手是客户端收到FIN包后,向服务器发送一个ACK包,表示已经收到请求。这样可以确保双方都能安全地断开连接。
react新出的哪两个钩子函数? 新出的getDerivedStateFromProps 与 getSnapshotBeforeUpdate 两个钩子。 少了componentWillMount,componentWillReceiveProps与componentWillUpdate三个都带有will的钩子。
1、getDerivedStateFromProps 这个钩子的作用其实就是从props获取衍生的state。getDerivedStateFromProps中返回一个对象用于更新当前组件的state,而不是直接取代。
2、getSnapshotBeforeUpdate 这个钩子的意思其实就是再组件更新前获取快照,此方法一般是结合componentDidUpdate使用,getSnapshotBeforeUpdate中返回的值将作为第三参数传递给componentDidUpdate。
为什么删掉will? 三个钩子函数是被废弃,但是不是直接不能用了,而是官方会给出警告并推荐我们在这三个钩子前添加UNSAFE_前缀。 为什么被废弃呢,因为使用率并不太高,这三个钩子很容易被误解和滥用,这几个钩子不稳定。
使用clear:both清除浮动
使用overflow:hidden清除浮动
使用伪元素::after清除浮动
Git merge是将两个分支合并成一个新的分支,它会将两个分支的修改合并到一起,形成一个新的提交。Git rebase也是将两个分支合并成一个新的分支,但是它会将当前分支的修改放到目标分支的最后面,形成一个线性的提交历史。区别在于,Git merge会保留原有的提交历史,而Git rebase会将原有的提交历史改写成一条直线。
在Redux中,定义Action-Type的常量是一种良好的编程习惯,可以提高代码的可读性和可维护性。为了防止定义的Action-Type常量重复,可以使用一些工具来帮助自动生成唯一的常量,例如使用uuid或者shortid等库。
具体来说,可以按照以下步骤来防止定义的Action-Type常量重复:
安装uuid或者shortid等库:可以使用npm或者yarn等包管理工具进行安装,例如:npm install uuid。 生成唯一的Action-Type常量:可以使用uuid或者shortid等库生成唯一的Action-Type常量,例如: import uuid from ‘uuid’; const ADD_TODO = ADD_TODO_${uuid.v4()}; 这样生成的ADD_TODO常量就是唯一的,可以避免与其他常量重复。
统一管理Action-Type常量:可以将所有的Action-Type常量都统一放在一个文件中进行管理,例如:
// ActionTypes.js import uuid from 'uuid';
export const ADD_TODO = ADD_TODO_${uuid.v4()}
; export const REMOVE_TODO = REMOVE_TODO_${uuid.v4()}
; export const EDIT_TODO = EDIT_TODO_${uuid.v4()}
;
// 其他常量… 这样可以方便地进行管理和维护,同时也避免了常量重复的问题。
总之,为了防止定义的Action-Type常量重复,可以使用一些工具来帮助自动生成唯一的常量,例如使用uuid或者shortid等库。同时,将所有的Action-Type常量统一放在一个文件中进行管理也是一个良好的编程习惯。
Vuex是Vue.js应用程序的状态管理模式和库。它充当应用程序中所有组件的集中存储,规则确保状态只能以可预测的方式发生变化。
Vuex的核心原理是将应用程序的状态保存在一个存储区中,该存储区负责管理整个应用程序的状况。存储是通过实例化Vuex.store对象来创建的,该对象以具有多个财产的对象作为参数。
import Vuex from 'vuex' import Vue from 'vue'
Vue.use(Vuex)
const store = new Vuex.Store({ state: { count: 0 } })
1、父组件向子组件传递数据 props
父组件通过 props 向子组件传递数据,子组件通过 $emit 和父组件通信
props的特点:
props只能是父组件向子组件进行传值,props使得父子组件之间形成一个单向的下行绑定。子组件的数据会随着父组件的更新而响应式更新。
2.子组件向父组件传递数据($emit的用法)
$emit的特点:
$emit 绑定一个自定义事件,当这个事件被执行的时候就会将参数传递给父组件,而父组件通过v-on监听并接收参数
3.兄弟组件通信
兄弟组件通信可以借助父组件交互
A组件 B组件
A组件数据传递给共同的父组件 再有父组件接受后传递给B组件
通过 $parent + $refs 以父组件为中间人来获取到兄弟组件,也可以进行通信。
4.Props/Events
Props是一种从父组件向子组件传递数据的方式,通过在子组件上设置props属性,可以实现数据的单向流动。而Events是一种从子组件向父组件传递数据的方式,通过在子组件上使用$emit方法触发事件,可以将数据传递给父组件。 5.$parent/$children Vue组件实例上提供了$parent和$children两个属性,可以分别访问父组件和子组件的实例。通过访问$parent和$children,可以实现跨级组件之间的通信。 6.$refs $refs是Vue组件实例上提供的一个属性,可以用来访问子组件实例或DOM元素。通过使用$refs,可以在父组件中访问子组件的属性和方法。 7.EventBus EventBus是一种基于事件的组件通信方式。通过在全局创建一个EventBus实例,可以在不同的组件中通过触发和监听事件来实现数据的传递和共享。 8.Vuex Vuex是Vue.js官方提供的状态管理库,可以用来管理应用程序中的共享状态。通过使用Vuex,可以实现组件之间的数据共享和通信,从而避免了通过props和events等方式手动传递数据的繁琐和复杂性。 需要根据实际情况选择合适的组件通信方式,避免过度使用全局事件和状态共享等方式带来的性能和维护性问题。
一、什么是CDN? CDN全程是Content Delivery Network,即内容分发网络。
CDN是构建在现有网络基础之上的智能虚拟网络,依靠部署在各地的边缘服务器,通过中心平台的负载均衡、内容分发、调度等功能模块,使用户就近获取所需内容,降低网络堵塞,提高用户访问响应速度和命中率。
CDN的关键技术主要有内容存储和分发技术。
简单来说,CDN就是根据用户位置分配最近的资源。
二、CDN的功能特点: (1)节省骨干网带宽,减少带宽需求量;
(2)提供服务器端加速,解决由于用户访问量大造成的服务器过载问题;
(3)服务商能使用Web Cache技术在本地缓存用户访问过的Web页面和对象,实现相同对象的访问无须占用主干的出口带宽,并提高用户访问因特网页面的相应时间的需求;
(4)能克服网站分布不均的问题,并且能降低网站自身建设和维护成本;
(5)降低“通信风暴”的影响,提高网络访问的稳定性
三、CDN的作用有哪些? 远程加速 若用户使用远程访问会根据DNS负载均衡的技术智能选择服务器,加快远程访问的速度 镜像服务 有效的解决了不同运营商之间互联瓶颈而造成的影响,实现了跨运营商的网络加速。 带宽优化 自动生成镜像Cache服务器,远程用户访问时可以直接从Cache服务器抓取数据,减轻源站点的负载。 抗攻击 各个CDN节点智能冗余机制,有效的防御黑客入侵攻击,并且抵制DDOS攻击对网站的影响。 四、使用CDN有什么好处? 使用CDN可以获取一些好处,无论它们是公有CDN还是提供静态内容的私有CDN,你的里程可能会有所不同,具体取决于通过CDN传递的流量以及你产生的流量。
用户在浏览器地址栏中输入URL。
浏览器将URL发送给DNS服务器,以获取域名的IP地址。
DNS服务器返回IP地址给浏览器。
浏览器使用HTTP协议向服务器发送请求。
服务器接收请求并返回响应。
浏览器接收响应并解析HTML代码。
浏览器根据HTML代码渲染页面。
页面加载完成后,浏览器会执行JavaScript代码。
页面加载完成后,浏览器会发送异步请求,如AJAX请求,以获取更多数据。
页面加载完成后,浏览器会将页面缓存起来,以便下次访问时更快地加载。
浏览器内核是指浏览器所采用的渲染引擎和JavaScript解释器,它们共同组成了浏览器的核心部分,负责解析和渲染网页内容,实现网页的布局、样式和交互等功能。
常见的浏览器内核包括:
Webkit内核:主要用于Safari、Chrome等浏览器,是一种基于C++的开源渲染引擎,它支持HTML、CSS、JavaScript等各种Web技术。 Gecko内核:主要用于Firefox等浏览器,是一种基于C++的开源渲染引擎,它支持HTML、CSS、JavaScript等各种Web技术。 Trident内核:主要用于IE浏览器,是一种基于C++的闭源渲染引擎,它支持HTML、CSS等Web技术,但对JavaScript的支持较弱。 Blink内核:主要用于Chrome等浏览器,是一种基于C++的开源渲染引擎,它是Webkit的分支,支持HTML、CSS、JavaScript等各种Web技术。
浏览器内核的作用是将网页的HTML、CSS、JavaScript等代码解析成可视化的网页,实现网页的布局、样式和交互等功能。不同的浏览器内核有着不同的特点和优缺点,开发者在开发网站时需要考虑不同内核的兼容性问题,以确保网站在各种浏览器中都能够正常访问。
闭包是指在函数内部创建一个新的作用域,并且该作用域可以访问函数外部的变量。简单来说,闭包就是函数和函数内部能访问到的变量的组合。
闭包的应用场景有很多,其中一些比较常见的包括:
封装变量:由于闭包可以访问函数外部的变量,因此可以使用闭包来封装私有变量,避免变量被外部访问和修改,从而保证程序的安全性和稳定性。 实现模块化:由于闭包可以创建独立的作用域,因此可以用闭包来实现模块化的开发方式,将变量和方法封装在一个闭包中,从而避免命名冲突和变量污染。 延迟执行:由于闭包可以访问函数外部的变量,因此可以用闭包来实现某些需要延迟执行的操作,例如setTimeout等。 缓存变量:由于闭包可以访问函数外部的变量,因此可以用闭包来缓存一些计算结果,避免重复计算,提高程序的性能。 实现回调函数:由于闭包可以访问函数外部的变量,因此可以用闭包来实现一些回调函数的功能,例如事件处理函数等。
总之,闭包是一种非常重要的JavaScript特性,它可以用于实现很多常见的编程需求,例如封装变量、实现模块化、实现回调函数等。但是,由于闭包会占用内存和资源,因此开发者在使用闭包时需要注意内存管理和性能优化。
props和state是React中两个非常重要的概念,它们用于管理组件的数据和状态。
相同点:
都是用于管理组件的数据和状态。 都可以触发组件的重新渲染。 都是React组件的内部状态,外部无法直接访问和修改。
不同点:
数据来源不同:props通常是由父组件传递给子组件的,而state通常是组件内部自己维护的。 可修改性不同:props是只读的,不能在组件内部直接修改,而state是可读写的,可以在组件内部修改。 更新方式不同:props的更新通常是由父组件触发的,而state的更新通常是由组件自身触发的。 render方法在哪些情况下会执行?
组件第一次挂载时会执行render方法。 组件的props或state发生变化时会执行render方法。 父组件重新渲染时,子组件也会重新渲染,因此render方法也会执行。 强制更新组件时,render方法也会执行。 总之,render方法是React组件中非常重要的一个方法,它用于根据当前组件的props和state生成对应的UI。在组件的生命周期中,render方法会在多个时机被执行,以保证组件的渲染和更新。
shouldComponentUpdate(nextProps, nextState)
nextProps: 表示下一个props。 nextState: 表示下一个state的值。 官方API解释道根据 shouldComponentUpdate() 的返回值,判断 React 组件的输出是否受当前 state 或 props 更改的影响。默认行为是 state 每次发生变化组件都会重新渲染。大部分情况下,你应该遵循默认行为。
shouldComponentUpdate(nextProps, nextState){ //组件是否需要更新,需要返回一个布尔值,返回true则更新,返回flase不更新,这是一个关键点 console.log('shouldComponentUpdate组件是否应该更新,需要返回布尔值',nextProps, nextState) return true } 当 props 或 state 发生变化时,shouldComponentUpdate() 会在渲染执行之前被调用。返回值默认为 true。首次渲染或使用 forceUpdate() 时不会调用该方法。
使用shouldComponentUpdate性能优化 React中props,state值的变化,会导致组件重新渲染。使用shouldComponentUpdate就是为了减少render不必要的渲染。 返回布尔值,然后做 Virtual DOM 比较,并得出是否需要做真实 DOM 更新,尽管React的虚拟算法复杂度已经有了很多优化,但是在大规模组件更新时,依然会是个不必要的损耗。会带来很多无必要的渲染并成为性能瓶颈。接下来使用来这个生命周期来解决吧
在React中,使用map函数来遍历props.children时,可能会收到异常显示。这是因为props.children不一定是数组类型,有可能是字符串、数字、布尔值、null或undefined等非数组类型,如果尝试对非数组类型使用map函数来遍历,就会出现异常。 为了遍历props.children,可以使用React.Children.map函数来遍历。React.Children.map函数可以遍历props.children,并对每个子元素执行指定的回调函数。该函数的语法如下: React.Children.map(children, function[(thisArg)]) 其中,children是要遍历的子元素,function是要执行的回调函数,thisArg是可选的回调函数中的this对象。
断点续传是一种文件传输技术,可以在文件传输过程中断开连接后自动恢复传输。对于大文件的传输,断点续传技术可以提高传输的可靠性和效率。下面是一些实现断点续传的方法: HTTP Range 请求 HTTP Range 请求是一种用于请求部分数据的 HTTP 请求,可以用于实现断点续传。在 HTTP Range 请求中,客户端可以指定请求数据的范围,服务器只返回指定范围内的数据。通过多次发送 HTTP Range 请求,可以实现大文件的断点续传。 文件分片 文件分片是一种将大文件分成多个小文件的方法,每个小文件可以独立传输。通过将大文件分成多个小文件,可以实现断点续传和多线程传输,从而提高传输的效率和可靠性。 断点续传协议 断点续传协议是一种专门用于文件传输的协议,例如 BitTorrent 协议。在断点续传协议中,文件被分成多个小块,每个小块可以独立传输,从而实现断点续传和多线程传输。 总之,实现断点续传需要根据具体情况选择合适的方法和技术,例如 HTTP Range 请求、文件分片和断点续传协议等。在实际开发中,需要考虑文件传输的可靠性、效率和安全性等因素,从而选择合适的断点续传方案。
Redux本来是同步的,但是在实际应用中,经常需要处理异步数据流,例如网络请求、定时器等,因此Redux提供了一些方便的方式来处理异步数据流,例如使用中间件、使用异步Action等。
实现原理:
使用中间件:Redux中间件是一个函数,它可以对Redux的dispatch方法进行增强,从而实现一些额外的功能,例如异步操作、打印日志、错误处理等。使用中间件可以方便地处理异步操作,例如使用thunk中间件来处理异步Action。 使用异步Action:Redux中的Action本质上是一个JavaScript对象,它描述了应用中发生的事件,例如用户点击按钮、网络请求返回等。但是,Redux并没有限制Action必须是同步的,因此可以使用异步Action来处理异步数据流。异步Action可以返回一个函数,该函数可以在内部执行异步操作,然后再通过dispatch方法来触发真正的Action。
中间件的实现原理:
中间件是一个函数,它接收Redux Store的dispatch方法和getState方法作为参数,并返回一个函数,该函数可以接收一个next参数,表示下一个中间件或者Redux Store的dispatch方法。中间件的实现原理如下: 中间件函数接收dispatch和getState方法作为参数,返回一个函数。 返回的函数接收next参数,表示下一个中间件或者Redux Store的dispatch方法。 返回的函数内部定义一个新的dispatch方法,它可以在原始的dispatch方法前后执行一些额外的逻辑,例如打印日志、处理错误等。 返回的函数最终返回next(action)或者dispatch(action),表示将action传递给下一个中间件或者Redux Store的dispatch方法。
同步action:执行了dispatch函数之后,对应的reducer纯函数立即得到执行,reducer执行完了之后,state立即就改变了,此时用store.getState函数,取到的是最新的state值; 异步action:原则上redux并没有提供异步action的处理方案,异步的action需要依赖第三方的中间件解决(如redux-thunk),dispatch了一个异步action(本质上是dispatch的一个函数)之后,目标state并不会立即响应,而是要看异步函数内部的逻辑,来决定state什么时候响应
redux-thunk redux-thunk相当于是基于store的升级,一般情况,我们传给store的action是一个对象,但是通过redux-thunk中间件,我们可以把部分的业务逻辑(异步请求)等放在action中进行处理。当store接收到函数类型的action,redux-thunk会执行该函数,并传入参数dispatch,当函数内部的逻辑执行完成后,会再次派发一个action继续向下执行。
redux-saga 在store的index文件中创建saga中间件连接到store,saga中间件可以监控派发的action,如果有action.type值与监控的变量一致,则执行该函数的内容,在这个函数中也可以再次派发一个新的action。
使用场景 两者都是在发送后端请求需要使用异步代码的时候使用
区别 redux-thunk:通过执行action中的函数实现业务逻辑,没有拓展API redux-saga:通过定义saga函数进行监控,同时提供一些常用的API redux-thunk将部分异步处理业务逻辑写在action中,redux-sagasaga则是放在监控的函数中。
44.为什么for循环比forEach性能高?
一、for( )循环 通过下标,对循环中的代码反复执行,功能强大,可以通过index取得元素。在处理比较复杂的处理的时候较为方便
二、forEach( )循环 forEach() 方法用于调用数组的每个元素,并将元素传递给回调函数。foreach有的也叫增强for循环,foreach其实是for循环的一个特殊简化版。注意,forEach() 对于空数组是不会执行回调函数的 三、for和forEach的区别 【3.1】遍历
for循环按顺序遍历,forEach使用iterator迭代器遍历
【3.2】数据结构
for循环是随机访问元素,foreach是顺序链表访问元素
【3.3】性能上
对于arraylist,是顺序表,使用for循环可以顺序访问,速度较快;使用foreach会比for循环稍慢一些。 对于linkedlist,是单链表,使用for循环每次都要从第一个元素读取next域来读取,速度非常慢;使用foreach可以直接读取当前结点,数据较快;
理解
Immutable Data 就是一旦创建,就不能再被更改的数据。对 Immutable 对象的任何修改或添加删除操作都会返回一个新的 Immutable 对象。Immutable 实现的原理是 Persistent Data Structure(持久化数据结构),也就是使用旧数据创建新数据时,要保证旧数据同时可用且不变。同时为了避免 deepCopy 把所有节点都复制一遍带来的性能损耗,Immutable 使用了Structural Sharing(结构共享),即如果对象树中一个节点发生变化,只修改这个节点和受它影响的父节点,其它节点则进行共享。
优点
降低 Mutable 带来的复杂度
节省内存空间
Undo/Redo,Copy/Paste,随意穿越!
拥抱函数式编程
缺点
容易与原生对象混
移动端适配是Web开发中非常重要的一环,因为不同的移动设备具有不同的屏幕尺寸、分辨率和像素密度,如果不进行适配,页面可能会出现布局错乱、字体过小、图片模糊等问题。在移动端适配中,我通常采用以下几种方法:
使用Viewport:Viewport是一种显示网页内容的区域,它的大小可以随着设备的屏幕尺寸和方向而变化。在移动端适配中,可以通过设置Viewport的meta标签来控制页面的缩放比例,例如:
这样可以让页面自适应设备的屏幕尺寸,并保持页面的比例不变。
使用媒体查询:媒体查询是CSS3中的一个功能,它可以根据设备的屏幕尺寸和方向来动态改变页面的样式,例如:
@media screen and (max-width: 768px) { /* 在屏幕宽度小于等于768px时应用的样式 */ } 这样可以针对不同的设备尺寸和方向设置不同的样式,从而实现移动端适配。
使用rem布局:rem是相对于根元素(即html元素)的字体大小来计算的单位,它的大小不会受到设备像素密度的影响。在移动端适配中,可以将根元素的字体大小设置为设备宽度的一定比例,例如:
html { font-size: calc(100vw / 7.5); /* 以7.5rem为基准 */ } 这样可以根据设备的屏幕宽度来动态调整字体大小和布局,从而实现移动端适配。
总之,移动端适配是Web开发中非常重要的一环,可以通过使用Viewport、媒体查询和rem布局等方法来实现适配。开发者在使用这些方法时,需要充分了解不同设备的特点和适配方法,以便更好地实现移动端适配。
使用响应式设计:通过使用百分比、弹性布局和媒体查询等技术,确保网站或应用程序能够在各种尺寸的屏幕上正确显示。
使用相对单位:使用相对单位(如em、rem)来设置字体大小、间距和元素大小,而不是使用固定单位(如px)。
确定基准宽度:通过了解目标设备的分辨率和视口宽度,选择合适的基准宽度,以便根据比例进行缩放。
使用CSS框架:使用流行的CSS框架(如Bootstrap、Foundation等)可以简化响应式设计和移动端适配的工作。
测试和调试:在移动设备上测试网站或应用程序,并根据需要进行调整,以确保良好的用户体验。
在移动端开发中,1像素的问题是一个比较普遍的问题,由于不同设备的像素密度不同,所以1像素的线在高像素密度的设备上会显得比较粗,影响页面的美观性和用户体验。为了解决1像素的问题,可以采用以下几种解决方案:
使用CSS3的scale属性:可以通过CSS3的scale属性将1像素的线条缩小到0.5像素,从而达到更细的效果,这样可以将1像素的线条缩小到0.5像素,从而达到更细的效果。
使用伪元素:可以通过在元素的before或after伪元素中添加1像素的线条,并将伪元素的高度设置为0.5像素,从而达到更细的效果 这样可以将1像素的线条缩小到0.5像素,并将伪元素的高度设置为0.5像素,从而达到更细的效果。这样可以将1像素的线条的宽度设置为0.01rem,从而达到更细的效果。
总之,在移动端开发中,1像素的问题是一个比较普遍的问题,可以通过使用CSS3的scale属性、伪元素和viewport单位等方法来解决。开发者在使用这些方法时,需要考虑不同设备的像素密度和适配方法,以便更好地实现1像素效果。
使用CSS3的缩放属性:将元素按比例缩小,再将样式属性放大,以达到1像素的效果。
使用viewport单位:使用vw和vh作为单位来设置元素宽度和高度,从而避免因不同设备像素密度导致的显示问题。
使用border-image:使用border-image属性设置边框图片,可以解决1像素边框模糊的问题。
使用伪类元素:通过:before和:after等伪类元素来实现1像素边框的效果。
使用JavaScript:在页面加载时,根据设备像素密度动态计算像素值,以达到1像素的效果。
弹性盒模型中的缩放机制通过 flex-shrink
和 flex-grow
属性来实现。
flex-shrink
属性定义了项目在容器缩小时所应该减少的比例,它接受一个无单位的数字作为值,默认值为 1
。当容器空间不足时,会根据所有项目的 flex-shrink
值的比例来计算每个项目所占据的空间的减少量。
flex-grow
属性定义了项目在容器放大时所应该增加的比例,它也接受一个无单位的数字作为值,默认值为 0
。当容器空间有剩余时,会根据所有项目的 flex-grow
值的比例来计算每个项目所占据的空间的增加量。
这些属性可以用来实现弹性布局,并且能够自适应地适应不同尺寸的屏幕和设备。
优化代码和资源:对于JS、CSS、图片等前端资源进行压缩、合并、去重等操作,以减少文件大小,提高加载速度。
使用CDN加速:使用内容分发网络(CDN)来加速静态资源的加载,减轻服务器负载,提高用户访问速度。
前端渲染与服务端渲染结合:在首屏加载时,可以采用服务端渲染,将页面的HTML等静态内容直接返回给浏览器,减少浏览器渲染时间,提高网站性能。
懒加载:对于非首屏内容,可以采用懒加载方式,当用户需要查看相应内容时再进行加载,减少首次加载时间。
预加载:对于用户可能会访问的页面或资源,可以通过预加载的方式提前加载好,使得用户访问时无需再进行加载,提升用户体验。
调和: 协调, 协调过程的官方定义: VirtualDOM是一种编程概念, 在这个概念中, UI以一种理想化的, 或者说 虚拟的 表现形式保存在内存中, 并通过 ReactDOM 等类库使之与 真实的DOM 同步. 这个过程叫做协调(调和) 调和是将虚拟DOM映射到真实DOM的过程, 严格来说并不能和Diff画等号 调和是使一致的过程 Diff是找不同的过程, Diff只是调和的一个环节
调和指的是将虚拟 DOM映射到真实 DOM 的过程。因此严格来说,调和过程并不能和 Diff 画等号,调和是“使一致”的过程,而 Diff 是“找不同”的过程,它只是“使一致”过程中的一个环节
Diff算法性能突破的关键点在于 分层对比 类型一致的节点才有继续Diff的必要性 key属性的设置,可以帮助我们尽可能重用同一层级内的节点
装饰器是一种特殊类型的声明,它能够被附加到类声明,方法, 访问符,属性或参数上
是一种在不改变原类和使用继承的情况下,动态地扩展对象功能
同样的,本质也不是什么高大上的结构,就是一个普通的函数,@expression 的形式其实是Object.defineProperty的语法糖
expression求值后必须也是一个函数,它会在运行时被调用,被装饰的声明信息做为参数传入
方法/属性装饰 同样,装饰器可以用于修饰类的方法,这时候装饰器函数接收的参数变成了:
target:对象的原型
propertyKey:方法的名称
descriptor:方法的属性描述符
可以看到,这三个属性实际就是Object.defineProperty的三个参数,如果是类的属性,则没有传递第三个参数
我们以首次渲染为切入点,拆解 Fiber 架构下 ReactDOM.render 所触发的渲染链路,结合源码理解整个链路中所涉及的初始化、render 和 commit等过程
TypeScript是由Microsoft Corporation开发和维护的面向对象的编程语言。它是JavaScript的超集,包含所有元素。
TypeScript完全遵循OOPS概念,在TSC(TypeScript编译器)的帮助下,我们可以将Typescript代码(.ts文件)转换为JavaScript(.js文件)。
为什么要使用TypeScript
TypeScript的设计目的应该是解决JavaScript的“痛点”:弱类型和没有命名空间,导致很难模块化,不适合开发大型程序。另外它还提供了一些语法糖来帮助大家更方便地实践面向对象的编程。
TypeScript简化了JavaScript代码,使其更易于阅读和调试。
TypeScript是开源的。
TypeScript为JavaScript IDE和实践提供了高效的开发工具,例如静态检查。
使用TypeScript,我们可以比普通的JavaScript做出巨大的改进。
TypeScript为我们提供了ES6(ECMAScript 6)的所有优点,以及更高的工作效率。
TypeScript可以帮助我们避免开发人员通过类型检查代码编写JavaScript时经常遇到的痛苦错误。
强大的类型系统,包括泛型。
TypeScript代码可以按照ES5和ES6标准进行编译,以支持最新的浏览器。
支持静态类型。
TypeScript将节省开发人员的时间。
为什么使用泛型 TypeScript 中不建议使用 any 类型,不能保证类型安全,调试时缺乏完整的信息。
TypeScript可以使用泛型来创建可重用的组件。支持当前数据类型,同时也能支持未来的数据类型。扩展灵活。可以在编译时发现你的类型错误,从而保证了类型安全。
什么是泛型
泛型的本质是参数化类型,通俗的将就是所操作的数据类型被指定为一个参数,这种参数类型可以用在类、接口和方法的创建中,分别成为泛型类,泛型接口、泛型方法。
TypeScript中的泛型跟java中的泛型基本类似。
虚拟dom的理解 实际上它只是一层对真实DOM的抽象,以JavaScript对象(VNode节点)作为基础的树,用对象的属性来描述节点,最终可以通过一系列操作时这棵树映射到真实环境上,创建虚拟DOM就是为了更好将虚拟的节点渲染到页面视图中,所以虚拟DOM对象的节点与真实DOM的属性一一照应
虚拟DOM的实现原理 通过JS模拟网页文档节点,生成JS对象树(虚拟DOM),然后再进行一步生成真实的DOM树,再绘制到屏幕。如果后面有内容发生改变,React会重新生成一棵全新的虚拟DOM树,再与前面的虚拟DOM树进行比对diff,把差异的部分打包成patch,再应用到真实DOM,然后渲染到屏幕浏览器。
diff .React需要同时维护两棵虚拟DOM树:一棵表示当前的DOM结构,另一棵在React状态变更将要重新渲染时生成。React通过比较这两棵树的差异,决定是否需要修改DOM结构,以及如何修改。这种算法称作Diff算法。
key 当同一层级的某个节点添加了对于其他同级节点唯一的key属性,当它在当前层级的位置发生了变化后。react diff算法通过新旧节点比较后,如果发现了key值相同的新旧节点,就会执行移动操作(然后依然按原策略深入节点内部的差异对比更新),而不会执行原策略的删除旧节点,创建新节点的操作。这无疑大大提高了React性能和渲染效率
实则用到了diff算法中的element 层对比,