当前位置:   article > 正文

前端基础知识_前端开发基础

前端开发基础

前端基础知识

HTML+CSS

1. html5新增内容

语义化标签:比如header、nav、footer、section、article

绘图方面:加入了canvas绘图和SVG绘图;

媒体方面:加入了video和audio标签

本地离线存储:localStorage和sessionStory两种本地离线缓存

以及一些新技术:webwoker/websocket/GelolCation

2. CSS3的新特性:

1.新增选择器:属性选择器、伪类选择器、伪元素选择器

2.增加了媒体查询

3.文字阴影

4.边框

5.盒子模型box-sizing

6.渐变

7.过度

8.自定义动画

9.背景的属性

10.2D和3D

4. 语义化标签(语义化标签是指正确的标签包含了正确的内容,结构良好,便于阅读)

Header页面头部

main页面主要内容

footer页面底部

nav导航栏

aside侧边栏

article加载页面一块独立内容

section相当于divfigure加载独立内容(上图下字)

figcaptionfigure的标题

hgroup标题组合标签mark高亮显示dialog加载对话框标签(必须

配合open属性)

Embed加载插件的标签video加载视频audio加载音频(支持格式ogg,mp3,wav)

5. Canvas和Svg有什么区别?

1.svg绘制出来的每一个图形的元素都是独立的DOM节点,能够方便的绑定事件或用来修改。canvas输出的是一副画布

2.svg输出的图形是矢量图形,后期可以修改参数来自由放大缩小,不会失真和锯齿。而canvas输出标量画布,就像一张图片一样,放大会失真或者锯齿

6. link与@import的区别

1、link属于Xhtml标签,除了加载CSS之外还能用于定义RSS,@import是CSS提供的,只能用于加载CSS

2、link加载的文件,在页面加载的时候,link文件会同时加载,而@import引入的CSS文件,是页面在加载完成后再加载的

3、@import有兼容性问题,IE5以下的浏览器是无法识别的,而link无兼容性问题

4、link的样式的权重高于@import的权重。

7. 行内元素、块级元素、可变元素

行内元素 :

相邻的行内元素会排列在同一行,不会独占一行设置宽高无效(a、br、I、em、img、input、select、span、sub、sup、u、textarea)

块级元素 :

会独占一行可以设置宽高等属性(div、h1-h6、hr、p、ul、ol、table、address、blockquote、dir、from、menu)

可变元素 :

根据上下文预警决定该元素为块元素还是内联元素(button、del、iframe、ins)

8. title与h1的区别、b与strong的区别、i与em的区别

title与h1的区别:

定义:

​ title:概括了网站信息,可以告诉搜索引擎或者用户关于这个网站的内容主题是什么

​ h1:文章主题内容,告诉蜘蛛我们的网站内容最主要是什么

区别:

​ title他是显示在网页标题上、h1是显示在网页内容上

​ title比h1添加的重要 (title > h1 ) ==》对于seo的了解

场景:

​ 网站的logo都是用h1标签包裹的

b与strong的区别:

定义:

​ b:实体标签,用来给文字加粗的。

​ strong:逻辑标签,用来加强字符语气的。

区别:

​ b标签只有加粗的样式,没有实际含义。

​ strong表示标签内字符比较重要,用以强调的。

题外话:为了符合css3的规范,b尽量少用该用strong就行了。

i与em的区别:

定义:

​ i:实体标签,用来做文字倾斜的。

​ em:是逻辑标签,用来强调文字内容的

区别:

​ i只是一个倾斜标签,没有实际含义。

​ em表示标签内字符重要,用以强调的。

场景:

​ i更多的用在字体图标,em术语上(医药,生物)。

9. img标签的title和alt有什么区别

区别一:

​ title : 鼠标移入到图片显示的值

​ alt : 图片无法加载时显示的值

区别二:

​ 在seo的层面上,蜘蛛抓取不到图片的内容,所以前端在写img标签的时候为了增加seo效果要加入alt属性来描述这张图是什么内容或者关键词。

10. line-height和heigh区别

line-height是每一行文字的高,如果文字换行则整个盒子高度会增大(行数*行高)。

height是一个死值,就是这个盒子的高度。

11. png、jpg、gif、webp

png :无损压缩,尺寸体积要比jpg/jpeg的大,适合做小图标。

jpg :采用压缩算法,有一点失真,比png体积要小,适合做中大图片。

gif :一般是做动图的。

webp :同时支持有损或者无损压缩,相同质量的图片,webp具有更小的体积。兼容性不是特别好。

12. px,rem,em的的区别

px:绝对长度单位,像素px是相对于显示器屏幕分辨率来说的

em:相对长度单位,相对于当前对象内文本的字体尺寸,em的值并不是固定的,em会继承父级元素的字体大小(参考物是父元素的font-size),em中所有的字体都是相对于父元素的大小决定的

rem:相对于html根元素的font-size

13. BFC及其应用

BFC(BlockFormatContext)块级格式化上下文,是页面盒模型中的一种CSS渲染模式,相当于一个独立的容器,里面的元素和外部的元素相互不影响。

创建BFC的方式有:

1.html根元素2.float浮动3.绝对定位4.overflow不为visible5.display为表格布局或者弹性布局;

BFC主要的作用是:

1.清除浮动2.防止同一BFC容器中的相邻元素间的外边距重叠问题

14. 重绘(Repaint)和回流(Reflow)

重绘是当节点需要更改外观而不会影响布局的,比如改变 color 就叫称为重绘

回流是布局或者几何属性需要改变就称为回流。

回流必定会发生重绘,重绘不一定会引发回流。回流所需的成本比重绘高的多,改变深层次的节点很可能导致父节点的一系列回流

15. 浮动

非IE浏览器下,容器不设置高度且子元素浮动时,容器高度不能被撑开。此时,内容会溢出到容器外面影响布局.

浮动的工作原理

浮动元素脱离文档流,不占据空间(引起“高度塌陷”)

浮动元素碰到包含它的边框或者其它浮动元素的边框停留

浮动元素可以左右移动,知道遇到另一个浮动元素或者遇到它外边缘的包含框。浮动框不属于文档流中的普通流,但元素浮动之后,不会影响块级元素的布局,只会影响内联元素的布局。此时文档流中的普通流就会表现得该浮动框不存在一样的布局模式。当包含框的高度小于浮动框的时候,此时就会出现“高度塌陷”

浮动元素引起的问题

父元素的高度无法撑开,影响与父元素同级的元素

与浮动元素同级的非浮动元素会跟随其后

若浮动的元素不是第一个元素,则该元素之前的元素元素也要浮动,否则会影响页面的显示结构

清除浮动的方式

  1. 给父级元素设置高度

  2. 最后一个浮动元素之后添加一个空div标签,并添加clear: both样式

  3. 包含浮动元素的父级元素添加overflow: hidden或overflow: auto样式

  4. 使用 ::after 伪元素

  5. 使用clear属性清除浮动

16. 定位(Position)

absolute绝对定位,脱离文档流相对于父级定位

relative相对定位不脱离文档流,相对于自身定位

fixed固定定位,脱离文档流,相对于浏览器窗口定位

static默认值,元素出现在正常的流中

17. css选择器及其优先级

!important声明的样式的优先级最高

如果优先级一致,则最后出现的样式生效

继承得到的样式的优先级最低

样式来源不同时,优先级顺序为:

内联样式 > 内部样式 > 外部样式 > 浏览器用户自定义样式 > 浏览器默认样式

!important > 内联样式 > id > class > 标签 > 通配

选择器 格式优 先级权重

Id选择器 #id 100

类名选择器 .className 10

属性选择器 div[att$=value] 10

伪类选择器 div:hover 10

标签选择器 div 1

伪元素选择器 div::after 1

相邻兄弟选择器 h2+p 0

子选择器 ul>li 0

后代选择器 p span 0

通配符 * 0

18. CSS属性哪些可以继承

文字系列:font-size、color、line-height、text-align…

不可继承属性:border、padding、margin…

19. margin和padding在什么场合下使用

margin:外边距自身边框到另一个边框之间的距离

padding:内边距自身边距到自身内容之间的距离

当需要在border外侧添加空白时用margin,当需要在border内侧添加空白时用padding

20. 盒子模型

一个css盒子从外到内可以分成四个部分:margin(外边距),border(边框),padding(内边距),content(内容)。

