前端八股(基于黑马八股文档的二次总结)

一、HTML5、CSS3

(1)HTML5和CSS3的新特性:

HTML5:
1、自定义属性:data-id
2、语义化标签: header,nav,footer ,aside, article, section
3、多媒体标签:音频 ,视频(audio, video) 如果浏览器不支持自动播放怎么办?在属性中添加 autoplay
!!!!!(4)画布(Canvas)
5、地理(Geolocation) API
6、本地离线存储 localStorage 长期存储数据 浏览器关闭后数据不丢失、sessionStorage 的数据在浏览器关闭后自动删除
8、表单控件 calendar , date , time , email , url , search , tel , file , number
!!!!!9、新的技术 webworker, websocket , Geolocation

CSS3:
1、颜色: 新增 RGBA , HSLA 模式
2、文字阴影(text-shadow)
3、边框: 圆角(border-radius) 边框阴影 : box-shadow
4、盒子模型: box-sizing
5、背景:background-size background-origin background-clip
6、渐变: linear-gradient , radial-gradient
7、过渡 : transition 可实现动画
8、自定义动画 animate @keyfrom
9、媒体查询 多栏布局 @media screen and (width:800px) {…}
10、border-image
11、2D 转换;transform: translate(x,y) rotate(x,y) skew(x,y) scale(x,y)
12、3D 转换
13、字体图标 font-face
14、弹性布局 flex

(2)Localstorage、sessionStorage、cookie 的区别:

共同点: 都是保存在浏览器端、且同源的

区别:
1、cookie 数据始终在同源的 http 请求中携带(即使不需要),即 cookie 在浏览器和服务器间来回传递,而 sessionStorage 和 localStorage 不会自动把数据发送给服务器,仅在本地保存。cookie 数据还有路径(path)的概念,可以限制 cookie 只属于某个路径下
2、存储大小限制也不同,cookie 数据不能超过 4K,同时因为每次 http 请求都会携带 cookie、所以 cookie 只适合保存很小的数据,如会话标识。sessionStorage 和 localStorage 虽然也有存储大小的限制,但比 cookie 大得多,可以达到 5M 或更大
3、生命期不同,sessionStorage:仅在当前浏览器窗口关闭之前有效;localStorage:始终有效,窗口或浏览器关闭也一直保存,因此用作持久数据;cookie:只在设置的 cookie 过期时间之前有效,即使窗口关闭或浏览器关闭
4、作用域不同,sessionStorage 不在不同的浏览器窗口中共享,即使是同一个页面;localstorage在所有同源窗口中都是共享的;cookie 也是在所有同源窗口中都是共享的
5、web Storage 支持事件通知机制,可以将数据更新的通知发送给监听者
6、web Storage 的 api 接口使用更方便

(3)H5 的浏览器存储有哪些?

1、cookie

2、localStorage、sessionStorage

3、indexedDB
内嵌在浏览器端的非关系型数据库,数据以键值对的形式存储,兼容性良好
indexDB 直接操作的存储对象是 ObjectStore,这有点类似其他数据库中 table 概念

4、websql:内嵌在浏览器的关系型数据库,前端可以像在使用 mysql、Oracle 一样的写 sql 语句,并存储信息。兼容性良好。存储后可在浏览器 resource 中查看

5、flash cookie
flash cookie 现在用的地方比较多

(4)如何使一个盒子水平垂直居中?

1、子绝父相,top和left设置为50%,margin-left和margin-top设置为负宽高一半

.parent { width: 500px;
	height: 500px;
	border: 1px solid #000;
	position: relative;
}
.child { 
	width: 100px;
	height: 100px;
	border: 1px solid #999;
	position: absolute;
	top: 50%;
	left: 50%; 
	margin-top: -50px;
	 margin-left: -50px;
}
</style>

2、子绝父相,top和left设置为50%, transform: translate(-50%, -50%);

<style>
        .parent {
            width: 500px;
            height: 500px;
            border: 1px solid #000;
            position: relative;
        }

        .child {
            width: 100px;
            height: 100px;
            border: 1px solid #999;
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
        }
    </style>

3、子绝父相,top、bottom、left、right设置为0,margin:auto

	<style>
        .parent {
            width: 500px;
            height: 500px;
            border: 1px solid #000;
            position: relative;
        }

        .child {
            width: 100px;
            height: 100px;
            border: 1px solid #999;
            position: absolute;
            margin: auto;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
        }
    </style>

4、父元素,display: table-cell;vertical-align: middle;text-align: center; 子元素display: inline-block;

<style>
        .parent {
            width: 500px;
            height: 500px;
            border: 1px solid #000;
            display: table-cell;
            vertical-align: middle;
            text-align: center;
        }

        .child {
            width: 100px;
            height: 100px;
            border: 1px solid #999;
            display: inline-block;
        }
    </style>

5、利用 display:flex;设置垂直水平都居中

<style>
        .parent {
            width: 500px;
            height: 500px;
            border: 1px solid #000;
            display: flex;
            justify-content: center;
            align-items: center;
        }

        .child {
            width: 100px;
            height: 100px;
            border: 1px solid #999;
        }
    </style>

6、计算父盒子与子盒子的空间距离

<style>
        .parent {
            width: 500px;
            height: 500px;
            border: 1px solid #000;
        }

        .child {
            width: 100px;
            height: 100px;
            border: 1px solid #999;
            margin-top: 200px;
            margin-left: 200px
        }
    </style>

(5)如何垂直居中一个 img?

#container {
            display:table-cell;
            text-align:center;
            vertical-align:middle;
        }

!!!!!(6)如何实现双飞翼(圣杯)布局?

(7)CSS 的盒模型?

盒子模型可以用来对元素进行布局,包括实际内容、内边距,边框,外边距这几个部分。
盒子模型分为两种: 第一种是 W3C 标准的盒子模型**(标准盒模型)**
对应box-sizing: content-box;
第二种 IE 标准的盒子模型**(怪异盒模型)**
对应box-sizing: border-box;
同时涉及二者的长宽设置问题

(8)渐进增强和优雅降级

优雅降级和渐进增强印象中是随着 CSS3 流出来的一个概念。由于低级浏览器不支持
CSS3,但 CSS3 的效果又太优秀不忍放弃,所以在高级浏览器中使用 CSS3 而低级浏览器只保证最基本的功能。

a{
display:block;
width:200px;
height: 100px;
background:aquamarine;
/*我就是要用这个新 css 属性*/
transition:all 1s ease 0s;
/*可是发现了一些低版本浏览器不支持怎么吧*/
/*往下兼容*/ -webkit-transition:all 1s ease 0s;
-moz-transition:all 1s ease 0s;
-o-transition: all 1s ease 0s;
/*那么通常这样考虑的和这样的侧重点出发的 css 就是优雅降级*/
}
a:hover{
height:200px;
}
/ *那如果我们的产品要求我们要重低版本的浏览器兼容开始*/
a{
/*优先考虑低版本的*/ -webkit-transition:all 1s ease 0s;
-moz-transition:all 1s ease 0s;
-o-transition: all 1s ease 0s;
/*高版本的就肯定是渐进渐强*/
transition:all 1s ease 0s;
}

“优雅降级”观点认为应该针对那些最高级、最完善的浏览器来设计网站
“渐进增强”观点则认为应关注于内容本身

(9)哪些是块级元素那些是行内元素

行内元素: a、span、b、img、strong、input、select、lable、em、button、textarea 、selecting
块级元素:div、ul、li、dl、dt、dd、p、h1-h6、blockquote、form
区别:1、块级元素会独占一行,其宽度自动填满其父元素宽度;行内元素不会独占一行,相邻的行内元素会排列在同一行里,直到一行排不下,才会换行,其宽度随元素的内容而变化
2、一般情况下,块级元素可以设置 width,height 属性,行内元素设置 width, height 无效
3、块级元素可以设置 margin 和 padding; 行内元素的水平方向的padding-left,padding-right,margin-left,margin-right 都产生边距效果,但是竖直方向的
padding-top,padding-bottom,margin-top,margin-bottom 都不会产生边距效果。

(10)CSS 中选择器的优先级以及 CSS 权重如何计算?

标签选择器、伪元素:1;
类选择器、伪类选择器、属性选择器: 10;
id选择器: 100;
内联样式:1000;
!important: 无穷大
CSS 权重计算方式: 标签(伪元素)选择器的数量1+类选择器(伪类、属性)的数量10+id选择器的数量*100
如果权重相同,采用就近原则

(11)CSS 哪些属性可以继承?

可继承的样式: font-size font-family color, UL LI DL DD DT;
不可继承的样式:border padding margin width height;

!!!!!(12)HTML5 的离线存储的使用,工作原理

在用户没有与因特网连接时,可以正常访问站点或应用,在用户与因特网连接时,更新用户机器上的缓存文件
原理: HTML5 的离线存储是基于一个新建的.appcache 文件的缓存机制(不是存储技术),通过这个文件上的解析清单离线存储资源,这些资源就会像 cookie 一样被存储了下来。之后当网络在处于离线状态下时,浏览器会通过被离线存储的数据进行页面展示

(13)语义化标签

语义化标签是指在HTML中使用具有明确含义的标签来描述网页内容的结构和含义。
好处:
(1)对于开发者而言,使用语义化标签使得代码可读性更高,便于团队开发与维护
(2)对于用户而言,样式文件未加载时,页面结构清晰;用户更容易理解页面内容的组织和关系。
(3)有利于SEO(搜索引擎优化),搜索引擎通常会根据网页的内容结构和语义来确定其相关性和排名。使用语义化标签可以帮助搜索引擎更好地理解页面内容,从而提高网页在搜索结果中的排名,使用户更容易找到相关的信息。

(14)HTML5事件

onclick、onblur、onfocus、oninput、onchange、onerror、onload、键盘和鼠标的一些

(15) H5input 元素 type 属性值?

text、password、checkbox、radio、search、submit、url、button、tel、e-mail、date、time等

(16)CSS 中哪些属性可继承,哪些不可以

能继承的一般是些字体属性啊、文本属性啊
不能继承的一半就是和布局、位置有关的组件

(17)CSS 单位中 px、em 和 rem 的区别?

px:图像的分辨率通常用像素来表示。分辨率表示图像在水平和垂直方向上的像素数量
em:em 是相对长度单位,相对于其父元素的字体大小进行计算,例如,如果父元素的字体大小为 16px,而子元素的字体大小设置为 1.5em,则子元素的字体大小将为 16px * 1.5 = 24px。如果嵌套使用 em 单位,则其计算方式将基于所有父元素的字体大小,直到找到一个具有绝对字体大小(如px)的元素为止。如果找不到绝对字体大小,则浏览器会默认使用浏览器的默认字体大小。
rem: 字体相对于根元素(html)的字体大小

!!!!!(18)rem 适配方法如何计算 HTML 跟字号及适配

CSS 中 link 和@import 的区别

<link>:
<link> 是 HTML 中的一个标签,用于在 HTML 文档中引入外部 CSS 文件。
使用 <link> 标签可以在 HTML 页面的 部分指定外部样式表文件的路径和其他属性。
由于 <link> 是在页面加载时同时加载的,因此它可以并行加载多个外部样式表,从而加快页面加载速度。
一般情况下,推荐使用<link> 标签来引入外部样式表。

@import:
@import 是 CSS 的一种规则,用于在 CSS 文件中引入其他外部 CSS 文件。
使用 @import 规则可以在 CSS 文件中嵌套引入其他样式表,但它必须出现在 CSS 文件的顶部,并且只能引入一次。
@import 的加载是串行的,即一个文件加载完成后才会加载下一个文件,这可能会导致页面加载速度较慢。
由于 @import 是 CSS 的一部分,因此它可以用于在不支持 JavaScript 的情况下动态地加载样式表。
link 引入的样式权重大于@import

适用范围不同 : @import 可以在网页页面中使用,也可以在 CSS 文件中嵌套使用;而 link 只能将 CSS 文件引入到网页页面中

(19)Display:none 与 visibility:hidden 的区别

dispaly:none 设置该属性后,该元素下的元素都会隐藏,占据的空间消失
visibility:hidden 设置该元素后,元素虽然不可见了,但是依然占据空间的位置
display:none 会引起回流(重排)和重绘,因为它修改了DOM结构;而 visibility:hidden只会引起重绘

(20)Position 的值有哪些,分别有哪些作用

静态定位、绝对定位、相对定位、固定定位

(21)清除浮动的办法

1、使用 CSS 中的 clear:both(放一个空的 div,并设置上述 css)属性来清除元素的浮动
2、给父元素添加 clearfix 样式:
.clearfix:after{content: “”;display: block;height: 0;clear: both;visibility: hidden;}
.clearfix{display: inline-block;} /* for IE/Mac */
3、给父级元素设置双伪元素;

aaa
.clearfix:after{ content:""; /*设置内容为空*/ height:0; /*高度为 0*/ line-height:0; /*行高为 0*/ display:block; /*将文本转为块级元素*/ visibility:hidden; /*将元素隐藏*/ clear:both; /*清除浮动*/ } .clearfix{ zoom:1; /*为了兼容 IE*/ } 4、给父级元素设置 overflow:hidden;或 overflow:auto;本质是构建一个 BFC

!!!!!(22)简述弹性盒子 flex 布局及 rem 布局

如何解决 margin“塌陷”?

