css
1.HTML5新增了哪些内容
- 语义化更好的内容标签(header,footer,main,nav,aside,article,section)
- 音频 ,视频标签(audio, video)
- 画布(canvas)
- 表单控件 calendar , date , time , email , url , search , tel , file , number
- 地理位置API(geolocation)
- 拖拽释放API(Drap and drop)
- WebAPI:localStorage、sessionStorage、webworker、websocket
2.CSS3新增了哪些内容
- 颜色: 新增 RGBA , HSLA 模式
- 文字阴影(text-shadow)
- 边框: 圆角(border-radius) 边框阴影 : box-shadow
- 盒子模型: box-sizing
- 背景:background-size background-origin background-clip
- 渐变: linear-gradient , radial-gradient
- 过渡 : transition 可实现属性的渐变
- 自定义动画 animate @keyfrom
- 媒体查询 多栏布局 @media screen and (width:800px) {…}
- border-image 图片边框
- 2D 转换/3D 转换;transform: translate(x,y) rotate(x,y) skew(x,y) scale(x,y)
- 字体图标 iconfont/icomoon
- 弹性布局 flex
3.什么是HTML语义化
- HTML语义化是指使用合适的HTML标签做合适的事,既是不使用css属性也可以将网页内容以文档的形式展现出来。
- 有助于提高网站的可访问性和搜索引擎优化(SEO),便于浏览器、搜索引擎以及其他设备(如屏幕阅读器)解析和理解网站内容。
4.常见的布局方式
- 表格布局:由 <table> 标签定义。每个表格均有若干行( <tr>),每行被分割为若干单元格(<td>)。
- 浮动布局:通过float属性创建浮动元素,实现浮动布局。浮动布局会脱离文档流,容易造成父元素高度塌陷问题。
- 定位布局:通过postion属性创建定位元素,以精确控制网页对象的显示位置,布局精准,不会出现错行和误差问题;缺点是缺乏灵活性,栏目之间不能够协同变化,还会存在叠加等风险。
- 流动布局:流动布局是HTML默认的布局方式,通过百分比控制元素尺寸,随文档流自上而下按顺序动态分布。
- 弹性布局:和浮动一样都用于网页布局,但flex比浮动要更强大。flex不会产生脱标现象,布局网页更灵活、更简单
- 栅格布局:与弹性布局相似,栅格系统也是由栅格容器包裹栅格元素进行使用。对于栅格布局来说,它的思想实际上非常简单,将一块区域绘制成格子,然后将元素填进去即可
5.弹性布局和栅格布局
- Flex布局:
Flexible Box
的缩写,也称为弹性布局
。W3C于
2009年提出。是一种以轴线为标准的一种布局方式。 - Grid布局:
Grid 布局
又称为网格布局
,微软于 2010 年提出。是一种将容器划分为单元格的布局形式。 - 总结:布局的操作性和复杂度上来看,
Grid
布局要比Flex
布局强大,但是Grid会有一些浏览器兼容性、响应式设计、性能优化等问题
6.圣杯布局和双飞翼布局
- 最终效果相同,两侧宽度固定,中间宽度自适应(三栏布局)
- 圣杯布局代码结构上更加自然和直观,在平时的开发中更容易形成这样的布局结构;
- 双飞翼布局由于不使用定位,所以代码更加简洁,允许页面的最小宽度小于圣杯布局。
7.px、em、rem、vwwh、%
- px:表示计算机的像素单位,1像素就是1px
- em:相对于元素font-size大小的单位
- rem:相对于根元素font-size大小的单位
- vwvh:相对于浏览器可视窗口尺寸的单位
- %:相对于父元素尺寸的单位
- calc()方法可以进行不同单位之间的运算
8.媒体查询
- 媒体查询允许根据不同的设备或屏幕尺寸和分辨率应用不同的样式。是创建响应式页面的关键。
- 媒体查询的组成:
- @media:创建媒体查询
- 媒体类型:定义了媒体查询适用的设备类型。例如,
all
适用于所有设备,print
用于打印机和打印预览模式,screen
用于电脑屏幕、平板和智能手机等,speech
适用于基于语音识别的设备。 - 媒体特性:在媒体查询中使用的条件,如宽度(width)、高度(height)和颜色等,用于限制样式的应用条件。
9.css盒模型
- 盒子模型分为两种:
- W3C 标准的盒子模型(标准盒模型)可以通过box-sizing:content-box来设置;
- IE 标准的盒子模型(怪异盒模型)可以通过box-sizing:border-box来设置;
- 标准盒模型与怪异盒模型的表现效果的区别之处:
- 标准盒模型下盒子的大小 = content + border + padding + margin
- 怪异盒模型下盒子的大小=width(content + border + padding) + margin
10.css选择器权重
!Important > 行内样式 > ID选择器 > 类选择器 > 标签 > 通配符 > 继承 > 浏览器默认属性
11.如何实现一个元素水平居中
- 块级元素
- postion:abslute;
top:50%;
left:50%;
transform:translate(-50%,-50%); - display:flex;
justify-content:center;
align-items:center; - display: grid;
place-items: center;
- postion:abslute;
- 行内元素
- text-align:center;
line-height:20px;
- text-align:center;
12.css中哪些属性是可以继承的、哪些是不可以继承的
- 能继承的属性
- 字体系列属性:font、font-size、font-weight、font-family、font-style;
- 文本系列属性:
- 内联元素:color、line-height、text-align
- 块级元素:text-align、text-indent;
- 元素可见性:visibility
- 不能继承的属性
- 盒子模型的属性:display、overflow、width、height、min-width、min-height、max-width、max-height、margin、padding、border;
- 背景属性:background、background-color、background-image;
- 定位属性:float、clear、position、top、right、bottom、left;
13.Input元素type属性值
- text 默认。定义单行输入字段,用户可在其中输入文本。默认是 20 个字符;
- password 定义密码字段。字段中的字符会被遮蔽;
- search 定义用于搜索的文本字段;
- number 定义带有 spinner 控件的数字字段;
- email 定义用于 e-mail 地址的文本字段;
- url 定义用于 URL 的文本字段;
- radio 定义单选按钮。
- checkbox 定义复选框。
- button 定义可点击的按钮(大多与 JavaScript 使用来启动脚本)
- reset 重置按钮,用于重置表单数据。
- submit 定义提交按钮。提交按钮向服务器发送数据。
- range 滑动条,用于选择一个范围内的值
- color 定义拾色器。
- image 定义图像作为提交按钮;
- file 定义输入字段和 "浏览..." 按钮,供文件上传
- date 定义日期字段(带有 calendar 控件)
- month 定义日期字段的月(带有 calendar 控件)
- time 定义日期字段的时、分、秒(带有 time 控件)
14.display和visibility的区别
- dispaly:none 设置该属性后,该元素下的元素都会隐藏,占据的空间消失;visibility:hidden 设置该元素后,元素虽然不可见了,但是依然占据空间的位置
- visibility 具有继承性,其子元素也会继承此属性。
- display:none 会引起回流(重排)和重绘 visibility:hidden 会引起重绘。
15.BFC模式
- BFC(Block formatting context)直译为"块级格式化上下文"。它是一个独立的渲染区域, 只有 Block-level box 参与,它规定了内部的 Block-level Box 如何布局,并且与这个区域 外部毫不相干。
- 哪些元素会生成 BFC:
- 元素变为浮动元素,即加float样式(非none)
- 元素变为定位元素,即加position样式(值为absolute或fixed)
- 元素变为弹性元素,即加display:flex
- 给父级元素设置 overflow:hidden 或 overflow:auto
- 元素变为行内块显示模式
16.如何清除浮动
- 方案1 BFC模式:让标准流中父容器变为BFC模式,这样就可以保证父容器中子元素渲染不会影响外界了(即:不会引起父容器高度变化)
- 方案2 clear:利用clear样式来清除浮动引起的父容器高度塌陷。在浮动元素后添加一个元素,并设置其clear属性为both。这会使得该元素下移,直到其顶部在所有前面的左浮动和右浮动元素下面。
- 方案3 伪元素:在父元素中添加一个伪元素(::before,::after),并设置其clear属性为both。这种方法的优点是不需要添加额外的HTML元素。
17.如何解决margin塌陷问题
- **第一种情况:**两个同级元素,垂直排列,上面的盒子给 margin-bottom 下面的盒子给margin-top,那么他们两个的间距会重叠,以大的那个计算。
- 解决方法:两个外边距不同时出现
- **第二种情况:**两个父子元素,内部的盒子给 margin-top,其父级也会受到影响,同时产生上边距,父子元素会进行粘连。解决方案:
- 为父盒子设置 border
- 为父盒子设定 padding 值
- 为父盒子添加 overflow:hidden;
- 为父盒子添加 position:fixed;
- 为父盒子添加 display:table;
18.伪类和伪元素
- 伪类
- :target 选择器可用于选取当前活动的目标元素。
- :checked 选中 单选框或复选框被选中 的元素
- :disabled 选中禁用状态下的表单控件
- :hover 鼠标悬浮状态下
:first-child
匹配第一个子元素。- :last-child 匹配最后一个子元素。
- :nth-child(n) 选择属于其父元素的第 n 个子元素并且必须是<p>元素
- :nth-last-child(n) 选择属于其父元素的倒数第 n 个子元素并且必须是<p>元素
- :nth-of-type(n) 选择属于其父元素第 n 个<p>元素
- :nth-last-of-type(n) 选择属于其父元素倒数第 n 个<p>元素
- 伪元素
- ::before 在元素前插入一个伪元素
- ::after 在元素后面插入一个伪元素
::first-letter
匹配元素中文本的首字母。::first-line
匹配元素中第一行的文本(只能在块元素中使用)。::selection
匹配被用户选中的部分。
19.伪类和伪元素的区别
- 伪类存在的意义是为了通过选择器,格式化DOM树以外的信息以及不能被常规CSS选择器获取到的信息。伪元素可以创建一些文档语言无法创建的虚拟元素。
- 伪类用单冒号:表示;而伪元素用双冒号::表示。
- 一个选择器可以同时使用多个伪类(但有的伪类会互斥);而一个选择器只能同时使用一个伪元素(未来的版本可能会支持多伪元素)。
20.使用css如何让浏览器支持比12px小的字体,比如10px
针对谷歌浏览器内核,加 webkit 前缀,用 transform:scale()这个属性进行缩放!
p span{
display:block;
font-size:10px;
-webkit-transform:scale(0.8); //缩放
}
21.为什么要使用less、sass
- 嵌套:允许子选择器嵌套在父选择器内,提高样式的可读性,缓解css命名冲突问题;
- 变量:允许定义和重复使用样式中的值,轻松管理颜色、字体大小等属性;
- 混合(Minxins):可以创建样式块,实现样式的重用;
- 继承:允许选择器继承另一个选择器的样式,以提高代码的复用性;
- 函数:允许自定义函数,以便执行各种操作。
22.less和sass的区别
less | sass | |
---|---|---|
实现方式 | 基于JavaScript,是在客户端 进行处理的 | 基于Ruby,是在服务器端 进行处理的 |
语法 | 大括号 | 缩进 |
定义变量 | @ | $ |
变量作用域 | 全局、局部 | 全局(可以通过在变量后跟!default 改变变量的属性值) |
混合(Mixins) | 直接命名、直接通过命名调用 | 通过@mixin定义、通过@include引入 |
继承 | .a { &:extend(.b) } | .a { @extend .b } |
解析方式 | Less可以向上/向下解析 | Sass只能向上解析 |
其他 | @if、@else、@for、@while、@each、@function、扩展scss |
JavaScript
1.js的数据类型有哪些
- 基本类型:null,undfiend,boolean,number,string,symbol,bigin
- 引用类型:Object(包含Object,Array,Function)
2.ES6新增了哪些内容
let块级作用域声明方式、const声明常量、箭头函数、模版字符串、解构赋值、展开运算符、模块、class类、Set、Map、Promise
3.常用的运行算符
- 算术运算符:+ - * / % ++ -- **
- 比较运算符:== === != !== > < >= <=
- 逻辑运算符:&& || !
- 展开运算符
- 三元运算符
4.运算符的优先级(从高到低)
-
小括号
()
-
一元运算符
delete ++ -- !
-
算术运算符 先乘除
*
/ % 后加减
+
- -
移位运算符
<< >>
-
比较运算符 先大小
>
< >= <= 后相等 == !=
-
按位运算符
&
^
|
-
逻辑运算符
&& ||
-
三元运算符
-
赋值
= += -= *= /= %= &= |= ^= <<= >>= >>>=
5.说一下innerHTML 与 innerText的作用与区别?
- 作用:都可以获取或者设置元素的内容
- 区别:innerHTML可以解析内容中的html标签
- innerText不能解析内容中的html标签
6.JavaScript 由以下三部分组成:
- ECMAScript:是JavaScript的核心,描述了语言的基本语法和数据类型。它是一套标准,定义了一种语言的规范,规定了基本语法、数据类型、关键字等的设计规范,也是解析引擎设计的参考标准,但与具体实现无关。
- DOM(文档对象模型):是一套操作页面元素的API,可以把HTML看做是文档树,通过DOM提供的API可以对树上的节点进行操作,从而改变页面的内容和结构。
- BOM(浏览器对象模型):是一套操作浏览器功能的API,通过BOM可以操作浏览器窗口,比如弹出框、控制浏览器跳转、获取分辨率等,与浏览器交互的部分功能都是通过BOM来实现的。
7.介绍 JS 有哪些内置对象?
- 数据封装类对象:Object、Array、Boolean、Number、String
- 其他对象:Function、Arguments、Math、Date、RegExp、Error
- ES6 新增对象:Symbol、Map、Set、Promises、Proxy、Reflect
8.说几条写 JavaScript 书写的基本规范?
- 代码一定要正确缩进,建议使用"二个或者四个空格"缩进
- 语句结束使用分号;
- 规范定义 JSON 对象,补全双引号
- 用{}和[]声明对象和数组
- 变量和函数在使用前进行声明
- 以大写字母开头命名构造函数,全大写命名常量
- 代码段使用花括号{}包裹
- 还有要书写正确的标识标签
9.什么是标识符?
- 在JS中,可以自定义命名的东西都属性标识符;
- 比如变量名,函数名,参数名都是标识符
10.offsetWidth,clientWidth,scrollWidth的区别?
- offsetWidth返回值包含 content + padding + border + 包含滚动条;
- clientWidth返回值只包含 content + padding,不包含滚动条;
- scrollWidth返回值包含 content + padding + 溢出内容的尺寸;
11.解释什么是Json
- json是一种轻量级的数据交换格式,一般用于数据传递
- 里边只允许出现双引号
- JSON的语法表示三种类型值,简单值(字符串,数值,布尔值,null), 数组,对象
12.检测数据类型的方法有哪些
- typeof:基本类型检测;
- instanceof:判断a是否是b的实例;
- Object.prototype.toString.call() :使用call把Object对象的toString方法指向value,获取value的原生构造函数名;
- constructor:属性可能会被改写,导致检测结果不准确;
13.为什么typeof检测null等于object
null 其实属于自己的类型 Null,而不属于Object类型。因为JavaScript 数据类型在底层是以二进制的形式表示的,二进制的前三位为 0 会被 typeof 判断为对象类型,null 的二进制位恰好都是 0 ,因此,null 被误判断为 Object 类型。 属于javascript历史遗留问题。
14.为什么typeof检测Array等于object
在JavaScript里 array 的原型是object.prototype,所以array会显示object
15.为什么typeof检测函数不等于object
如果一个对象实现了[[call]]方法就是function,否则为object。
16.null和undfiend的区别
- null。表示一个空的对象指针,通常用于表示一个变量不包含任何对象。在JavaScript中,null被视为一个空值或缺少值的对象指针,它是一个被明确赋予的值,用来表示没有有效的对象引用。转化为数值是0
- undefined。表示一个未初始化(未定义)的值,通常用于表示尚未赋值的变量。在JavaScript中,undefined是一个全局变量,在没有被赋值的情况下,默认的初始值就是undefined。当你尝试使用一个未初始化的变量时,JavaScript引擎会返回undefined。转化为数值是NAN。
17.其他类型转化成数值
- null 转换之后是 0
- undefined 转换之后是 NaN
- Object 转换之后是 NaN
- String
- 如果字符串中都是数值, 那么就可以正常转换
- 如果字符串是一个空串
""
/" "
, 那么转换之后就是0
- 如果字符串中不仅仅是数字, 那么转换之后是
NaN
- Boolean
true
转换之后是1
false
转换之后是0
- Array
- 空数组,当将其转换成number时,得到的结果为0;
- 只有一个数字成员的数组,得到的结果是该数字;
- 多个数字成员的数组,得到的结果为NaN;
18.介绍一下symbol?怎么迭代symbol描述的键?
- symbol是js为了解决命名冲突而引入的一种ES6新的基本数据类型,表示独一无表示独一无二的值。
- 独一无二性:每个 Symbol 值都是唯一的,无法通过简单的值比较相等。
- 不可变性:Symbol 值一旦创建,就不能被修改。
- 隐藏性:使用 Symbol 作为属性键,这些属性对于常规的对象遍历和操作是不可见的。
- 作为属性键:Symbol 可以作为对象的属性键,用于创建对象的私有属性或隐藏属性,以避免命名冲突。
- symbol常用的的方法
- Symbol.for() 全局符号注册表
- Symbol.keyFor() 查询全局注册表
- Object.getOwnPropertySymbols() 获取对象内部symbol命名的key
- Reflect.ownKeys() 获取对象内部所有的key
19.介绍一下bigint?为什么会出现bigint
- bigint是js为了解决数值过大导致的精度失真问题而引入的一种ES6新的基本数据类型,表示表示任意长度的整数。
- bigint不能直接和普通数据类型进行运算,必须保证参与运算的值都是bigint类型
- 创建bigint的方式有两种
- 在一个整数字面量后面添加一个字母
n
,如9007199254740991n
- 使用
BigInt()
函数将普通整数值转换为BigInt类型,如BigInt(9007199254740991)
- 在一个整数字面量后面添加一个字母
20.var、let、const的作用
- var :变量声明方式,声明的变量具有变量提升,一般情况下会提升到全局,但是在函数内部会形成局部变量。支持重复声明,支持修改。
- let:块级作用域声明方式,不具备变量提升。不支持重复声明,支持修改。
- const:常量声明方式,不具备变量提升。不支持重复声明,不支持修改。
21.const声明的引用类型数据可以修改吗
因为const只能浅层检测引用类型数据指针(地址),所以不能直接修改引用类型数据的指针(地址),但是可以修改引用类型数据内部的元素。
22.Math常用的方法
- min、max、abs绝对值、PI、pow幂、sqrt平方根、sell向上取整、floor向下取整、trunc保留整数位、round四舍五入、random随机数
23.数值常用的方法
- toFixed(digits):将数字转换为指定小数位数的字符串。
- toPrecision(precision):将数字转换为指定有效位数的字符串。
- isNaN(value):检查一个值是否为 NaN(非数字)
- isFinite(value):检查一个值是否是有限数。
- parseInt(string, radix):将字符串解析为整数。
- parseFloat(string):将字符串解析为浮点数。
- Number()将其他类型数据转化成数值
24.字符串常用的方法
- 不改变原字符串:trim、toLowerCase、toUpperCase、chartAt、includes、indexOf、lastIndexOf、search、match、startsWith、endsWith、silce、substr、substring、replace、replaceAll、concat、repeat、split。
25.函数常用的方法
- call、apply、bind
25.对象常用的方法
- 不改变原对象:Object.keys、Object.values、Object.entries、Object.isFrozen、obj.hasOwnProperty、key in obj
- 改变原对象:Ovject.create、Object.assign、Object.freeze、Object.defineProperty、Object.defineProperties
26.数组常用的方法
- 改变原数组:push、pop、unshift、shift、store、reverse、splice、fill;
- 不改变原数组:at、includes、indexOf、lastIndexOf、slice、concat、flat(Infinity)、toString、join、some、every、find、findindex、forEach、Map、flatMap、filter、reduce、reduceRight
27.伪数组
- 伪数组的特征
- 具有length属性;
- 按索引方式存储数据;
- 不具有数组的方法.
- 伪数组转数组的方法
- Array.from()
- Array.prototype.slice.call()
- 展开运算符(...)
- 常见的伪数组
- new Set()
- arguments
- document.getElementsByClassName('div')
28.循环语句
- while:while 语句只要指定条件为 true,就会执行循环
- 参数1:必须。定义执行循环的条件
- do/while:先执行一次代码块,再检查条件是否为真,为真就继续循环
- 参数1:必须。定义执行循环的条件
- for:可以指定代码块循环的次数
- 参数1:可选,初始化的变量,也可以指定多个;
- 参数2:可选,条件判断语句;
- 参数3:可选,每次循环后执行的语句;
- for/of:用于遍历数组
- 参数1:必须。数组的元素。
- 参数2:必须。指定遍历的数组。
- for in:用于迭代对象或者数组
- 参数1:必须。对象的键或数组的索引。
- 参数2:必须。指定迭代的的对象或者数组。
- forEach:遍历数组
- 参数1:对数组元素执行的回调函数
- 参数2:this指向
- forEach没有返回值
29.forEach、for中断循环、跳出循环?
- forEach:中断循环try/catch/throw;跳出当前循环return;
- for:中断循环break;跳出当前循环continue;
30.for of为什么不可以遍历对象
对象是不可迭代的。es6中引入了iterator接口,只有提供了iterator接口的数据类型才可以使用“for-of”来循环遍历;而普通对象默认没有提供iterator接口,因此无法用“for-of”来进行遍历。
31.字符串slice和substring的区别
- 都可以从字符串中指定起止位置提取并返回一个新的字符串,且不修改原数组。
- 两者第二个参数都可以省略(默认提取到字符串末尾)。
- slice如果参数是负数,则表示从字符串的尾部开始计数,。
- substring如果任一参数是负数,它会被视为0。
32.数组去重的方法有哪些
- Array.from(new Set())
- arr.filter((item, index) => arr.indexOf(item) === index);
- arr.reduce((total, item) => (total?.includes(item) ? total : [...total, item]) , []);
33.数组拍平的方法有哪些
- arr.flat(Infinity)
- arr.toString().split(',').map((item) => Number(item));
- arr.reduce((total, item) => (Array.isArray(item) ? [...total, ...flat(item)] : [...total, item]),[],);
34.arguments
- 在JavaScript函数内部,arguments对象是一个类数组对象,它存储了函数被调用时传递的所有参数。
- 动态参数列表:arguments对象可以接受任意数量的参数。这意味着你可以在调用函数时传递任意数量的参数,而不需要在函数定义中明确指定形式参数的个数。
- 通过索引访问参数:可以通过arguments对象的索引来访问函数的参数。例如,arguments[0]表示第一个参数,arguments[1]表示第二个参数,以此类推。
- 类数组对象:虽然arguments对象看起来像一个数组,但它并不是一个真正的数组。它没有数组特有的方法,如push()和pop(),但可以通过length属性获取参数的数量。
35.什么是纯函数
- 返回值取决于参数
- 不依赖于外部状态,也不改变外部状态的函数
36.匿名函数(IIFN)
- 匿名函数,即没有名称的函数
- 如果单独只写一个匿名函数,此时是不符合语法要求的 会报错。需要给 匿名函数包裹一个括号,使之成为表达式。
- 被小括号包裹的内容会被js识别为一个函数表达式
37.什么是闭包函数
- 在函数内部声明一个函数,并且使用了外部函数的变量,被称为闭包函数
- 闭包函数的优点:实现私有属性和方法,减少对外界的污染;
- 闭包函数的缺点:外部函数执行完之后,内部函数不会被销毁,造成变量长期贮存,占用内存空间
- 解决闭包:使用call,apply,bind改变内部函数的this指向;内部函数改用箭头函数
- 使用场景:防抖、节流、缓存、封装私有变量、函数柯里化等
38.函数柯里化
概念:把一个接收多个参数的函数变成接收单一参数 并且返回能够接收新参数的函数
39.什么是递归函数
- 一个函数直接或间接地调用自身,称为递归。
- 常用场景:遍历属性结构、生成斐波那契数列、深拷贝
40.什么是回调函数
- 在javascript中,回调函数指的是一个被作为参数传递给另一个函数的函数;
- 回调函数本身不是异步的,但是可以通过异步机制(例如事件循环、Promises、async/await)来实现异步行为,例如定时器、延时器、axios请求、hooks、事件
41.箭头函数和普通函数的区别
- this指向。箭头函数的this在定义时就已经确定,不会在运行时改变,它继承自外围作用域的this值;普通函数的this在运行时确定,可以通过call、apply、bind方法改变。
- 原型属性。箭头函数没有原型属性;普通函数有原型属性
- 构造函数。箭头函数不能作为构造函数使用,不能通过new关键字调用;普通函数可以作为构造函数使用。
- 语法形式。箭头函数使用=>符号定义,而普通函数使用function关键字定义
- 函数体语法。箭头函数的函数体可以省略括号,但有一定的限制。如果箭头函数的函数体只有一行语句,则可以省略大括号和return关键字;如果箭头函数的函数体多于一行语句,则必须使用大括号和return关键字;普通函数的函数体必须使用大括号。
- arguments对象。箭头函数不绑定arguments对象,但可以通过剩余参数代替;普通函数有arguments对象,用于存储所有传递的参数
- Generator函数。箭头函数不能作为Generator函数使用,不能使用yield关键字;普通函数可以作为Generator函数。
42.Generator函数
- Generator函数是一种特殊类型的函数,它可以在执行过程中暂停并在需要时恢复执行。当Generator函数被调用时,它并不会立即执行,而是返回一个遍历器对象(Iterator),这个对象可以逐步遍历Generator函数的内部状态。
- Generator函数使用步骤
- Generator 函数使用
function*
声明,通过yield
关键字产生一个值,并挂起函数的执行。 - 可以通过调用
iterator.next()
方法逐一遍历迭代器对象,也可以为其传参,执行后标记为未完成。 - 当运行到
iterator.return()
语句时,迭代器对象会被标记为“完成”,不再产生新的值。
- Generator 函数使用
- iterator对象的方法:
- next()逐一遍历迭代器对象
- return()返回return的对象同时停止迭代
- throw()中断迭代
- 主要用途包括:解决回调地狱、迭代和生成无限序列、替代回调函数。
function
* generator() {
yield
'one'
;
yield
'two'
;
return
'done'
;
}
const iterator = generator(); //
返回一个遍历器对象
console.log(iterator.next());
//{ value: 'one', done: false }
console.log(iterator.next());
//{ value: 'two', done: false }
console.log(iterator.next());
//{ value: 'done', done: true }
43.防抖和节流
- 防抖(debounce)和节流(throttle)是性能优化中常用的两种技术,用以控制函数执行的频率,以减少计算资源的使用。
- 防抖:指的是在一定时间内,对于频繁触发的事件,重新计算时间,只让其最后一次触发时执行。例如搜索框、页面改变大小。
- 节流:指的是在一定时间内,对于频繁触发的事件,只让其执行一次,例如:触底加载、页鼠标不断点击时。
44.引用类型和值类型的区别
值类型 | 基本数据类型 | |
---|---|---|
存储位置 | 栈(stack) | 指针存放在 栈(stack)、实体存放在 堆(heap) |
数据大小 | 固定 | 不固定 |
占用空间 | 小 | 大 |
存取速度 | 块 | 慢 |
数据类型 | 简单 | 复杂、可嵌套 |
访问方式 | 按值访问 | 按指针访问 |
45.什么是深拷贝和浅拷贝
- 深拷贝。只复制对象内容,不复制对象的指针,拷贝出来的对象是一个全新的对象,修改这个新对象的时候,不会影响源对象。
- 浅拷贝。只复制对象的指针,不复制对象的内容,拷贝出来的新对象指针还是指向原来的对象。修改这个新对象时,原来的对象也会被修改。引用类型的数据,默认都是浅拷贝。
46.深拷贝的方法
- JSON.stringfy(JSON.parse())
- 取不到值为 undefined 的 key;
- 如果对象里有函数,函数无法被拷贝下来;
- 无法拷贝copyObj对象原型链上的属性和方法;
- 展开运算符:只能进行浅层的拷贝
- Object.assign :只能进行浅层的拷贝
- 递归实现深拷贝
- 在递归过程中,需要记录已经遍历过的对象。
- 需要处理不同数据类型(如数组和对象)。
- 使用插件实现
- lodash的cloneDeep函数
- Immutable.js生成不可变数组或对象(Map不可变对象 List不可变数组)
47.什么是同步任务和异步任务
- js是一门单线程语言,单线程意味着所有任务都需要排队,只有前一个任务执行完之后,才能执行下一个任务。这种情况显然是不合理的,比如说我挂起一个30秒的延时器,那么后面的任务就会被阻塞,导致cpu空闲且无法执行其他任务。针对这一情况,javascript把这些阻塞进程的任务统一放在了异步任务队列中等待执行,任务队列通知主线程某个异步任务可以执行了,这个异步任务就会被放在主线程中按顺序执行。
- 同步任务(synchronous)就是主线程中的任务,按照顺序一个个的执行,比如:普通函数、new Promise()、console.log()等等
- 异步任务 (asynchronous) 就是任务队列中的、会阻塞到进程的任务,只有“任务队列”通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。比如:DOM 事件回调、定时器回调、网络请求的回调、promise.then()、promise.catch()的回调。异步任务又分为宏任务和微任务:
- 宏列队 macrotask queue:用来保存待执行的宏任务(回调),比如:DOM 事件回调、定时器回调、网络请求的回调
- 微列队 microtask queue:用来保存待执行的微任务(回调),优先级高于宏任务,比如:promise.then()、promise.catch()、MutationObserver 、queueMiscrotask()
48.宏任务和微任务的区别
- 执行优先级不同。宏任务的优先级相对较低,而微任务的优先级较高。
- 执行时机不同。宏任务会被添加到事件队列中,在每个事件循环中执行一次;微任务会在当前宏任务执行完毕后立即执行,而不会添加到事件队列中,微任务的执行时机是在当前宏任务的末尾,在下一个宏任务之前。
- 用途不同。宏任务通常包括定时器任务(如setTimeout、setInterval)、网络请求、用户交互事件(如点击、滚动等),这些是相对较大的任务,需要等待一定时间或特定的触发条件才会执行;微任务通常包括Promise回调、DOM变动观察器等,这些是相对较小的任务,适合在当前宏任务执行完毕后立即执行。
- 总结:宏任务是事件循环中的较大任务,通常处理用户交互、渲染等任务;微任务是较小的任务,通常用于处理异步操作的结果,由于微任务具有较高的优先级,它们可以在用户交互之前或渲染之前得到及时处理。
49.Promise的作用
- Promise的主要作用是处理异步操作。它允许你以更同步的方式编写异步代码,提高了代码的可读性和可维护性。
- 处理异步任务结果。Promise区分成功(resolve)和失败(reject)的状态,使得错误处理更加明确和直接。
- 避免回调地狱。Promise对象可以链式调用,减少嵌套回调的使用,避免代码过于复杂和难以管理。
- 支持并发操作。例如,使用Promise.all()可以并行执行多个操作,等待所有操作完成后执行某些逻辑。
- 便于代码的模块化和复用。通过将异步操作封装成Promise对象,可以提高代码的复用性和模块化程度。
50.promise的三种状态?怎么改变promise的状态
- 等待中(Pending)。这是Promise的初始状态,表示异步操作尚未开始或结果尚未确定。
- 已完成(Fulfilled)。当异步操作成功完成并返回结果时,Promise的状态变为Fulfilled。
- 已拒绝(Rejected)。当异步操作执行失败时,Promise的状态变为Rejected。
51.Promise.then和Promise.catch
- Promise函数有两个参数resolve和reject,当我们调用resolve()时,Promise函数会从等待状态变为成功状态,当我们调用reject()时,Promise函数会从等待状态变为失败状态。
.then():在promise函数中调用
resolve()后执行的函数,用于处理执行成功的结果。可以通过resolve(参数)获得参数。.catch():在promise函数中调用
reject()后执行的函数,用于处理执行失败的结果。可以通过reject(参数)获得参数。- .then和.catch都属于异步任务中的微任务。
52.promise.all和promise.race的区别
Promise.all
和Promise.race
都是用于处理多个Promise实例的方法,但它们的行为和用途有所不同。Promise.all
。接收一个Promise数组作为参数。只有所有结果都执行成功或失败的时候,才会变为成功状态或者失败状态,否则仍然会处于等待状态。如果所有Promise都执行成功,则返回所有执行成功的结果。如果有一个执行失败,就会返回第一个执行失败的结果。Promise.race
。接收一个Promise数组作为参数,返回的第一个执行成功的Promise结果。romise.all
适用于需要等待所有异步操作完成再进行下一步处理的场景,例如并行下载多个文件并将它们合并为一个文件;Promise.race
适用于需要在多个异步操作中获取最先完成的结果的场景,例如设置超时机制或不知道哪个接口响应更快的情形。
53.proimse是同步还是异步
Promise本身是同步的。Promise是一个用于异步编程的对象,它允许你以同步的方式编写异步代码,但Promise对象本身在创建时立即执行,不会造成主线程的阻塞。然而,Promise的回调函数,如then()和catch(),是异步执行的,它们会在当前脚本的所有同步任务执行完毕后调用。
54.promise.then的交替执行
如果是单个promise实例,即使有多个then,仍然会按照顺序执行。如果是多个promise实例同时调用.then,then会出现交替执行的情况。这个是编译器做的优化,主要是为了避免某一个promise占用的时间太长。
55.怎么解决回调地狱
- promise实现链式调用
- generator函数
- async/await
56.不使用promise能否把请求数据返回出来?
- async/await
- generator函数
- 回调函数(类似于react中的子父传值)
57.async和await
async
和await
是ECMAScript 2017 (ES8)标准引入的新特性,用于简化异步操作。async:用于修饰一个异步操作的函数
,该函数返回一个Promise对象。如果函数中没有返回值,会默认返回一个Promise对象。如果在函数中 return 一个直接量,async 会把这个直接量通过Promise.resolve()
封装成 Promise 对象;- await:用来等待一个异步方法执行完成。后面await如果是一个 Promise 对象,返回该Promise执行成功或者失败的结果。如果不是 Promise 对象,就直接返回对应的值。注意await 只能出现在 async 函数中,await会阻塞进程。
58.原型和原型链
- 每个对象都有一个prototype属性,表示对象的原型(prototype也是一个对象)。
- prototype作为对象的内部属性,是不能被直接访问的,但是可以通过__proto__来访问。
- 原型链,当访问对象的属性或方法时,首先对象会从自身去找,找不到就会往原型(prototype)中去找,如果原型(prototype)中找不到,就会往原型后面的原型上去找,这样就形成了链式的结构,称为原型链。
- 原型链的最顶层是Object,在往上就是null。
59.this指向问题
- 全局作用域中的函数:非严格模式下其内部this指向window
- 对象内部的函数:其内部this指向对象本身:
- 构造函数:其内部this指向生成的实例:
- 由apply、call、bind改造的函数:其this指向第一个参数:
- 箭头函数:箭头函数没有自己的this,看其外层的是否有函数,如果有,外层函数的this就是内部箭头函数的this,如果没有,则this是window。(函数定义时的this,而不是调用时this)
60.怎么改变this指向?
- call():在改变this指向的同时会调用函数
- apply():在改变this指向的同时会调用函数,第二个参数接收的是一个数组。
- bind():在改变this指向的同时不会调用原来的函数,而使生成并调用一个新的已经改变过this指向的函数
61.new做了什么
- 在内存创建一个新对象
- 把构造函数中this指向新建的对象
- 会在新对象上添加一个__proto__属性,指向函数的原型对象prototype
- 判断函数返回值,如果值是引用类型就直接返回值;否则返回this(创建的新对象)
62.构造函数
- 什么是构造函数:JS中的任何一个普通函数,当用new关键字来调用时,它就是构造函数。构造函数与函数定义无关,与调用方法有关。构造函数一般首字母大写。
- 构造函数的目的:在JavaScript中,构造函数是用来初始化新创建的对象的函数。构造函数的主要目的是在创建对象时初始化对象的属性。
- 构造函数的意义:使用对象字面量创建一系列同一类型的对象时,这些对象可能具有一些相似的属性和方法,此时会产生很多重复的代码,把这些重复性的特征和属性抽象出来,做成构造函数,可以实现代码复用。
- 构造函数的作用:构造新对象,设置对象的属性和方法。创建对象时完成初始化,当我们在new一个对象并传入参数的时候,会自动调用构造函数并完成参数的初始化。
- 常见的构造函数:Object、Array、String、Boolean、Number、Date等。
- 构造函数的this指向:
- 当以函数的形式调用时,this是window
- 当以方法的形式调用时,谁调用方法this就是谁
- 当以构造函数的形式调用时,this就是新创建的那个对象
- 自定义构造函数:
- 首字母大写
- 通过new创建实例对象
- 创建构造函数时,里面的属性和方法前必须加this,this就表示当前运行时的对象
- 返回值
- 不写return,返回一个this对象
- return一个基本数据类型,返回一个this对象
- return一个复杂数据类型,返回一个复杂数据类型,比如对象、数组
63.构造函数和普通函数的区别
- 普通函数是小驼峰的名命方式,而构造函数是大驼峰的名命方式(行业规范)。
- 我们知道普通函数的this指向是指向全局对象的,而构造函数内部的this指向当前对象的实例。
- 使用的方式不同,普通函数直接调用,构造函数必须使用new 来调用,通过 new.target 来判断调用的方式是不是构造函数。
- 任何函数只要使用new操作符调用就是构造函数,而不使用new操作符调用的函数就是普通函数
63.es6class类
- 类(class)是ES6新的基础性语法糖结构,用于创建对象的模板。可以看成构造函数的另一种写法,这种写法可以让对象原型的写法更加清晰、更像面向对象编程的语法而已。
- 类必须使用
new
调用,否则会报错。普通构造函数使用new创建的是实例化对象,不使用new则执行的是普通函数的调用。 - 类的数据类型就是函数,类本身就指向构造函数。
- 函数受函数作用域限制,而类受块作用域限制。
64.constructor
- constructor 方法是一个特殊的方法,用于创建和初始化一个由
class
创建的对象。通过 new 关键字生成对象实例时,自动会调用该方法。 - 一个类只能拥有一个名为"constructor"构造函数,不能出现多个,如果定义了多个"constructor"构造函数,则将抛出 一个SyntaxError错误。
- 如果没有定义"constructor"构造函数,class 会默认添加一个空的"constructor"构造函数。
65.super
- super代表的是父类的构造函数。super可以用来调用父类的属性和方法,也可以用来调用父类的构造函数。
- super继承。
- ES6 class 可以通过
extends
关键字实现继承,同时子类必须在constructor中调用super,否则新建实例时会报错。这是因为子类自己的this
对象,必须先通过父类的构造函数完成塑造,得到与父类同样的实例属性和方法,然后再对其进行加工,加上子类自己的实例属性和方法。如果不调用super
方法,子类就得不到this
对象,只有调用super
之后,才可以使用this
关键字。 - 子类如果没有定义constructor方法,super方法会被默认添加。
- ES6 class 可以通过
- super方法。
super
作为函数调用时,代表父类的构造函数。super
虽然代表了父类的构造函数,但是返回的是子类的实例,即super
内部的this
指的是子类的实例,因此super()
在这里相当于A.prototype.constructor.call(this)
。
- super对象。
- 在普通方法中,指向父类的原型对象。由于
super
指向父类的原型对象,所以定义在父类实例上的方法或属性,是无法通过super
调用的。ES6 规定,在子类普通方法中通过super
调用父类的方法时,方法内部的this
指向当前的子类实例。由于this
指向子类实例,所以如果通过super
对某个属性赋值,这时super
就是this
,赋值的属性会变成子类实例的属性。 - 在静态方法中(statrc修饰的方法),指向父类。如果
super
作为对象,用在静态方法之中,这时super
将指向父类,而不是父类的原型对象。在子类的静态方法中通过super
调用父类的方法时,方法内部的this
指向当前的子类,而不是子类的实例。
- 在普通方法中,指向父类的原型对象。由于
66.构造器constructor为什么要使用super
因为子类自己的this
对象,必须先通过父类的构造函数完成塑造,得到与父类同样的实例属性和方法,然后再对其进行加工,加上子类自己的实例属性和方法。如果不调用super
方法,子类就得不到this
对象,只有调用super
之后,才可以使用this
关键字。
67.继承
- 实例继承:将子构造函数的 prototype 指向父构造函数的一个实例
- 原型继承:将子构造函数的 prototype 指向父构造函数的 prototype
- 构造函数绑定:使用 call 或 apply 方法,将父对象的构造函数绑定在子对象上
- 拷贝继承:如果把父对象的所有属性和方法,拷贝进子对象
- ES6 语法 extends:class ColorPoint extends Point {} 并在子类的构造器中调用super函数
68.什么是js严格模式
严格模式(Strict Mode)是一种在代码中启用的特殊模式,用于提供更严格的语法和错误检查,以改善代码质量和增强安全性。使用严格模式可以帮助大家避免一些常见的错误,并禁用一些不推荐使用的特性。
- 变量必须先声明后使用:在严格模式下,变量必须通过 var、let 或 const 关键字进行声明,否则会抛出 ReferenceError。在非严格模式下,未声明的变量会被隐式创建,并被添加到全局对象(比如浏览器环境中的 window 对象)中。
- 禁止删除变量、函数或函数参数:在严格模式下,使用 delete 操作符删除变量、函数或函数参数会抛出 SyntaxError。
- 禁止对只读属性进行赋值:在严格模式下,对只读属性(通过 const 关键字声明的常量)进行赋值会抛出 TypeError。
- 禁止使用八进制字面量:在严格模式下,以 0 开头的数字会被视为八进制字面量,这在非严格模式下是允许的。严格模式下,使用八进制字面量会抛出 SyntaxError。
- 限制 this 值:在严格模式下,函数内部的 this 值不再是全局对象(比如浏览器环境中的 window 对象),而是undefined,除非通过 call()、apply() 或 bind() 明确指定。
- 禁止使用重复的函数参数名:在严格模式下,函数参数名不能重复。在非严格模式下,重复的函数参数名会被忽略。
- 禁止使用 with 语句:在严格模式下,使用 with 语句会抛出 SyntaxError。with 语句在非严格模式下允许将对象的属性添加到作用域链中,但这被认为是不推荐使用的特性,因为它可能导致代码可读性和性能问题。
- 限制 eval 和 arguments 的赋值:在严格模式下,无法对 eval 和 arguments 进行赋值。在非严格模式下,这种赋值是允许的。
69.怎么阻止表单提交默认行为
- e.preventDefault()
- οnsubmit事件中return false
70.js事件流是什么?怎么修改事件传播机制?怎么阻止事件传播?
- 捕获阶段:从外向里依次查找元素
- 目标阶段:从当前事件源本身的操作
- 冒泡阶段:从内到外依次触发相关的行为
- addEventListener事件监听器的第三个参数设置成true捕获false冒泡
- event.stopPropagation() 阻止事件传播
71.dom事件委托原理,有什么优缺点
- 事件委托原理
- 利用事件冒泡机制,将事件监听器设置在其父节点上,通过event.target.nodeName判断是否是子节点来实现控制子节点。
- 优点
- 可以大量节省内存占用,减少事件注册
- 可以实现当新增子对象时,无需再对其进行事件绑定
- 缺点
- 如果把所有事件都用事件代理,可能会出现事件误判
72.栈内存和堆内存
- 在JavaScript中,数据是分为两类存储的:基本类型和对象类型。基本类型值指的是那些保存在栈内存(Stack)中的数据,而对象类型值则被保存在堆内存(Heap)中。
- 栈内存是一种后进先出(LIFO)的数据结构,主要用于存储函数的局部变量、临时数据、书签等。当你创建一个基本类型的变量时,它会被存储在栈内存中,并且占据一块连续的空间。
- 堆内存是用来存储对象的地方,对象可以包含多个值,大小不固定,可以动态地增加或减少。当你创建一个对象类型的变量时,这个对象会被存储在堆内存中。
73.主线程和任务队列
- JavaScript 中的主线程和任务队列是浏览器的 JavaScript 引擎如何工作的基本概念。
- 主线程:主线程是 JavaScript 引擎用来执行执行代码的地方。当 JavaScript 引擎开始执行代码时,程序的主线程就会被创建。
- 任务队列:JavaScript 是单线程的,这意味着它只有一个主线程来执行代码。但是,JavaScript 引擎还有其他的任务队列,如微任务队列和宏任务队列。
74.执行栈和调用栈
执行栈和调用栈通常是指程序在执行过程中的两种不同的数据结构。
- 执行栈(Execution Stack):在JavaScript中,执行栈是用来存储执行上下文(Execution Context)的数据结构。每当一个函数被调用时,就会为这个函数创建一个新的执行上下文并将其推入执行栈。执行栈是后进先出(LIFO)的数据结构。当函数执行完毕,它的执行上下文就会从栈中移除。
- 调用栈(Call Stack):调用栈是一个系统级的数据结构,用于存储一个个正在被执行的函数的地址。当一个函数调用另一个函数时,被调用的函数的地址会被添加到调用栈顶部。当这个函数执行完毕,它的地址会从调用栈顶部移除。在JavaScript中,调用栈是由JavaScript引擎管理的,开发者可以通过错误栈跟踪(stack trace)来查看调用栈的状态。
75.js事件循环机制(底层原理)
因为js引擎存在monitoring process进程,会持续不断的检查主线程执行栈是否为空,一旦为空,就会去Event Queue那里检查是否有等待被调用的函数。
整体会把所有代码分为两个部分:‘同步任务’,‘异步任务’。所有同步任务都在主线程上执行,形成一个执行栈。主线程之外还存在一个任务队列,专门存放异步任务(宏任务和微任务)。
- 宏任务进入到事件表(Event Table)中,并在里面注册回调函数,每当指定的事件完成时,Event Table会将这个函数移到事件队列(Event Queue)中
- 微任务也会进入到另一个事件表(Event Table)中,并在里面注册回调函数,每当指定的事件完成时,事件表(Event Table)会将这个函数移到事件队列(Event Queue)中
- 整体script作为第一个宏任务进入主线程,当主线程的任务执行完毕,主线程为空时,会检查微任务的事件队列(Event Queue),如果有任务,就会全部执行,如果没有就执行下一个宏任务
- 主线程不断重复上面的步骤,这就是Event Loop事件循环,只要主线程空了,就会去读取"任务队列"。这个过程会不断重复。
76.target 和 currentTarget 区别
- 都是事件对象上的属性
- event.target:返回触发事件的元素
- event.currentTarget:返回绑定事件的元素(相当于事件中this)
77.浮点数精度失真
- 计算机内部使用二进制浮点数表示法,而不是十进制。这种二进制表示法在某些情况下无法准确地表示某些十进制小数,从而导致精度丢失。
- 解决方法
- 保留指定位数的小数
- 获取最大小数位,根据最大小数位乘以10的倍数
- 使用decimal.js
浏览器
20.浏览器兼容性问题
23.什么是同源策略
24.什么是跨域请求,怎样解决跨域
25.axios发送请求无法携带token是什么原因,如何解决?
26.axios常用的api有哪些?
27.谈一下你对token验证机制的理解
28.怎样解决token过期(双token机制、请求拦截器)
25.localStorage
26.sessionStorage
27.localStorage和sessionStorage的区别
26.localStorage能储存多少数据量?数据量过大会导致什么?如何解决?
27.localstorage怎么实现跨域储存
27.session
28.cookie
26.cookie和session的区别
28.webWorker
29.webSocket
27.webpack的功能
32.http无状态协议
30.http和https的区别
31.如何优化网页打开速度
31.浏览器输入一个地址,敲下回车键
33.什么是mvc和mvvm
34.XSS攻击、CSRF攻击
react
- react的优缺点
- 优点
-
虚拟DOM:减少对真实DOM的操作,提高性能。
-
组件化:将代码分成一个个小的、可复用的组件,利于管理、维护。
-
使用JSX:在React中可以嵌入HTML和JavaScript。
-
单向数据流:React的单向数据流使得应用的状态更改时,可以更容易地追踪和调试。
-
- 缺点
- react主要关注UI构建,并不算是一个完整的框架,基本都需要加上reactrouter和flux/redux才能写大型应用。
-
较高的入门曲线,需要理解组件、状态、属性、状态管理等概念。
- 优点
- vue和react有什么区别
- 数据流不同。Vue支持双向数据绑定,而React提倡单向数据流,即数据从父组件流向子组件,子组件不能直接修改父组件的数据。
- 性能优化不同。Vue通过其响应式系统和虚拟DOM自动优化性能,而React则需要开发者手动优化性能,例如通过使用
shouldComponentUpdate
或PureComponent
。 - 状态管理不同。Vue通常使用Vuex进行状态管理,而React则更多使用Redux或Context API进行状态管理。
- 设计理念和架构不同。Vue最初是基于MVVM模式设计的,而React则更多地基于函数式编程和组件化思想;Vue提供了指令系统,使得模板更加易于编写和理解,而React则推荐使用JSX,它允许在JavaScript中编写类似HTML的模板语法。
- 单向数据流
- 单向数据流是一种数据流动模式,数据只能从父组件流向子组件,子组件不能直接修改父组件的数据。这种模式有助于简化状态的管理和维护,降低了组件之间的耦合度,提高代码的可维护性和可预测性。
- diff算法
-
diff
算法是一种用于比较虚拟 DOM 树的两个版本之间差异的算法。这使得 React 可以高效地更新真实 DOM,只应用必要的更改,而不是重新渲染整个组件树。-
Tree Diff: DOM树对比,逐层对比。
-
Component Diff: 组件对比,比较同一层级的相同组件类型间的差异。
-
Element Diff: 标签对比,对比标签名、标签属性、标签内容。
-
-
- 什么是虚拟dom
- 虚拟DOM(Virtual DOM)是一种抽象层,它使用普通的JavaScript对象(JS对象)来描述DOM(文档对象模型)结构。
- 虚拟DOM对象通常包含标签名、属性和标签内容等信息,这些信息与真实的DOM树结构相对应,但虚拟DOM不是真实的DOM节点,因此被称为“虚拟”。
- 虚拟DOM的实现基于一种设计思想,即通过比较新旧虚拟DOM树的差异,从而最小化对真实DOM进行的操作,以提高性能和效率。
- react渲染dom的流程
-
首先使用JSX创建react元素结构,这个元素结构就是后期生成虚拟dom的模版;
-
babel会把这些元素结构编译成react.createElement()
-
React.createElement()会将这些元素转化成虚拟dom
-
最终render函数会将这些虚拟dom渲染成真实dom,插入文档中。
-
如果后续数据发生变化,React就会生成新的虚拟dom,通过diff算法同层对比新旧dom,重新渲染发生变化的dom。
-
- react中key的作用
- key是列表通过map循环时给循环标签添加的属性,用于标记每一个循环元素。
- 在列表数据更新时,react可以通过key可以判断元素是新创建的还是被移动的元素,从而减少不必要的元素渲染。
- 如果使用index作为key值,当我们改变列表元素的顺序时,就会导致该元素后面的所有元素的key发生变化,元素也会重新渲染,
- 什么是受控组件和非受控组件
- 受控组件:指的是受react状态控制的表单控件,通过setState来驱动数据变化,需要绑定onChange和value属性。
- 非受控组件:指的是不受react状态控制的组件,表单数据由dom本身处理。非受控组件可以通过ref访问dom获得表单的值。
- 有状态组件和无状态组件
- 有状态组件:也被称为类组件,通过class类定义,拥有自己的状态数据,生命周期函数,适用于处理各种业务逻辑。
- 无状态组件:也被称为函数组件,没有自己的状态数据,生命周期函数,渲染结果由props决定,一般仅用于展示数据。
- 组件之间的通讯方式有哪些
- 父子传值
- 子父传值
- Context上下文传值
- redux
- 路由跳转时如何传递数据
- 通过url的?传值,可以通过useSearchParams.get()或者location.query获取
- 通过url的/传值,可以通过useParams()获取
- 通过query对象传值,可以通过useLocation.query获取
- 通过state传值,可以通过useLocation.state获取
- 什么是高阶组件(HOC)
- 接受一个组件作为参数,可以对这个组件进行操作,最终返回一个增强的组件。
- 高阶组件有哪些实现方式
- 什么是渲染劫持
- 根据条件判断是否对组件渲染进行拦截
- react严格模式
- 什么是jsx?jsx的特点
- jsx中可以使用html、css、js
- 使用jsx有哪些注意事项
- 组件懒加载
- Fragment的作用
- 空标签,既有标签容器的作用又不会生成额外的标签元素
- 说一说你对类组件的理解
- 类组件中常用的生命周期函数
- state和props的区别
- state是组件的状态,可以任意修改。
- props是外部传递给组件的参数,不能直接修改。
- shouldComponentUpdate()
- 是否允许组件更新
- getDerivedStateFromProps()
- 根据props更新state
- PureComponent类
- forceupdata()
- 强制渲染页面
- this.setState如何获取修改后的最新值
- 从第二个参数回调函数中获取
- state中的数据可以不用this.setState修改
- 使用this.setState修改会生成虚拟dom,重新渲染页面。
- 不使用则不会重新渲染页面
- this.setState是同步的还是异步的
- 在受react控制的情况下是异步的;
- 在不受react控制的方法中是同步的,比如说setTimeout
- 类组件对于引用类型数据如何进行渲染优化
- 转化成字符串进行对比;
- 对比引用类型数据里面的属性
- 类组件中声明数据的方式
- 在state中声明
- 在组件中直接声明
- 说一说你对hooks组件的理解
- hooks组件中常用的hooks
- useState和useReducer的区别
- useCallBack和useMemo的区别
- React.memo
- hooks为什么只能在组件最上层使用
- hooks的实现就是基于fiber的。每个组件都会生成一个 FiberNode(节点),组件内使用的 hook 会以链表的形式挂在 FiberNode 的 memoizedState 上面。各个 FiberNode 汇聚起来会变成一颗 Fiber 树,React 每次会以固定的顺序遍历这棵树,这样就把整个页面的 hook 都串联起来了。
- react按照固定的顺序来执行hooks的,在循环、判断、嵌套中使用,就会打乱hooks的 调用的顺序,就会导致 react 无法区分出对应的 hook
- 自定义hooks
- 自定义 Hooks 是 React 中一种重用逻辑的方式。它们允许我们将组件逻辑提取到可重用的函数中,以便在多个组件中共享。自定义 Hooks 通常以"use"开头;
- 应用场景:管理Table分页器状态。
- 介绍redux
- RTK(Redux Tool Kit)
- redux和RTK的区别
- redux如何处理异步action
- redux异步action的作用
脚手架相关
1.yarn和npm的区别
2.yarn常用指令
3.npm常用指令
4.nvm
2.webpack
3.webpack打包流程
4.webpack常见的loader
5.tree shaking
6.tree shaking工作原理