HTML
1、有哪些常用的 HTML 标签?
- 语义化标签: <header>、<nav>、<footer>、<article>、<section>、<aside>
- 标题标签:<h1>-<h6>
- 特殊标签:<a>、<img>、<p>、<span>、<div>、<script>、<style>
- 列表标签:<ul>、<ol>、<li>
- 表格标签:<table>、<tr>、<td>、<th>
- 表单标签:<form>、<input>、<select>、<option>、<button>、<textarea>
2、什么是 HTML5,HTML5 有哪些新特性?
HTML5是HTML的新标准,他在HTML的基础上增加了许多新特性:
- 语义化标签:
-
-
- <header>:定义文档的头部区域
- <nav>:导航区域
- <article>:内容区域
- <section>:对文档的某一部分进行分段或者分块
- <aside>:一个与主要内容无关的区域
- <footer>:底部区域
-
- 多媒体支持:音频<audio>、视频<video>、SVG和Canvas等图像元素,这些都可以直接在页面进行嵌入
- 新的表单控件:HTML5引入了新的表单控件,如日期选择器、搜索框、滑块等,这些控件都能提高用户体验
- Web:HTML5提供了两种新的客户端存储机制:localStorage和sessionStorage,它们可以在让Web在客户端存储数据,从而提示性能和用户体验
- 地理位置支持:HTML5 提供了一种新的 API,即 Geolocation API,它可以让 Web应用程 序获取用户的地理位置信息。
- Web Socket:一种新的通信协议,允许服务端主动向客户端推送数据。
3、iframe 标签的作用是什么?有哪些优缺点?
<iframe>标签可以允许在当前的HTML文档里面嵌入另一个HTML文档
优点:
- 可以在当前页面嵌入其他页面或者文档,拓展页面的功能
- 可以使用一个文档来管理页面内容,简化了页面管理
缺点
- 过多的嵌入可能会导致页面的加载速度和性能
- 可能会影响页面的可访问性,因为有些设备可能不支持查看某些文档
4、什么是HTML语义化?为什么要语义化?
HTML语义化可以在编写代码的时候,通过其带有含义的标签来标记页面的不同部分,使页面结构更加清晰和易于理解。
HTML语义化的目的是在于增强页面的可读性和可维护性,使得开发人员和搜索引擎能够更快的理解页面的结构和内容。
此外语义化的HTML更方便SEO的抓取,可以使得搜索引擎能更方便的抓取页面,提高网站在搜索引擎中的排名
CSS 布局
1、 CSS 选择器有哪些?优先级分别是什么
选择器
选择器 | 权重 |
id选择器 #id | 100 |
类选择器 .classname | 10 |
属性选择器 div[class="foo"] | 10 |
伪类选择器 div::last-child | 10 |
标签选择器 div | 1 |
伪元素选择器 div:after | 1 |
兄弟选择器 div+span | 0 |
子选择器 ui>li | 0 |
后代选择器 div span | 0 |
通配符选择器 * | 0 |
优先级
- !important
- 内联样式
- ID选择器
- 类选择器/伪类选择器/属性选择器
- 标签选择器/伪元素选择器
- 关系选择器/通配符选择器
2、有哪些常⻅的 CSS 布局?
- 盒模型布局:盒模型布局通常是指通过设置元素的margin、border、padding等属性,控制元素在页面中的位置和大小。
- 浮动布局:浮动布局通过设置元素的float属性,使元素脱离文档流然后向左或者向右浮动,从而实现对页面布局的控制。
- 定位布局:定位布局是指通过设置元素的position属性为fixed、relative、absolute,控制元素在页面上的位置。
- 弹性布局:弹性布局通过设置父元素的display的属性为flex或inline-flex,控制子元素在页面中的位置和大小
- 网格布局:网格布局通过设置元素的display为grid,使用网格线将页面分割为若干的行和列,控制元素在页面中的位置和大小。
- 表格布局、圣杯布局和双飞翼布局
- 响应式布局:响应式布局可以根据设备屏幕的大小和方向自动调整页面布局
3、 CSS 中的 1 像素问题是什么?有哪些解决方案?
1像素在现在一些高密度像素屏幕的设备上会出现变粗或者模糊的情况,因为,在这些屏幕上1css的px实际上对应了多个真实的物理像素块。
- 使用transform的scale方法对线条进行缩放。
- 使用与屏幕大小相关的vw、vh来代替固定的px单位。因为vw和vh会根据屏幕大小进行自适应,从而可以在不同屏幕下实现更自然的1px效果。
- 使用媒体查询,针对不同设备的像素密度调整1px的值。
4、什么是盒子模型?
CSS盒子模型值的是用于布局和设计网页的CSS样式规范。CSS盒子模型将每个HTML元素都表示为一个矩形的盒子。这个盒子包括外边距(margin)、边距(border)、内边距(padding)、内容(content)。
5、哪些 CSS 属性可以继承?
所谓继承就是指 html 元素可以从⽗元素那里继承一部分 css 属性,即使当前元素没有定义该 属性。
可以被继承的属性:
1. 字体系列属性
字体系列属性主要包括: font-size、font-family、font-variant、font-style、font-weight、 font、letter-spacing、word-spacing、text-transform 和 line-height。如果没有在一个元素上 设置这些属性,则其继承上层的相应属性。
2. 文本系列属性
文本系列属性主要包括: color、direction、text-align、text-indent、text-decoration、textshadow、white-space、word-wrap 和 hyphens。只有 color 属性可以被继承自⽗元素,其它 都不能继承。
3. 其他系列属性
其他系列属性主要包括: visibility、cursor、list-style 和 quotes。list-style 属性可以继承,但 quotes 属性不能被继承。
inherit(继承)值 每一个属性可以指定值为“inherit”,即:对于给定的元素,该属性和它⽗元素相对属性的计算 值取一样的值。继承值通常只用作后备值,它可以通过显式地指定“inherit”而得到加强,
4.继承的局限性
继承虽然减少了重复定义的麻烦,但是,有些属性是不能继承的,例如border(边框)、 margin(边距)、padding(补⽩)和背景等。 这样设定是有道理的,例如设定了边框,如果此属性也继承的话,那么在这个内所有的元素都 会有边框,这无疑会产生一个让⼈眼花缭乱的结果。 同样的,影响元素位置的属性,例如margin(边距)和padding(补⽩),也不会被继承。 p { font-size: inherit; } 同时,浏览器的缺省样式也在影响着继承的结果。
css属性一旦继承了不能被取消,只能重新定义样式。
6、什么是响应式设计?响应式设计的基本原理是什么?如何进行实现 ?
响应式设计是指通过一些技术手段,使得网站或应用在不同终端设备(如桌面电脑、平板电 脑、手机等)上能够自适应地呈现最佳的用户体验。
响应式设计的基本原理是根据屏幕的尺寸和分辨率等信息,动态调整页面的布局和元素的样 式,以便使页面在不同的设备上呈现出最佳的效果。实现响应式设计通常需要使用 HTML、 CSS 和 JavaScript 技术,其中 CSS 媒体查询是实现响应式设计的核⼼技术之一。
为了实现响应式设计,开发⼈员需要为不同屏幕尺寸和分辨率等场景提供不同的布局和样式。 一种实现方式是使用流体网格布局和百分比尺寸等技术,以便根据设备屏幕的宽度和高度等信 息自适应地调整页面的布局和元素的大小。另一种实现方式是使用 CSS 媒体查询,根据设备 的屏幕尺寸和分辨率等信息,加载不同的样式文件或应用不同的样式规则,以便实现不同场景 下的最佳效果。
响应式设计的优点包括可以提高用户体验、提高网站访问率和转化率、降低开发成本等。同 时,响应式设计也有一些缺点,例如需要在各种设备上进行充分的测试和调试、可能需要加载 大量的 CSS 和 JavaScript 文件等。 总之,响应式设计是一种非常重要的前端开发技术,能够帮助开发⼈员在不同终端设备上提供 最佳的用户体验,提高网站的访问率和转化率,同时也能减少开发成本和维护成本。
之前做过防掘金的页面,里面用到过媒体查询,里面通过检测设备视窗大小来某些模块是否展示,因为,设备大小不同能够放下的模块还是不一样。具体到模块里面就采用流式布局来实现不同设备上的微小差异。
7、CSS3 新增了哪些特性?
- 选择器:属性选择器、结构伪类选择器、伪元素选择器
- 边框与圆角: border-radius、border-image、box-shadow
- 文本:text-overflow、word-wrap、word-break、text-shadow
- 过渡(Transform):用于将元素从一种状态平滑过渡到另外一种状态,只有在特定的事件才会触发
- 动画(Animation):通过定义关键帧和时间函数来精确控制动画,可以实现比过渡更加自由和复杂的动画效果,且无需事件触发。
- 弹性盒子:弹性盒子是CSS3提供的一种新的布局方式,相比传统的浮动定位更加灵活高效,常用在移动端。
- 多媒体查询:CSS3 支持多媒体查询,即根据设备类型来适应不同的屏幕尺寸,从而为用 户带来更好的体验。
8、怎么用CSS 实现一个宽高自适应的正方形?
- vw、vh自适应方式
<div class="square"></div>
.square {
width: 25vw; /* 利用vw单位实现自适应宽度 */
padding-top: 25vw; /* 利用padding实现自适应高度 */
background-color: red;
}
- 伪元素
<div class="square"></div>
.square {
position: relative;
width: 50%;
background-color: red;
}
.square::before {
content: "";
display: block;
padding-top: 100%;
}
ps:利用padding百分比值的特性来实现高度与宽度相等的效果
9、CSS 中,有哪些方式可以隐藏页面元素?有什么区别?
- display:none 完全隐藏元素,元素不占据任何空间
- visibility:hidden 隐藏元素,但元素在页面任然占据空间
- opacity:0 将元素透明度设为0,元素隐藏但任然占空间
- z-index:-1 将元素层级设为负数,但任然占据空间
- overflow:hidden
10、怎么使用用CSS3 来实现动画?你实现过哪些动画?
11、CSS 有哪些常用单位?这些单位各有什么区别?
- 绝对长度单位:
-
- px:CSS像素,是最常用的单位,用于值一个固定大小的元素,不随设备的变化而变化
- 相对长度单位:
-
- em:em在设置自身字体大小的font-size属性时实际上是相对与父元素的字体大小而言,如果没有设置,则继承父元素,如果父元素没有,则相当与浏览器默认字体
-
-
- ps: 注意:任意浏览器的默认字体大小都是16px,也就是说,所有未经调整的浏览器都 符合: 1em = 16px。比如,12px = 0.75em,10px = 0.625em
-
-
- rem:相对于 HTML 根元素 设置的字体大小,与 em 一样,如果没有设置则相对于浏览 器的默认字体大小。这个单位可谓集相对单位和绝对单位的优点于一身,通过它既可以做 到只修改根元素就成比例地调整所有字体大小,又可以避免字体大小逐层复合的连锁反 应。在实际应用中,rem 经常被用于响应式布局,以便元素可以根据视口大小进行自适应 调整。⽬前,除了 IE8 及更早版本外,所有浏览器均已支持 rem 。
扩展:如何通过 rem 实现简单的响应式布局?/ rem 适配⽅案?
使用 rem 实现简单的响应式布局可以通过以下步骤来完成:
- 确定基准字体大小
通常情况下,浏览器默认的基础字体大小是 16px。为了使用 rem 单位方便计算,可以将基准字体大小设置为 10px,这样 1rem 就等于 10px,进而 1.6rem 就等于 16px。
css
html {
font-size: 62.5%; /* 62.5% of 16px = 10px */
}
2. 使用 rem 进行布局
接下来,你可以使用 rem 单位来定义你的布局尺寸。假设你希望在不同屏幕尺寸下有不同的布局:
css
.container {
width: 30rem; /* 30rem = 300px (assuming 1rem = 10px) */
margin: 0 auto;
}
@media (max-width: 768px) {
.container {
width: 100%; /* Full width on smaller screens /
padding: 0 1rem; / Add some padding using rem units */
}
}
3. 媒体查询与 rem 单位结合
使用媒体查询可以根据不同的屏幕尺寸调整布局。在媒体查询中,同样可以使用 rem 单位来定义断点和元素尺寸:
css
/* Example media queries /
@media (max-width: 768px) {
/ Adjust styles for smaller screens /
.container {
width: 100%; / Full width on smaller screens /
padding: 0 1rem; / Adjust padding using rem units */
}
}
@media (min-width: 1024px) {
/* Adjust styles for larger screens /
.container {
width: 60rem; / 60rem = 600px (assuming 1rem = 10px) */
}
}
4. rem 适配方案
对于不同屏幕密度和字体大小偏好的设备,rem 单位能够提供一种相对一致的布局体验。通常,使用 rem 单位的布局更容易实现响应式设计,因为它们相对于根元素的字体大小进行缩放,而不是依赖于视口宽度或固定像素尺寸。
总结
通过使用 rem 单位,你可以创建一个简单且灵活的响应式布局。确保在设计过程中考虑到不同屏幕尺寸和分辨率,使用媒体查询来调整布局以确保在各种设备上都能提供良好的用户体验。
-
- %:百分比布局,当父元素的某些属性发生变化,通过百分比布局,可让其子元素也同步的做出改变,以实现响应式的布局
- vw和vh:vw和vh是和视窗大小有关的单位,其本身就可以反映页面的大小,所以,使用他的页面元素自然可以实现响应式,1vw相当于视窗宽度的1/100,1vh相当于视窗高度的1/100
扩展:⽤过vw 和 vh 吗?应⽤场景是什么?
12、有哪些 CSS 性能优化的操作或技巧?
- 使用合适的选择器:选择器的复杂度会影响CSS渲染性能。尽量使用简单的选择器,避免使用通配符和后代选择器。
- 避免使用inline样式:虽然inline的优先级高方便修改,但是会增加HTML文件的大小,降低页面的加载速度,所以不建议这样使用。
- 避免使用!important:!important会影响CSS属性的优先级,而且会增加解析和渲染的时间
- 避免过度继承:过度继承会导致样式冗余和继承链深度加深,影响页面加载的时间
- 避免使用高消耗的属性和值:某些属性和值的计算成本较高,例如box-shadow和border-radius,应该避免使用
JavaScript
1、JavaScript 中如何中⽌网络请求?
在js中,我们可以通过 AbortController和AbortSignal来中止请求。在创建请求时,将AbortConroller的signal属性给请求绑定上,这样我们可以随时调用abort方法来中止网络请求
const controller = new AbortController();
const signal = controller.signal;
fetch(url, { signal }).then(response => {
// Handle the response
}).catch(error => {
if (error.name === 'AbortError') {
console.log('Request was cancelled');
} else {
console.log('Request failed:', error);
}
在上面的示例中,我们通过调用 controller.abort() 方法来取消网络请求。
使用 AbortController 和 AbortSignal 是中⽌网络请求的一种可靠方式,并且在现代浏览器中
得到了⼴泛支持。
2、什么是 BOM 和 DOM?分别列举一些它们的函数
BOM(Browser Object Model)是浏览器对象模型,它提供了一些浏览器窗口和框架的对象,并提供了一些api来操作这些对象
下面是一些常见的Bom函数:
- alert():在浏览器中显示一个警告框
- confirm():在浏览器中显示一个确认框
- setTimeOUt():在指定的时间后执行代码
- setInterval():指定的时间间隔执行同一段代码
- addEventListener():监听事件并触发回调函数
DOM(Document Object Model)是文档对象模型,它制定了一些api可以允许开发者访问并操作html中的元素或者内容
下面是一些常见的Dom函数:
- getElementByClassName():通过类名寻找元素数组
- getElemetById():通过寻找元素对象
- querySelectorAll():返回指定选择器的所有元素对象集合
- appendChild():将一个节点添加到父元素的末尾
- removeChild():将一个节点从父元素中删除
3、深拷贝和浅拷贝有什么区别?JS 怎么实现深拷贝?
浅拷贝:在创建对象的时候,新对象的属性会直接引用原来对象中相同的属性。这意味着原始对象的值改变的时候,新对象的值也会随之改变。
深拷贝 :在创建的对象的时候,新对象的属性值会从原始对象的相同属性中复制一份一样的值,其中也包括嵌套的数组和对象。这意味着原始对象的修改与新对象无关。
有两种方法:Json序列化和递归拷贝对象
JSON
这是实现深拷⻉的一种简单方式,但它有一些限制,例如不能复制函数和特殊对象(如 Date)。同时,它不能处理包含循环引用的对象。
const originData = {name:"hh",age:1}
const newData = JSON.parse(Json.stringfy(originData)
递归拷贝
这种方法涉及递归遍历对象,并创建一个新的对象,复制原始对象的属性,并在需要时递归复 制嵌套的对象和数组。这种方法可以处理循环引用,并复制函数和特殊对象。
function clone(obj) {
if (typeof (obj) == 'object' && obj !== null) {
let res = Array.isArray(obj) ? [] : {}
for (let key in obj) {
res[key] = clone(obj[key])
}
return res
}
return obj
}
const originData = {
name: 'hh',
age: 11,
sex: '男',
socres: {
chinese: 14
}
}
const data = clone(originData)
originData.socres.chinese = 45
console.log(data);
// { name: 'hh', age: 11, sex: '男', socres: { chinese: 14 } }
深拷⻉的缺点是它可能会更加耗时,因为需要递归遍历整个对象图,复制所有属性和嵌套的对 象和数组。而浅拷⻉是一种更快的复制方式,因为它只复制了对象的引用。在某些情况下,浅拷⻉可能会更有效。
4、如何使用 JavaScript 来判断用户设备类型?比如判断是 PC 端还是移动端访问?
利用 navigator.userAgent 属性来获取用户代理信息,然后通过正则表达式判断是否为移 动设备。示例代码如下:
function isMobile() {
return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera
Mini/i.test(navigator.userAgent);
}
// 使用示例
if (isMobile()) {
console.log('This is a mobile device.');
} else {
console.log('This is a desktop device.');
}
5、JS 中数组是如何在内存中存储的?
1、在哪里存储?
JS中的数组是在堆内存中进行存储的,并且在栈内存中有指针来指向数组在堆内存的起始地 址。
2、以什么形式进行存储?
JS中的数组继承于对象,因此可以存储不同数据类型的元素,可以是字符串、对象、数字、 布尔值等,各个元素占的内存大小不一,JS引擎很难直接分配一块连续内存来进行存储,容易造成空间浪费。为了解决这种问题,JS引擎设有快数组和慢数组。
快数组采用线性存储的方式,占用一块连续内存来进行存储。新创建的数组默认都是快数组。
快数组长度可变,可动态扩展和收缩。当push元素,需要扩容时,会申请一块原来的1.5倍 +16的内存空间,并将原来的数据拷⻉过去,返回++length;当pop元素后,会判断当前容量 是否大于等于length*2+16,决定是否收缩容量,并根据length+1 == old_length 来决定收缩一 半容量还是回收全部容量。
慢数组采用字典存储结构(key,value,description)来记录映射关系,内存不连续。
快数组=》慢数组:快数组扩容时,如果出现大量“孔”,如原数组为[1,2], 突然a[1999] = 123, 全填充数组变得特别稀疏,容量变成原来的9倍以上,或者新增的索引值比原来最大索引值 大 于1024,则快数组变成慢数组。
慢数组=》快数组:慢数组收缩时,如果元素实际所占内存小于数组所占内存容量的一半,则 可转化为快数组。如上述例⼦,delete a[1999],慢数组则有机会转为快数组。
3、数组元素占据多大内存?
首先,在V8引擎当中,数字区分为Smi和HeapNumber两种,前者代表小整数(可以用32位表 示的数字),后者代表浮点数和无法用32位表示的数,比如NaN,Infinity,-0,1.1等。 (JS 数字默认为64位表示,为加快数字运算速率,将小整数优化为32位进行运算)
其次,根据不同元素类型,数组可分大致分为6种类型:
1、PACKED_SMI_ELEMENTS:元素全为Smi类型的全填充数组
2、HOLEY_SMI_ELEMENTS:元素全为Smi类型的带孔数组
3、PACKED_DOUBLE_ELEMENTS:元素全为HeapNumber类型的全填充数组
4、HOLEY_DOUBLE_ELEMENTS:元素全为HeapNumber类型的带孔数组 5、PACKED_ELEMENTS:存在元素无法用HeapNumberr(Double)或Smi类型表示的全填 充数组
6、HOLEY_ELEMENTS:存在元素无法用HeapNumberr(Double)或Smi类型表示的带孔数组
Smi类型的数组各个元素只占4字节,HeapNumber(Double)类型元素的各个元素占8字节, 而对于PACKED_ELEMENTS和HOLEY_ELEMENTS这类数组,取决于数组中是否有Double类 型元素,有则全为8字节,无则4字节。
另外,数组类型的转化只有从上到下,如PACKED_SMI_ELEMENTS => PACKED_DOUBLE_ELEMENTS => PACKED_ELEMENT,如 【1】 =》 【1,0.1】 =》 【1,{}】 【1,{}】 =》 【1,0.1】依旧为PACKED_ELEMENT类型数组
注意,元素内存大小 只有数组类型变化时,才会改变。如【1,0.1】此时元素占8字节,变成 【1,{}】数组类型变化,并且数组中没有Double类型元素,则此时元素占4字节,如果此 时还有Double类型元素,则依旧占8字节。
6、JS 中 Map 和 WeakMap 有什么区别?
在js中,Map和weak都是键值对的集合,但它们有几个重要区别:
- 键类型:Map的键可以为任何类型,包括基本类型和对象类型,而weakMap必须是对象类型。
- 垃圾回收:Map对象中的键和值都会被常规垃圾回收机制回收,而WeakMap中的键是弱引用,即在对象被垃圾回收时,WeakMap对应的键值对也会被自动清除。这使得WeakMap通常用于缓存或元数据,当对象不再被使用时,WeakMap会自动清理对应的数据,避免内存泄漏。
- 迭代器:Map对象里面有内置的迭代器,可以通过for..of来遍历循环,而weakMap则没有内置的迭代器,不能直接遍历键值对。
7、用 CSS 和 JS 来实现动画分别有哪些优缺点?
CSS:
- 硬件加速:CSS动画会使用浏览器的GPU来进行硬件加速,能够流程和高效的运行。
- 简单易用:CSS动画只需要调用对应的动画属性,通过几行代码就可以实现。
- 低资源占用:CSS动画通常比js动画使用更少的CPU和内存资源。
JS:
- 自由控制:JS动画能够更加自由的控制动画的额速度,方向等,可以实现更加复杂的动画效果。
- 兼容性好:由于JS是浏览器的通用语言,因此在实现动画的时候可以更好的兼容不同的浏览器。
- 可维护性强:使用JS实现电脑时,能够更好的维护和拓展代码。
8、JS 中怎么阻⽌事件冒泡和事件默认行为?
在JS中,可以通过以下方式阻止事件的冒泡和默认行为:
阻止事件冒泡:事件冒泡是指当一个子元素触发了某个事件之后,事件会一直冒泡到它的父元素,一直到根节点。为了阻止事件冒泡,可以使用事件对象的stopPropagation()方法。
document.getElementById("child").addEventListener("click",
function(event) {
// 阻⽌事件冒泡
event.stopPropagation();
});
什么是冒泡和阻止冒泡的原因和方法
很简单的一个例子,盒子one中有一个盒子two,盒子two中有一个button上面绑着事件a,而这个相同事件恰巧在盒子one和two中也有,当button事件被触发时,one和two中的事件也会被触发,所以我们需要进行阻止。
Html:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div class="one">
<div class="two">
<button class="butt">Catch me</button>
</div>
</div>
<script type="text/javascript" src="js/jquery2.0.min.js" ></script>
<script type="text/javascript" src="js/Test1.js" ></script>
</body>
</html>
JS:
$(function(){
$('.one').on('click',function(){
console.log('oneoneone');
})
$('.two').on('click',function(){
console.log('twotwotwo');
});
$('.butt').on('click',function(){
console.log('buttonbuttonbutton');
});
});
点击按钮之后打开审查元素看到控制台下,会发现所有的事件都被触发了,就像这样:
这就是为什么有时候需要阻止冒泡的原因之一了。
至于阻止冒泡的方法很简单,常用的是在要实现的事件的Js代码末尾加个return false; 或者event.stopPropagation();
譬如这个例子中,button绑定的事件才是要实现的事件,所以像这样
$(function(){
$('.one').on('click',function(){
console.log('oneoneone');
})
$('.two').on('click',function(){
console.log('twotwotwo');
});
$('.butt').on('click',function(){
console.log('buttonbuttonbutton');
return false; //或者改成 event.stopPropagation();
});
});
阻⽌事件默认行为:
事件的默认行为是指事件发生时,浏览器会默认执行的一些操作,例如提交表单、打开链接 等。为了阻⽌事件的默认行为,可以使用事件对象的 preventDefault() 方法。例如:
document.getElementById("link").addEventListener("click",
function(event) {
// 阻⽌链接的默认跳转行为
event.preventDefault();
});
上面的代码中,当链接被点击时,链接不会跳转到指定的地址。 需要注意的是,阻⽌事件的冒泡和默认行为可能会影响用户体验,因此需要谨慎使用。在一些 场景下,可以使用阻⽌事件传播的方式来实现事件委托、事件代理等功能。
9、什么是防抖和节流?如何用 JS 编码实现?
防抖:在连续触发某个事件的时候,当某一段时间内,没有再次触发的时候才会执行事件处理函数。比如说我们监听用户输入框中的文字,只用用户停止输入一段时间,才会去发送请求数据。
节流:在一段时间内只执行一次的函数,无论在一段时间内事件被触发多少次,只会执行该事件内的某一次操作。 比如说,当我们 需要监听用户滚动页面时,我们可以在用户滚动时,每隔一定时间就执行一次滚动事件。
防抖节流共同点:
防抖和节流都是为了防止用户的高频触发,从而浪费性能,降低回调的执行频率,节省计算资源。
10、前端有哪些实现跨页面通信的方法?
- Cookie:通过页面间共享Cookie实现简单的跨页面通信,但是Cookie大小有限制,不能存储过多的数据。
- localStorage和sessionStorage:HTML5提供本地存储的能力,可以通过localStorage或sessionStorage实现页面间数据共享,相比Cookie更加方便,但是也有大小限制。
- websocket:WebSocket是一种持久化的协议,可以在浏览器和服务器之间实现双向通信,也可以在不同页面之间实现通信。
- BroadcastChannel API:这是一个HTML5新增的API,允许多个页面间通信,可以广播消息或者向特定页面发送消息。
11、什么是虚拟 DOM?使用虚拟 DOM 一定更快吗
虚拟 DOM(Virtual DOM)是一种将浏览器 DOM 抽象为 JavaScript 对象的技术,用于提高 DOM 操作的效率和性能。
虚拟 DOM 可以在渲染前对组件的变化进行计算,减少 DOM 操作 的次数,从而提高渲染性能。 使用虚拟 DOM 可以提高性能,但并不是一定更快。虚拟 DOM 需要进行额外的计算和比较操作,而这些操作也会消耗一定的时间和性能。
因此,虚拟DOM适用于大规模、高度动态的页面,而在简单的静态页面中使用虚拟DOM并不能提高性能。此外,虚拟DOM还可以提高开发效率,使代码更易于维护和调试。
从图中一看便知,肯定是第2种方式比较快,因为第1种方式中间还夹着一个虚拟DOM的步骤,所以虚拟DOM比真实DOM快这句话是错的,或者说不严谨。正确的说法应该是:虚拟DOM算法操作真实DOM,性能高于直接操作DOM,虚拟DOM和虚拟DOM算法是两种概念。 虚拟DOM算法 = 虚拟DOM + Diff算法
12、JS 脚本延迟加载的方式有哪些?
- async属性:该属性可以使脚本异步加载,即在页面加载的过程中不会阻塞页面的渲染,和其他资源同步加载,但是不能保证脚本的执行顺序。
- defer属性:该属性也可以使脚本异步加载,但是会在DomContentLoaded事件之前执行,也就是在页面加载完成之后执行,可以保证脚本之间的执行顺序。
- 动态添加script标签:可以在页面加载完成后,通过JavaScript动态添加标签,实现延迟加载。
PS:defer和async属性只能控制外部脚本,不适合内联脚本。
13、什么是点击穿透,怎么解决?
点击穿透:设置B盒子在A盒子前面,给B盒子绑定touchstart事件,给A盒子设置click事件,点击B设置触发touchstart事件(使B盒子,overflow:hidden),同时,也会触发A盒子的ckick事件,导致用户感觉点击无效或者出现异常,这就是点击穿透。
PS:主要使因为click不是立马执行,而是点击之后的300ms的延迟。
解决办法:
- 使用touch代替click事件
- 将当前元素的pointer-events属性设置为none,可以禁用当前元素的鼠标事件,从而避免发生点击穿透的问题
14、什么是 JS 对象的可枚举性(enumerable)?
JS对象的可枚举性指的是对象的某些属性是否可以被for... in循环枚举到。因为每一个对象属性都会有一个可枚举标识,这个可枚举标识表示了该对象属性是否可以被枚举到。在对象属性创建的时候。
默认情况下创建的所有对象的属性都是可枚举的,可以使用Object.defineProperty或者Object.defineProperties来设置enumerable特性为false。
PS:它们接受三个参数:obj对象、属性名、属性描述符
15、JS 如何顺序执行10 个异步任务?
- 通过Promise的then方法(可能会存在回调地狱)
- Promise的async和await
16、介绍一下 JS中setTimeout 的运行机制?
setTimeOut函数:用来指定某个函数或者某段代码,在多少毫秒后执行。它接受两个参数,第一个是函数或者某段代码,第二个是延迟的时间。返回一个整数,表示定时器timer的编号,可以用来取消该定时器。是一个异步函数 。
任务队列
一个先进先出的队列,它里面存放着各种事件和任务。 所有任务可以分成两种,一种是同步任务,另一种是异步任务。
同步任务
在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务。
- 输出 如:console.log()
- 变量的声明
- 同步函数:如果在函数返回的时候,调用者就能够拿到预期的返回值或者看到预期的效
果,那么这个函数就是同步的。
异步任务
- setTimeout和setInterval
- DOM事件
- Promise
- process.nextTick
- fs.readFile
- http.get
- 异步函数:如果在函数返回的时候,调用者还不能够得到预期结果,而是需要在将来通过一定的手段得到,那么这个函数就是异步的。
优先关系
异步任务要挂起,先执行同步任务,同步任务执行完毕才会响应异步任务。
JS执行机制
由于 JS 是单线程,所以同一时间只能执行一个任务,其他任务就得排队,后续任务必须等到前一个任务结束才能开始执行。 为了避免因为某些长时间任务造成的无意义等待,JS 引入了异步的概念,用另一个线程来管理异步任务。
同步任务直接在主线程队列中顺序执行,而异步任务会进入另一个任务队列,不会阻塞主线程; 等到主线程队列空了(执行完了)的时候,就会去异步队列查询是否有可执行的异步任务了(异步任务通常进入异步队列之后还要等一些条件才能执行,如 ajax 请求、文件读写),如果某个异步任务可以执行了便加入主线程队列,以此循环;
定时器也是一种异步任务,通常浏览器都有一个独立的定时器模块,定时器的延迟时间就由定时器模块来管理,当某个定时器到了可执行状态,就会被加入主线程队列。
setTimeout 注册的函数 fn 会交给浏览器的定时器模块来管理,延迟时间到了就将 fn 加入主进程执行队列,如果队列前面还有没有执行完的代码,则又需要花一点时间等待才能执行到fn,所以实际的延迟时间会比设置的长; 如在 fn 之前正好有一个超级大循环,那延迟时间就不是一丁点了。
setInterval 的实现机制跟 setTimeout 类似,只不过 setInterval 是重复执行的。 对于setInterval(fn, 100) 容易产生一个误区: 并不是上一次 fn 执行完了之后再过 100ms 才开始执行下一次 fn。 事实上,setInterval 并不管上一次 fn 的执行结果,而是每隔 100ms 就将 fn 放入主线程队列; 而两次 fn 之间具体间隔多久就不一定了,跟 setTimeout 实际延迟时间类似,
和 JS 执行情况有关。
17、怎么用 JS 实现要考虑哪些问题?
在前端实现大文件的分片上传,需要考虑以下几个问题:
- 分片上传:将大文件切割成多个小块进行上传,可以避免一次性上传大文件导致的上传时间过长,网络中段等问题。通常情况下,每个块大小为1MB左右。
- 断点续传:由于网络等问题,上传的过程中可能会出现中断,所以需要能够从中断的地方继续上传。
- 并发上传:多个文件同时上传,需要对上传文件队列进行管理,保证上传速度和顺序。
- 上传进度显示:及时回显上传进度,让用户知道上传的进度和状态。
18、什么是箭头函数?能使用 new 来创建箭头函数么?
箭头函数是ES6新增的一种使用箭头(=>)定义函数的一种方法,可以简化函数表达式的结构,写出更加简洁的代码。
尽管箭头函数为函数定义带来了便利,但相比于普通函数它还存在几个缺陷:
- 没有this: 对于普通函数来说,内部的 this 指向函数运行时所在的对象,而对于箭头函数来说,它没有 自己的 this 对象,当在其内部访问 this 时,会沿着作用域链查找 this 的值。这就意味着,如 果箭头函数被一层或多层非箭头函数包含,则 this 会指向最近一层非箭头函数的 this。也就是 说,箭头函数的 this 在编写代码的时候就已经确定了,不会随代码的运行而发生改变。另 外,由于箭头函数没有自己的this,所以也就不能用 call()、apply()、bind() 这些方法去改变 this 的指向。
- 没有原型、super、new.target:之所以设计箭头函数,仅仅是为了实现一种简洁的函数定义语法,无需考虑与函数(对象)相关的东西,所以箭头函数没有原型,即没有prototype属性,也没有相关的super、new.target等。
不能通过new关键字调用:
JS函数有两个内部方法:Call和Construct。当通过new调用普通函数时,执行Construct方法,创建一个实例对象,然后再执行函数体,将this绑定到实例上。然而当直接调用时,执行Call方法,直接执行函数体。而由于箭头函数并没有Construct方法,不能被用作构造函数,。
19、什么是前端路由?什么时候适合使用前端路由?它有哪些优点和缺点?
前端路由和后端路由区别
- 前端路由(Client-Side Routing):
-
- 定义:前端路由是在单页应用(SPA)中使用的一种路由方式,通过JavaScript在客户端(浏览器)中处理路由。传统的多页应用(MPA)每次加载新页面时都会向服务器请求,而SPA则在加载初始页面后,通过JavaScript动态地更新页面内容而无需重新加载整个页面。
- 工作原理:前端路由使用浏览器的
history
API 或者 hash(#
)来管理不同的路由状态。当用户在应用程序中导航时,JavaScript会拦截路由变化,并根据定义的路由规则加载相应的视图或组件,从而实现页面的切换和更新。
- 后端路由(Server-Side Routing):
-
- 定义:后端路由是传统的web应用程序中使用的一种路由方式,通过服务器端来处理不同的URL请求。每次用户请求新页面时,服务器会根据请求的URL来决定返回哪个HTML页面或者其他资源。
- 工作原理:后端路由依赖于服务器端应用程序的路由配置。服务器接收到来自浏览器的请求后,会根据请求的URL路径,调用相应的服务器端处理逻辑(例如处理业务逻辑、查询数据库等),然后生成HTML页面或其他资源并返回给客户端浏览器。
区别总结:
- 位置:前端路由在客户端浏览器中处理路由,而后端路由在服务器端处理路由。
- 处理方式:前端路由通过JavaScript更新页面内容,后端路由通过服务器生成并返回完整的页面。
- 应用场景:前端路由适用于单页应用(SPA),能够实现快速响应和流畅的用户体验;后端路由适用于传统的多页应用(MPA),可以在每次请求时动态生成页面。
在现代web开发中,前端路由因其能够提供更好的用户体验和性能表现,特别是在需要频繁页面切换和动态内容更新的应用中得到广泛应用。
什么是前端路由?
前端路由是指:在前端中使用JavaScript实现的页面切换路由系统,它可以根据URL的变化, 通过修改DOM来实现单页面应用SPA的页面切换效果,无需每次请求页面时都要从服务器获 取完整的HTML页面
在传统的Web应用中,每次点击页面链接或刷新页面时,浏览器都会向服务器发送请求,接收 服务器返回的HTML页面,而在使用前端路由的SPA单页面应用中,页面的切换是通过 JavaScript动态修改DOM内容来实现的,这样可以避免每次都要向服务器请求页面时的开销,从而提高页面的响应速度和用户体验
传统的Web应用,将所有的 HTML、CSS 和 JavaScript 文 件都存放在服务器上,然后网页切换页面时,每次都要发送请求来接收服务器响应回来的 HTML页面。而使用前端路由的SPA单页面应用,是第一次加载网页时,发送http请求,请求 服务器返回HTML、CSS、JavaScript文件等静态资源,这些文件被下载到浏览器中,并存储 在浏览器的缓存中,当用户在SPA单页面应用进行页面切换时,前端路由会根据浏览器中对应 URL文件的路径信息,动态地加载相应的JavaScript文件,并执行里面的逻辑来更新切换页面 内容。
什么时候适合使用前端路由?
前端路由适合用于构建单页面应用,特别是需要快速响应用户操作,避免不必要的页面刷新应 用,例如需要高度交互的应用,如社交网络,⾳乐播放器
它有哪些优点和缺点?
- 优点: 快速响应:前端路由进行页面切换时不需要向服务器发送http请求,从而快速响应用户操 作,提高加载速度 降低服务器压力:采用前端路由,降低了请求次数,减轻了服务器的负担。 提高应用的交互性:前端路由实现页面无缝切换,避免了传统应用中页面卡顿⽩屏等现象
- 缺点: 不利于SEO,由于前端路由是根据文件里面的URL修改DOM来切换,而不是加载新的 HTML页面,所以不利于搜索引擎的搜索。 初次加载慢:由于前端路由需要在初次加载时候将所有的静态资源(HTML、CSS、 JavaScript)文件都加载到客户端,因此首次加载时间较长,影响用户体验 复杂度高:前端路由需要在客户端处理好切换页面逻辑以及前进后退等操作,增加了应用 的复杂度。
20、为什么 JS 要被设计为单线程?
JS之所以被设计为单线程,而非多线程,和历史有关,JS最初只是用来做一些简单的输入校验处理,开发者并没有打算把它运用在很复杂的场景里面。另外如果采用多线程,可能会导致结果不统一。比如现在有两个JS线程,一个线程要修个某个DOM节点,而另一个线程是删除它,此时浏览器不知道以哪个线程为准。当然可以通过锁来解决,但这样又会带来更大的复杂性。
此外,JS 最初是为了解决网页交互的问题而诞生的,而网页交互的需求大部分是基于用户事 件的,比如点击按钮、输入文本等。这些操作的响应速度要求很高,如果在响应事件的同时还 要处理其他任务,可能会导致网页卡顿、响应变慢等用户体验不佳的问题。
因此为了避免多线程带来的复杂性和降低开发难度,并且满足网络交互的高响应速度需求,JS被设计为单线程。虽然单线程有局限性,但是可以通过异步编程、事件循环机制等技术手段来实现高效的并发处理。
浏览器的多进程架构
补充一下,“JS 是单线程的”指的是执行 JS 的线程只有一个,是浏览器提供的 JS 引擎线程 (主线程)。如今的主流浏览器都是多进程架构的,以 Chrome 为例,它包含了 1 个 浏览器 主进程、1个 GPU 进程、1 个网络进程、多个渲染进程或多个插件进程。作为前端开发者, 应重点关注其渲染进程,渲染进程的核⼼任务是将 HTML、CSS 和 JavaScript 转换为可交互 的网页,排版引擎 Blink 和 JS 引擎 V8 都是运行在该进程中,默认情况下,Chrome 会为每个 Tab 标签创建一个渲染进程。一个渲染进程通常由以下线程组成:
JS 引擎线程(主线程):
JavaScript 引擎,也称为 JS 内核,负责处理 JS 脚本,执行代码。
当主线程空闲且任务队列不为空时,会依次取出任务执行。
注意,该线程与 GUI 渲染线程互斥,当 JS 引擎线程执行 JS 时间过长,将导致页⾯渲染的阻 塞。
GUI 渲染线程:
主要负责页⾯的渲染,解析 HTML、CSS,构建DOM树,布局和绘制等。 当界⾯需要重绘或者由于某种操作引发重排时,将执行该线程。 注意:该线程与 JS 引擎线程互斥,当执行 JS 引擎线程时,GUI 线程会被挂起,当任务队列 空闲时,主线程才会去执行 GUI 渲染。
事件触发线程:
用于控制事件循环,将准备好的事件交给 JS 引擎线程执行。 当主线程遇到异步任务,如 setTimeOut(或 ajax 请求、⿏标点击事件),会将它们交由对应 的线程处理,处理完毕后,事件触发线程会把对应的事件添加到任务队列的尾部,等待 JS 引 擎的处理。
注意:由于 JS 的单线程关系,队列中的待处理事件都得排队等待,只有在 JS 引擎空闲时才 能被执行。
定时器触发线程: 负责执行定时器一类函数的线程,如 setTimeout,setInterval 等。
主线程依次执行代码时,遇到定时器,会将定时器交由该线程进行计时,当计时结束,事件触 发线程会将定时器的回调函数添加到任务队列的尾部,等待 JS 引擎空闲后执行。
异步 http 请求线程:
负责执行异步请求一类的函数的线程,如 Promise,axios,ajax 等。 主线程依次执行代码时,遇到异步请求,会将函数交给该线程处理。当监听到状态码变更,如 果设置有回调函数,事件触发线程会将相应的回调函数添加到任务队列的尾部,等待 JS 引擎 空闲后执行。
21、JS 代码中的 use strict 是什么?有什么作用?
“use strict”是ECMAScript5引入的一种严格模式,它用于指示JavaScript引擎采用更加严格的方式解析和执行代码。
当在JavaScript代码中使用“use strict”声明时,代码将会在严格模式下进行。严格模式包含了一些额外的规则和限制,有助于开发者避免一些常见的错误。
使用“use strict”的主要作用包括:
- 消除JavaScript中的一些不合理、不安全的语法,减少代码出错的可能性。
- 防止使用未声明的变量、函数,强制开发者进行声明。
- 禁止删除变量、函数等,避免意外删除某些重要的变量和函数。
- 提高代码性能,因为JavaScript引擎可以更好的进行优化。
使用“use strict”的方式有两种:
- 在JavaScript文件开头使用“use strict”
- 在函数体内部第一条语句中使用“use strict”(作用域只在函数内)
22、如何使用 JS 判断某个字符串长度(要求支持 Emoji 表情)?
在JavaScript中,可以使用String类型的length属性,来获取字符串的长度,但是由于Emoji表情占了两个字符的位置,因此直接使用length属性获取的不对。
正确的方法:
- 正则表达式替换:利用正则表达式将emoji替换成单字符,再获取长度
const str = "H& ";
const len = str.replace(/\uD83C[\uDF00-\uDFFF]|\uD83D[\uDC00-
\uDE4F]/g,"-").length;
console.log(len)
- ES6特性 ES6大幅增强了对字符串的处理能力。 借用数组,可以快速判断带有emoji字符的字符串长度。
const str = "A& ";
const arr = Array.from(str);
console.log(str.length,arr.length)
23、JS 在什么情况下会存在数字精度丢失的问题,如何解决?
在计算浮点数的时候,原因:
- 计算机的原理存储是二进制,而二进制不能精确的存储二进制,会产生精度丢失
- 二进制在计算浮点数时因为截断和舍入误差会导致精度丢失
解决方法:
- 将小数转化成整数进行计算,避免小数带来的精度问题
- 使用第三方库big.js等,可以提供更高精度的数字计算功能,避免精度丢失。
24、说说你对 JS 模块化方案的理解,比如 CommonJS、AMD、CMD、ES Module 分别是什么?
JS模块化是指,将一个JS应用拆分成多个模块或者文件,并通过一定的规范或者语法,定义它们之间的依赖关系,以达到方便复用,维护和拓展的目的。
- CommonJs:一种用于服务器端的模块化规范,主要用于Node.js,它通过exports来导出模块,通过require来引入模块。
- AMD:一种用于浏览器端的异步加载模块化规范,主要用于RequireJs,它通过define来定义模块,通过require来引入模块。
- CMD:一种用于浏览器端的延迟执行的模块化规范,主要用于SeaJs,它通过define来定义模块,通过require来引入模块。
- ES Moudle:一种官方规范,用于浏览器端和Node.js中,通过import来引入模块,通过export来导入模块
ES6 Module 与 CommonJS 的差异:
CommonJS 模块输出的是一个值的拷⻉,ES6 模块输出的是值的引用。 CommonJS 模块输出的是值的拷⻉,也就是说,一旦输出一个值,模块内部的变化 就影响不到这个值。 exports.a = 1; // 等价于 module.exports.a = 1; console.log(exports === module.exports); // true ES6 模块的运行机制与 CommonJS 不一样。JS 引擎对脚本静态分析的时候,遇到 模块加载命令import,就会⽣成一个只读引用。等到脚本真正执行时,再根据这个只 读引用,到被加载的那个模块⾥⾯去取值。换句话说,ES6 的import有点像 Unix 系 统的“符号连接”,原始值变了,import加载的值也会跟着变。因此,ES6 模块是动态 引用,并且不会缓存值,模块⾥⾯的变量绑定其所在的模块。 CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。 运行时加载: CommonJS 模块就是对象;即在输入时是先加载整个模块,⽣成一个对 象,然后再从这个对象上⾯读取方法,这种加载称为“运行时加载”。 编译时加载: ES6 模块不是对象,⽽是通过 export 命令显式指定输出的代码,import 时采用静态命令的形式。即在import时可以指定加载某个输出值,⽽不是加载整个模 块,这种加载称为“编译时加载”。 CommonJS 加载的是一个对象(即module.exports属性),该对象只有在脚本运行完才会⽣ 成。⽽ ES6 模块不是对象,它的对外接口只是一种静态定义,在代码静态解析阶段就会⽣ 成。
25、如果使用 Math.random() 来计算中奖概率,会有什么问题吗?
使用Math.Random()来计算中奖概率是不可靠的。因为Math.random()函数的随机性并不是真随机。他是基于一个种子值生成的伪随机数序列。如果你在相同的环境中使用相同的种子值,那么生成的随机数序列是相同的。
真随机数是通过物理过程生成的随机数,其值是完全不可预测的。
真随机数的生成依赖于自然现象的随机性,例如量子现象、大气噪声、热噪声等。
真随机数生成器通常通过硬件设备来实现,如量子物理现象的利用或者通过收集环境噪声来生成。
26、怎么使用JS 实现元素拖拽功能?
为需要拖拽的元素添加mousedown、mousemove、mouseup事件监听器。在mousedown事件函数中,记录下按的位置,以及相对于元素的位置。在mousemove事件处理函数中,计算鼠标移动的距离,并更新元素的位置。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Drag and Drop Example</title>
<style>
#draggable {
width: 100px;
height: 100px;
background-color: #4286f4;
position: absolute;
cursor: move;
}
</style>
</head>
<body>
<div id="draggable"></div>
<script>
const draggable = document.getElementById('draggable');
let offsetX, offsetY;
let isDragging = false;
// 鼠标按下时记录偏移量
draggable.addEventListener('mousedown', (e) => {
isDragging = true;
offsetX = e.clientX - draggable.getBoundingClientRect().left;
offsetY = e.clientY - draggable.getBoundingClientRect().top;
});
// 鼠标移动时更新元素位置
document.addEventListener('mousemove', (e) => {
if (isDragging) {
draggable.style.left = (e.clientX - offsetX) + 'px';
draggable.style.top = (e.clientY - offsetY) + 'px';
}
});
// 鼠标释放时停止拖拽
document.addEventListener('mouseup', () => {
isDragging = false;
});
</script>
</body>
</html>
27、JS 会出现内存泄漏问题么?在哪些情况下可能会出现内存泄漏?
内存泄漏
JavaScript 也会出现内存泄漏问题。内存泄漏是指一些被分配的内存空间,因为某些原因而无 法被垃圾回收机制回收,导致占用内存空间无法被释放,最终会导致程序崩溃。
内存泄漏通常出现在以下几个情况
- 定时器没有被清除:如果在页面关闭前,某个定时器没有被清除,它所引用的对象就不会被垃圾回收,从而导致内存泄漏。
- 闭包:如果一个闭包中引用了外部变量,而这个闭包被其他代码引用,那么它所引用的外部变量就不会被垃圾回收,从而导致内存泄漏。
- 循环引用:如歌两个对象或者多个对象之间形成了循环引用,即相互引用对方,那么它们都不会被垃圾回收,从而导致内存泄漏。
什么是 Javascript 的事件流?有哪些事件流模型?
Javascript的事件流是指浏览器中所有事件的传递和处理的过程。事件流分为三个阶段:事件捕获、目标阶段、事件冒泡阶段
- 事件捕获:事件从最外层的文档节点一直往下传递,一直到达事件的目标元素。如果在这个过程中又事件处理的程序,则这个事件将被调用。
- 目标阶段:当事件传递到了目标节点后,根据目标节点上绑定的函数的顺序,依次执行。
- 事件冒泡阶段:事件在目标函数处理后,事件从目标元素开始向根节点方向向上传递,如果在这个过程中遇到绑定的函数也会进行处理。
29、垃圾回收机制
ES6
1、ES6 有哪些新特性?
ES6(ECMAScript 6.0)是 JavaScript 语言的下一代标准,泛指 ES2015、ES2016、ES2017
及以后的标准,但有时特指 ES2015 标准。ES6 的新特性有:
- let 和 const:ES6 引入了用于声明变量的新关键字 let 和 const,解决了使用 var 时出现的一些不合理的问题,如变量提升、重复声明等。
- 变量的解构赋值:所谓解构赋值,就是按照一定的规则从变量(如数组、对象)中提取值,然后同时给多个变量赋值。数组、对象、字符串以及函数参数等都可以进行解构赋值。
- rest 参数:rest 参数用于获取函数的多余参数,可以替代函数的 arguments 对象。
- 扩展运算符:相当于 rest 参数的逆运算,可将一个数组转为用逗号分隔的参数序列。
- 箭头函数:ES6 引入了箭头函数,使得函数的定义更加方便、简洁。
- BigInt:ES6 引入了一种新的原始数据类型 BigInt(大整数),它能表示范围更大的数值。
- Symbol:Symbol 是 ES6 引入一种新的原始数据类型,表示独一无二的值。可作为对象的属性使用,确保属性名不重复。
- Set 和 Map:Set 是一种类似于数组的数据结构,但无重复的值。Map 是一种类似于对象的集合,但属性可以是任意类型。
- Promise:Promise 是一种异步编程的解决方案,比回调函数更加强大。与 Promise 相关的还有 Generator 和 async。
- Iterator:Iterator 是一种接口,若部署在数据结构(如对象)上,该数据结构就能被
for...of 遍历。数组身上默认部署了该接口,所以能被遍历。 - Class:Class 类似于其它⾯向对象语言(如 Java、C++)的写法,可以看成是 ES5 构造函数的语法糖。
- Module:ES6 引入了新的模块加载方案 Module,在编译时就能确定模块的依赖关系,相比于 CommonJS 的运行时加载效率更高。
2、ES5 中的类和 ES6 中的 class 有什么区别?
- 语法不同:ES5中使用构造函数来创建对象,ES6中使用class来创建对象
- 继承方式不同:ES5中使用原型链来继承对象,ES6中使用extends来继承对象
- 类方法的定义不同:ES5中类方法定义在构造函数的原型对象上,而ES6中类方法定义在类的内部。
- 类属性的定义方式不同:ES5中类属性定义在构造函数的原型对象上,而ES6中类方法定义在类的内部。
- 类的调用方式不同:ES6中需要使用new关键字来创建类的实例,而ES6中类的调用方式跟简单,只需要像函数一样调用即可。
PS: 需要注意的是,虽然 ES6 中引⼊了类的概念,但在底层实现上仍然是基于原型链的。因此, 理解原型链继承和类的继承是理解 JavaScript面向对象编程的关键。
3、什么是 ES6 中的 Promise?它的使用场景有哪些?
ES6中Promise是一种处理异步操作的方式,它是一个对象,用于表示一个异步操作的完成状态和结果。Promise有三种状态:pending(等待中)、fulfilled(已完成)和rejected(失败)
优点:
- 可以避免回调地狱,将回调函数变为链式调用,代码可读性更好
- 能够支持多个并发请求:Promise.all()可以让多个Promise并行执行,提高了执行效率
使用的场景:
- 处理异步请求:比如Ajax请求、文件读取等。
- 优化回调函数:将回调函数转化成Peomise链,提高代码可读性
- 实行并发请求:Promise.all()可以让多个请求并行执行