父子之间的margin塌陷:
(1)overflow: hidden
(2)为父盒子设置 border,为外层添加 border 后父子盒子就不是真正意义上的贴合(可以设置成透明:border:1px solid transparent
(3)为父盒子设定 padding 值
兄弟之间的margin塌陷:
(1)只给其中一个设置margin值

!!!!!(23)什么是外边距重叠?重叠的结果是什么?

(24)雪碧图 ( 精灵图 )?(必会)

精灵图是把网站上用到的一些图片整合到一张单独的图片中,从而减少你的网站的 HTTP 请求数量,该图片使用 css background 和 background-position 属性渲染,这也就意味着你的标签变得更复杂了,图片是在 css 中定义,并非在<image>
优点:
1、减少网页的 http 请求,从而加快了网页加载速度,提高用户体验
2、减少图片的体积,因为每个图片都有一个头部信息,把多个图片放到一个图片里,就会共用同一个头信息,从而减少了字节数
3、解决了网页设计师在图片命名上的困扰,只需对一张集合的图片上命名就可以了,不需要对每一个小元素进行命名
缺点:(了解即可吧)
1、在宽屏,高分辨率的屏幕下的自适应页面,你的图片如果不够宽,很容易出现背景断裂
2、CSS Sprites 在开发的时候,要通过 photoshop 或其他工具测量计算每一个背景单元的精确位置
3、在维护的时候比较麻烦,如果页面背景有少许改动,一般就要改这张合并的图片
4、精灵图不能随意改变大小和颜色。改变大小会失真模糊,降低用户体验,CSS3 新属性可以改变精灵图颜色,但是比较麻烦,并且新属性有兼容问题,现在一般用字体图标代替精灵图

!!!!!(25)less 和 Scss 的配置使用以及特点

::before 和::after 中双冒号和单冒号有什么区别、作用?

最开始CSS使用单冒号来表示伪类或者伪元素,CSS3后修订为伪元素使用双冒号,伪类单冒号,但是低版本的ie并不支持双冒号,所谓为了兼容性,,继续使使用 :after 这种老语法表示伪元素。
想让插入的内容出现在其它内容前,使用::before,否者,使用::after;
伪类与伪元素都是用于向选择器加特殊效果
伪类与伪元素的本质区别就是是否抽象创造了新元素

(26)CSS3 新增伪类

p:first-of-type 选择属于其父元素的首个

元素的每个

元素
p:last-of-type 选择属于其父元素的最后

元素的每个

元素
p:nth-child(n) 选择属于其父元素的第 n 个子元素的每个

元素
p:nth-last-child(n) 选择属于其父元素的倒数第 n 个子元素的每个

元素
p:nth-of-type(n) 选择属于其父元素第 n 个

元素的每个

元素
p:nth-last-of-type(n) 选择属于其父元素倒数第 n 个

元素的每个

元素
p:last-child 选择属于其父元素最后一个子元素的每个

元素
p:target 选择当前活动的

元素
:not§ 选择非

元素的每个元素
:enabled 控制表单控件的可用状态
:disabled 控制表单控件的禁用状态
:checked 单选框或复选框被选中

(27)img 的 alt 与 title 的异同,还有实现图片懒加载

表面上: alt 是图片加载失败时,显示在网页上的替代文字; title 是鼠标放上面时显示的文字,title是对图片的描述与进一步说明
alt 是 img 必要的属性,而 title 不是
对于网站 seo 优化来说,title 与 alt 还有最重要的一点: 搜索引擎对图片意思的判断,主要靠 alt 属性。所以在图片 alt 属性中以简要文字说明,同时包含关键词,也是页面优化的一部分
由于过多的图片会严重影响网页的加载速度,并且移动网络下的流量消耗巨大,所以
延迟加载几乎是标配了
图片懒加载:
图片懒加载是延迟加载技术的一种应用,主要用于延迟加载页面中的图片资源。它使得页面在初始加载时只加载可视区域内的图片,当用户滚动页面到达新的图片时才会加载新的图片资源。
图片懒加载通常通过监听页面滚动事件来实现,当用户滚动到图片所在位置时,JavaScript 脚本会动态加载图片资源。
图片懒加载可以减少页面初始加载时需要下载的图片数量,从而加快页面的加载速度,并且节省用户的带宽和服务器资源。
原理: 先设置图片的 data-set 属性(当然也可以是其他任意的,
只要不会发送 http 请求就行了,作用就是为了存取值)值为其图片路径,由于不是 src,所以不会发送 http 请求。 然后我们计算出页面 scrollTop 的高度和浏览器的高度之和, 如果图片距离页面顶端的坐标 Y(相对于整个页面,而不是浏览器窗口)小于前两者之和,就说明图片就要显示出来了(合适的时机,当然也可以是 其他情况),这时候我们再将data-set 属性替换为 src

(28)BFC 是什么?

BFC全称Block Formatting Context,它是一块独立的渲染区域,它规定了在该区域中,常规流块盒的布局;
常规流块盒的特点:
(1)水平方向,撑满包含块
(2)在包含块的垂直方向上依次摆放
(3)若外边距无缝相邻,则进行外边距合并
(4)其自动高度和摆放位置,无视浮动元素
BFC渲染区域:这个区域由某个HTML元素创建,以下元素会在其内部创建BFC区域(常见):
(1)根元素
(2)浮动和绝对定位
(3)overflow不等于visible的块盒
(4)display 为 inline-block, table-cell, table-caption, flex, inline-flex

具体规则:
(1)创建BFC的元素,它的自动高度需要计算浮动元素
(2)创建BFC的元素,他的边框盒不会与浮动元素重叠
(3)创建BFC的元素,不会和它的子元素进行外边距合并。

(29)Style 标签写在 body 后与 body 前的区别

区别
1、 写在 body 标签前利于浏览器逐步渲染:
resourcesdownloading->CSSOM+DOM->RenderTree(composite)->Layout->paint
2、写在 body 标签后:
由于浏览器以逐行方式对 html 文档进行解析;
当解析到写在尾部的样式表(外联或写在 style 标签)会导致浏览器停止之前的渲染,等待加载且解析样式表完成之后重新渲染;

(30)使用CSS怎么让Chrome支持小于12px的文字比如10px

<style>
	p span{font-size:10px;-webkit-transform:scale(0.8);display:block;}
</style>
<p>
	<span>豪豪豪 10px</span>
</p>

二、JS基础

(1)JavaScript 的基本类型有哪些?引用类型有哪些?

基本数据类型:number、string、boolean、null、undefined
引用数据类型:function、object、Array
null 和undefined 的区别:
(1)undefined:表示变量声明但未初始化时的值
(2)null:表示准备用来保存对象,还没有真正保存对象的值。

未初始化定义的值用 typeof 检测出来是"undefined"(字符串),而 null 值用 typeof 检测出来是 “object”

(2)如何判断 JavaScript 的数据类型?

1.typeof
typeof 可以用来区分除了 Null 类型以外的原始数据类型,对象类型的可以从普通对象里面识别出函数。
typeof 不能识别 null,如何识别 null:
使用===全等操作符:

let a = null
a === null // tru

下列两组注意区分开:
typeof Number(1) // “number”
typeof String(“1”) // “string”

typeof new Number(1) // “object”
typeof new String(1) // "object

2.instanceof
instanceof 不能用于判断原始数据类型的数据:

3 instanceof Number // false
'3' instanceof String // false
true instanceof Boolean // fals

instanceof 可以用来判断对象的类型:

var date = new Date()
date instanceof Date // true 
var number = new Number()
number instanceof Number // true var string = new String()
string instanceof String // true

需要注意:instanceof 的结果并不一定是可靠的,因为在 ECMAScript7 规范中可以通
过自定义 Symbol.hasInstance 方法来覆盖默认行为

3.Array.isArray
Array.isArray(value)可以用来判断 value 是否是数组:

Array.isArray([]) // true
Array.isArray({}) // false
(function () {console.log(Array.isArray(arguments))}()) // false

(3)创建对象有几种方法

(1)字面量
(2)new Object
(3)显式构造函数
(4)object.create() :

var P = {name:'o3'};
var o3 = Object.create(P);

(4)简述创建函数的几种方式?

第一种(函数声明):

function sum1(num1,num2){
	return num1+num2;
}

第二种(函数表达式)

var sum2 = function(num1,num2){
	return num1+num2;
}

第三种(函数对象方式)
var sum3 = new Function(“num1”,“num2”,“return num1+num2”);

(5)请指出 JavaScript 宿主对象和原生对象的区别?

宿主对象就是由 JavaScript 运行环境(通常是浏览器或 Node.js)提供的对象,比如说BOM和DOM。
原生对象就是是由 JavaScript 语言规范定义的对象,这些对象的行为和功能在所有 JavaScript 运行环境中都是一致的,不受宿主环境的影响。

(6)JavaScript 内置的常用对象,并列举该对象常用的方法

Array 数组
length 属性 动态获取数组长度
join() 将一个数组转成字符串。返回一个字符串
reverse() 将数组中各元素颠倒顺序
delete 运算符 只能删除数组元素的值,而所占空间还在,总长度没变(arr.length)
shift() 删除数组中第一个元素,返回删除的那个值,并将长度减 1
pop() 删除数组中最后一个元素,返回删除的那个值,并将长度减 1
unshift() 往数组前面添加一个或多个数组元素,长度要改变。
push() 往数组结尾添加一个或多个数组元素,长度要改变。
concat( ) 连接数组
slice( ) 返回数组的一部分
sort( ) 对数组元素进行排序
splice( ) 插入、删除或替换数组的元素
toLocaleString( ) 把数组转换成局部字符串
toString( ) 将数组转换成一个字符串
forEach 遍历所有元素:

var arr = [1, 2, 3];
arr.forEach(function(item, index) {
// 遍历数组的所有元素
console.log(index, item);
});

slice() 方法:
slice() 方法用于从数组中提取出指定范围的元素,返回一个新的数组,原始数组不会被修改。
slice() 方法接受两个参数,第一个参数是起始索引(包括),第二个参数是结束索引(不包括)。如果省略第二个参数,则会提取从起始索引到数组末尾的所有元素。
slice() 方法不会改变原始数组,它只是返回一个包含提取元素的新数组。
例如:array.slice(startIndex, endIndex)

splice() 方法:
splice() 方法用于向/从数组中添加/删除元素,并返回被删除的元素组成的数组。
splice() 方法接受多个参数,第一个参数是起始索引,第二个参数是要删除的元素个数,后面的参数是要添加到数组的元素(可选)。
splice() 方法会改变原始数组,它会直接在原始数组上进行操作,并返回被删除的元素组成的数组。
例如:array.splice(startIndex, deleteCount, item1, item2, …)
every 判断所有元素是否都符合条件

var arr = [1, 2, 3];
var arr1 = arr.every(function(item, index) {
if (item < 4) {
return true;
}
}) console.log(arr1); // true

sort 排序

var arr = [1, 5, 2, 7, 3, 4];
var arr2 = arr.sort(function(a, b) {
	// 从小到大
	return a-b; 
	// 从大到小
	return b-a;
}) 
console.log(arr2); // 1,2,3,4,5,7

map 对元素重新组装,生成新数组

var arr = [1, 5, 2, 7, 3, 4];
var arr2 = arr.map(function(item, index) {
	return '<b>' + item + '</br>';
})
console.log(arr2);

filter 过滤符合条件的元素

var arr = [1, 2, 3, 4];
var arr2 = arr.filter(function(item, index) {
	if (item>2) {
		return true;
	}
})
console.log(arr2); // [3, 4]

Math 数学对象
Math.PI 圆周率
Math.abs() 绝对值
Math.ceil() 向上取整(整数加 1,小数去掉)
Math.floor() 向下取整(直接去掉小数)
Math.round() 四舍五入
Math.pow(x,y) 求 x 的 y 次方
Math.sqrt() 求平方根

String 字符串对象
length 获取字符串的长度。如:var len = strObj.length
toLowerCase() 将字符串中的字母转成全小写。如:strObj.toLowerCase()
toUpperCase() 将字符串中的字母转成全大写。如:strObj.toUpperCase()
charAt(index) 返回指定下标位置的一个字符。如果没有找到,则返回空字符串
substr() 在原始字符串,返回一个子字符串
substring() 在原始字符串,返回一个子字符串
区别:‘’’ “abcdefgh”.substring(2,3) = “c”
“abcdefgh”.substr(2,3) = “cde”
split() 将一个字符串转成数组

(7)=== 和 == 的区别

区别
===:三个等号我们称为等同符,当等号两边的值为相同类型的时候,直接比较等号两边的值,值相同则返回 true,若等号两边的值类型不同时直接返回 false。也就是说三个等号既要判断值也要判断类型是否相等
==:两个等号我们称为等值符,当等号两边的值为相同类型时比较值是否相同,类型不同时会发生类型的自动转换,转换为相同的类型后再作比较。也就是说两个等号只要值相等就可以

(8)null,undefined 的区别

null 表示一个对象被定义了,值为“空值”;
undefined 表示不存在这个值。
typeof null //“object” null : 是一个对象(空对象, 没有任何属性和方法);
注意: 在验证 null 时,一定要使用=== ,因为 == 无法分别 null 和 undefined
undefined 表示"缺少值",就是此处应该有一个值,但是还没有定义。
null 表示"没有对象",即该处不应该有值。典型用法是:
4.1) 作为函数的参数,表示该函数的参数不是对象
4.2) 作为对象原型链的终点

(9)如何区分数组和对象?

方法一:通过 ES6 中的 Array.isArray 来识别

Array.isArray([]) //true
 Array.isArray({}) //false

方法二:通过 instanceof 来识别

[] instanceof Array //true
 {} instanceof Array //false

方法三:通过调用 constructor 来识别

{}.constructor //返回 object
[].constructor //返回 Array

方法四:通过 Object.prototype.toString.call 方法来识别

Object.prototype.toString.call([]) //["object Array"]
Object.prototype.toString.call({}) //["object Object"]

(10)判断两个对象相等

1、判断两个对象是否指向同一内存
2、使用 Object.getOwnPropertyNames 获取对象所有键名数组
3、判断两个对象的键名数组是否相等
4、遍历键名,判断键值是否都相等

(11)什么是类数组(伪数组),如何将其转化为真实的数组

伪数组
1、具有 length 属性
2、按索引方式存储数据
3、不具有数组的 push.pop 等方法

可以用对真正数据遍历方法来遍历它们。典型的是函数
document.childnodes 之类的,它们返回的 nodeList 对象都属于伪数组
伪数组–>真实数组
1.使用 Arrray.from()–ES6
2.[].slice.call(eleArr) 或则 Array.prototype.slice.call(e)

(12)如何遍历对象的属性?

1、遍历自身可枚举的属性 (可枚举,非继承属性) Object.keys()
2、遍历自身的所有属性(可枚举,不可枚举,非继承属性) Object.getOwnPropertyNames()方法
3、遍历可枚举的自身属性和继承属性 (可枚举,可继承的属性) for i
4、遍历所有的自身属性和继承属性

(13)src 和 href 的区别是

src(source)指向外部资源的位置,指向的内容将会嵌入到文档中当前标签所在位置;在请求 src 资源时会将其指向的资源下载并应用到文档中,如 JavaScript 脚本,img 图片和iframe 等元素
当浏览器解析到该元素时,会暂停其他资源的下载和处理,直到将该资源加载、编译、执行完毕,类似于将所指向资源嵌入当前标签内
href(hypertext reference/超文本引用)指向网络资源所在位置,建立和当前元素(锚点)或当前文档(链接)之间的链接,如果我们在文档中添加
<link href="common.css" rel="stylesheet"/>那么浏览器会识别该文档为 CSS 文件,就会并行下载资源并且不会停止对当前文档的处理

(14)JavaScript 中的作用域、预解析与变量声明提升

作用域:变量有效使用的范围
全局作用域:最外层函数定义的变量拥有全局作用域,对任何内部函数来说,都是
可以访问的
局部作用域:局部作用域一般只在固定的代码片段内可访问到,而对于函数外部是无
法访问的,最常见的例如函数内部
块级作用域:凡是代码块就可以划分变量的作用域,这种作用域的规则就叫块级作用域
预解析: 包含变量提升(函数内声明的变量只会提升至该函数作用域最顶层)和函数提升

(15)什么是作用域链?