标准盒子模型(box-sizing:content-box;):

元素框的总宽度=元素(element)的width+padding的左边距和右边距的值+margin的左边距和右边距的值+border的左右宽度

元素框的总高度=元素(element)的height+padding的上下边距的值+margin的上下边距的值+border的上下宽度。

怪异盒子模型(box-sizing:border-box;):

总宽度=width

总高度=height

21. 隐藏元素的方法

方法说明
display: none;渲染树不会包含该渲染对象,因此该元素不会在页面中占据位置,也不会响应绑定的监听事件
visibility: hidden;元素在页面中仍占据空间,但是不会响应绑定的监听事件
opacity: 0;透明度设置为0,来隐藏元素。元素在页面中仍然占据空间,并且能够响应元素绑定的监听事件
position: absolute;通过使用绝对定位将元素移除可视区域内,以此来实现元素的隐藏
z-index: -10;使用其余元素遮盖当前元素实现隐藏
clip/clip-path使用元素裁剪的方法来实现元素的隐藏,这种方法下,元素仍在页面中占据位置,但是不会响应绑定的监听事件
transform: scale(0,0)将元素缩放为 0,来实现元素的隐藏。这种方法下,元素仍在页面中占据位置,但是不会响应绑定的监听事件

22. opacity:0、visibility:hidden、display:none

1.display:none-不占空间,不能点击,会引起回流,子元素不影响,可以脱离文档流

2.visibility:hidden-占据空间,不能点击,引起重绘,子元素可设置visible进行显示,元素不会脱离文档流,会占有原来的位置

3.opacity:0-占据空间,可以点击,引起重绘,子元素不影响

23. display属性值及其作用

属性值作用
none元素不显示,并且会从文档流中移除
block块元素类型。默认宽度为父元素宽度,可设置宽高,换行显示
inline行内元素类型。默认宽度为内容宽度,不可设置宽高,同行显示
inline-block行内块元素类型。默认宽度为内容宽度,可以设置宽高,同行显示
list-item像块类型元素一样显示,并添加样式列表标记
table此元素会作为块级表格来显示
inherit规定应该从父元素继承display属性的值

24. flex布局属性

flex-direction:弹性容器中子元素排列方式(主轴排列方式)

flex-wrap:设置弹性盒子的子元素超出父容器时是否换行

align-content:设置行对齐

justify-content:设置弹性盒子元素在主轴上的对齐方式

align-item:设置弹性盒子元素在侧轴上的对齐方式

flex-flow:是flex-direction和flex-wrap简写形式

25. 实现单行、多行文本溢出隐藏

单行文本溢出

overflow: hidden;      // 溢出隐藏

text-overflow: ellipsis;  // 溢出部分使用省略号显示

white-space: nowrap;    // 规定段落中的文本不可换行
  • 1
  • 2
  • 3
  • 4
  • 5

多行文本溢出

overflow: hidden;     // 溢出隐藏

text-overflow:ellipsis; //溢出用省略号显示

display:-webkit-box;   // 作为弹性伸缩盒子模型显示。-webkit-box-orient:vertical; // 设置伸缩盒子的子元素排列方式:从上到下垂直排列

-webkit-line-clamp:3;   // 显示的行数
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

26. 用CSS画一个三角形