作用域链

在 JavaScript 中,每个函数都有自己的词法环境(Lexical Environment),用于存储变量和函数声明。当执行一个函数时,JavaScript 引擎会创建一个新的执行上下文,并在执行上下文中创建一个词法环境,该词法环境包含了函数内部声明的变量和函数。

当在函数内部访问一个变量时,JavaScript 引擎会首先在当前词法环境中查找该变量,如果找到则直接使用;如果没有找到,则会向外层词法环境继续查找,直到找到该变量或达到全局词法环境为止。这个查找变量的过程就是作用域链的形成过程。

!!!!!!(16)如何延长作用域链?

1、try - catch 语句的 catch 块;会创建一个新的变量对象,包含的是被抛出的错误对象的声明
2、with 语句。with 语句会将指定的对象添加到作用域链中

(17)Function foo() {}和 var foo = function() {} 的用法区别

1、第二种foo是一个变量,可以改变,而第一种不可以改变
2、第一种在预解析时会进行变量提升,而第二种不会

(18)索引类型

根据数据库的功能,可以在数据库设计器中创建四种索引:唯一索引、非唯一索引、主键索引和聚集索引。 尽管唯一索引有助于定位信息,但为获得最佳性能结果,建议改用主键或唯一约束
**唯一索引:**不允许其中任何两行具有相同索引值的索引。
**非唯一索引:**是相对唯一索引,允许其中任何两行具有相同索引值的索引
**主键索引:**数据库表经常有一列或列组合,其值唯一标识表中的每一行。该列称为表的主键。在数据库关系图中为表定义主键将自动创建主键索引,主键索引是唯一索引的特定类型
聚集索引(也叫聚簇索引): 在聚集索引中,表中行的物理顺序与键值的逻辑(索引)顺序相同。一个表只能包含一个聚集索引

三、WebAPI

(1)什么是DOM

DOM(文档对象模型)是一种用于表示和操作HTML、XML等文档结构的树形数据结构。它将文档中的每个元素、属性、文本等都视为一个节点,并将它们组织成一个树状结构,使得开发者可以通过编程方式访问和修改文档的内容、结构和样式。
W3C DOM 标准被分为 3 个不同的部分:
核心 DOM - 针对任何结构化文档的标准模型
XML DOM - 针对 XML 文档的标准模型
HTML DOM - 针对 HTML 文档的标准模

!!!!!(2)dom 节点的 Attribute 和 Property 有何区别?

(3)dom 事件的级别?

DOM 级别一共可以分为四个级别:DOM0 级、DOM1 级、DOM2 级和 DOM3 级。而 DOM 事件分为 3 个级别:DOM 0 级事件处理,DOM 2 级事件处理和 DOM 3 级事件处理。
由于 DOM 1 级中没有事件的相关内容,所以没有 DOM 1
dom0: element.οnclick=function(){}
dom2: element.addEventListener(‘click’, function(){}, false) // 默认是 false。false:冒泡阶段执行,true:捕获阶段产生。
dom3: element.addEventListener(‘keyup’, function(){}, false) // 事件类型增加了很多,鼠标事件、键盘事件(同时 DOM3 级事件也允许使用者自定义一些事件)

(4)dom 事件模型?

DOM 事件模型分为两种:事件捕获事件冒泡
事件捕获:事件从根元素出发,向内一级级传播至目标元素
事件冒泡:相反,事件从目标元素出发,向外一级级传播至根元素
事件传播
事件捕获和事件冒泡都有事件传播阶段,传播阶段就是事件从触发开始到结束的过程。
网景用的事件传播方式是捕获,IE 用的事件传播方式是冒泡

(5)dom 事件流?

事件捕获阶段:事件传播由目标节点的祖先节点逐级传播到目标节点。先由文档的根节点 document(window)开始触发对象,最后传播到目标节点,从外向内捕获事件对象
处于目标阶段:事件到达目标对象,事件触发,如果事件不允许冒泡,事件会在这一阶段停止传播
事件冒泡阶段:从目标节点逐级传播到 document 节点

注意:
若addEventListener中第三个参数为flase(默认为false):在捕获阶段不会处理响应元素的注册的事件。
若addEventListener中第三个参数为true(默认为false):在捕获阶段处理响应元素的注册的事件

(6)事件冒泡是如何工作的,怎么阻止

事件冒泡: 在一个对象上触发某类事件,如果此对象定义了此事件的处理程序,那么此事件就会调用这个处理程序,如果没有定义此事件处理程序或者事件返回true,那么这个事件会向这个对象的父级对象传播,从里到外,直至它被处理(父级对象所
有同类事件都将被激活),或者它到达了对象层次的最顶层,即 document 对象。
阻止事件冒泡的方法:
(1)W3C方法是:event.stopPropagation(); 事件处理过程中,阻止冒泡事件,但不会阻止默认行为(跳转至超链接)
(2)阻止默认行为:W3C的方法是 e.preventDefault(),IE 则是使用 e.returnValue = false
元素的默认行为
(1)a标签的跳转
(2)导航(二级导航)
(3)submit按钮的提交
(4)右键菜单(web应用程序里,在线Word)
(5)文本框的输入
(6)…

(7)JavaScript 动画和 CSS3 动画有什么区别?

总结:如果动画只是简单的状态切换,不需要中间过程控制,在这种情况下,css
动画是优选方案。它可以让你将动画逻辑放在样式文件里面,而不会让你的页面充斥
Javascript 库。然而如果你在设计很复杂的富客户端界面或者在开发一个有着复杂 UI
状态的 APP。那么你应该使用 js 动画,这样你的动画可以保持高效,并且你的工作流
也更可控。所以,在实现一些小的交互动效的时候,就多考虑考虑 CSS 动画。对于一些复杂控制的动画,使用 javascript 比较可靠

(8)事件执行过程

在这里插入图片描述

(9)获取元素位置

1、通过元素的 offsetLeft 和 offsetTop
dom 元素的 offsetLeft、offsetTop 指的是元素相对于其 offseParent 指定的坐标来说的。offsetParent:是指当前元素最近的经过定位的父级元素,如果没有则一直向上直至 body。注意当前元素为 fixed 时,其 offsetParent 的值为 null

(10)谈谈事件委托的理解?

当我们需要对很多元素添加事件的时候,可以通过将事件添加到它们的上级元素而将事件委托给上级元素来触发处理函数。这主要得益于浏览器的事件冒泡机制。
缺点:
1、事件委托基于冒泡,对于不冒泡的事件不支持
2、层级过多,冒泡过程中,可能会被某层阻止掉。
3、理论上委托会导致浏览器频繁调用处理函数,虽然很可能不需要处理。所以建议就近委托,比如在 table 上代理 td,而不是在 document 上代理 td。
4、把所有事件都用代理就可能会出现事件误判。比如,在 document 中代理了所有 button 的 click事件,另外的人在引用改 js 时,可能不知道,造成单击button触发了两个 click事件

(11)JavaScript 中的定时器有哪些?他们的区别及用法

1)setTimeout() 方法用于在指定的毫秒数后调用函数或计算表达式。
2)setInterval() 方法可按照指定的周期(以毫秒计)来调用函数或计算表达式。

(12)比较 attachEvent 和 addEventListener?

attachEvent语法:Element.attachEvent(Etype,EventName)
addEventListener语法:Element.addEventListener(Etype,EventName,boole)
boole:该参数是一个布尔值:false 或 true 必须填写.false 代表支持浏览器事件捕获功能,true 代表支持浏览事件冒泡功能

(13)document.write 和 innerHTML 的区别?

document.write 是直接写入到页面的内容流,如果在写之前没有调用 document.open, 浏览器会自动调用 open。每次写完关闭之后重新调用该函数,会导致页面被重写
innerHTML 则是 DOM 页面元素的一个属性,代表该元素的 html 内容。你可以精确到某一个具体的元素来进行更改。如果想修改 document 的内容,则需要修改
document.documentElement.innerElement
innerHTML 将内容写入某个 DOM 节点,不会导致页面全部重绘
innerHTML 很多情况下都优于 document.write,其原因在于其允许更精确的控制要刷新页面的那一个部分

(14)什么是 window 对象?什么是 document 对象?

简单来说,document 是 window 的一个对象属性。
window对象:
Window 对象表示浏览器中打开的窗口。
如果文档包含框架(frame 或 iframe 标签),浏览器会为 HTML 文档创建一个
window 对象,并为每个框架创建一个额外的 window 对象
所有的全局函数和对象都属于 Window 对象的属性和方法

document 对象:
该对象是 window 和 frames 对象的一个属性,是显示于窗口或框架内的一个文档

区别:
(1)window 指窗体。document 指页面。document 是 window 的一个子对象。
(2)用户不能改变 document.location(因为这是当前显示文档的位置)。但是,可以
改变 window.location (用其它文档取代当前文档)window.location 本身也是一个对象, 而 document.location 不是对象

!!!!!!(15)Js 拖动的原理?

(16)描述浏览器的渲染过程,DOM 树和渲染树的区别

1、浏览器的渲染过程:
(1)解析 HTML 构建 DOM(DOM 树),并行请求 css/image/js
(2)CSS 文件下载完成,开始构建 CSSOM(CSS 树)
(3)CSSOM 构建结束后,和 DOM 一起生成 Render Tree(渲染树)
(4)布局(Layout):计算出每个节点在屏幕中的位置
(5)显示(Painting):通过显卡把页面画到屏幕上
2、DOM 树 和 渲染树 的区别
(1)DOM 树与 HTML 标签一一对应,包括 head 和隐藏元素
(2)渲染树不包括 head 和隐藏元素,大段文本的每一个行都是独立节点,每一个节点都有对应的 css 属性

(17)获取到页面中所有的 CheckBox 怎么做

var domList = document.getElementsByTagName(‘input’);
var checkBoxList = [];
var len = domList.length;//缓存到局部变量
while (len--) {//使用 while 的效率会比 for 循环更高
	if (domList[len].type == ‘checkbox’) { 
		checkBoxList.push(domList[len]);
	}
}

(18)简单说一下页面重绘和回流?

(1)回流:当 render tree 的一部分或全部的元素因改变了自身的宽高,布局,显示或隐藏,或者元素内部的文字结构发生变化 导致需要重新构建页面的时候,回流就产生了
(2)重绘:当一个元素自身的宽高,布局,及显示或隐藏没有改变,而只是改变了元素的外观风格的时候,就会产生重绘。例如你改变了元素的 background-color…
因此得出了一个结论:回流必定触发重绘,而重绘不一定触发回流

(19)如何最小化重绘(repaint)和回流(reflow)

(1)需要要对元素进行复杂的操作时,可以先隐藏(display:“none”),操作完成后再显示
(2)需要创建多个 DOM 节点时,使用 DocumentFragment 创建完后一次性的加入 document
(3)使用绝对定位或固定定位: 对于不会影响文档流的元素,可以使用绝对定位或固定定位,这样可以避免它们对其他元素的布局产生影响,从而减少回流的发生。
(4)尽量避免用 table 布局(table 元素一旦触发回流就会导致 table 里所有的其它元素回流
(5)缓存 Layout 属性值,如:var left = elem.offsetLeft; 这样,多次使用 left 只产生一次回流

(20)Js 延迟加载的方式有哪些?

JS 延迟加载,也就是等页面加载完成之后再加载 JavaScript 文件
JS 延迟加载有助于提高页面加载速度
一般有以下几种方式:
(1)defer 属性: 在<script>标签定义了 defer 属性。标签中设置 defer属性,等于告诉浏览器立即下载,但延迟执行标签定义了 defer 属性。
用途: 脚本在执行时不会影响页面的构造。也就是说,脚本会被延迟到整个页面都解析完毕之后再执行
HTML5 规范要求脚本按照它们出现的先后顺序执行。在现实当中,延迟脚本并不一定会按照顺序执行
defer 属性只适用于外部脚本文件
支持 HTML5 的实现会忽略嵌入脚本设置的 defer 属性

(2)async 属性:HTML5 为<script>标签定义了 async 属性。与 defer 属性类似,都用于改变处理脚本的行为。同样,只适用于外部脚本文件
目的:不让页面等待脚本下载和执行,从而异步加载页面其他内容。异步脚本一定会在页面 load 事件前执行。不能保证脚本会按顺序执行
(3)动态创建 DOM 方式

在这里插入图片描述

(4)使用 setTimeout 延迟方法
在这里插入图片描述

(5)让 JS 最后加载
把 js 外部引入的文件放到页面底部,来让 js 最后引入,从而加快页面加载
例如引入外部 js 脚本文件时,如果放入 html 的 head 中,则页面加载前该 js 脚本就会被加载入页面,而放入 body 中,则会按照页面从上倒下的加载顺序来运行 JavaScript 的代码,所以我们可以把 js 外部引入的文件放到页面底部,来让 js 最后引入,从而加快页面加载速度
注意: 这段代码直到文档加载完才会加载指定的外部 js 文件。因此,不应该把那些页面正常加载需要依赖的 javascript 代码放在这里。而应该将 JavaScript 代码分成两组。一组是因页面需要而立即加载的 javascript 代码,另外一组是在页面加载后进行操作的 javascript 代码。这些需等到页面加载后再执行的 JavaScript 代码,应放在一个外部文件,然后再引进来

四、JS高级

(1)typeof 和 instanceof 区别

在 javascript 中,判断一个变量的类型可以用 typeof:
(1)number、string、boolean这三个可以直接判断
(2)对象、数组、null返回的是object
(3)函数类型返回的是function
(4)不存在的变量、函数或者 undefined,将返回 undefined

在 javascript 中,instanceof 用于判断某个对象是否被另一个函数构造

(2)解释一下什么是回调函数

回调函数就是一个通过函数指针调用的函数(回调函数,要调用它时,使用函数指针来调用)。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不
是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应
案例:

// 异步函数,接受一个回调函数作为参数
function fetchData(callback) {
    // 模拟异步操作,1秒后返回结果
    setTimeout(function() {
        const data = '这是异步操作返回的数据';
        // 调用回调函数,并将结果作为参数传递给它
        callback(data);
    }, 1000);
}

// 回调函数,用于处理异步操作返回的数据
function handleData(data) {
    console.log('接收到的数据是:', data);
}

// 调用异步函数,并将回调函数传递给它
fetchData(handleData);

与异步操作的关系:
在编程中,异步操作是指不会立即执行完毕的操作,而是需要一定时间才能完成,比如文件读取、网络请求、定时器等。
一旦异步操作完成,我们通常需要执行一些特定的逻辑来处理异步操作的结果。这就是回调函数发挥作用的地方。
回调函数作为参数传递给异步函数,当异步操作完成后,这个回调函数就会被调用。这样,我们就可以在异步操作完成后执行特定的逻辑。回调函数可以用来处理异步操作的返回值、处理错误、更新UI等。

(3)什么是闭包

闭包就是能够读取其他函数内部变量的函数。例如在 javascript 中,只有函数内部的子函数才能读取局部变量,所以闭包可以理解成“定义在一个函数内部的函数“。在本质上,闭包是将函数内部和函数外部连接起来的桥梁。”

function func(){
	var a =1 ,b = 2;
	funciton closure(){ 
		return a+b;
	} 
	return closure; 
}

(4)什么是内存泄漏,场景,解决方法

内存泄漏是指在程序执行过程中,由于错误的内存管理导致的内存无法被正确释放的情况。当内存泄漏发生时,程序使用的内存会持续增长,最终导致程序运行变慢甚至崩溃。
场景:
(1)未正确释放事件监听器:例如使用 addEventListener。如果不正确地移除这些事件监听器,就会导致内存泄漏。因为即使DOM元素被移除,但是事件监听器仍然存在,会持续占用内存。
解决方法:在不需要监听事件的时候,确保使用 removeEventListener 方法移除事件监听器

(2)定时器未清除: 使用 setInterval 或 setTimeout 创建的定时器,如果不清除,会持续执行,可能导致内存泄漏。特别是在单页应用中,定时器可能会在页面切换时被忘记清除。
解决方法: 在不需要定时器时,确保使用 clearInterval 或 clearTimeout 方法清除定时器。

var serverData = loadData();
setInterval(function() { 
	var renderer = document.getElementById('renderer');
	if(renderer) {
		renderer.innerHTML = JSON.stringify(serverData);
	}
}, 5000); 		//This will be executed every ~5 secon

这个例子阐述着 timers 可能发生的情况:计时器会引用不再需要的节点或数据
解决方法: 在不需要定时器时,确保使用 clearInterval 或 clearTimeout 方法清除定时器。

(3)闭包引用: 当一个函数内部定义了另一个函数,并且内部函数引用了外部函数的变量,形成闭包时,如果内部函数被保存在外部作用域中,那么外部函数的作用域中的变量将无法被垃圾回收,可能导致内存泄漏。

var theThing = null;
var replaceThing = function () { 
	var originalThing = theThing;
	var unused = function () {
		if (originalThing) 				// a reference to 'originalThing' 
			console.log("hi");
	};
	theThing = {
		longStr: new Array(1000000).join('*'),
		someMethod: function () {
			console.log("message");
		}
	};
};
setInterval(replaceThing, 1000);

解决方法:在不需要使用闭包时,确保内部函数不引用外部函数的变量,或者在不需要时及时释放对闭包的引用

(4)循环引用: 当两个或多个对象之间存在相互引用,并且没有其他对象引用它们时,就会形成循环引用,可能导致内存泄漏。

(5)动态DOM: 如果动态创建的DOM元素没有被正确地移除,例如在页面切换时未清除旧页面上的DOM元素,就会导致内存泄漏。
解决方法:在不需要使用的DOM元素时,确保使用 removeChild 或 innerHTML 等方法将其从DOM树中移除。

(5)说说你对原型(prototype)理解

(6)常见的 js 中的继承方法有哪些

(1)原型链继承

function Parent() {
    this.name = 'Parent';
}
Parent.prototype.sayHello = function() {
    console.log('Hello from Parent');
};

function Child() {
    this.age = 10;
}
Child.prototype = new Parent();

var child = new Child();
console.log(child.name); // 输出 'Parent'
child.sayHello(); // 输出 'Hello from Parent'

(2)借用构造函数继承(伪造对象或经典继承) :在子类构造函数内部调用超类型构造函数。通过使用 apply()和 call()方法可以在新创建的子类对象上执行构造函数

unction Parent(name) {
    this.name = name || 'Parent';
}

function Child(name) {
    Parent.call(this, name);
    this.age = 10;
}

var child = new Child('Child');
console.log(child.name); // 输出 'Child'

(3)组合继承(原型+借用构造)(伪经典继承)

function Parent(name) {
    this.name = name || 'Parent';
}
Parent.prototype.sayHello = function() {
    console.log('Hello from Parent');
};

function Child(name) {
    Parent.call(this, name);
    this.age = 10;
}
Child.prototype = new Parent();

var child = new Child('Child');
console.log(child.name); // 输出 'Child'
child.sayHello(); // 输出 'Hello from Parent'

(4)寄生式继承

var parent = {
    name: 'Parent',
    sayHello: function() {
        console.log('Hello from Parent');
    }
};

var child = Object.create(parent);
child.age = 10;

console.log(child.name); // 输出 'Parent'
child.sayHello(); // 输出 'Hello from Parent'

(5)原型式继承

function createChild(parent) {
    var child = Object.create(parent);
    child.age = 10;
    return child;
}

var parent = {
    name: 'Parent',
    sayHello: function() {
        console.log('Hello from Parent');
    }
};

var child = createChild(parent);
console.log(child.name); // 输出 'Parent'
child.sayHello(); // 输出 'Hello from Parent'

(6)寄生组合式继承

function inheritPrototype(child, parent) {
    var prototype = Object.create(parent.prototype);
    prototype.constructor = child;
    child.prototype = prototype;
}

function Parent(name) {
    this.name = name || 'Parent';
}
Parent.prototype.sayHello = function() {
    console.log('Hello from Parent');
};

function Child(name) {
    Parent.call(this, name);
    this.age = 10;
}
inheritPrototype(Child, Parent);

var child = new Child('Child');
console.log(child.name); // 输出 'Child'
child.sayHello(); // 输出 'Hello from Parent'

(7)介绍 this 各种情况下的指向问题

1、以函数形式调用时,this 指向 window
2、以方法的形式调用时,this 是调用方法的对象
3、以构造函数的形式调用时,this 是新创建的那个对象
4、使用 call 和 apply 调用时,this 是指定的那个对象
5、箭头函数:箭头函数的 this 看外层是否有函数

(8)for in 和 for of 的区别

1、推荐在循环对象属性的时候使用 for…in,在遍历数组的时候的时候使用 for…of
2、for…in 循环出的是 key,for…of 循环出的是 value
3、注意,for…of 是 ES6 新引入的特性。修复了 ES5 引入的 for…in 的不足
4、for…of 不能循环普通的对象,需要通过和 Object.keys()搭配使用

(9)用 JavaScript 实现冒泡排序

<script>
        let nums = [23,45,18,37,92,13,24]
        for(let i=0;i<nums.length-1;i++){
            for(let j=0;j<nums.length-i-1;j++){
                if(nums[j]>nums[j+1]){
                    let temp = nums[j];
                    nums[j]=nums[j+1];
                    nums[j+1] = temp;
                }
            }
        }
        console.log(nums);
</script>

(10)随机选取 10–100 之间的 10 个数字并排序

<script>
        let nums = []
        for(let i=0;i<10;i++){
            let temp = parseInt(Math.random()*(100-10+1))+10
            nums.push(temp);
        }
        nums.sort(function(a,b){
            return a-b;
        })
        console.log(nums);
    </script>

(11) foo=”get-element-by-id”,转化成“getElementById”

<script>
        function combo(msg){ 
            var arr=msg.split("-");
            for(var i=1;i<arr.length;i++){ 
                arr[i] = arr[i][0].toUpperCase() + arr[i].slice(1);
            }
            msg=arr.join(""); 
            return msg; 
        }
        console.log(combo('boy-girl-man-woman'));
    </script>

(12)提取url中的GET参数,返回一个json字符串

<script>
        function serilizeUrl(url) { 
            var result = {}
            if(/\?/.test(url)){
                let str_para = url.substring(url.indexOf('?')+1);
                let str_arr = str_para.split('&');
                for(let i=0;i<str_arr.length;i++){
                    let temp = str_arr[i].split('=')
                    result[temp[0]] = temp[1];
                }
                return result;
            }
            return null;
        }
        console.log(serilizeUrl("http://item.taobao.com/item.htm?a=1&b=2&c=&d=xxx&e"));
</script>

(13)写一个 function,清除字符串前后的空格。(兼容所有浏览器)

if (!String.prototype.trim) {
	String.prototype.trim = function() {
		return this.replace(/^\s+/, "").replace(/\s+$/,"");
	}
}	
var str = " \t\n test string ".trim();
alert(str == "test string");

(14)判断一个字符串中出现次数最多的字符,统计这个次数

<script>
        let str = "sdflklsdjklklglsdkg"
        let json = {}
        for(let i = 0;i<str.length;i++){
            if(!json[str[i]]){
                json[str[i]] = 1
            }
            else {
                json[str[i]]++
            }
        }
        for(key in json){
            console.log(key+" "+json[key])
        }
</script>

(15)将数字 12345678 转化成 RMB 形式

<script>
        let num = 3422343.5252
        let str = num.toString();
        let dot_index = 0
        if(/\./.test(str))
            dot_index = str.indexOf('.');      
        else
            dot_index = str.length;    
        console.log(deal(str,dot_index))
        function deal(str,dot_index){
            let dh_index = [],dh_temp=0
            let result = ""
            for(let i=dot_index-1;i>=0;i-=3){
                if(i-3>=0){
                    dh_index.push(i-3);
                }
            }
            dh_index = dh_index.reverse()
            for(let i=0;i<str.length;i++){
                result += str[i];
                if(i==dh_index[dh_temp]){
                    result += ','
                    dh_temp++;
                }
            }
            return result
        }   
        
</script>

(16)深度clone

    <script>
        function clone(obj) {
            if (typeof obj == 'object') {
                if (obj instanceof Array) {
                    var result = [];
                    for (var i = 0; i < obj.length; i++) {
                        result[i] = clone(obj[i]);
                    }
                    return result;
                } else {
                    var result = {};
                    for (var i in obj) {
                        result[i] = clone(obj[i]);
                    }
                    return result;
                }
            }
            else {
                return obj;
            }
        }
        var obj1=[12, {a: 11, b: 22}, 5];
        var obj2=clone(obj1);
        obj2[1].a+=5;
        console.log(obj1, obj2); 

    </script>

(17)js 数组去重,能用几种方法实现

(1)使用Set

let arr = [1,2,3,4,3,2,3,4,6,7]
        let sett = new Set(arr)

(2)使用indexOf

let arr = [1,2,3,4,3,2,3,4,6,7]
        let newArr = []
        for(let i=0;i<arr.length;i++){
            if(arr.indexOf(arr[i])==i){
                newArr.push(arr[i])
            }
        }
        console.log(arr)
        console.log(newArr)

(3)双重for循环

(18)Javascript 垃圾回收机制

在Javascript中,基本数据类型存储在栈中,引用数据类型存储在堆中,但是引用数据类型会在栈中存储一个实际对象的引用。
当一个对象没有任何的变量或属性对它进行引用,此时我们将永远无法操作该对象,这种对象就是一个垃圾。
Javascript是一门单线程语言,它是运行在主线程上的,而在进行垃圾回收的时候就会阻塞Javascript脚本的执行,需等待垃圾回收完毕后再恢复脚本执行,这种行为叫全停顿
栈空间的数据回收方式 :在栈空间中有一个记录当前执行状态的指针,称为 ESP。当某一个执行上下文结束的时候,JS 就会将 ESP 移动到下一个执行上下文,整个下移操作就是销毁了上一个执行上下文的过程。这样上一个执行上下文虽然保存在栈空间当中,但是已经是无效内存了。而当有的数据要保存进来时,这一块内容就会覆盖掉。

在栈空间中,旧的执行上下文被移除后,仅仅是从栈空间中被移除了。但是如果这一段执行上下文含有堆空间的地址,那么对应堆空间的内存是不会被直接销毁的。而如果想要回收堆中的垃圾数据,就需要使用 JS 中的垃圾回收器。

方法一:引用计数标记

(1)当声明一个变量并且将一个引用类型数据赋值给这个变量的时候,这个引用类型数据的引用次数就标记为 1
(2)如果当这个引用类型数据又赋值给另一个变量,那么引用次数就+1
(3)如果变量被其他的值覆盖,则引用次数-1
(4)当这个引用类型数据的引用次数变为0的时候,这个变量就没有被使用了,也无法访问,垃圾回收器就会在执行时,销毁引用次数为0的引用类型数据,回收其所占用的内存空间。
注意: 这种方式可能会造成循环引用的问题

function test()
{
    let A = new Object();
    let B = new Object();

    A.pointer= B;
    B.pointer = A;
}
test();

当对象A和对象B的属性相互引用这,按照引用计数策略,他们的引用计数都是为2,但是在test()执行完成后,在函数执行完,函数作用域中的数据对象A和对象B都应该被GC销毁掉。如果执行多次,将会造成严重的内存泄漏。

解决办法: 在函数结束时,将其指向null

//切断引用关系
A = null;  // 将A指向null,两个引用对象计数器都-1变为1
B = null;	//将B指向null,两个引用对象计数器又都-1变为0

优点:
引用计数为零时,发现垃圾立即回收;最大限度减少程序暂停
缺点:
无法回收循环引用的对象;空间开销比较大

方法二:标记清除

垃圾回收程序运行的时候,会标记内存中的存储所有变量(记住,标记方法有很多种)。然后,它会将所有在上下文中的变量,以及被在上下文的变量引用的变量的标记去掉。在此之后在被加上标记的变量就是待删除的了,原因是任何在上下文中的变量都访问不到他们了。随后垃圾回收程序做一次内存清理,销毁带标记的所有值并收回他们的内存!
优点:
(1)实现简单,标记情况无非是打与不打的两种情况,通过二进制(0和1)就可以为其标记。
(2)能够回收循环引用的对象
(3)是v8引擎使用最多的算法。
缺点:
在清除垃圾之后,剩余对象的内存位置是不变的,就会导致空闲内存空间不连续。这样就出现了内存碎片,并且由于剩余空间不是整块,就需要内存分配的问题。

标记整理(Mark-Compact)算法 在标记结束后标记整理算法会将不需要清理的对象向内存一端移动,最后清理边界的内存。

(19)V8引擎对GC的优化

分代回收机制:
v8中将内存分成了两个区,新生代老生代。新生代对象存活时间较短。而老生代存储存活时间较长或常驻内存的对象。对于新老两块内存区域的垃圾回收频率不同,所以V8 采用了两个垃圾回收器来管控。

新生代垃圾回收

新生代垃圾回收通过Scavenge策略进行垃圾回收,具体采用Cheney算法。Cheney算法将堆内存也分为两个区,一个使用状态的空间我们称为使用区。一个处于闲置状态的空间称为空闲区。新加入的对象都会被存放到使用区,当使用区快被写满时,就执行一次垃圾回收操作。

(1)垃圾回收流程
先对使用区中的活动做标记
标记完成后,将使用区的活动对象复制进空闲区并进行排序
将原先使用区对象占用的空间释放
最后进行角色互换,把空闲区变为使用区,使用区变为空闲区
(2)新生代对象何时会到老生代?
第一种情况:经过多次复制后依然存活的对象会被认为是生命周期较强的对象,会被移到老生代管理。
第二种情况:如果复制一个对象到空闲区时,空闲区空间占用超过25%,那么这个对象将被移到老生代区域。原因是,当完成Scavenge回收后,空闲区转变成使用区,需继续进行内存分配,若占比过大,将会影响后续内存的分配。

老生代垃圾回收

老生代数据大多是存活的对象,不需要时常清除更新,所以采用上面提到的标记清除法来进行垃圾回收。因为上面也提到标记清除后会产生大量内存碎片,所以V8就采用了上文所说的标记整理法来解决这个问题。

并行策略虽然可以增加垃圾回收的效率,对于新生代这样存放较小对象的回收器能有很好的优化,但其实还是全停顿式的。对于存放较大对象的老生代来说,这些较大对象GC时哪怕使用并行策略依旧会消耗大量时间。所以V8对老生代进行了优化,从全停顿标记切换到了增量标记
增量标记:就是将一次GC分成多步小GC标记,让JS和小GC标记交替执行,直到标记完成。

并发回收

并发主要发生在工作线程上。当在工作线程(辅助线程)执行GC是,应用程序可以继续在主线程运行并不会被挂起。
这也是有问题的,因为GC也在进行,应用程序也在执行,此时对象的引用关系随时都有可能变化,所以之前做的一些标记就需要改变,所以需要读写锁机制来控制这一点。

(20)js 如何处理防抖和节流

在进行窗口的 resize、scroll,输入框内容校验等操作时,如果事件处理函数调用的频率无限制,会加重浏览器的负担,导致用户体验非常糟糕
此时我们可以采用 debounce(防抖)和 throttle(节流)的方式来减少调用频率,同时又不影响实际效果

函数防抖:
函数防抖(debounce):当持续触发事件时,一定时间段内没有再触发事件,事件处理函数
才会执行一次,如果设定的时间到来之前,又一次触发了事件,就重新开始延时
函数节流:
函数节流(throttle):当持续触发事件时,保证一定时间段内只调用一次事件处理函数

总结:
函数防抖:将几次操作合并为一此操作进行。原理是维护一个计时器,规定在 delay 时间后触发函数,但是在 delay 时间内再次触发的话,就会取消之前的计时器而重新设置。这样一来,只有最后一次操作能被触发
函数节流:使得一定时间内只触发一次函数。原理是通过判断是否到达一定时间来触发函数

区别:
函数节流不管事件触发有多频繁,都会保证在规定时间内一定会执行一次真正的事件处理函数,而函数防抖只是在最后一次事件后才触发一次函数。比如在页面的无限加载场景下,我们需要用户在滚动页面时,每隔一段时间发一次Ajax 请求,而不是在用户停下滚动页面操作时才去请求数据。这样的场景,就适合用节流技术来实现

五、ES6

(1)说几个 ES6 的新增方法

1、 let 和 const

2、模板字符串(Template String)
用一对反引号(`)标识,它可以当作普通字符串使用,也可以用来定义多行字符串,也可以在字符串中嵌入变量,js 表达式或函数,变量、js 表达式或函数需要写在${ }中。

3、函数的扩展
3.1)函数的默认参数:ES6 为参数提供了默认值。在定义函数时便初始化了这个参数,以便在参数没有被传递进去时使用。
3.2)箭头函数:在 ES6 中,提供了一种简洁的函数写法,我们称作“箭头函数”。

4、对象的扩展
4.1)属性的简写:ES6 允许在对象之中,直接写变量。这时,属性名为变量名, 属性值为变量 的值。

var foo = 'bar';
var baz = {foo}; //等同于 var baz

4.2)Object.keys()方法:获取对象的所有属性名或方法名(不包括原形的内容),返回一个数组。

4.3)Object.assign ()
assign 方法将多个原对象的属性和方法都合并到了目标对象上面。可以接收多个参数,第一个参数是目标对象,后面的都是源对象

5、for…of 循环

6、import 和 export
export 用于对外输出本模块(一个文件可以理解为一个模块)变量的接口
import 用于在一个模块中加载另一个含有 export 接口的模块
import 和 export 命令只能在模块的顶部,不能在代码块之中

7、Promise 对象

8、解构赋值
8.1)数组的解构赋值

let [a, b, c] = [1, 2, 3];
 // a = 1 // b = 2 // c=3

8.2)对象的解构赋值

let { foo, bar } = { foo: 'aaa', bar: 'bbb' }; // foo = 'aaa' // bar = 'bbb'
let { baz : foo } = { baz : 'ddd' }; // foo = 'ddd'

9、Set
9.1)Set 属性和方法
Size() 数据的长度
Add() 添加某个值,返回 Set 结构本身。
Delete() 删除某个值,返回一个布尔值,表示删除是否成功。
Has() 查找某条数据,返回一个布尔值。
Clear()清除所有成员,没有返回值。
9.2)主要应用场景:数组去重

10、class

11、…
展开运算符可以将数组或对象里面的值展开;还可以将多个值收集为一个变量

12、async、await
使用 async/await, 搭配 Promise,可以通过编写形似同步的代码来处理异步流程, 提高代码的简洁性和可读性 async 用于声明一个 function 是异步的,而 await 用于等待一个异步方法执行完成

13、Symbol

14、Proxy

(2)ES6 的继承和 ES5 的继承有什么区别

ES5 的继承是通过原型或者是构造函数机制来实现
ES6 用过 class 关键字定义类,里面有构造方法,类之间通过 extends 关键字实现,子类必须在 constructor 方法中调用 super 方法

(3)var、let、const 之间的区别

1.变量提升
2.块级作用域
3.const的特性

(4)module、export、import 有什么作用

export、import 就是用来实现前端模块化的工具。
import 引入的模块是静态加载(编译阶段加载)而不是动态加载(运行时加载)。

在用import引入时,如果是用export方法定义的导出,必须要知道指定的变量名。而如果使用export default定义的时候,import可以起任意的名字,这里可以理解为,用export default声明导出模块时,自动生成了一个叫default的变量,当使用import命令导入时,会自动将这个defualt变量赋值给声明的变量中。这也就解释了为什么export default仅有一个。注:export default命令其实只是输出一个叫做default的变量,所以它后面不能跟变量声明语句.

(5)举例ES6 对 String 字符串类型做的常用升级优化

模板字符串:在拼接大段字符串时,用反斜杠(`)取代以往的字符串相加的形式,
能保留所有空格和换行,使得字符串拼接看起来更加直观,更加优雅。
ES6 在 String 原型上新增了 includes()方法,用于取代传统的只能用 indexOf()查找包含字符的方法(indexOf()返回-1 表示没查到,不如 includes()方法返回 false 更明确,语义更清晰),还新增了 startsWith(), endsWith(), padStart(),padEnd(),repeat()等方法,可方便的用于查找,补全字符串。

(6)举例 ES6 对 Array 数组类型做的常用升级优化

解构赋值
扩展运算符
ES6 在 Array 原型上新增了 find()方法,用于取代传统的只能用 indexOf()查找包含数组项目的方法,且修复了 indexO()f 查找不到 NaN 的 bug([NaN].indexOf(NaN) === -1).此外还新增了 copyWithin(), includes(), fill(),flat()等方法,可方便的用于字符串的查找,补全,转换等

(7)举例 ES6 对 Function 函数类型做的常用升级优化

1、箭头函数
箭头函数内的 this 指向的是函数定义时所在的对象,而不是函数执行时所在的对
。ES5 函数里的 this 总是指向函数执行时所在的对象,这使得在很多情况下 this 的指向变得很难理解,
箭头函数的内部没有自己的 this,这也就导致了 this 总是指向上一层的 this,如果上一层还是箭头函数,则继续向上指,直到指向到有自己 this的函数为止,并作为自己的 this。箭头函数不能用作构造函数,因为它没有自己的 this,无法实例
2、函数默认赋值
ES6 之前,函数的形参是无法给默认值得,只能在函数内部通过变通方法实现。ES6 以更简洁更明确的方式进行函数默认赋值

(8)举例 ES6 对 Object 类型做的常用升级优化?

1、对象属性变量式声明。
2、对象的解构赋值
3、对象的扩展运算符(…)
4、 super 关键字
ES6 在 Class 类里新增了类似 this 的关键字 super。同 this 总是指向当前函数所在的对象不同,super 关键字总是指向当前函数所在对象的原型对象

(1)新增了 assign()方法
(2)新增了 is()方法
(3)新增了 getOwnPropertyDescriptors()方法
(4)ES6 在 Object 原型上新增了 getPrototypeOf()和 setPrototypeOf()方法,用来获取或设置当前对象的 prototype 对象。
(5)ES6 在 Object 原型上还新增了 Object.keys(),Object.values(),Object.entries()方法,用来获取对象的所有键、所有值和所有键值对数组。

(9)使用箭头函数应注意什么/箭头函数和普通函数的区别

用了箭头函数,this指向是会改变的
不能够使用 arguments 对象
不能用作构造函数,这就是说不能够使用 new 命令,否则会抛出一个错误
不可以使用 yield 命令,因此箭头函数不能用作 Generator 函数

(10)setTimeout、Promise、Async/Await 的区别

事件循环中分为宏任务队列微任务队列
宏任务(macrotask):在新标准中叫 task
主要包括:script(整体代码),setTimeout,setInterval,setImmediate,I/O,ui rendering
微任务(microtask):在新标准中叫 jobs
主要包括:process.nextTick, Promise,MutationObserver(html5 新特性)

setTimeout、Promise、Async/Await 的区别
setTimeout 的回调函数放到宏任务队列里,等到执行栈清空以后执行
Promise.then 里的回调函数会放到相应宏任务的微任务队列里,等宏任务里面的同步代码执行完再执行
async 函数表示函数里面可能会有异步方法,await 后面跟一个表达式
async 方法执行时,遇到 await 会立即执行表达式,然后把表达式后面的代码放到微任务队列里,让出执行栈让同步代码先执行

(11)Promise 怎么让一个函数无论成功还是失败都能被调用?

1.笨方法:在then和catch中都调用
2.finally中调用,但是此时的函数只能在末尾调用,若需要再中间调用则解决不了。
3.使用promise.all()

(12)ES6 如何转化为 ES5

浏览器对 ES6 的支持程度并不是很好,如果写了ES6 的代码,需要运行在浏览器上的时候,需要将 ES6 的代码转成 ES5 的代码去浏览器上运行。
babel 是一个 ES6 转码器,可以将 ES6 代码转为 ES5 代码,以便兼容那些还没支持 ES6 的平台

(13)Promise 中 reject 和 catch 处理上有什么区别

(1)reject是用来抛出异常,catch是用来处理异常
(2)reject是Promise的方法,而catch是Promist对象的方法
(3)reject 后的东西,一定会进入 then 中的第二个回调,如果 then 中没有写第二个回调,则进入catch
(4)网络异常(比如断网),会直接进入 catch 而不会进入 then 的第二个回调

(14)理解 async/await

async await 是用来解决异步的,async 函数是 Generator 函数的语法糖
使用关键字 async 来表示,在函数内部使用 await 来表示异步
async 函数返回一个 Promise 对象,可以使用 then方法添加回调函数
当函数执行的时候,一旦遇到 await 就会先返回,等到异步操作完成,再接着执行函数体内后面的语句

(15)手写一个 Promise

<script>
          const p = new Promise((resolve,reject) => {
            reject(4);
            resolve(5);
            
          }).then(result => {
            console.log(result);
          },error => {
            console.log(error);
          })
</script>

!!!!!!(16)Promise 如何封装一个 Ajax

(17)设计对象,键名的类型有个 symbol 类型,并且遍历 key

let name = Symbol('name');
let product = {
[name] : "平衡车",
"price" : 1999
};
Reflect.ownKeys(product);

(18)下面 Set 结构,打印出的 size 值是多少

let s = newSet();
s.add([1]);s.add([1]);
console.log(s.size);
2

注意加的是[1],而不是1

(19)说一下 ES6 的导入导出模块

导入模块:通过 import 关键字
// 只导入一个
import {sum} from “./example.js”
// 导入多个
import {sum,multiply,time} from “./exportExample.js”
// 导入一整个模块
import * as example from "./exportExample.js

导出模块:通过 export 关键字
//可以将 export 放在任何变量,函数或类声明的前面
export var firstName = ‘Chen’
//也可以使用大括号指定所要输出的一组变量
var firstName = ‘Chen’;
var lastName = ‘Sunny’;
var year = 1998;
export {firstName, lastName, year}
//使用 export default 时,对应的 import 语句不需要使用大括号
let bosh = function crs(){}
export default bosh;
import crc from ‘crc’;
//不使用 export default 时,对应的 import 语句需要使用大括号
let bosh = function crs(){}
export bosh;
import {crc} from 'crc

六、Ajax/计算机网络相关

(1)Ajax 应用和传统 web 应用有什么不同

页面加载方式:
传统 Web 应用:传统 Web 应用通常采用服务器端渲染(Server-Side Rendering, SSR)方式,即每次用户请求页面时,服务器会生成完整的 HTML 页面并将其发送给浏览器。
Ajax 应用:Ajax 应用通常采用客户端渲染(Client-Side Rendering)方式,即页面的大部分内容在客户端通过 JavaScript 动态加载和渲染,与服务器的交互是通过异步的 Ajax 请求进行的,页面在加载时不需要重新刷新。

用户体验:
传统 Web 应用:由于每次请求都需要加载完整的页面,因此页面切换会有较明显的延迟,用户体验相对较差。
Ajax 应用:使用 Ajax 技术可以实现页面的局部更新,从而提升用户体验,因为页面切换和数据加载是异步进行的,用户可以更快地获取到所需的信息。

数据交互方式:
传统 Web 应用:在传统 Web 应用中,页面的数据交互主要通过页面的完整加载和提交表单来实现。
Ajax 应用:Ajax 应用通过 JavaScript 发起异步请求来获取和提交数据,页面的数据交互更加灵活,并且可以在不重新加载页面的情况下更新部分数据。

(2)Ajax 请求总共有多少种 Callback

1)onSuccess 2)onFailure 3)onUninitialized 4)onLoading
5)onLoaded 6)onInteractive 7)onComplete 8)onException