{

	width: 0;

	height: 0;

	border-left:100px solid transparent;

	border-right:100px solid transparent;

	border-top:100px solid transparent;

	border-bottom:100px solid #ccc;

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

27. 一个盒子不给宽度和高度如何水平垂直居中

方式一:
<div class='container'>
	<div class='main'>main</div>
</div>

.container{
		display: flex;
		justify-content: center;
		align-items: center;
		width: 300px;
		height: 300px;
		border:5px solid #ccc;
}
.main{
	background: red;
}
方式二:
<div class='container'>
	<div class='main'>main</div>
</div>

.container{
		position: relative;
		width: 300px;
		height: 300px;
		border:5px solid #ccc;
}
.main{
		position: absolute;
		left:50%;
		top:50%;
		background: red;
		transform: translate(-50%,-50%);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

28. 实现水平垂直居中

 利用绝对定位(一) 

. parent  {

 position :  relative ;

}

. child  {

   position :  absolute ;

   left : 50 % ;

   top : 50 % ;

 transform : translate(-50 % , -50 % )

}

 利用绝对定位(二):适用于已知盒子宽高 

. parent  {

 position :  relative ;

}

. child  {

   position :  absolute ;

   top : 0;

   bottom : 0;

   left : 0;

   right : 0;

 margin :  auto ;

}

 利用绝对定位(三):适用于已知盒子宽高 

. parent  {

 position :  relative ;

}

. child  {

   position :  absolute ;

   top : 50 % ;

   left : 50 % ;

   margin-top : -50 px ;   **/\* 自身 height 的一半 \*/**

 margin-left : -50 px ;  **/\* 自身 width 的一半 \*/**

}

 flex布局 

. parent  {

   display :  flex ;

   justify-content :  center ;

 align-items :  center ;

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77

HTTP

29. 常见的HTTP请求方法

方法作用
GET向服务器获取数据
POST向服务器发送数据
PUT修改数据
PATCH用于对资源进行部分修改
DELETE删除指定数据

30. get请求和post请求的区别

1、get请求一般是去取获取数据(其实也可以提交,但常见的是获取数据);post请求一般是去提交数据。

2、get因为参数会放在url中,所以隐私性,安全性较差,请求的数据长度是有限制的,不同的浏览器和服务器不同,一般限制在2~8K之间,更加常见的是1k以内;post请求是没有的长度限制,请求数据是放在body中;

3、get请求刷新服务器或者回退没有影响,post请求回退时会重新提交数据请求。

4、get请求可以被缓存,post请求不会被缓存。

5、get请求会被保存在浏览器历史记录当中,post不会。get请求可以被收藏为书签,因为参数就是url中,但post不能。它的参数不在url中。

31. http常见状态码

100接受的请求正在处理,信息类状态码

2xx(成功)表示成功处理了请求的状态码

200(成功)服务器已成功处理了请求。

3xx(重定向)表示要完成请求,需要进一步操作。通常这些状态代码用来重定向。

301,永久性重定向,表示资源已被分配了新的URL

302,临时性重定向,表示资源临时被分配了新的URL

303,表示资源存在另一个URL,用GET方法获取资源

304,(未修改)自从上次请求后,请求网页未修改过。服务器返回此响应时,不会返回网页内容

4xx(请求错误)这些状态码表示请求可能出错,妨碍了服务器的处理

400(错误请求)服务器不理解请求的语法

401表示发送的请求需要有通过HTTP认证的认证信息

403(禁止)服务器拒绝请求

404(未找到)服务器找不到请求网页

5xx(服务器错误)这些状态码表示服务器在尝试处理请求时发生内部错误。这些错误可能是服务器本身的错误,而不是请求的错误

500(服务器内部错误)服务器遇到错误,无法完成请求

503表示服务器处于停机维护或超负载,无法处理请求

32. 为什么会有跨域问题

1、浏览器从一个域名的网页去请求另一个域名的资源时,域名、端口、协议任一不同,都是跨域。

2、在前后端分离的模式下,前后端的域名是不一致的,此时就会发生跨域访问问题。在请求的过程中我们要想回去数据一般都是post/get请求,所以跨域问题出现。

3、解决跨域的方法:

第一种jsonp的方法。

第二种使用CORS解决跨域问题,即跨域资源共享,在后端设置响应头部,加一句代码:access-control-allow-origin:"*"或者允许交互的域名。

第三种使用vue,找到config文件下->index.js文件,修改proxyTable中的target的值,就可实现用前端解决跨域。

第四种,使用代理(nginx代理,nodejs中间件代理);

第五种,使用postmessage

33. http和https的区别?

  1. 端口不同

​ http :80端口

​ https :443端口

  1. https比http更加安全

34. HTTP协议规定的协议头和请求头有什么?

1.请求头信息:

​ Accept:浏览器告诉服务器所支持的数据类型

​ Host:浏览器告诉服务器我想访问服务器的哪台主机

​ Referer:浏览器告诉服务器我是从哪里来的(防盗链)

​ User-Agent:浏览器类型、版本信息

​ Date:浏览器告诉服务器我是什么时候访问的

​ Connection:连接方式

​ Cookie

​ X-Request-With:请求方式

2.响应头信息:

​ Location:这个就是告诉浏览器你要去找谁

​ Server:告诉浏览器服务器的类型

​ Content-Type:告诉浏览器返回的数据类型

​ Refresh:控制了的定时刷新

35. ajax请求跨域接口,发送了几次请求?

所有跨域的js在提交post请求的时候,如果服务端设置了可跨域访问,都会默认发送两次请求,第一次预检请求,查询是否支持跨域,第二次才是真正的post提交

36. ajax是什么?怎么实现的?

创建交互式网页应用的网页开发技术

在不重新加载整个网页的前提下,与服务器交换数据并更新部分内容

通过XmlHttpRequest对象向服务器发送异步请求,然后从服务器拿到数据,最后通过JS操作DOM更新页面

1.创建XmlHttpRequest对象 xmh

2.通过xmh对象里的open()方法和服务器建立连接

3.构建请求所需的数据,并通过xmh对象的send()发送给服务器

4.通过xmh对象的onreadystate chansge事件监听服务器和你的通信状态

5.接收并处理服务器响应的数据结果

6.把处理的数据更新到HTML页面上

37. async函数的基本用法

async函数返回一个Promise对象,可以使用then方法添加回调函数。

当函数执行的时候,一旦遇到await就会先返回,等到异步操作完成,再接着执行函数体内后面的语句。

38. setTimeout、Promise、Async/Await的区别

setTimeout:

setTimeout的回调函数放到宏任务队列里,等到执行栈清空以后执行;

Promise:

Promise本身是同步的立即执行函数,当在executor中执行resolve或者reject的时候,此时是异步操作,会先执行then/catch等,当主栈完成时,才会去调用resolve/reject方法中存放的方法。

async:

async函数返回一个Promise对象,当函数执行的时候,一旦遇到await就会先返回,等到触发的异步操作完成,再执行函数体内后面的语句。可以理解为,是让出了线程,跳出了async函数体

39. promise

Promise是一种解决异步编程的方案,相比回调函数和事件更合理和更强大。

promise三种状态:

pending初始状态也叫等待状态

fulfiled成功状态

rejected失败状态;状态一旦改变,就不会再变

Promise的特点:

1、Promise对象的状态不受外界影响

2、Promise的状态一旦改变,就不会再变,任何时候都可以得到这个结果,状态不可以逆,

Promise的缺点:

1、无法取消Promise,一旦新建它就会立即执行,无法中途取消

2、如果不设置回调函数,Promise内部抛出的错误,不会反映到外部

3、当处于pending(等待)状态时,无法得知目前进展到哪一个阶段,是刚刚开始还是即将完成

用Promise来解决什么问题:

1.回调地狱,代码难以维护,常常第一个的函数的输出是第二个函数的输入这种现象

2.promise可以支持多并发的请求,获取并发请求中的数据这个promise可以解决异步的问题,本身不能说promise是异步的

40. async/await

async声明function是一个异步函数,返回一个promise对象,可以使用 then 方法添加回调函数。
async函数内部return语句返回的值,会成为then方法回调函数的参数。如果async函数没有返回值 async函数返回一个undefined的promise对象

await 操作符只能在异步函数 async function 内部使用
如果一个 Promise 被传递给一个 await 操作符,await 将等待 Promise 正常处理完成并返回其处理结果,也就是说它会阻塞后面的代码,等待 Promise 对象结果;如果等待的不是 Promise 对象,则返回该值本身。

41. promise和async await的区别是什么?

1.都是处理异步请求的方式

2.promise是ES6,async await 是ES7的语法

3.async await是基于promise实现的,他和promise都是非阻塞性的

优缺点:

1.promise是返回对象我们要用then,catch方法去处理和捕获异常,并且书写方式是链式,容易造成代码重叠,不好维护,async await 是通过tra catch进行捕获异常

2.async await最大的优点就是能让代码看起来像同步一样,只要遇到await就会立刻返回结果,然后再执行后面的操作

promise.then()的方式返回,会出现请求还没返回,就执行了后面的操作

42. token存在sessionstorage还是loaclstorage?

token:验证身份的令牌,一般就是用户通过账号密码登录后,服务端把这些凭证通过加密等一系列操作后得到的字符串

1.存loaclstorage里,后期每次请求接口都需要把它当作一个字段传给后台

2.存cookie中,会自动发送,缺点就是不能跨域

如果存在localstorage中,容易被XSS攻击,但是如果做好了对应的措施,那么是利大于弊

如果存在cookie中会有CSRF攻击

43. token的登录流程

1.客户端用账号密码请求登录

2.服务端收到请求后,需要去验证账号密码

3.验证成功之后,服务端会签发一个token,把这个token发送给客户端

4.客户端收到token后保存起来,可以放在cookie也可以是localstorage

5.客户端每次向服务端发送请求资源的时候,都需要携带这个token

6.服务端收到请求,接着去验证客户端里的token,验证成功才会返回客户端请求的数据

44. 页面渲染的过程是怎样的?

DNS解析

建立TCP连接

发送HTTP请求

服务器处理请求

渲染页面

浏览器会获取HTML和CSS的资源,然后把HTML解析成DOM树

再把CSS解析成CSSOM

把DOM和CSSOM合并为渲染树

布局

把渲染树的每个节点渲染到屏幕上(绘制)

断开TCP连接

JS(js是单线程的语言)+TS

45. js的基础数据类型

基础数据类型 :字符串(String)、数字(Number)、布尔(Boolean)、空(Null)、未定义(Undefined)、Symbol、bigint

引用数据类型 :Object(对象(Object)、数组(Array)、函数(Function)、日期(Date)、正则(RegExp))

46. es6新特性

1、let、const

2、箭头函数

3、类的支持

4、字符串模块

5、symbols

6、promises

47. let与var与const的区别

var声明的变量会挂载在window上,而let和const声明的变量不会,var声明的变量存在变量提升,let和const不存在变量提升

同一作用域下var可以声明同名变量,let和const不可以,let和const声明会形成块级作用域。

const一旦声明必须赋值,不能用null占位,声明后不能再修改,如果声明的是复合类型数据,可以修改属性

48. js中的作用域与变量声明提升

作用域:

每一个变量、函数都有其作用的范围,超出范围不得使用,这个叫做作用域

全局变量、局部变量:

全局变量:在全局范围内声明的变量,如vara=1;

只有赋值没有声明的值,如a=1(注:如果a=2在函数环境中,也是全局变量)

局部变量:

写入函数的变量,叫做局部变量,作用范围仅限函数内部

作用:

程序安全,内存的释放

作用域链:

查找变量的过程。先找自己局部环境内部有没有声明或者是函数,如果有,则查看声明有无赋值或者是函数的内容,如果没有,则向上一级查找。

变量声明提升:

在预编译阶段,编译器会把所有定义的变量全部提升到最顶部,即,把变量声明的语句会自动放置在最顶部。

49. null和undefined的区别?

null用来表示尚未存在的对象,常用来表示函数企图返回一个不存在对象

undefined主要指定义了变量,但是并未赋值

NAN(notaNumber)不是一个明确数值的数字类型

ECMAScript认为undefined是从null派生出来的,他们的值是一样的,但是类型却不一样。

所以

null==undefined //true

null===undefined //false

50. =区别

1、对于string、number等基础类型,=是有区别的

a)不同类型间比较,==之比较"转化成同一类型后的值"看"值"是否相等,===如果类型不同,其结果就是不等。

b)同类型比较,直接进行"值"比较,两者结果一样。

2、对于Array,Object等高级类型,=是没有区别的

进行"指针地址"比较

3、基础类型与高级类型,=是有区别的

a)对于==,将高级转化为基础类型,进行"值"比较

b)因为类型不同,===结果为false

4、!=为==的非运算,!=的非运算

51. 强制类型转换和隐式类型转换有哪些

强制:
转换成字符串: toString()、String()
转换成数字:Number()、parseInt()、parseFloat()
转换成布尔类型:Boolean()

隐式:
拼接字符串:let str = 1 + “”;

数据类型的比较

52. js如何判断数据类型

1、利用typeof操作符,语法“typeof变量”;

2、利用instanceof运算符;

3、利用constructor属性,语法“变量.constructor==数据类型”;

4、利用toString()函数。

53. new操作符具体做了什么

  1. 创建了一个空的对象

  2. 将空对象的原型,指向于构造函数的原型

  3. 将空对象作为构造函数的上下文(改变this指向)

  4. 对构造函数有返回值的处理判断

54. 箭头函数与普通函数的区别

箭头函数是匿名函数,不能作为构造函数,不能使用new

箭头函数不能绑定arguments,要用rest参数解决

箭头函数没有原型属性

箭头函数的this永远指向其上下文的this,箭头函数不能绑定this,会捕获其所在的上下文的this值,作为自己的this值

55. this指向

1.一般指向调用者

2.事件触发——指向——事件源

3.new实例化——指向——生成的实例

4.call/apply改变this——指向传入的对象

5.bind绑定——指向——传入的对象

6.箭头函数——指向——当前函数声明作用域

7.定时器——指向window(但仅限定时器使用function作为执行器)

56. call、apply、bind区别

共同点:功能一致,可以改变this指向

语法: 函数.call()、函数.apply()、函数.bind()

区别:

  1. call、apply可以立即执行。bind不会立即执行,因为bind返回的是一个函数需要加入()执行。

  2. 参数不同:apply第二个参数是数组。call和bind有多个参数需要挨个写。

57. 闭包

闭包可以简单理解成:

定义在一个函数内部的函数。其中一个内部函数在包含它们的外部函数之外被调用时,就会形成闭包。

特点:

1.函数嵌套函数。

2.函数内部可以引用外部的参数和变量。

3.参数和变量不会被垃圾回收机制回收。

58. 防抖节流

什么是防抖:

触发高频事件后n秒内函数只会执行最后一次,如果n秒内高频事件再次被触发,则重新计算时间

当事件触发时,相应的函数不会立即触发,而是等待一段时间;
当事件连续触发时,函数的触发等待时间会被不断重置(推迟)。

什么是节流:

高频事件触发,在n秒内只会执行第一次,所以节流会稀释函数的执行效率

如果事件被频繁出发,那么节流函数会按照一定的频率来执行函数; 不管中间触发了多少次,执行函数的频率总是固定的。

防抖靠定时器,节流靠变量控制

59. 深拷贝浅拷贝的区别

1、浅拷贝:浅拷贝只复制某个对象的引用,而不复制对象本身,新旧对象还是共享同一块内存

Object.assign()方法可以把任意多个的源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象。

Object.assign()拷贝的是对象的属性的引用,而不是对象本身。

2、深拷贝:深拷贝会创造一个一摸一样的对象,新对象和原对象不共享内存,修改新对象不会改变原对对象。

JSON转换(缺点:如果对象有函数,函数无法被拷贝下来;无法拷贝对象原型链上的属性和方法;当数据的层次很深,会栈溢出):

JSON.parse,JSON.stringify

递归函数(缺点:无法保存引用;当数据层次很深,会栈溢出)

60. localStorage、sessionStorage、cookie的区别

公共点:在客户端存放数据

区别:

  1. 数据存放有效期

​ sessionStorage:仅在当前浏览器窗口关闭之前有效。【关闭浏览器就没了】

​ localStorage:始终有效,窗口或者浏览器关闭也一直保存,所以叫持久化存储。

​ cookie:只在设置的cookie过期时间之前有效,即使窗口或者浏览器关闭也有效。

  1. localStorage、sessionStorage不可以设置过期时间

​ cookie 有过期时间,可以设置过期(把时间调整到之前的时间,就过期了)

  1. 存储大小的限制

​ cookie存储量不能超过4k

​ localStorage、sessionStorage不能超过5M

61. js原型和原型链

原型:

函数都要prototype(显示原型)属性,而prototype会自动初始化一个空对象,这个对象就是原型对象。

原型对象中会有一个constructor属性,这个属性将指向了函数本身。

实例化对象都有一个_proto_(隐式原型)属性,_proto_属性指向原型对象。

原型链:

从实例对象往上找构造这个实例的相关对象,然后这个关联的对象再往上找,找到创造它的上一级的原型对象,以此类推,一直到object.prototype原型对象终止,原型链结束。

62. 前段事件流:事件流描述的是从页面中接收事件的顺序

事件捕获阶段

处于目标阶段

事件冒泡阶段

63. 箭头函数

ES6中允许使用“箭头”(=>) 来定义函数。箭头函数相当于匿名函数,并且简化了函数定义

特点

  • 箭头函数不绑定this,箭头函数里的this永远指向定义箭头函数时所处的作用域
  • 箭头函数的this永远不会变,call、apply、bind也无法改变
  • 箭头函数只能声明成匿名函数,但可以通过表达式的方式让箭头函数具名
  • 箭头函数没有原型prototype
  • 因为this的指向问题,箭头函数不能作为构造函数使用
  • 箭头函数没有 arguments 在箭头函数内部访问这个变量访问的是外部环境的arguments, 可以使用 …代替

64. 判断数组的方式

1、Object.prototype.toString.call([1, 2, 3]) // [object Array]

2、通过ES6的Array.isArray([1, 2, 3])做判断 // true or false

3、[1, 2, 3] instanceof Array // true or false

4、Array.prototype.isPrototypeOf([1, 2, 3]) // true or false

5、通过原型链去判断:[1, 2, 3].proto === Array.prototype

65. 操作数组的方法有哪些?

push()

pop()

sort()

splice()

unshift()

shift()

reverse()

concat()

join()

map()

filter()

ervery()

some()

reduce()

isArray()

findIndex()

哪些方法会改变原数组?

push() pop() unshift() shift() sort() reverse() splice()

66. 数组的遍历方法

方法改变原数组特点
forEach无返回值
map返回新数组,可链式调用
filter过滤数组,返回包含符合条件的元素的数组,可链式调用
for…offor…of遍历具有Iterator迭代器的对象的属性,返回的是数组的元素、对象的属性值,不能遍历普通的obj对象,将异步循环变成同步循环
every遍历的数组里的元素全部符合条件时,返回true
some遍历的数组里的元素至少有一个符合条件时,返回true
find返回第一个符合条件的值
findIndex返回第一个返回条件的值的索引值
reduce对数组正序操作
reduceRight对数组逆序操作

67. JS数组去重

new set :

var arr1 = [1,2,3,2,4,1];

function unique(arr){
	return [...new Set(arr)]
}

console.log(  unique(arr1) );
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

indexOf :

var arr2 = [1,2,3,2,4,1];

function unique( arr ){

	var brr = [];

	for( var i=0;i<arr.length;i++){

		if(  brr.indexOf(arr[i]) == -1 ){

			brr.push( arr[i] );
		}
	}
	return brr;
}

console.log( unique(arr2) );
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

Sort :

var arr3 = [1,2,3,2,4,1];

function unique( arr ){

	arr = arr.sort();

	var brr = [];

	for(var i=0;i<arr.length;i++){

		if( arr[i] !== arr[i-1]){

			brr.push( arr[i] );
		}
	}
	return brr;
}

console.log( unique(arr3) );
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

68. slice是干嘛的、splice是否会改变原数组

  1. slice是来截取的

​ 参数可以写slice(3)、slice(1,3)、slice(-3)

​ 返回的是一个新的数组

  1. splice 功能有:插入、删除、替换

​ 返回:删除的元素

​ 该方法会改变原数组

69. find和filter的区别

区别一:返回的内容不同

​ filter 返回是新数组

​ find 返回具体的内容

区别二:

​ find :匹配到第一个即返回

​ filter : 返回整体(没一个匹配到的都返回)

70. some和every的区别

some ==》 如果有一项匹配则返回true

every ==》 全部匹配才会返回true

71. forEach、map和for循环

forEach

没有返回值:

 var a = [1,2,3,4,5] var b = a.forEach((item) => { item = item * 2 }) 
console.log(b)
 // undefined
  • 1
  • 2
  • 3

无法中断执行;

可以使用return跳过当前循环;

跳过数组的空位,但不会跳过null和undefined;

var a = [null, , undefined] a.forEach(item => { 
console.log('item', item)
 // null undefined
})
  • 1
  • 2
  • 3
  • 4

改变数组情况;

为什么直接修改item无法修改原数组呢,因为item的值并不是相应的原数组中的值,而是重新建立的一个新变量,值和原数组相同。因此,如果item是基础数据类型,那么并不会改变数组里面的值,如果是引用类型,那么item和数组里面的值是指向同一内存地址,则都会被改变。

var a = [1,2,3,4,5] a.forEach((item) => { item = item * 2 }) 

console.log(a) 

// [1,2,3,4,5]
  • 1
  • 2
  • 3
  • 4
  • 5

数组中的对象的值也没有改变,是因为新创建的变量和原数组中的对象虽然指向同一个地址,但改变的是新变量的值,也就是重新赋值,即新对象的值为2,原数组中的对象还是{num:1}。

var a = [1,'1',{num:1},true] a.forEach((item, index, arr) => { item = 2 }) 

console.log(a) 

// [1,'1',{num:1},true]
  • 1
  • 2
  • 3
  • 4
  • 5

由于对象是引用类型,新对象和旧对象指向的都是同一个地址,所以新对象把num变成了2,原数组中的对象也改变了。

var a = [1,'1',{num:1},true] a.forEach((item, index, arr) => { item.num = 2 item = 2 })

console.log(a) 

// [1,'1',{num:2},true]
  • 1
  • 2
  • 3
  • 4
  • 5

手写forEach方法;

Array.prototype.new_forEach = function(callback) { for (let i = 0; i < this.length; i++) { callback(this[i], i, this) } }
  • 1

map

有返回值:

var a = [1,2,3,4,5] 

var b = a.map((item) => { return item = item * 2 }) 

console.log(a) 

// [1,2,3,4,5] 

console.log(b) 

// [2,4,6,8,10]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

无法中断执行,同forEach;

可以使用return跳过当前循环,同forEach;

跳过数组的空位,但不会跳过null和undefined,同forEach;

改变数组情况,同forEach;

手写map方法;

Array.prototype.new_map = function(callback) { 

const res = [] for (let i = 0; i < this.length; i++) 

{ res.push(callback(this[i], i, this)) }

 return res 

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

for循环

for循环是个语句,forEach和map则是表达式;

for循环可以使用break结束循环;

for循环可以使用continue语句跳过当前循环;

for循环不会跳过数组的空位,会默认空位为undefined;

性能对比

for 循环当然是最简单的,因为它没有任何额外的函数调用栈和上下文;

forEach 其次,因为它其实比我们想象得要复杂一些,它的函数签名实际上是array.forEach(function(currentValue, index, arr), thisValue)它不是普通的 for 循环的语法糖,还有诸多参数和上下文需要在执行的时候考虑进来,这里可能拖慢性能;

map 最慢,因为它的返回值是一个等长的全新的数组,数组创建和赋值产生的性能开销很大。

72. forEach如何跳出循环

forEach是不能通过break或者return来实现跳出循环的,forEach的回调函数形成了一个作用域,在里面使用return并不会跳出,只会被当做continue

使用try…catch

function getItemById(arr, id) {

  var item = null;

  try {

   arr.forEach(function (curItem, i) {

     if (curItem.id == id) {

       item = curItem;

       throw Error();

     }

    })

  } catch (e) {}

  return item;
  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

73. 伪数组(类数组)

一个拥有length属性和若干索引属性的对象可以被成为类数组对象,类数组对象和数组类似,但不能调用数组的方法
常见的类数组对象:arguments和DOM方法的返回结果,还有一个函数也可以被看作是类数组对象,因为它含有 length 属性值,代表可接收的参数个数

74. 类数组如何转换为数组

通过call方法调用数组的slice方法

Array.prototype.slice.call(arrayLike);
  • 1

通过call方法调用数组的splice方法

Array.prototype.splice.call(arrayLike, 0);
  • 1

通过apply调用数组的concat方法

 Array.prototype.concat.apply([], arrayLike);
  • 1

通过Array.from方法

Array.from(arrayLike);
  • 1

通过展开运算符

const array = [...arrayLike]
  • 1

75. 如何遍历类数组

arguments是一个对象,它的属性是从 0 开始依次递增的数字,还有callee和length等属性,与数组相似;但是它却没有数组常见的方法属性,如forEach, reduce等,所以叫它们类数组

使用call或apply方法

 function  sum() {

Array.prototype.forEach.call(arguements, a => { console.log(a) })

}

 function  sum() {

Array.prototype.forEach.apply(arguements, [a => { console.log(a)] })

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

使用Array.from方法将类数组转化成数组

 function  sum() {

   const  args  =  Array.from(arguements)

args.forEach(a => { console.log(a) })

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

使用展开运算符将类数组转成数组

 function  sum() {

   const  args  =  [...arguements]

args.forEach(a => { console.log(a) })

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

76. 找出多维数组最大值

function fnArr(arr){

	var newArr = [];

	arr.forEach((item,index)=>{

		newArr.push( Math.max(...item)  )

	})

	return newArr;

}

console.log(fnArr([

	[4,5,1,3],

	[13,27,18,26],

	[32,35,37,39],

	[1000,1001,857,1]

]));
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

77. 找出字符串出现最多次数的字符以及次数

var str = 'aaabbbbbccddddddddddx';

var obj = {};

for(var i=0;i<str.length;i++){

	var char = str.charAt(i);

	if( obj[char] ){

		obj[char]++;

	}else{

		obj[char] = 1;

	}

}

console.log( obj );

//统计出来最大值

var max = 0;

for( var key in obj ){

	if( max < obj[key] ){

		max = obj[key];

	}

}

//拿最大值去对比

for( var key in obj ){

	if( obj[key] == max ){

		console.log('最多的字符是'+key);

		console.log('出现的次数是'+max);

	}

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49

78. JS继承有哪些方式

 方式一:ES6 

class Parent{
  constructor(){
    this.age = 18;
  }
}

class Child extends Parent{
  constructor(){
    super();
    this.name = '张三';
  }
}
let o1 = new Child();
console.log( o1,o1.name,o1.age );

 方式二:原型链继承 

function Parent(){
  this.age = 20;
}
function Child(){
  this.name = '张三'
}
Child.prototype = new Parent();
let o2 = new Child();
console.log( o2,o2.name,o2.age );

 方式三:借用构造函数继承 

function Parent(){
  this.age = 22;
}
function Child(){
  this.name = '张三'
  Parent.call(this);
}
let o3 = new Child();
console.log( o3,o3.name,o3.age );

 方式四:组合式继承 

function Parent(){
  this.age = 100;
}
function Child(){
  Parent.call(this);
  this.name = '张三'
}
Child.prototype = new Parent();
let o4 = new Child();
console.log( o4,o4.name,o4.age );
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53

79. TypeScript,它的作用是什么

为 JS 添加类型支持,以及提供最新版的 ES 语法的支持,是的利于团队协作和排错,开发大型项目

80. TypeScript的内置数据类型

// 数字类型:用于表示数字类型的值。TypeScript 中的所有数字都存储为浮点值。

let num: number = 1;

// 字符类型: 用于表示字符串类型的值

let str: string = “CoderBin”;

// 布尔类型:一个逻辑二进制开关,包含true或false

let flag: boolean = true

// void 类型:分配给没有返回值的方法的类型。

let unusable: void = undefined;

81. TypeScript的主要特点

跨平台 :TypeScript 编译器可以安装在任何操作系统上,包括 Windows、macOS 和 Linux。

ES6 特性 :TypeScript 包含计划中的 ECMAScript 2015 (ES6) 的大部分特性,例如箭头函数。

面向对象的语言 :TypeScript 提供所有标准的 OOP 功能,如类、接口和模块。

静态类型检查 :TypeScript 使用静态类型并帮助在编译时进行类型检查。因此,你可以在编写代码时发现编译时错误,而无需运行脚本。

可选的静态类型 :如果你习惯了 JavaScript 的动态类型,TypeScript 还允许可选的静态类型。

82. TypeScript中never和void的区别

void 表示没有任何类型(可以被赋值为 null 和 undefined)。

never 表示一个不包含值的类型,即表示永远不存在的值。

拥有 void 返回值类型的函数能正常运行。拥有 never 返回值类型的函数无法正常返回,无法终止,或会抛出异常。

VUE2

83. diff算法

diff 算法是一种通过同层的树节点进行比较的高效算法

其有两个特点:

比较只会在同层级进行, 不会跨层级比较

在diff比较的过程中,循环从两边向中间比较

diff 算法在很多场景下都有应用,在 vue 中,作用于虚拟 dom 渲染成真实 dom 的新旧 VNode 节点比较

84. 什么是MVVM?

MVVM分为Model、View、ViewModel三者。
Model 代表数据模型,数据和业务逻辑都在Model层中定义;
View 代表UI视图,负责数据的展示;
ViewModel 负责监听 Model 中数据的改变并且控制视图的更新,处理用户交互操作;
Model 和 View 并无直接关联,而是通过 ViewModel 来进行联系的,Model 和 ViewModel 之间有着双向数据绑定的联系。因此当 Model 中的数据改变时会触发 View 层的刷新, View 中由于用户交互操作而改变的数据也会在 Model 中同步。
这种模式实现了 Model 和 View 的数据自动同步,因此开发者只需要专注对数据的维护操作即可,而不需要自己操作 dom。

85. mvvm与mvc的区别

mvc模型视图控制器,视图是可以直接访问模型,所以,视图里面会包含模型信息,mvc关注的是模型不变,所以,在mvc中,模型不依赖视图,但是视图依赖模型。

mvvm模型视图和vmvm是作为模型和视图的桥梁,当模型层数据改变,vm会检测到并通知视图层进行相应的修改。

86. Vue组件data为什么必须是个函数

解释一:

根实例对象data可以是对象也可以是函数 (根实例是单例),不会产生数据污染情况。组件实例对象data必须为函数 一个组件被复用多次的话,也就会创建多个实例,本质上,这些实例用的都是同一个构造函数。如果data是对象的话,对象属于引用类型,会影响到所有的实例。所以为了保证组件不同的实例之间data不冲突,data必须是一个函数。

解释二:

保证每个组件内数据的独立性,防止出现变量污染。对象为引用类型,当复用组件时,由于数据对象都指向同一个data对象,当在一个组件中修改data时,其他重用的组件中的data会同时被修改;而使用返回对象的函数,由于每次返回的都是一个新对象(Object的实例),引用地址不同,则不会出现这个问题。

87. vue的生命周期

beforeCreate(创建前)

这个时候,在实例被完成创建出来,el和data都没有初始化,不能访问data、method,一般在这个阶段不进行操作。

created(创建后)

这个时候,vue实例中的data、method已被初始化,

属性也被绑定,但是此时还是虚拟dom,真实dom还没生成,$el还不可用。

这个时候可以调用data和method的数据及方法,created钩子函数是最早可以调用data和method的,

故一般在此对数据进行初始化。

beforeMount(挂载前)

此时模板已经编辑完成,但还没有被渲染至页面中(即为虚拟dom加载为真实dom),此时el存在则会显示el。

在这里可以在渲染前最后一次更改数据的机会,不会触发其他的钩子函数,一般可以在这里做初始数据的获取。

Mounted(挂载后)

此时模板已经被渲染成真实DOM,用户已经可以看到渲染完成的页面,页面的数据也是通过双向绑定显示data中的数据。

这实例创建期间的最后一个生命周期函数,当执行完mounted就表示,实例已经被完全创建好了,

此时,如果没有其它操作的话,这个实例,就静静的躺在我们的内存中,一动不动。

beforeUpdate

更新前状态(view层的数据变化前,不是data中的数据改变前),重新渲染之前触发,

然后vue的虚拟dom机制会重新构建虚拟dom与上一次的虚拟dom树利用diff算法进行对比之后重新渲染。

只有view上面的数据变化才会触发beforeUpdate和updated,仅属于data中的数据改变是并不能触发。

updated

数据已经更改完成,dom也重新render完成。

beforeDestroy

销毁前执行($destroy方法被调用的时候就会执行),一般在这里善后:清除计时器、清除非指令绑定的事件等等…’)

destroyed

销毁后(Dom元素存在,只是不再受vue控制),卸载watcher,事件监听,子组件。

88. 在created和mounted去请求数据,有什么区别?

created:在渲染前调用,通常先初始化属性,然后做渲染

mounted:在模板渲染完成后,一般都是初始化页面后,在对元素节点进行操作

请求的数据对DOM有影响,那么使用created

如果请求的数据对DOM无关,可以放在mounted

89. Vue 的父子组件生命周期钩子函数执行顺序

渲染顺序 :先父后子,完成顺序:先子后父

更新顺序 :父更新导致子更新,子更新完成后父

销毁顺序 :先父后子,完成顺序:先子后父

加载渲染过程 父 beforeCreate->父 created->父 beforeMount->子 beforeCreate->子 created->子 beforeMount->子 mounted->父 mounted。子组件先挂载,然后到父组件

子组件更新过程

父 beforeUpdate->子 beforeUpdate->子 updated->父 updated

父组件更新过程

父 beforeUpdate->父 updated

销毁过程

父 beforeDestroy->子 beforeDestroy->子 destroyed->父 destroyed

90. methods 与 computed两者之间区别

  1. methods 调用需要使用(), computed计算属性直接只用函数名

  2. 两者写法都一样,都是方法,但是computed计算属性必须有一个返回值,但是methods不一定

  3. 当数据没有发生改变,调用methdos每次都会重新计算代码,computed有依赖缓存,只会执行一次代码,之后就返回之前的结果

91. computed(计算属性)和watch差异

1.computed是计算一个新的属性,并将该属性挂载到Vue实例上,而watch是监听已经存在且已挂载到Vue实例上的数据,所以用watch同样可以监听computed计算属性的变化;

2.computed本质是一个惰性求值的观察者,具有缓存性,只有当依赖变化后,第一次访问computed值,才会计算新的值。而watch则是当数据发送变化便会调用执行函数;

3.从使用场景上来说,computed适用一个数据被多个数据影响,而watch使用一个数据影响多个数据

92. vue组件通信

父传子:props

子传父:this.$emit

兄弟:EventBUS

大规模:vuex

依赖注入(provide / inject)

路由传参

事件传参

本地存储

插槽传参

93. v-model实现原理

v-model 本质上是语法糖(可以看成是value + input方法的语法糖),v-model 在内部为不同的输入元素使用不同的属性并抛出不同的事件:

text 和 textarea 元素使用 value 属性和 input 事件

checkbox 和 radio 使用 checked 属性和 change 事件

select 字段将 value 作为 prop 并将 change 作为事件

v-model用于实现视图层与数据层的双向绑定,数据层变化时可以驱动视图层更新,当视图层变化时会改变数据。v-model本质上是一个语法糖,默认情况下相当于:value和@input的结合。

94. vue数据绑定的几种方式

1.单向绑定双大括号{{}}html内字符串绑定

2.v-bind绑定html属性绑定

3.双向绑定v-model

4.一次性绑定v-once依赖于v-model

95. vue中常用指令

指令作用
v-on缩写为@,绑定事件
v-bind简写为:,动态绑定
v-slot简写为#,组件插槽
v-for循环对象或数组元素,同时生成DOM
v-show显示内容与否
v-if显示与隐藏,决定当前DOM元素是否渲染
v-else必须和v-if连用 不能单独使用 否则报错
v-text解析文本
v-html解析html标签

96. 常见修饰符

v-on

修饰符作用
.stopevent.stopPropagation(),阻止单击事件继续传播(阻止默认事件)
.preventevent.preventDefault(),提交事件不再重载页面(阻止默认行为)
.native监听组件根元素的原生事件
.once点击事件将只会触发一次

v-model 的修饰符

修饰符作用
.lazy取代 input 监听 change 事件
.number输入值转为数值类型
.trim输入首尾空格过滤

键盘事件的修饰符

.enter

.tab

.delete (捕获“删除”和“退格”键)

.esc

.space

.up

.down

.left

.right

系统修饰键

.ctrl

.alt

.shift

.meta

鼠标按钮修饰符

.left

.right

.middle

97. v-for与v-if优先级

v-for比v-if具有更高的优先级,如果每一次都需要遍历整个数组,将会影响速度,尤其是当之需要渲染很小一部分的时候。

98. v-if和v-show的区别

都是用来控制元素的显示、隐藏,区别就在于它们各是通过什么去控制元素的显示、隐藏

v-show:通过css样式中的display:none;控制元素显示、隐藏

v-if:通过控制vue的虚拟dom树上的节点,来联动控制真实dom上的节点,从而控制元素的显示、隐藏很多人认为是控制真实dom树上的节点,来显示隐藏,其实不完全对;而是间接的控制,v-if直接控制的是vue生成的虚拟dom树,当虚拟dom树上的节点被删除时,vue的响应系统会实时的删除对应的真实dom树上的节点;从而控制元素的显隐

使用场景:需要频繁切换DOM时,使用v-show;反之则使用v-if

1、v-if

此元素进入页面后,此元素只会显示或隐藏不会被再次改变显示状态,此时用v-if更加合适,如请求后台接口通过后台数据控制某块内容是否显示或隐藏,且这个数据在当前页不会被修改

作用:当用v-if来隐藏元素时,初次加载时就不用渲染此dom节点,提升页面加载速度

2、v-show

此元素进入页面后,此元素会频繁的改变显示状态,此时用v-show更加合适,如页面中有一个toggle按钮,点击按钮来控制某块区域的显示隐藏

作用:当用v-show来隐藏元素时,只会在初次加载时渲染此dom节点,之后都是通用display来控制显隐,如果此时使用v-if,那会频繁的操作dom,会极大的影响性能,但用display则不会

避免v-for和v-if在一起使用:

Vue 处理指令时,v-for 比 v-if 具有更高的 优先级****,存在性能问题。

99. 动态绑定class与style

classstyle
绑定对象:class=“{className:isActive }” 或 :class=“classNameObject”:style=“{color:‘#ffffff’}” 或:style=“styleObject”
绑定数组:class=“[‘active’,‘is-success’, { ‘is-disabled’: isDisabled }]”:style=“[styleObject1, styleObject2, styleObject3, …]”

100. route与router区别

1.router是vueRouter的一个对象,通过vue.use(vueRouter)和vueRouter构造函数得到一个router的实例对象,这个对象中是一个全局的对象,他包含了所有的路由包含了许多关键的对象和属性。

2.route是一个跳转的路由对象,每一个路由都会有一个route对象,是一个局部的对象,可以获取对应的name,path,params,query等

101. vue路由传参的两种方式,params和query方式与区别

动态路由也可以叫路由传参,就是根据不同的选择在同一个组件渲染不同的内容

query:类似 get, 跳转之后页面 url后面会拼接参数,类似?id=1, 非重要性的可以这样传, 密码之类还是用,params刷新页面id还在

params:类似 post, 跳转之后页面 url后面不会拼接参数 , 但是刷新页面id 会消失

102. vue路由的实现

前端路由就是更新视图但不请求页面,利用锚点完成切换,页面不会刷新

官网推荐用vue-router.js来引入路由模块

定义路由组件

定义路由,使用component进行路由映射组件,用name导航到对应

路由

创建router实例,传入routes配置

创建和挂载根实例

用router-link设置路由跳转

103. Vue路由模式

路由模式有俩种:history、hash

区别:

  1. 表现形态不同

​ history:http://localhost:8080/about

​ hash:http://localhost:8080/#/about

  1. 跳转请求

​ history : http://localhost:8080/id ===>发送请求

​ hash : 不会发送请求

  1. 打包后前端自测要使用hash,如果使用history会出现空白页

104. 路由导航守卫有哪些

全局、路由独享、组件内

  1. 全局

beforeEach、beforeResolve、afterEach

  1. 路由独享

beforeEnter

  1. 组件内

beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave

使用场景:判断是否登录,如果登录就next否则就跳转到登录页面

105. Vue中key的作用和原理

key是为Vue中的VNode标记的唯一id,在patch过程中通过key可以判断两个虚拟节点是否是相同节点,通过这个key,我们的diff操作可以更准确、更快速

diff算法的过程中,先会进行新旧节点的首尾交叉对比,当无法匹配的时候会用新节点的key与旧节点进行比对,然后检出差异

尽量不要采用索引作为key

如果不加key,那么vue会选择复用节点(Vue的就地更新策略),导致之前节点的状态被保留下来,会产生一系列的bug

更准确 :因为带 key 就不是就地复用了,在 sameNode 函数 a.key === b.key 对比中可以避免就地复用的情况。所以会更加准确。

更快速 :key的唯一性可以被Map数据结构充分利用,相比于遍历查找的时间复杂度O(n),Map的时间复杂度仅仅为O(1),比遍历方式更快。

106. elementui是怎么做表单验证的?

1.在表单中加rules属性,然后再data里写校验规则

2.内部添加规则

3.自定义函数校验

107. vue中遍历全局的方法有哪些?

1.普通遍历

对象.forEach()

   arr.forEach(function(item,index,arr){

     console.log(item,index)

   })

2.对元素统一操作  

对象.map()

  var newarr = arr.map(function(item){

     return item+1

   })

3.查找符合条件的元素 

对象.filter()

    arr.filter(function(item){

     if(item > 2){

       return false

     }else{

      return true

     }

   })

4.查询符合条件的元素,返回索引 

对象.findindex()

    arr.finindex(function(item){

      if(item>1){

        return true

      }else{

        return false

      }

    })

对象.evening()  遇到不符合的对象会停止

对象.some()  找到符合条件的元素就停止
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59

108. 如何搭建脚手架?

下载:node cnpm webpack vue-cli

创建项目:

​ 1.找到对应的文件,然后利用node指令创建(cmd)

​ 2.vue init webpack xxxx

​ 3.回车项目描述

​ 4.继续回车

​ 5.选择vue build

​ 6.回车

​ 7.输入n

​ 8.不按照yarn

​ 9.输入npm run dev

109. 如何封装一个组件?

1.使用Vue.extend()创建一个组件

2.使用Vue.components()方法注册组件

3.如果子组件需要数据,可以在props中接收定义

4.子组件修改好数据,要把数据传递给父组件,可以用emit()方法

原则:

​ 把功能拆开

​ 尽量让组件原子化,一个组件做一件事情

​ 容器组件管数据,展示组件管视图

110. 封装一个可复用的组件,需要满足什么条件?

1.低耦合,组件之间的依赖越小越好

2.最好从父级传入信息,不要在公共组件中请求数据

3.传入的数据要进行校验

4.处理事件的方法写在父组件中

111. vue的过滤器怎么使用?

vue的特性,用来对文本进行格式化处理

使用它的两个地方,一个是插值表达式,一个是v-bind

分类:

​ 1.全局过滤器

      Vue.filter('add',function(v){

        return v < 10 ? '0' + v : v

      })
使用:<div>{{33 | add}}</div>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

​ 2.本地过滤器

​ 和methods同级

      filter:{

        add:function(v){

         return v < 10 ? '0' + v : v

        }

      }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

112. vue中如何做强制刷新?

1.localtion.reload()

2.this.$router.go(0)

3.provide和inject

113. vuex的五大属性

Vuex是单向数据流

state=>基本数据(数据源)

getters=>从基本数据派生的数据(类似计算属性)

mutations=>提交更改数据的方法,同步!

actions=>像一个装饰器,包裹mutations,使之可以异步

modules=>模块化vuex

114. 谈谈你对keep-alive的了解

  1. 是什么

vue系统自带的一个组件,功能:是来缓存组件的。===》提升性能

  1. 使用场景

就是来缓存组件,提升项目的性能。具体实现比如:首页进入到详情页,如果用户在首页每次点击都是相同的,那么详情页就没必要请求N次了,直接缓存起来就可以了,当然如果点击的不是同一个,那么就直接请求。

115. scoped原理

  1. 作用:让样式在本组件中生效,不影响其他组件。

  2. 原理:给节点新增自定义属性,然后css根据属性选择器添加样式。

116. Vue中如何做样式穿透

stylus样式穿透使用:>>>

sass和less使用:/deep/

通用使用: :v-deep

117. 从0到1自己构架一个vue项目,有哪些步骤、哪些重要插件、目录结构你会怎么组织

1.从0创建一个项目我大致会做以下事情:项目构建、引入必要插件、代码规范、提交规范、常用库和组件

2.目前vue3项目我会用vite或者create-vue创建项目

3.接下来引入必要插件:路由插件vue-router、状态管理vuex/pinia、ui库我比较喜欢element-plus和antd-vue、http工具我会选axios

4.其他比较常用的库有vueuse,nprogress,图标可以使用vite-svg-loader

5.下面是代码规范:结合prettier和eslint即可

6.最后是提交规范,可以使用husky,lint-staged,commitlint

7.目录结构我有如下习惯: .vscode:用来放项目中的 vscode 配置

plugins:用来放 vite 插件的 plugin 配置

public:用来放一些诸如 页头icon 之类的公共文件,会被打包到dist根目录下

src:用来放项目代码文件

api:用来放http的一些接口配置

assets:用来放一些 CSS 之类的静态资源

components:用来放项目通用组件

layout:用来放项目的布局

router:用来放项目的路由配置

store:用来放状态管理Pinia的配置

utils:用来放项目中的工具方法类

views:用来放项目的页面文件

118. Vue项目优化

(1)代码层面的优化

v-if 和 v-show 区分使用场景

computed 和 watch 区分使用场景

v-for 遍历必须为 item 添加 key,且避免同时使用 v-if

长列表性能优化

事件的销毁

图片资源懒加载

路由懒加载

第三方插件的按需引入

优化无限列表性能

服务端渲染 SSR or 预渲染

(2)Webpack 层面的优化

Webpack 对图片进行压缩

减少 ES6 转为 ES5 的冗余代码

提取公共代码

模板预编译

提取组件的 CSS

优化 SourceMap

构建结果输出分析

Vue 项目的编译优化

(3)基础的 Web 技术的优化

开启 gzip 压缩

浏览器缓存

CDN 的使用

使用 Chrome Performance 查找性能瓶颈

119. vue3.0 特性

(1)监测机制的改变

3.0 将带来基于代理 Proxy 的 observer 实现,提供全语言覆盖的反应性跟踪。这消除了 Vue 2 当中基于 Object.defineProperty 的实现所存在的很多限制:

只能监测属性,不能监测对象

检测属性的添加和删除;

检测数组索引和长度的变更;

支持 Map、Set、WeakMap 和 WeakSet。

新的 observer 还提供了以下特性:

用于创建 observable 的公开 API。这为中小规模场景提供了简单轻量级的跨组件状态管理解决方案。

默认采用惰性观察。在 2.x 中,不管反应式数据有多大,都会在启动时被观察到。如果你的数据集很大,这可能会在应用启动时带来明显的开销。在 3.x 中,只观察用于渲染应用程序最初可见部分的数据。

更精确的变更通知。在 2.x 中,通过 Vue.set 强制添加新属性将导致依赖于该对象的 watcher 收到变更通知。在 3.x 中,只有依赖于特定属性的 watcher 才会收到通知。

不可变的 observable:我们可以创建值的“不可变”版本(即使是嵌套属性),除非系统在内部暂时将其“解禁”。这个机制可用于冻结 prop 传递或 Vuex 状态树以外的变化。

更好的调试功能:我们可以使用新的 renderTracked 和 renderTriggered 钩子精确地跟踪组件在什么时候以及为什么重新渲染。

(2)模板

模板方面没有大的变更,只改了作用域插槽,2.x 的机制导致作用域插槽变了,父组件会重新渲染,而 3.0 把作用域插槽改成了函数的方式,这样只会影响子组件的重新渲染,提升了渲染的性能。

同时,对于 render 函数的方面,vue3.0 也会进行一系列更改来方便习惯直接使用 api 来生成 vdom 。

(3)对象式的组件声明方式

vue2.x 中的组件是通过声明的方式传入一系列 option,和 TypeScript 的结合需要通过一些装饰器的方式来做,虽然能实现功能,但是比较麻烦。3.0 修改了组件的声明方式,改成了类式的写法,这样使得和 TypeScript 的结合变得很容易。

此外,vue 的源码也改用了 TypeScript 来写。其实当代码的功能复杂之后,必须有一个静态类型系统来做一些辅助管理。现在 vue3.0 也全面改用 TypeScript 来重写了,更是使得对外暴露的 api 更容易结合 TypeScript。静态类型系统对于复杂代码的维护确实很有必要。

(4)其它方面的更改

vue3.0 的改变是全面的,上面只涉及到主要的 3 个方面,还有一些其他的更改:

支持自定义渲染器,从而使得 weex 可以通过自定义渲染器的方式来扩展,而不是直接 fork 源码来改的方式。

支持 Fragment(多个根节点)和 Protal(在 dom 其他部分渲染组建内容)组件,针对一些特殊的场景做了处理。

基于 treeshaking 优化,提供了更多的内置功能。

120. vue3和vue2有哪些区别?

1.双向数据绑定的原理不同

2.是否支持碎片

3.API不同

4.定义数据变量方法不同

5.生命周期的不同

6.传值不同

7.指令和插槽不同

8.main.js不同

121. 说说你 对 proxy 的理解,Proxy 相比于 defineProperty 的优势

Object.defineProperty() 的问题主要有三个:

不能监听数组的变化 :无法监控到数组下标的变化,导致通过数组下标添加元素,不能实时响应

必须遍历对象的每个属性 :只能劫持对象的属性,从而需要对每个对象,每个属性进行遍历,如果属性值是对象,还需要深度遍历。Proxy 可以劫持整个对象,并返回一个新的对象

必须深层遍历嵌套的对象

Proxy的优势如下:

针对对象: 针对整个对象,而不是对象的某个属性 ,所以也就不需要对 keys 进行遍历

支持数组:Proxy 不需要对数组的方法进行重载,省去了众多 hack,减少代码量等于减少了维护成本,而且标准的就是最好的

Proxy的第二个参数可以有 13 种拦截方:不限于apply、ownKeys、deleteProperty、has等等是Object.defineProperty不具备的

Proxy返回的是一个新对象,我们可以只操作新的对象达到目的,而Object.defineProperty只能遍历对象属性直接修改

Proxy作为新标准将受到浏览器厂商重点持续的性能优化,也就是传说中的新标准的性能红利

Object.defineProperty的优势如下:

兼容性好,支持 IE9,而 Proxy 的存在浏览器兼容性问题,而且无法用 polyfill 磨平

122. 懒加载与预加载的区别

这两种方式都是提高网页性能的方式,两者主要区别是一个是提前加载,一个是迟缓甚至不加载。懒加载对服务器前端有一定的缓解压力作用,预加载则会增加服务器前端压力

懒加载也叫延迟加载 ,指的是在长网页中延迟加载图片的时机,当用户需要访问时,再去加载,这样可以提高网站的首屏加载速度,提升用户的体验,并且可以减少服务器的压力。它适用于图片很多,页面很长的电商网站的场景。懒加载的实现原理是,将页面上的图片的 src 属性设置为空字符串,将图片的真实路径保存在一个自定义属性中,当页面滚动的时候,进行判断,如果图片进入页面可视区域内,则从自定义属性中取出真实路径赋值给图片的 src 属性,以此来实现图片的延迟加载。

预加载指的是将所需的资源提前请求加载到本地 ,这样后面在需要用到时就直接从缓存取资源。 通过预加载能够减少用户的等待时间,提高用户的体验。我了解的预加载的最常用的方式是使用 js 中的 image 对象,通过为 image 对象来设置 scr 属性,来实现图片的预加载。

123. 内存泄露

意外的全局变量: 无法被回收

定时器: 未被正确关闭,导致所引用的外部变量无法被释放

事件监听: 没有正确销毁 (低版本浏览器可能出现)

闭包:

第一种情况是我们由于使用未声明的变量,而意外的创建了一个全局变量,而使这个变量一直留在内存中无法被回收。

第二种情况是我们设置了setInterval定时器,而忘记取消它,如果循环函数有对外部变量的引用的话,那么这个变量会被一直留在内存中,而无法被回收。

第三种情况是我们获取一个DOM元素的引用,而后面这个元素被删除,由于我们一直保留了对这个元素的引用,所以它也无法被回收。

第四种情况是不合理的使用闭包,从而导致某些变量一直被留在内存当中。

dom 引用: dom 元素被删除时,内存中的引用未被正确清空控制台console.log打印的东西

124. 首屏优化该如何去做?

1.使用路由懒加载

2.非首屏组件使用异步组件

3.首屏不中要的组件延迟加载

4.静态资源放在CDN上

5.减少首屏上JS、CSS等资源文件的大小

6.使用服务端渲染

7.简历减少DOM的数量和层级

8.使用精灵图请求

9.做一些loading

10.开启Gzip压缩

11.图片懒加载

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/701059
推荐阅读
相关标签
  

闽ICP备14008679号