(3)什么是 Ajax,Ajax 都有哪些优点和缺点?

Ajax是指一种创建交互式网页应用的网页开发技术。沟通客户端与服务器,可以在【不必刷新整个浏览器】的情况下,与服务器进行异步通讯的技术
原理
通过 XmlHTTPRequest 对象来向服务器发异步请求,从服务器获得数据,然后用 javascript 来操作 DOM 而更新页面。这其中最关键的一步就是从服务器获得请求数据。
XMLHTTPRequest 是 Ajax 的核心机制,它是在 IE5 中首先引入的,是一种支持异步请求的技术。简单的说,也就是 javascript 可以及时向服务器提出请求和处理响应,而不阻塞用户。达到无刷新的效果。

Ajax 的优点
1、最大的一点是页面无刷新,用户的体验非常好。
2、使用异步方式与服务器通信,具有更加迅速的响应能力。
3、可以把以前一些服务器负担的工作转嫁到客户端,利用客户端闲置的能力来处理, 减轻服务器和带宽的负担,节约空间和宽带租用成本。并且减轻服务器的负担,Ajax 的原则是“按需取数据”,可以最大程度的减少冗余请求,和响应对服务器造成的负担。
4、基于标准化的并被广泛支持的技术,不需要下载插件或者小程序。

Ajax 的缺点
1、Ajax 不支持浏览器 back 按钮。
2、安全问题 Ajax 暴露了与服务器交互的细节。
3、对搜索引擎的支持比较弱。
4、破坏了程序的异常机制。
5、不容易调试

(3)常见的 HTTP 状态码以及代表的意义

100 => 正在初始化(一般是看不到的)

101 => 正在切换协议(websocket 浏览器提供的)
HTTP 状态码 101 是「切换协议」表明服务器正在根据客户端的请求切换协议。
一般情况下,客户端发送一个协议升级请求,请求服务器切换到另一种更适合的通信协议。例如,客户端可能发送一个 WebSocket 升级请求,请求服务器从 HTTP 协议切换到 WebSocket 协议。
当服务器收到这样的请求时,如果支持升级到指定的协议,就会发送一个状态码为 101 的响应,表示同意切换协议。这个响应通常会伴随着一个升级头(Upgrade header),用来指定要升级到的协议。接着,客户端和服务器就会按照新的协议进行通信。

200( OK):请求已成功,请求所希望的响应头或数据体将随此响应返回。

202 => 表示接受
HTTP 状态码 202 是「已接受」表明请求已被接受,但处理尚未完成。通常,服务器在接收到请求后会返回 202 状态码,表示请求已被接受,但处理可能需要一段时间,或者在后台进行。

301 => 永久重定向/永久转移
HTTP 状态码 301 是「永久重定向」表明请求的资源已被永久移动到了新的位置,并且未来所有对该资源的请求都应该使用新的 URL。

302 => 临时重定向/临时转移(一般用来做服务器负载均衡)
HTTP 状态码 302 是「临时重定向」表明请求的资源已临时移动到了新的位置,但未来请求仍应该使用原始的 URL。

303( See Other):告知客户端使用另一个 URL 来获取资源。
304 => 本次获取的内容是读取缓存中的数据,会每次去服务器校验

400( Bad Request):请求格式错误。1)语义有误,当前请求无法被服务器理解。除非进行修改,否则客户端不应该重复提交这个请求;2)请求参数有误。
401 => 未认证,没有登录网站
403 => 禁止访问,没有权限
404( Not Found):请求失败,请求所希望得到的资源未被在服务器上发现。

500( Internal Server Error):服务器遇到了一个未曾预料的状况,导致了它无法完成对请求的处理。
503 => 服务器超负荷(假设一台服务器只能承受 10000 人,当第 10001 人访问的时候,如果服务器没有做负载均衡,那么这个人的网络状态码就是 503)

(4)请介绍一下 XMLHTTPrequest 对象及常用方法和属性

通过 XMLHTTPRequest 对象,Web 开发人员可以在页面加载以后进行页面的局部更新
方法:
open(String method,String url,boolean asynch,String username,String password)
send(content)
setRequestHeader(String header,String value)
getAllResponseHeaders()
getResponseHeader(String header)
abort()

open():该方法创建 HTTP 请求
第一个参数是指定提交方式(post、get)
第二个参数是指定要提交的地址是哪
第三个参数是指定是异步还是同步(true 表示异步,false 表示同步)
第四和第五参数在 HTTP 认证的时候会用到。是可选的
setRequestHeader(String header,String value):设置消息头(使用 post 方式才会使用到,get 方法并不需要调用该方法)
xmlHTTP.setRequestHeader(“Content-type”,“application/x-www-form-urlencoded”);
send(content):发送请求给服务器
如果是 get 方式,并不需要填写参数,或填写 null
如果是 post 方式,把要提交的参数写上

onreadystatechange:请求状态改变的事件触发器(readyState 变化时会调用此方法),一般用于指定回调函数
readyState:请求状态 readyState 一改变,回调函数被调用,它有 5 个状态
0:未初始化
1:open 方法成功调用以后
2:服务器已经应答客户端的请求
3:交互中。HTTP 头信息已经接收,响应数据尚未接收。
4:完成。数据接收完成

responseText:服务器返回的文本内容
responseXML:服务器返回的兼容 DOM 的 XML 内容
status:服务器返回的状态码
statusText:服务器返回状态码的文本信息

(5)Ajax 的实现流程是怎样的?

步骤:
1、创建 XMLHTTPRequest 对象,也就是创建一个异步调用对象.
2、创建一个新的 HTTP 请求,并指定该 HTTP 请求的方法、URL 及验证信息.
3、设置响应 HTTP 请求状态变化的函数.
4、发送 HTTP 请求.
5、获取异步调用返回的数据.
6、使用 JavaScript 和 DOM 实现局部刷新

<script type="text/javascript">
        var HTTPRequest;
        function checkUsername() {
              //创建 XMLHTTPRequest 对象
            if (window.XMLHTTPRequest) {
                  //在 IE6 以上的版本以及其他内核的浏览器(Mozilla)等
                HTTPRequest = new XMLHTTPRequest();
            } else if (window.ActiveXObject) {
                  //在 IE6 以下的版本
                HTTPRequest = new ActiveXObject();
            }
              //创建 HTTP 请求
            HTTPRequest.open("POST", "Servlet1", true);
               //因为我使用的是 post 方式,所以需要设置消息头
            HTTPRequest.setRequestHeader("Content-type",
                "application/x-www-form-urlencoded"); 
                  //指定回调函数
            HTTPRequest.onreadystatechange = response22;
               //得到文本框的数据
            var name = document.getElementById("username").value; 
              //发送 HTTP 请求,把要检测的用户名传递进去
            HTTPRequest.send("username=" + name);
        }
          //接收服务器响应数据
        function response22() {
              //判断请求状态码是否是 4【数据接收完成
            if(HTTPRequest.readyState==4) {
           //再判断状态码是否为 200【200 是成功的】
                if(HTTPRequest.status==200) {
           //得到服务端返回的文本数据
                    var text = HTTPRequest.responseText; //把服务端返回的数据写在 div 上
                    var div = document.getElementById("result");
                    div.innerText = text;
                }
            }
        }
    </script>

(6)Ajax 接收到的数据类型有哪些,数据如何处理?

JSON 对象直接循环使用
JSON 字符串转 JSON 使用
String 直接使用

处理数据
1、字符串转对象
// 第一种方式:eval();
var data=‘{“student”:[{“name”:“张三”,“age”:“11”},{“name”:“李四”,“age”:“11”},{“name”:“王五”,“age”:“11”}]}’;
eval(‘(“+data+”)’);

// 第二种方式:JSON.parse();
var data=‘{“student”:[{“name”:“张三”,“age”:“11”},{“name”:“李四”,“age”:“11”},{“name”:“王五”,“age”:“11”}]}’;
JSON.parse(data);

区别: eval()方法不会去检查给的字符串时候符合 json 的格式,同时如果给的字符串中存在 js 代码 eval()也会一并执行,而JSON.parse()方法会检查需要转换的字符串是否符合 json 格式。相比而言 eval()方法是很不安全,推荐使用 JSON.parse()来实现 json格式字符串解析

2、对象转字符串
JSON.stringify(json)

(7)为什么会有跨域的问题出现,如何解决跨域问题

跨域: 它是由浏览器的同源策略造成的,是浏览器对javascript 施加的安全限制,防止他人恶意攻击网站。当一个页面的文档或者脚本试图从不同源的服务器加载资源时,就会出现跨域问题。
解决方式
1、jsonp
原理:动态创建一个 script 标签。利用 script 标签的 src 属性不受同源策略限制。因为所有的 src 属性和 href 属性都不受同源策略限制。可以请求第三方服务器数据内容。
步骤
1.1)去创建一个 script 标签
1.2)script 的 src 属性设置接口地址
1.3)接口参数,必须要带一个自定义函数名 要不然后台无法返回数据。
1.4)通过定义函数名去接收后台返回数据

//去创建一个 script 标签
var script = document.createElement("script"); 
//script 的 src 属性设置接口地址 并带一个 callback 回调函数名称
script.src = "HTTP://127.0.0.1:8888/index.php?callback=jsonpCallback"; 
//插入到页面
document.head.appendChild(script); 
//通过定义函数名去接收后台返回数据 
function jsonpCallback(data){
	//注意 jsonp 返回的数据是 json 对象可以直接使用
	//Ajax 取得数据是 json 字符串需要转换成 json 对象才可以使用。
}

跨域服务器在返回数据时,会将数据包裹在这个回调函数中,

<script>
function myCallback(data) {
  console.log('Received data:', data);
}
</script>
myCallback({ "name": "John", "age": 30 });

2、 CORS:跨域资源共享
原理:服务器设置 Access-Control-Allow-OriginHTTP 响应头之后,浏览器将会允许跨域请求
限制:浏览器需要支持 HTML5,可以支持 POST,PUT 等方法兼容 ie9 以上
需要后台设置
Access-Control-Allow-Origin: * //允许所有域名访问,或者
Access-Control-Allow-Origin: HTTP://a.com //只允许所有域名访问

3、反向代理
4、window+iframe

(8)Get 和 Post 的区别?什么情况下用到

(1)用途方面: GET 请求通常用于从服务器获取数据,而POST通常用于提交数据给服务器
(2)参数传递方式: GET 请求通过 URL 参数传递数据,数据会附加在 URL 的末尾,由于是明文传输,因此不适合传输敏感信息;而POST 请求将数据放在BODY中,因此适用于传输大量数据,数据不会暴露在 URL 中,POST 请求相对于 GET 请求更安全。
(3)缓存: GET 请求可以被缓存,适用于无持续性的无副作用的请求,如静态资源的获取。POST 请求默认不会被缓存,因为它可能对服务器资源进行修改,需要重新请求获取最新的数据。

(9)解释 jsonp 的原理

原理:
通过动态创建 script 标签,然后通过标签的 src 属性获取 js 文件中的 js 脚本,该脚本的内容是一个函数调用,参数就是服务器返回的数据,为了处理这些返回的数据,需要事先在页面定义好回调函数,(本质上使用的并不是 Ajax 技术,Ajax 请求受同源策略的影响,不允许进行跨域请求)而 script 标签的 src 属性中的链接却可以访问跨域的 js 脚本,利用这个特性,服务端不在返回 json 格式的数据,而是返回调用某个函数的 js 代码,在 src 中进行了调用,这样就实现了跨域

!!(10)jQuery 中 Ajax 、fetch 、axios 异同,适用场景?

(11)Ajax 注意事项及适用和不适用场景

Ajax 开发时,网络延迟——即用户发出请求到服务器发出响应之间的间隔——需要慎重考虑。不给予用户明确的回应,没有恰当的预读数据,或者对 XMLHTTPRequest 的不恰当处理,都会使用户感到延迟,这是用户不希望看到的,也是他们无法理解的。通常的解决方案是,使用一个可视化的组件来告诉用户系统正在进行后台操作并且正在读取数据和内容。

(12)HTTP 与 HTTPS的区别

安全性:
HTTP:HTTP 是一种明文传输协议,数据在传输过程中不进行加密,存在安全风险。
HTTPS:HTTPS 在 HTTP 的基础上加入了 SSL/TLS 加密,所有数据在传输过程中都进行加密处理,确保数据的安全性。

数据传输方式:
HTTP:HTTP 使用 TCP 协议传输数据,数据传输过程中不进行加密处理。
HTTPS:HTTPS 也使用 TCP 协议传输数据,但在 TCP 连接之上加入了 SSL/TLS 加密处理,确保数据在传输过程中的安全性。

端口号:
HTTP:HTTP 默认使用端口号 80。
HTTPS:HTTPS 默认使用端口号 443。

证书要求:
HTTP:HTTP 不需要证书,任何网站都可以使用 HTTP 协议。
HTTPS:HTTPS 需要网站持有有效的 SSL/TLS 证书,证书由可信的第三方机构颁发,用于验证网站的身份,并确保数据传输的安全性。

SEO(搜索引擎优化):
HTTP:由于 HTTP 传输的数据不安全,因此在搜索引擎优化(SEO)方面可能会受到影响。
HTTPS:HTTPS 提供了更高的数据安全性,同时也提高了网站在搜索引擎中的排名,因为搜索引擎更倾向于显示安全的网站。

(13)简述 cookie 机制,并结合该机制说明会话保持原理

Cookie 是进行网站用户身份验证,实现服务端 Session 会话持久化的一种非常好的方式
1、为什么需要 Cookie
HTTP 是一种无状态的协议,客户端与服务器建立连接并传输数据,数据传输完成后,连接就会关闭。再次交互数据需要建立新的连接,因此,服务器无法从连接上跟踪会话,也无法知道用户上一次做了什么。这严重阻碍了基于 Web 应用程序的交互,也影响用户的交互体验。
本质上讲,Cookie 是一段文本信息,解决 HTTP 无状态性的有效手段,服务器可以设置或读取 Cookie 中所包含的信息。当用户登录后,如果服务器需要记录用户状态,就在响应用户请求时发送包含登录凭据的 Cookie 到用户浏览器客户端,而浏览器对该Cookie 进行某种形式的存储(内存或硬盘)。用户再次访问该网站时,浏览器会发送该 Cookie(Cookie 未到期时)到服务器,服务器对该凭据进行验证,合法时使用户不必输入用户名和密码就可以直接登录。
2、 Cookie 的类型

按其存储位置可分为:内存式 Cookie和硬盘式 Cookie
内存式 Cookie 存储在内存中,浏览器关闭后就会消失,由于其存储时间较短,因此也被称为非持久 Cookie会话 Cookie
硬盘式 Cookie 保存在硬盘中,其不会随浏览器的关闭而消失,除非用户手工清理或到了过期时间。由于硬盘式 Cookie 存储时间是长期的,因此也被称为持久 Cookie

3、Cookie 的实现原理
Cookie 定义了一些 HTTP 请求头和 HTTP 响应头,通过这些 HTTP 头信息使服务器可以与客户进行状态交互。
客户端请求服务器后,如果服务器需要记录用户状态,服务器会在响应信息中包含一个Set-Cookie 的响应头,客户端会根据这个响应头存储 Cookie 信息。再次请求服务器时,客户端会在请求信息中包含一个 Cookie 请求头,而服务器会根据这个请求头进行用户身份、状态等较验。

下面是一个实现 Cookie 机制的,简单的 HTTP 请求过程:
3.1)客户端请求服务器
客户端请求 IT 笔录网站首页,请求头如下:
GET / HTTP/1.0
HOST: itbilu.com
3.2)服务器响应请求
Cookie 是一种 key=value 形式的字符串,服务器需要记录这个客户端请求的状态,因此在响应头中包一个 Set-Cookie 字段。响应头如下:
HTTP/1.0 200 OK
Set-Cookie: UserID=itbilu; Max-Age=3600; Version=1
Content-type: text/html ……
3.3)再次请求时,客户端请求中会包含一个 Cookie 请求
客户端会对服务器响应的 Set-Cookie 头信息进行存储。再次请求时,将会在请求头中
包含服务器响应的 Cookie 信息。请求头如下
GET / HTTP/1.0
HOST: itbilu.com
Cookie: UserID=itbilu

(14)从输入 URL 到页面加载显示完成,这个过程经历了什么

1、浏览首先会查看缓存,如果资源未缓存,发起新请求。如果已缓存,检验是否⾜够新鲜,⾜够新鲜直接提供给客户端,否则与服务器进⾏验证。
(强缓存:
浏览器首先检查强缓存,如果缓存中存在请求的资源且缓存未过期(即缓存有效期内),则浏览器直接从缓存中获取资源,不发送请求到服务器。在这种情况下,请求的响应状态码为 200(OK),浏览器不会向服务器发送请求。
协商缓存:
如果强缓存失效,浏览器会发送带有缓存验证信息的请求到服务器。服务器根据请求中的缓存验证信息(如 Last-Modified、ETag 等)来判断资源是否已经被修改。
如果资源未被修改,服务器返回状态码 304(Not Modified),通知浏览器直接使用缓存中的资源,不返回实际的资源内容;如果资源已被修改,则返回新的资源内容和状态码 200。

2.浏览器查找域名对应的 IP 地址(DNS 查询:浏览器缓存->系统缓存->路由器缓存->ISP DNS 缓存->根域名服务器)
3.打开⼀个socket与⽬标IP地址,端⼝建⽴TCP链接,三次握⼿如下:
客户端发送⼀个TCP的SYN=1,Seq=X的包到服务器端口
服务器发回SYN=1, ACK=X+1, Seq=Y的响应包
客户端发送ACK=Y+1, Seq=Z
4.TCP链接建⽴后发送HTTP请求
5.服务器接受请求并解析,将请求转发到服务程序,服务器检查HTTP请求头是否包含缓存验证信息,如果验证缓存新鲜,返回304等对应状态码
6.服务器将响应报⽂通过TCP连接发送回浏览器
7。浏览器接收HTTP响应,然后根据情况选择关闭TCP连接或者保留重⽤,关闭TCP连接的四次挥手如下:
主动⽅发送Fin=1, Ack=Z, Seq= X报⽂
被动⽅发送ACK=X+1, Seq=Z报⽂
被动⽅发送Fin=1, ACK=X, Seq=Y报⽂
主动⽅发送ACK=Y, Seq=X报⽂
8.解析HTML⽂档,构件DOM树,下载资源,构造CSSOM树,执⾏js脚本,这些操作没有严格的先后顺序

js解析如下:
浏览器创建Document对象并解析HTML,将解析到的元素和⽂本节点添加到⽂档中,此时document.readystate为loading

HTML解析器遇到没有async和defer的script时,将他们添加到⽂档中,然后执⾏⾏内 或外部脚本。这些脚本会同步执⾏,并且在脚本下载和执⾏时解析器会暂停。这样就可以⽤document.write()把⽂本插⼊到输⼊流中。同步脚本经常简单定义函数和注册事件处理程序,他们可以遍历和操作script和他们之前的⽂档内容

当解析器遇到设置了async属性的script时,开始下载脚本并继续解析⽂档。脚本会在它 下载完成后尽快执⾏,但是解析器不会停下来等它下载。异步脚本禁止使用document.write(),它们可以访问⾃⼰script和之前的⽂档元素当⽂档完成解析,document.readState变成interactive

所有defer脚本会按照在⽂档出现的顺序执⾏,延迟脚本能访问完整⽂档树,禁止使⽤ document.write()

浏览器在Document对象上触发DOMContentLoaded事件

此时⽂档完全解析完成,浏览器可能还在等待如图⽚等内容加载,等这些内容完成载⼊ 并且所有异步脚本完成载⼊和执⾏,document.readState变为complete,window触发 load事件

9.显示完成页面(HTML解析过程中会逐步显示⻚⾯)

(15)你知道的 HTTP 请求方式有几种

HTTPRequestMethod 共计 17 种
1、GET 请求指定的页面信息,并返回实体主体。
2、HEAD 类似于 get 请求,只不过返回的响应中没有具体的内容,用于获取报头
3、POST 向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被
包含在请求体中。POST 请求可能会导致新的资源的建立和/或已有资源的修改。

4、PUT 从客户端向服务器传送的数据取代指定的文档的内容。
5、DELETE 请求服务器删除指定的页面。
6、CONNECT HTTP/1.1 协议中预留给能够将连接改为管道方式的代理服务器。
7、OPTIONS 允许客户端查看服务器的性能。
8、TRACE 回显服务器收到的请求,主要用于测试或诊断。
9、PATCH 实体中包含一个表,表中说明与该 URI 所表示的原内容的区别。
10、MOVE 请求服务器将指定的页面移至另一个网络地址。
11、COPY 请求服务器将指定的页面拷贝至另一个网络地址。
12、LINK 请求服务器建立链接关系。
13、UNLINK 断开链接关系。
14、WRAPPED 允许客户端发送经过封装的请求。
15、LOCK 允许用户锁定资源,比如可以再编辑某个资源时将其锁定,以防别人同时对其进行编辑。
16、MKCOL 允许用户创建资源
17、Extension-mothed 在不改动协议的前提下,可增加另外的方法

(16)描述一下 HTTP 的请求过程与原理

HTTP 请求的过程
域名解析 --> 发起 TCP 的 3 次握手 --> 建立 TCP 连接后发起 HTTP 请求 -->服务器响
应 HTTP 请求,浏览器得到 html 代码 -->浏览器解析 html 代码,并请求 html 代码中的资源(如 js、css、图片等) --> 浏览器对页面进行渲染呈现给用户
请求原理
HTTP 协议是应用层的一种协议,是一种 C/S 架构服务,基于 TCP/IP 协议来通信,监听在TCP 的 80 端口上,HTTP 协议实现的是客户端可以向服务端获得 web 资源

(17)HTTPS 的原理

原理: HTTPS 在传输数据前需要客户端(浏览器)与服务器(网站)之间进行一次握手,通常称为 SSL/TLS 握手。在握手过程中将确立双方加密传输数据的密码信息.TLS/SSL 协议是一套加密传输协议,使用了非对称加密,对称加密,以及 HASH 算法,
(SSL/TLS 握手过程包括以下步骤:
客户端发送一个握手请求给服务器,请求建立安全连接,并向服务器发送自己支持的加密算法和通信协议版本等信息。
服务器收到客户端的请求后,确认双方使用的加密算法和协议,并发送自己的数字证书给客户端。
客户端收到服务器的数字证书后,首先验证证书的有效性,包括验证证书的签发机构、有效期等信息。如果验证通过,则生成一个随机数,并使用服务器的公钥加密这个随机数,并发送给服务器。
服务器收到客户端发送的加密的随机数后,使用自己的私钥进行解密,得到客户端生成的随机数,并使用客户端的公钥加密一个确认信息,并发送给客户端。
客户端收到服务器发送的确认信息后,使用服务器的公钥解密,得到确认信息,至此,SSL/TLS 握手过程完成,安全连接建立成功。)
HTTPS 为什么安全
因为网络请求需要中间有很多的服务器路由器的转发。中间的节点都可能篡改信息,而如果使用 HTTPS,密钥在你和终点站才有。HTTPS 之所以比 HTTP 安全,是因为他利用 ssl/tls协议传输。它包含证书,卸载,流量转发,负载均衡,页面适配,浏览器适配,refer 传递等。保障了传输过程的安全性

(18) TCP 连接的三次握手、四次挥手

TCP三次握手、四次挥手
在这里插入图片描述
在这里插入图片描述
三次握手:
第一次握手:客户端第一次发送一条连接请求数据,SYN = 1,ACK = 0就是代表建立连接请求,发送的具体数据第一个字节编号记为x,赋值seq。
第二次握手:服务端收到请求后,返回 客户端的SYN = 1,加上自己的确认号ACK=1,发送的具体数据第一个字节编号记为y,赋值seq,希望客户端下一次返回编号x + 1个字节为止的数据,记为ack = x + 1。
客户端得出客户端发送接收能力正常,服务端发送接收能力也都正常,但是此时服务器并不能确认客户端的接收能力是否正常
第三次握手: 客户端收到服务端返回的请求确认后,再次发送数据,原封不动返回ACK = 1,这里就不需要再发送 SYN=1了,为什么呢?因为此时并不是跟服务端进行连接请求,而是连接确认,所以只需要返回ACK = 1代表确认,同样的,发送的具体数据第一个字节编号记为seq = x + 1,希望服务端下次传输的数据第一个字节编号记为ack = y + 1

为什么是三次握手
为了防止已失效的连接请求报文段突然有送到了服务器,因而产生错误,假设两次握手时,客户发出的第一个请求连接报文段在某一网络节点长时间滞留,以致延误到连接释放后才到达服务器。服务器收到失效的连接请求报文段后,认为是客户又发出一次新的连接请求。于是向客户发送确认报文段,同意建立连接,此时在假定两次握手的前提下,连接建立成功。这样会导致服务器的资源白白浪费。

四次挥手:
状态位: FIN = 1:代表要求释放连接

第一次挥手:Client发送一个FIN,用来关闭Client到Server的数据传送,Client进入FIN_WAIT_1状态。
第二次挥手:Server收到FIN后,发送一个ACK给Client,确认序号为收到序号+1(与SYN相同,一个FIN占用一个序号),Server进入CLOSE_WAIT状态。
第三次挥手:Server发送一个FIN,用来关闭Server到Client的数据传送,Server进入LAST_ACK状态。
第四次挥手:Client收到FIN后,Client进入TIME_WAIT状态,接着发送一个ACK给Server,确认序号为收到序号+1,Server进入CLOSED状态,完成四次挥手

关闭连接时,服务器收到对方的FIN报文时,仅仅表示对方不再发送数据了但是还能接收数据,而自己也未必全部数据都发送给对方了,所以己方可以立即关闭,也可以发送一些数据给对方后,再发送FIN报文给对方来表示同意现在关闭连接,因此,己方ACK和FIN一般都会分开发送,从而导致多了一次。为了确保正确关闭连接,所以需要四次。

(19)TCP 与 UDP 的区别有哪些

TCP是面向连接的,这个连接是可靠的、全双工的,并且包含了序列号和确认机制,确保数据的可靠性和顺序性。而UDP是面向无连接,所以TCP传输更可靠。
由于 TCP 的连接管理、确认和重传机制会增加一些额外的开销,所以它的效率不如 UDP。

(20)HTTP2 / HTTP1 之间的区别是什么

多路复用(Multiplexing):
HTTP/1.x 中,每个请求都需要建立单独的 TCP 连接,这导致了连接开销和延迟。而 HTTP/2 支持多路复用,允许在同一连接上并发发送多个请求和响应,从而减少了连接建立和关闭的开销,提高了性能。

头部压缩(Header Compression):
在 HTTP/1.x 中,每个请求和响应都会携带大量的头部信息,这些头部信息会占用大量的带宽。HTTP/2 使用了 HPACK 算法对头部信息进行压缩,减少了数据传输时的开销,提高了效率。

二进制传输(Binary Protocol):
HTTP/1.x 是基于文本的协议,消息内容和头部都是以纯文本形式传输的,这导致了一些不必要的解析开销。而 HTTP/2 使用了二进制格式进行数据传输,提高了解析效率和传输速度。

服务器推送(Server Push):
HTTP/2 支持服务器推送功能,允许服务器在客户端请求之前将相关资源推送给客户端,从而减少了客户端请求的延迟和等待时间,提高了页面加载速度。

(21)介绍一下 websocket

websocket 是一种网络通信协议,是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通信的协议。它允许在客户端和服务器之间进行双向实时通信。相比传统的 HTTP 请求-响应模型,WebSocket 提供了更高效的实时数据传输机制,特别适用于需要实时更新和即时通信的应用场景,如在线聊天、实时游戏等。

以下是 WebSocket 的一些主要特点和工作原理:
全双工通信: WebSocket 允许客户端和服务器之间建立持久的连接,双方可以同时发送和接收数据,实现了真正的全双工通信。这使得服务器可以主动向客户端推送数据,而不需要客户端发起请求。

简化的握手过程:WebSocket 握手过程使用 HTTP 协议进行升级,客户端发起 WebSocket 握手请求,服务器返回确认,并升级连接为 WebSocket 连接。这个握手过程相对简单,且只发生一次,之后客户端和服务器之间的通信就直接基于 WebSocket 协议进行。

低延迟、高效率:WebSocket 通过减少头部开销和减少不必要的握手和连接关闭的开销,实现了更低的延迟和更高的效率。与传统的 HTTP 请求-响应模型相比,WebSocket 能够更快速地传输数据,并且减少了网络带宽的消耗。

跨域支持:由于同源策略的限制,Web 应用通常只能与相同源的服务器进行通信。但是,WebSocket 提供了一种跨域通信的机制,允许在不同源之间建立连接,从而扩展了其应用范围。

客户端:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>WebSocket Chat</title>
</head>
<body>
  <input type="text" id="messageInput" placeholder="Type a message...">
  <button onclick="sendMessage()">Send</button>
  <ul id="messageList"></ul>

  <script>
    const ws = new WebSocket('ws://localhost:8080');

    ws.onopen = function() {
      console.log('Connected to WebSocket server');
    };

    ws.onmessage = function(event) {
      const messageList = document.getElementById('messageList');
      const listItem = document.createElement('li');
      listItem.textContent = event.data;
      messageList.appendChild(listItem);
    };

    function sendMessage() {
      const messageInput = document.getElementById('messageInput');
      const message = messageInput.value;
      ws.send(message);
      messageInput.value = '';
    }
  </script>
</body>
</html>

服务器:

const WebSocket = require('ws');

// 创建 WebSocket 服务器
const wss = new WebSocket.Server({ port: 8080 });

// 监听连接事件
wss.on('connection', function connection(ws) {
  console.log('Client connected');

  // 监听消息接收事件
  ws.on('message', function incoming(message) {
    console.log('Received: %s', message);

    // 广播收到的消息给所有连接的客户端
    wss.clients.forEach(function each(client) {
      if (client !== ws && client.readyState === WebSocket.OPEN) {
        client.send(message);
      }
    });
  });
});

(22)浏览器加载页面,script 脚本阻塞,defer 和 async 区别

加载页面的过程: 从浏览器地址栏的请求链接开始,浏览器通过 DNS 解析查到域名映射的 IP 地址,成功之后浏览器端向此 IP 地址取得连接,成功连接之后,浏览器端将请求信息通过 HTTP 协议向此 IP 地址所在服务器发起请求,服务器接收到请求之后等待处理,最后向浏览器端发回响应,此时在 HTTP 协议下,浏览器从服务器接收到 text/html 类型的代码,浏览器开始显示此 html,并获取其中内嵌资源地址,然后浏览器再发起请求来获取这些资源,并在浏览器的 html 中显示
script 脚本阻塞的解决办法:
1、 推迟加载(延迟加载)
如果页面初始的渲染并不依赖于 js 或者 CSS ,可以用推迟加载,就是最后再加载 js 和 css,把引用外部文件的代码写在最后

2、 defer 延迟加载

在文档解析完成开始执行,并且在 DOMContentLoaded 事

件之前执行完成,会按照他们在文档出现的顺序去下载解析。效果和把 script 放在文档,最后之前是一样的
注意: defer 最好用在引用外部文件中使用,用了 defer 不要使用 document.write()方法;使用 defer 时最好不要请求样式信息,因为样式表可能尚未加载,浏览器会禁止该脚本等待样式表加载完成,相当于样式表阻塞脚本执行

3、 异步加载
async 异步加载:就是告诉浏览器不必等到加载完外部文件,可以边渲染边下载,什么时候下载完成什么时候执行。

defer 和 async 的区别:
<script async src=“example.js”></script>有了 async 属性,表示
后续文档的加载和渲染与 js 脚本的加载和执行是并行进行的,即异步执行;<script defer src=“example.js”></script>
有了 defer 属性,加载后续文档的过程和 js 脚本的加载(此时仅加载不执行)是并行进行的(异步),js 脚本的执行需要等到文档所有元素解析完成之后DOMContentLoaded 事件触发执行之前

(23)拆解一下 URL 的各个部分,分别是什么意思(高薪常问)

例如:scheme://host:port/path?query#fragment
1、 .scheme:通信协议,常用的 HTTP,ftp,maito 等
2、 .host:主机,服务器(计算机)域名系统 (DNS) 主机名或 IP 地址
3、.port:端口号,整数,可选,省略时使用方案的默认端口,如 HTTP 的默认端口为
80
4、.path:路径,由零或多个"/“符号隔开的字符串,一般用来表示主机上的一个目录
或文件地址
5、.query:查询,可选,用于给动态网页传递参数,可有多个参数,用”&“符号隔开,
每个参数的名和值用”="符号隔开
6、.fragment:信息片断,字符串,用于指定网络资源中的片断。例如一个网页中有
多个名词解释,可使用 fragment 直接定位到某一名词解释。(也称为锚点)

!!!!!!(24)为什么要使用模板引擎

(25)CDN(内容分发网络)

CDN(Content Delivery Network,内容分发网络)是一种通过将内容分发到世界各地的多个服务器节点,以提高用户访问网站或应用程序时的速度和性能的网络架构。

基本上,CDN 的工作原理是将网站的静态资源(例如图片、CSS、JavaScript 文件等)复制到位于全球不同地理位置的多个服务器上。当用户请求访问网站时,CDN 会自动将用户的请求路由到离用户最近的服务器,从而减少数据传输的延迟和提高网站的加载速度。

(26)SSE(Server-Sent-Events)

SSE是一种用于实现服务器主动向客户端推送数据的技术,也被称为"事件流"。它基于HTTP协议,利用了其长连接特性,在客户端和服务器之间建立一条持久化连接,并通过这条连接实现服务器向客户端的实时数据推送。
工作原理:
(1)建立连接:客户端通过简单的 HTTP 请求(通常是 GET 请求)与服务器建立连接,请求一个特殊的 URL,该 URL 由服务器提供。
(2)服务器响应:服务器接收到客户端的请求后,会向客户端发送一个 HTTP 响应,响应的内容类型通常是 text/event-stream
(3)保持连接:服务器保持与客户端的连接打开状态,随时准备向客户端发送数据。
(4)服务器推送数据:一旦服务器有新的数据需要向客户端推送,它会将数据封装成特定格式的文本,并通过之前建立的连接发送给客户端。
(5)客户端接收数据:客户端收到服务器发送的数据后,通过 JavaScript 的 EventSource 接口进行处理,从而实现相应的业务逻辑。

(27)JWT(json web token)

JWT(JSON Web Token,JSON Web 令牌)是一种用于在网络应用中安全地传输信息的开放标准(RFC 7519)。它可以通过数字签名或加密来验证信息的完整性,并可信地将信息传递给其他系统或服务。JWT 通常用于身份验证和信息交换,常见于 Web 应用程序和移动应用程序中。
JWT 的结构:
一个 JWT 通常由三部分组成,每部分使用点号 . 分隔,形式如下:
header.payload.signature
(1)Header(头部):头部通常由两部分组成,令牌的类型(即 “JWT”)和所使用的签名算法,例如:

{
  "alg": "HS256",
  "typ": "JWT"
}

(2)Payload(载荷):载荷包含了 JWT 所要传递的信息,一般包括三种类型:
注册的声明(Registered Claims):包含一些预定义的声明,如 iss(Issuer,发行者)、exp(Expiration Time,过期时间)、sub(Subject,主题)等。
私有的声明(Private Claims):包含自定义的声明,用于传递一些额外的信息。
公共的声明(Public Claims):包含一些公开的信息,供任何人使用。
(3)Signature(签名):签名用于验证消息是否被篡改过,通常是对头部和载荷进行签名,并使用一个密钥进行加密,例如:

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret)

(28)网络状态&强网弱网环境

判断在线还是离线: navigator.onLine
强网和弱网:navigator.connection

七、Vue

(1)Vue 的最大的优势是什么?

响应式数据绑定: 当数据发生变化时,相关的视图会自动更新,无需手动操作 DOM,极大地提高了开发效率。

组件化开发: Vue.js 鼓励组件化开发,将 UI 划分为独立的、可复用的组件。每个组件都有自己的状态和行为,使得代码更易于维护和管理,同时也提高了代码的复用性和可维护性。

使用 Vue.js 编写出来的界面效果本身就是响应式的,这使网页在各种设备上都能
显示出非常好看的效果。

vue 是单页面应用,按需加载,使页面局部刷新,不用每次跳转页面都要请求所有数据和 dom,这样大大加快了访问速度和提升用户体验。

!!!!!!(2)Vue 和 jQuery 两者之间的区别是什么?

(3)MVVM 和 MVC 区别是什么?哪些场景适合?

MVVM 即 Model-View-ViewModel 的简写,即模型-视图-视图模型,模型(Model)指的是后端传递的数据,视图(View)指的是所看到的页面,视图模型(ViewModel)是 mvvm 模式的核心,它是连接 view 和 model 的桥梁。它有两个方向:
(1)一是将模型(Model)转化成视图(View),即将后端传递的数据转化成所看到的
页面,实现的方式是:数据绑定,
(2)二是将视图(View)转化成模型(Model),即将所看到的页面转化成后端的数据。
实现的方式是:DOM 事件监听。
这两个方向都实现的,我们称之为数据的双向绑定

MVC 是 Model-View- Controller 的简写。即模型-视图-控制器。M 和 V 指的意思和MVVM 中的 M 和 V 意思一样。C 即 Controller 指的是页面业务逻辑,使用 MVC 的目的就是将 M和 V 的代码分离。MVC 是单向通信。也就是 View 跟 Model,必须通过 Controller。

3、两者之间的区别
MVC 和 MVVM 其实区别并不大,都是一种设计思想,MVC 和 MVVM 的区别并不是 VM完全取代了 C,只是在 MVC 的基础上增加了一层 VM,只不过是弱化了 C 的概念,ViewModel存在目的在于抽离 Controller 中展示的业务逻辑,而不是替代 Controller,其它视图操作业务等还是应该放在 Controller 中实现,也就是说 MVVM 实现的是业务逻辑组件的重用,使开发更高效,结构更清晰,增加代码的复用性

(4)Vue 数据双向绑定的原理是什么?

Vue.js 是采用数据劫持结合发布者-订阅者模式的方式,通过 Object.defineProperty()来劫持各个属性的 setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。
1、需要 observe 的数据对象进行递归遍历,包括子属性对象的属性,都加上 setter 和 getter,
这样的话,给这个对象的某个值赋值,就会触发 setter,那么就能监听到了数据变化
2、compile 解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图
3、Watcher 订阅者是 Observer 和 Compile 之间通信的桥梁,主要做的事情是:
3.1)在自身实例化时往属性订阅器(dep)里面添加自己
3.2)自身必须有一个 update()方法
3.3)待属性变动 dep.notice()通知时,能调用自身的 update()方法,并触发 Compile 中绑定的回调,则功成身退。

(5)Object.defineProperty 和 Proxy 的区别

1、Proxy 可以直接监听对象而非属性,Proxy 返回的是一个新对象,我们可以只操作新的对象达到目的,而Object.defineProperty 只能遍历对象属性直接修改
2、Proxy 可以直接监听数组的变化;
3、Proxy 有多达 13 种拦截方法,不限于 apply、ownKeys、deleteProperty、has 等等是Object.defineProperty 不具备
4、Object.defineProperty 是 ES5 引入的标准方法,在各个主流浏览器中都有良好的兼容性;Proxy 是 ES6 引入的新特性,在一些旧版本的浏览器中可能不被支持,需要通过 polyfill 或者转译器进行兼容处理。

(6)Vue 生命周期总共分为几个阶段?

Vue 实例从创建到销毁的过程,就是生命周期。也就是从开始创建、初始化数据、编译模板、挂载 Dom→渲染、更新→渲染、卸载等一系列过程,我们称这是 Vue 的生命周期。
beforeCreate: 在实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前被调用。在这个阶段,组件实例已经创建,但是尚未初始化数据和事件等配置。这个阶段适合执行一些初始化操作,例如设置一些基本的数据或配置。
created: 在实例创建完成后被立即调用。在这个阶段,实例已经完成了数据的观测 (data observer),并且在初始化了 methods、computed、watcher 和事件等配置。但是此时组件还未挂载到 DOM 上,所以无法访问到组件的 $el。
beforeMount: 在挂载开始之前被调用:相关的 render 函数首次被调用。在这个阶段,Vue 实例的模板编译完成,并且将要开始挂载到 DOM 上,但是实际的 DOM 元素尚未创建。在这个阶段可以进行一些组件准备工作,例如获取数据、计算属性等
mounted: 在挂载完成后被立即调用,此时组件已经被挂载到 DOM 上。在这个阶段,可以访问到组件的 $el,并且组件的 DOM 结构已经被渲染出来,可以进行一些 DOM 相关的操作。通常在这个阶段可以进行一些初始化操作,例如初始化第三方库、绑定事件监听器等。
beforeUpdate: 在数据更新之前被调用,发生在虚拟 DOM 重新渲染和打补丁之前。在这个阶段,可以访问到组件的最新数据,但是尚未重新渲染到视图上。在这个阶段适合执行一些数据更新前的准备工作,例如在更新前对数据进行处理或者验证。
updated: 在数据更新之后被调用,发生在虚拟 DOM 重新渲染和打补丁之后。在这个阶段,组件的数据已经更新到最新状态,并且重新渲染到视图上。在这个阶段可以执行一些 DOM 相关的操作,例如重新计算某些 DOM 属性或者触发某些事件。
beforeDestroy: 在实例销毁之前被调用。在这个阶段,实例仍然完全可用,可以访问到组件的数据和方法,但是实例将要被销毁,所以无法再对数据进行响应式操作。在这个阶段适合执行一些清理工作,例如清除定时器、解绑事件监听器等。
destroyed: 在实例销毁之后被调用。在这个阶段,组件的实例已经完全被销毁,所有的事件监听器和绑定的数据都已经被清除。在这个阶段可以执行一些与组件销毁相关的操作,例如释放资源、取消订阅等。

(7)第一次加载页面会触发哪几个钩子函数?

当页面第一次页面加载时会触发 beforeCreate, created, beforeMount, mounted 这几个钩子函数

(8)请说下封装 Vue 组件的过程?

(1)确定组件的功能和设计:包括组件的外观、行为和结构等。
(2)创建.vue文件,编写组件的模版、逻辑、样式。
(3)使用Vue.component()注册组件,子组件需要数据,可以在 props 中接受定义,而子组件修改好数据后,想把数据传递给父组件,可以采用$emit 方法。

(9)Vue 组件如何进行传值的?

1、父组件向子组件传递数据:
父组件内设置要传的数据,在父组件中引用的子组件上绑定一个自定义属性并把数据绑定在自定义属性上,在子组件添加参数 props 接收即可
2、子组件向父组件传递数据
子组件通过 vue 实例方法 e m i t 进行触发并且可以携带参数,父组件监听使用 @ ( v − o n )进行监听,然后进行方法处理 3 、非父子组件之间传递数据 3.1 引入第三方 n e w v u e 定义为 e v e n t B u s 3.2 )在组件中 c r e a t e d 中订阅方法 e v e n t B u s . emit 进行触发并且可以携带参数,父组件监听使用@(v-on)进行监听,然后进行方法处理 3、非父子组件之间传递数据 3.1 引入第三方 new vue 定义为 eventBus 3.2)在组件中 created 中订阅方法 eventBus. emit进行触发并且可以携带参数,父组件监听使用@von)进行监听,然后进行方法处理3、非父子组件之间传递数据3.1引入第三方newvue定义为eventBus3.2)在组件中created中订阅方法eventBus.on(“自定义事件名”,methods 中的方法名)
3.3) 在另一个兄弟组件中的 methods 中写函数,在函数中发布 eventBus 订阅的方法eventBus.$emit("自定义事件名”)
3.4) 在组件的 template 中绑定事件(比如 click)

(10)组件中写 name 选项有什么作用?

(1)项目使用 keep-alive 时,可搭配组件 name 进行缓存过滤
(2)DOM 做递归组件时需要调用自身 name
(3)vue-devtools 调试工具里显示的组见名称是由 vue 中组件 name 决定

(11)Vue 组件 data 为什么必须是函数

组件中的 data 写成一个函数,数据以函数返回值形式定义,这样每复用一次组件,就
会返回一份新的 data,类似于给每个组件实例创建一个私有的数据空间,让各个组件实例维护各自的数据。而单纯的写成对象形式,就使得所有组件实例共用了一份 data,就会造成一个变了全都会变的结果

(12)怎么在组件中监听路由参数的变化?

(13)Vue3和Vue2的Diff算法

  • 28
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值