一阶段
1.网络中使用最多的图片格式有哪些
• gif 支持动画,只有全透明和不透明两种模式,只有 256 种颜色 • jpg 采用有损压缩算法,体积较小,不支持透明,不支持动画 • png 采用有损压缩算法,体积也相对较小,支持透明背景,不支持动画 • svg 一般会保存颜色及形状相对简单的图片,可 任意放大图形显示,边缘异常清晰 • BMP 无损压缩格式,画质最好,文件太大,不利于网络传输
2.请简述css盒子模型
在网页中,一个元素占有空间的大小由几个部分构成,其中包括元素的内容(content), 元素的内边距(padding),元素的边框(border), 元素的外边距(margin)四个部分, 这就是盒子模型。
3.视频/音频标签的使用
• 视频 <video src="课堂示例/qr.ogg" controls height="300" autoplay loop muted></video> o 属性: controls 控件、 autoplay: 自动播放谷歌和火狐静音下支持 ie 支持、 muted 静音播放、 loop 循环、 poster 未播放前显示的内容 • 音频 <audio src="课堂示例/梦然-少年.mp3" controls autoplay loop muted></audio> o 属性: controls 控件、 autoplay 自动播放谷歌不支持,火狐静音下支持 ie 支 持、 loop 循环播放、 muted 静音播放
4.HTML5新增的内容有哪些
• h5 的语法 o DOCTYPE 可以使用小写 o 单标签没有结束标签 o 可以省略结束的标签: li、 dt、 dd、 p、 option、 colgroup(用于对表格中的列进行 组合,以便对其进行格式化)、 thead、 tbody、 tfoot、 tr、 td、 th o 可以省略的标签 html head body tbody • 新增标签特点:语义化, ie8 及以下不生效 o header 标签头部 o section 划分板块 o article 与上下文无关的内容 o aside 可以放侧边工具栏 o nav 导航 o figure 和 figcaption 类似于 dl 标签 o footer 底部 o main 比较重要的部分 o mark 标记默认是黄色的高亮,可以修改样式内联10 • 多媒体标签 o 音频 <audio src="课堂示例/梦然-少年.mp3" controls autoplay loop muted></audio> 内联 <audio controls> <source src="课堂示例/梦然-少年.ogg" type="audio/ogg"></source> <source src="课堂示例/梦然-少年.mp3" type="audio/mpeg"></source> controls 控件 autoplay 自动播放谷歌不支持,火狐静音下支持 ie 支持 loop 循环播放 muted 静音播放 o 视频 <video src="课堂示例/qr.ogg" controls height="300" autoplay loop muted> </video> <video controls> <source src="课堂示例/wje.mp4" type="video/mp4"></source> <source src="课堂示例/wje.ogg" type="video/ogg"></source> <source src="课堂示例/wje.webm" type="video/webm"></source> controls 控件 autoplay: 自动播放谷歌和火狐静音下支持 ie 支持 muted 静音播放 loop 循环 poster 未播放前显示的内容 • 表单新增 o type 类型 email 邮件格式 number 限制输入是数字 min 最小值 max 最大值 step 每次增加的数 url 地址路径或者网址都可以 color 色块 time 时间 range 滑动条 o 属性 required 必填 <input type="text" required autofocus> placeholder 提示信息 autocomplete 自动提示 on 提示 off 不提示 <input type="text" name="test" autocomplete="on" > autofocus 自动聚焦只能写一个 multiple 多选 <input type="file" multiple> pattern 正则限制输入的内容类型 <input type="text" pattern="[0-9]"> 限制输入 0-9 之间的数
5.Html5 新增的语义化标签有哪些
o header 标签头部 o section 划分板块 o article 与上下文无关的内容 o aside 可以放侧边工具栏 o nav 导航 o figure 和 figcaption 类似于 dl 标签 o footer 底部 o main 比较重要的部分 o mark 标记默认是黄色的高亮,可以修改样式内联
6.Css3新增的特性
css3 选择器 o 属性选择器 [属性名] 可以选择到官方或者自定义的属性 [属性名="属性值"] 匹配属性值 [属性名~=""] 包含该值必须单独出现的 [属性名*=""] 只要包含该值就行 [属性名^=""] 以该值开头 [属性名$=""] 以该值结尾 o 伪类选择器 构性伪类选择器(child 系列) 1.E:first-child E 必须是父元素里面的第一个孩子 2.E:last-child E 必须是父元素里面的最后一个孩子 3.E:**nth-child(n)** 不匹配前面的元素类型,如果对应的位置是该元素才匹 配 4. E:only-child 必须只有他自己一个孩子 结构性的伪类选择(type 系列) 1.E:first-of-type 匹配到该元素中的第一个孩子 2.E:last-of-type 匹配到该元素的最后一个孩子 3.E:**nth-of-type(n)** 匹配到该元素的第几个孩子 n 可以是表达式 2n 3n 2n+1 even(偶数) odd(奇数) 4.E:nth-last-of-type(n) 匹配到该元素的倒数第几个 目标伪类:结合锚点使用 状态伪类选择器 1.:enabled 元素可编辑 2.:disabled 元素不可编辑 3.:checked 选中 4.::selection 高亮状态一般修改字体颜色和背景色 动态伪类选择器 1.:link 未访问前 2.:visited 访问过后 3.:hover 鼠标滑过 4.:active 鼠标点击之后 层级选择器 后代选择器选择器选择器 子项选择器选择器>选择器 相邻的兄弟选择器+选择器紧挨着的兄弟 相邻的兄弟们选择器~选择器紧挨着的弟弟们 o css3 属性 阴影 1. box-shadow:x 轴偏移 y 轴偏移模糊距离阴影的颜色阴影的位置 (outset/inset) ;12 2. text-shadow:x 轴偏移 y 轴偏移模糊距离阴影的颜色; 透明 rgba 设置透明度 里面的内容不会被模糊 opacity:0-1; 0 完全透明 1 不透明 1.里面的内容也会被模糊 2.可以设置图片的模糊 3.过渡效果对 display 的隐藏和出现没有效果,可以通过设置 opacity 的值 背景 背景图的原点 background-origin 1.padding-box 默认值背景图从 padding 区域开始显示 2.content-box 背景图从 content 区域开始显示 3.border-box 背景图从 border 边框区域开始显示 背景图的裁切 background-clip 1.border-box 边框之外裁切 2.padding-box padding 之外裁切 3.content-box 内容区开始裁切 背景图大小的设置 background-size 圆角 border-radius 1.一个值四个角 2.两个值对角 3.三个值左上角右上角/左下角右下角 4.四个值左上角右上角右下角左下角(顺时针的角度) 5.正圆 border-radius: 50%/100%; 图片边框 border-image 1.border-image:图片路径偏移重复 2.border-image-source:url() 图片的路径 3.border-image-slice:数值图片的裁切不要加单位 4.border-image-repeat:平铺(repeat) 铺满(round) 拉伸(stretch)默认 过渡 transition: transition-property transition-duration transition-delay transition-timing-function(顺序不固定,当只有一个时间的时候,表示 过渡时间,两个时间第一个表示过渡时间,第二个表示延迟时间) transition-property 需要过渡的属性 transition-duration 过渡所需要的时间 s(秒)/ms(毫秒) 1s=1000ms transition-delay 过渡延迟时间 s(秒)/ms(毫秒) transition-timing-function 过渡效果 1.linear: 匀速 2.ease: 逐渐慢下来 3.ease-in: 加速 4.ease-out: 减速 5.ease-in-out 先加速后减速 动画 animation: animation 使用: animation: 动画名动画持续时间延迟时间动画效果执行次数13 animation-name: 动画名 animation-duration: 动画的持续时间 s/ms animation-delay: 动画的延迟时间 s/ms animation-timing-function: 动画的效果 animation-iteration-count: 具体的数值/infinite(无限循环) anmiation-direction: 动画执行的方向 1.normal 正向 2.reverse 反向 3. alternate 正向和反向交替运动 animation-play-state 动画是否播放 1.running 播放默认值 2.paused 暂停 定义动画 css @keyframes 动画名{ from{} ==>0% to{}==>100% } 关键帧分的是时间 @keyframes 动画名{ 0%{ css 属性:css 属性值 } 10%{} 0.5s 20%{} 1s 30%{} 100%{} } 渐变 线性渐变 background-image/background:linear-gradient(方向,颜色 1,颜色 2……) 渐变方向 to bottom 向下 to right 向右 to top 向上 to left 向左 to right bottom 向右下角 to left top 向左上角 to right top 向右上角 to left bottom 向左下角 数值+deg(角度) 设置百分比 css /* 0%-40% 是红色的纯色 40%-60% 红色到蓝色渐变 60%-100% ;蓝色的纯色*/14 background: linear-gradient(red 40%, blue 60%); 重复性的线性渐变 background:repeating-linear-gradient(red 40%, blue 60%); 径向渐变 bakrgound-image/background:radial-gradient(位置,颜色 1,颜色 2) 位置 center 中心 水平方向: left/center/right 垂直方向: top/center/bottom 兼容写法 css background: radial-gradient(left, red, blue); background: -webkit-radial-gradient(left, red, blue); background: - ms-radial-gradient(left, red, blue); 重复性的径向渐变 background: repeating-radial-gradient(red 20%, yellow 40%);
7.清除浮动的方式有哪些?请说出各自的优点
• 额外标签法(在最后一个浮动标签后,新加一个标签,给其设置 clear: both)不 推荐 o 优点:通俗易懂,方便 o 缺点:添加无意义标签,语义化差 • 父级添加 overflow 属性(overflow: hidden)不推荐 o 优点:代码简洁 o 缺点:内容增多的时候容易造成不会自动换行导致内容被隐蔽掉,无法显示要溢 出的元素 • 给父级设置高度 o 优点:简单,代码少,容易掌握 o 缺点:只适合高度固定的布局,要给出精确的高度,如果高度和父级 div 不一 样时,会产生问题 • 父级 div 定义 overflow:auto(必须定义 width 或 zoom:1,同时不能定义 height, 使用 overflow:auto 时,浏览器会自动检查浮动区域的高度) o 优点:简单,代码少,浏览器支持好 o 缺点:内部宽高超过父级 div 时,会出现滚动条。 • 使用 after 伪元素清除浮动(推荐使用) .clear:after{ content:""; display:block; clear:both; height:0; overflow:hidden; visibility:hidden }15 o 优点:符合闭合浮动思想,结构语义化正确 o 缺点: ie6-7 不支持伪元素: after,使用 zoom: 1 触发 hasLayout
8.定位的属性值有何区别
• static 默认值 • relative 相对定位,参考自己本身的位置,不会脱离文档流,文字不能被遮挡 • absolute 绝对定位,参考有定位属性(除了 static)的祖先元素,定位元素通过一层一层 向上找,找到有定位的祖先元素,如果找到 body 依然没有找到有定位的祖先元 素,参考浏览器窗口(子绝父相),脱离文档流,且文字能被遮挡,块级元素设置 margin:0 auto;会失效,内联元素设置定位转换成块元素 • fixed 固定定位,参考浏览器的窗口,不会跟随滚动条的滚动而滚动,脱离文档流, 宽度自适应的时候,宽度不显示,可以通过设置 width:100% • 粘性定位 sticky,参考浏览器的窗口,没有达到 top 值之前正常显示,达到 top 值 之后类似于固定定位,不会跟随滚动条滚动而滚动
9.html水平垂直居中的方式有哪些?
方法1:定位 ,50%,margin负距 .box{ width: 400px; height: 300px; border: 2px solid black; /* 把元素变成定位元素 */ position: absolute; /* 元素距离上,左都为50% */ left: 50%; top: 50%; /* 让元素的左外边距,上外边距为元素宽高的1/2 注意margin是负距*/ margin-top: -150px; margin-left: -200px; }
方法2:四方为都为0 ,margin:auto .box{ width: 400px; height: 300px; border: 2px solid black; position: absolute; left: 0; top: 0; bottom: 0; right: 0; margin: auto; }
3 方法三,元素尺寸不固定 .box2 { position: absolute; left: 50%; top: 50%; /* 设置元素的相对于自身的偏移度为负50%(也就是元素自身尺寸的一半)*/ transform: translate(-50%, -50%); }
10.Border-box与content-box的区别
• border-box o padding 和 border 被包含在定义的 width 和 height 之内。 o 对象的实际宽度就等于设置的 width 值,即使定义有 border 和 padding 也不 会改变对象的实际宽度;即 ( Element width = width+ margin) o 此属性表现为怪异模式下的盒模型 • content-box o padding 和 border 不被包含在定义的 width 和 height 之内。 o 对象的实际宽度等于设置的 width 值和 border、 padding 之和;即( Element width = width + border + padding + margin) o 此属性表现为标准模式下的盒模型
11.元素垂直居中
• 如果是图片,直接设置 img 的属性 vertical-align: middle;前提是需要设置父级元素 为块级元素并且设置高度 • 如果是单行文本,可以通过设置子元素的 line-height 值等于父元素的 height,这种 方法适用于子元素为单行文本的情况。16 • 通过定位父元素 position: relative 子元素 position: absolute top:50%; transform: translateY(-50%); • 通过伪元素:before 实现 CSS 垂直居中 父元素:before{ content:""; display:inline-block; vertical-align:middle; height:100%; } • 通过 display:table 实现,给父元素设置 display:table,子元素 display: table-cell 的 方式实现 CSS 垂直居中 • 通过 display:flex 实现,给父元素设置 display:flex; 子元素 align-self:center
12.BFC是什么?
BFC(Block formatting context)直译为"块级格式化上下文"。它是一个独立的渲染区域,只有box参与, 它规定了内部的Box如何布局,并且与这个区域外部毫不相干。
13.如何让chrome浏览器显示小于12px的文字
可以使用CSS3里的 transform:scale(0.8) 属性来应对这个问题
14.Css选择器有哪些,那些属性可以继承,优先级如何计算?Css3新增的伪类有哪些
• css 选择器 o id 选择器( # myid) o 类选择器(.myclassname) o 标签选择器(div, h1, p) o 相邻选择器(h1 + p) o 子选择器(ul > li) o 后代选择器(li a) o 通配符选择器( * ) o 属性选择器(a[rel = “external”]) o 伪类选择器(a: hover, li: nth - child) • 可以继承 o 字体类: 1. font-family:字体类型; 2. font-weight:字体加粗; 3. font-size:字体大小 4. font-style: 字体样式 5. text-indent: 缩进(只对块级元素生效) 6. text-align:对齐方式 7. line-height:行高 8. word-spacing:字之间的距离; 9. letter-spacing:字符之间的距离; 10.text-decoration:文本修饰 o 文本类: 1. color:颜色 o 列表:17 1. list-style-type:列表类型 2. list-style-image:图标路径 3. list-style-position:图标的位置 4. list-style:none;去掉列表符号 • 优先级就近原则,样式定义最近者为准; 载入样式以最后载入的定位为准; • 优先级为: !important > id > class > tag(标签选择器) important 比内联优先级高 • css3 新增的伪类 o 结构性伪类选择器(child 系列) 1. E:first-child E 必须是父元素里面的第一个孩子 2. E:last-child E 必须是父元素里面的最后一个孩子 3. E:nth-child(n) 不匹配前面的元素类型,如果对应的位置是该元素才匹配 4. E:only-child 必须只有他自己一个孩子 o 结构性的伪类选择(type 系列) 1. E:first-of-type 匹配到该元素中的第一个孩子 2. E:last-of-type 匹配到该元素的最后一个孩子 3. E:nth-of-type(n) 匹配到该元素的第几个孩子 n 可以是表达式 2n 3n 2n+1 even(偶数) odd(奇数) 4. E:nth-last-of-type(n) 匹配到该元素的倒数第几个 o 目标伪类:结合锚点使用 o 状态伪类选择器 1. :enabled 元素可编辑 2. :disabled 元素不可编辑 3. :checked 选中 4. ::selection 高亮状态一般修改字体颜色和背景色 o 动态伪类选择器 1. :link 未访问前 2. :visited 访问过后 3. :hover 鼠标滑过 4. :active 鼠标点击之后
15.Css选择器权重?
行内样式权重为1000; ID选择器权重为100; 类、伪类、属性选择器为10; 标签、伪元素选择器权重为1; 通配符、子选择器、相邻选择器权值为`0000`。 继承的样式没有权值
16.网页中有大量图片加载很慢 你有什么办法进行优化?
• 图片懒加载,在页面上的未可视区域可以添加一个滚动条事件,判断图片位置与浏 览器顶端的距离与页面的距离,如果前者小于后者,优先加载 • 如果为幻灯片、相册等,可以使用图片预加载技术,将当前展示图片的前一张和后 一张优先下载 • 如果图片为 css 图片,可以使用 CSSsprite(精灵图), SVGsprite(精灵图), Iconfont(字体图标)(精灵图,小图标…) • 如果图片过大,可以使用特殊编码的图片,加载时会先加载一张压缩的特别厉害的 缩略图,以提高用户体验 • 如果图片展示区域小于图片的真实大小,则应该在服务器端根据业务需要先行进行 图片压缩,图片压缩后大小与展示一致
17.行内元素/块级元素有哪些?
行内元素:a、b、span、img、input、strong、select、label、em、button、textarea 块级元素:div、ul、li、dl、dt、dd、p、h1-h6、blockquote
18.浏览器的标准模式和怪异模式区别?
标准模式:总宽度=width+margin(左右)+padding(左右)+border(左右) 怪异模式:总宽度=width+margin(左右)(width直接包括了padding(左右)+border(左右)
19.Margin和padding在什么场合下使用
• margin:用来调整盒子到盒子之间的距离,不会撑大显示的区域,但是会影响到别 的盒子 o 使用场景:需要在 border 外侧添加空白时;空白处不需要背景(色)时;上下 相连的两个盒子之间的空白,需要相互抵消时; • padding:用来调整子元素(内容)在父元素(盒子)内的位置,会把盒子撑大,如 果不想被撑大,要在原来宽高的基础上减去对应方向的 padding 值 o 使用场景:需要在 border 内测添加空白时;空白处需要背景(色)时;上下相 连的两个盒子之间的空白,希望等于两者之和时;
20.弹性盒子布局属性有那些请简述?
• 父元素: o 主轴方向 flex-direction 1. row 主轴从左向右默认值19 2. row-revese 主轴从右向左 3. column 主轴从上到下 4. column-reverse 主轴从下到上 o 主轴方向排列方式 justify-content 1. flex-start 主轴起点默认值 2. flex-end 主轴终点 3. center 居中 4. space-between 两端对齐 5. space-around 中间的留白是两边的 2 倍 6. space-evenly 平均分配留白 o 交叉轴排列方式 align-items 1. stretch 拉伸默认值去掉子元素的高度 2. flex-start 交叉轴的起点 3. flex-end 交叉轴的终点 4. center 居中 o 换行 flex-wrap 1 .nowrap 不换行,默认值,会将子元素压缩 2 .wrap 换行 3. wrap-reverse 反向换行 o 多行之间的排列方式 align-content 1. stretch 拉伸默认值需要去掉子元素的高 2. flex-start 主轴起点依次排列 3. flex-end 主轴终点依次排列 4. center 居中 5. space-between 两端对齐 6. space-around 中间空白是两端的 2 倍 7. space-evenly 平均分配 • 子元素: o 重写子项对应的交叉轴的对齐方式 align-self 1 .stretch 拉伸默认值去掉子元素的高度 2. flex-start 交叉轴的起点 3. flex-end 交叉轴的终点 4. center 居中 5. 放大 flex-grow 6. 0 不放大 7. 数值填充剩余的空间 o 压缩 flex-shrink 1. 1 压缩 2. 0 不压缩 3. 实现导航的滚动效果 a. 子项的宽度超出了父容器的宽度 b. 设置子项不压缩 flex-shrink:0; c. 父元素设置溢出显示滚动条 overflow-x:auto; o 子项的宽度 flex-basis:数值+px 类似于宽度20 o 排序 order 数值值越大越向后,可以设置负数
21.怎么实现标签的禁用
style=“pointer-events: none”
22.Flex布局原理
• flex 是 flexible Box 的缩写,意为“弹性布局”,用来为盒状模型提供最大的灵活性, 任何一个容器都可以指定为 flex 布局。当为父盒子设置为 flex 布局之后,子元素的 float、 clear、 vertical-align 属性将失效。 • 采用 flex 布局的元素,称为 flex 容器(flex container),简称“容器”。他的所有子元 素自动成为容器成员,称为 flex 项目(flex item),简称“项目”。 • 总结: flex 布局就是通过给父盒子添加 flex 属性,来控制子盒子的位置和排列方 式。
23.Px与rem的区别
• px: px 实际上就是像素,用 px 设置字体大小时,比较稳定和精确 o px 像素(Pixel),相对长度单位。像素 px 是相对于显示器屏幕分辨率而言的。 • em: em 就是根据基准来缩放字体的大小 em 的值并不是固定的; em 会根据父级 元素的字体大小变化 o em 是相对长度单位。相对于当前对象内文本的字体尺寸。如当前对行内文本的 字体尺寸未被人为设置,则相对于浏览器的默认字体尺寸。 • rem: rem 是根据根元素 <html> 字体大小变化,这样就意味着,我们只需要在根 元素确定一个参考值。一般情况下将根元素的字体大小设置为 html{font-size:100px} rem 是 CSS3 新增的一个相对单位(root em,根 em),这个单位引起了广泛关 注。
24.网页的三层结构有哪些
构成:结构层、表示层、行为层 分别是:HTML、CSS、JavajScript 作用:HTML实现页面结构、CSS完成页面的表现与风格、[JavaScript](https://so.csdn.net/so/search?from=pc_blog_highlight&q=JavaScript)实现客户端的一些功能和业务
25.请简述媒体查询
• 媒体指的就是各种设备 (移动设备, PC 设备),查询指的是要检测属于哪种设备,媒 体查询就是通过查询当前属于哪种设备, 让网页能够在不同的设备下正常的预览 • 语法 @media 关键字设备类型 and (媒体特性){} • 关键字: all(所有的设备类型)/only(限定某种设备)/not(排除设备) • 设备类型: o all(所有的设备) o screen 显示器移动设备笔记本 o print 打印设备 • 媒体类型 o 最小宽度 min-width 大于最小宽度 o 最大宽度 max-width 小于最大宽度 • 书写说明 o and 两侧必须有空格 o 媒体特性属性值后面不要加分号 o 多个媒体特性之间用 and 连接 <style> @media all and (min-width:500px) and (max-width:999px) { div { height: 600px; background-color: cadetblue; } } </style> • viewport 视口<meta name="viewport" content="width=device-width,initialscale=1.0"> o 视口 viewport 1. 布局视口,默认情况下,布局视口的宽是 980px,设置 css 样式的样式是 作用在布局视口 2. 可视视口设备的宽度 device-width 3. 完美/理想视口 width=device-width 布局视口和设备宽度一样 o initial-scale 初始缩放比例默认值 1 o minimum-scale(思该) 最小缩放比例默认值 1 o maximum-scale 最大缩放比例默认值 1 o user-scalable 用户是否可以手动缩放 no/0 不缩放
26.rem缺点
• 有局限性, IE8 及以下版本不支持 • 对 pc 页面来讲使用次数不多 • 数据量大:所有的图片、盒子都需要给一个准确的值,才能保证不同机型的适配;
27.常见的兼容性一阶段内容中记几个
• 在 ie 浏览器中, a 标签套图片会自带边框 ie10 及以下 o 解决:去掉边框 img{border:none} • 图片自带底部 3px 的留白22 o 解决: vertical-align: bottom/middle/top 给图片添加 display:block; 给图片添加 font-size:0; 给父元素添加 • 表单元素对齐不一致 o 解决: 设置怪异盒模型 设置浮动 • 透明度 opacity 在 ie 浏览器中不支持 0-1 o 解决: opacity 的值照常设置,适应正常的浏览器 单独设置 ie 中透明属性: filter:alpha(opacity=value);取值范围 value: 1-100(整数)1 完全透明 100 不透明
28.三栏布局方式两边固定中间自适应
• 绝对定位法:将左右两边使用绝对定位,绝对定位使其脱离文档流,后面的 center 会自然流动到他们上面,然后使用 margin 属性,留出左右元素的宽度,就可以使 中间元素自适应屏幕宽度。 • 自身浮动法:对左右分别使用 float:left 和 float:right,浮动使左右两个元素脱离文 档流,中间元素正常在文档流中,使用 margin 指定左右外边距对其进行一个定 位。 • margin 负值法:左右两栏均左浮动,左右两栏采用负的 margin 值。中间栏被宽度 为 100%的浮动元素包起来。
29.Doctype作用
• 声明叫做文件类型定义(DTD),作用是为了告诉浏览器该文件的类型。让浏览器解析器 知道应该用哪个规范来解析文档。
30.怎么实现一个三角形
<!-- 向下的三角形 --> div { height: 0; border-top: 20px solid pink; border-right: 20px solid transparent; border-bottom: 20px solid transparent; border-left: 20px solid transparent; /*透明*/ width: 0; }
31.Rem怎么计算?
rem是通过根元素进行适配的,网页中的根元素指的是html,我们通过设置html的字体大小就可以控制rem的大小; 1rem*16(这个是html的fontsize)=16px;
32、如何实现响应式布局
方案一:百分比布局 利用对属性设置百分比来适配不同屏幕,注意这里的百分比是相对于父元素; 能够设置的属性有width,、height、padding、margin,其他属性比如border、 font-size不能用百分比来设置的 由于没办法对font-size进行百分比设置,所以用的最多就是对图片和大块布局进行百分比设置。 方案二:使用媒体查询 (CSS3@media 查询) 利用媒体查询设置不同分辨率下的css样式,来适配不同屏幕。 媒体查询相对于百分比布局,可以对布局进行更细致的调整,但需要在每个分辨率下面都写一套css样式。 该布局的话适用于简单的网页,可以使移动端和pc端使用一套网址。从而节约成本。也方便后期的维护,bootcss就是用了CSS3的media来实现响应的 但是相对于复杂的网页就不适合了(如:淘宝,京东)等等 方案三.rem 响应式布局 rem布局的原理 rem:相对于根元素(即html元素)font-size计算值的倍数。 如 html的font-size为100px;那么2rem就为200px。 通俗的来讲的话rem就是通过JavaScript来获取页面的宽度,从而动态的计算rem。这样就会使不同分辨率下展现出相同的效果。 方案四.vw 响应式布局 vm,vh相应式布局通俗来讲就是有一点类似百分比布局 将页面的宽和高分别分为100份 1vm就是为宽度的百分之一,同理1vh及为高度的百分之一。段手机端用的最多就是这个方法,能保持不同屏幕下元素显示效果一致,也不用写多套样式。 方案五.flex 弹性布局 flex就是利用css3中的弹性盒子向下兼容到IE10 利用flex属性来适配不同屏幕, 该方法一般都会结合rem布局来写移动端页面
二阶段
1、Js基本数据类型有哪些
Number , String , Boolean , null , undefined , Symbol , BigInt • 数值类型(number)包含数字 • 字符串类型(string)由单双引号包住的字符串内容会原样输出 • 布尔类型(boolean)只会输出 true , false • undefined 数值定义但未初始化 • null 空 • Symbol 表示独一无二的值(ES6 新增) • BigInt 是一种特殊的数字类型,它支持任意长度的整数。
2、Js怎么判断数据类型?
typeof instanceof
3、怎么判断数据类型是数组还是对象?
1、从原型入手,Array.prototype.isPrototypeOf(obj); 利用isPrototypeOf()方法,判定Array是不是在obj的原型链中,如果是,则返回true,否则false。 2、也可以从构造函数入手,obj instanceof Array 3、变量.constructor 返回数据的类型
4、Typeof与instanceof有什么区别?
1.typeof用来检测基本类型(string,number,boolean),所有的引用类型都返回object 2.instanceof用来检测引用类型,返回布尔值 3.*instanceof*拥有类型兼容性规则(实例化对象 instanceof 该类 == true/false) 判断某个实例化对象是否属于该类,返回布尔值;
5、CDN是什么?
CDN(Content delivery networks,内容分发网络),其目的是通过在源服务器和用户之间增加一层新的网络架构,将网站的内容分发到最接近用户的网络“边缘”,使用户可以就近取得所需的内容,提高用户访问网站的响应速度。我们的日常生活中,无论是在网站上看新闻,网上购物,观看视频,还是聊天,都和CDN息息相关。
6、Js性能优化?
1、合理使用闭包函数,滥用闭包会导致栈溢出从而降低程序运行效率 2 事件委托 ----需要为多个元素绑定相同事件时,可以通过给父元素绑定事件提高程序运行效率 3:注意作用域: 访问全局变量会比访问局部变量要慢 4:垃圾收集---数据或方法在合适的时间进行销毁操作,赋值为null 5、创建DOM节点时,使用innerHTML方式解析标签,因为该方式是通过html解析器解析标签而非JS引擎 6、getscript方法-----引入外部js资源,可以用一个事件触发在合适的时间引入
7、Ajax如何使用
btn.onclick = function(){ // 1. 实例化一个 XMLHttpRequest 对象 let http = new XMLHttpRequest(); // 2. 规划一个请求(三要素) // 2.1 请求方式 GET || POST // 2.2 请求地址 // 2.3 同步还是异步可选的参数,如果省略就是异步的请求 http.open("GET","http://10.35.170.103/data.php"); //带有一个请求参数的请求 http.open("GET",`http://10.35.170.103/data.php?age=${age.value}&sex=${sex.value}`); // 3. 真实的发送请求 http.send(); // 4. 接收来自服务器端的响应 http.onreadystatechange = function(){ //服务器端已将返回的内容交付给客户端手里了 if(http.readyState === 4){ console.log(http.responseText); }}} 创建 XMLHttpRequest 对象 浏览器使用 XMLHttpRequest 对象与服务器进行交互,获取数据。一般现在流行的浏览器均支持 XMLHttpRequest 对象(IE5 和 IE6 使用 ActiveXObject)。 语法: var xml=new XMLHttpRequest(); 老版本的 IE 浏览器的创建方式为:var xml=new ActiveXObject(“Microsoft.XMLHTTP”); var xml; if (window.XMLHttpRequest) { xml=new XMLHttpRequest(); }else{ xml=new ActiveXObject("Microsoft.XMLHTTP"); } 向服务器发送请求 get 方式提交使用 XMLHttpRequest 对象的 open()方法向服务器发送请求 语法: open(请求方式,请求地址(get 发送的数据拼接在 url 后面),true(异 步)) xml.open("get","index.json",true); xmlH.send();// get 请求 send 保持为空 post 方式提交 使用 XMLHttpRequest 对象的 open()与 send() 方法向服务器发 送请求 语法: open(请求方式,请求地址,true(异步)) send() xml.open("post","index.json",true); //如果想要使用 post 提交数据,必须添加此行 xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); 通过 send 方法传递 //将数据 xhr.send('name=fox&age=18'); onreadystatechange 事件 当向服务器发送请求时 redyState 的值发生改变时触发 onreadystatechange 事件。 readyState 存有 XMLHttpRequest 的状态。从 0 到 4 发生变化。 0: 未初始化(uninitialized) 1: 正在加载(loading)----调用open方法 2: 加载完毕(load)----调用send方法 3: 交互过程(interactive)----到达服务端了 4: 完成(complete)-----服务端处理完成了 status 有两种数值,分别表示: 200: “OK” 404: 未找到页面 xml.onreadystatechange(function(){ if(xmlHttp.readyState==4&&xmlHttp.status==200){ console.log(xhr.responseText); }} 优点: 1.最大的优点就是页面无需刷新,在页面内与服务器通信,非常好的用户体验。 2.使用异步的方式与服务器通信,不需要中断操作。 3.可以把以前服务器负担的工作转嫁给客户端,减轻服务器和带宽,可以最大程度减少冗余请求。 4.基于标准化的并被广泛支持的技术,不需要下载插件或者小程序。 缺点: 1.AJAX干掉了Back和History功能,即对浏览器机制的破坏。 在动态更新页面的情况下,用户无法回到前一个页面状态,因为浏览器仅能记忆历史记录中的静态页面。一个被完整读入的页面与一个已经被动态修改过的页面之间的差别非常微妙;用户通常会希望单击后退按钮能够取消他们的前一次操作,但是在Ajax应用程序中,这将无法实现。 2.安全问题技术同时也对IT企业带来了新的安全威胁,ajax技术就如同对企业数据建立了一个直接通道。这使得开发者在不经意间会暴露比以前更多的数据和服务器逻辑。ajax的逻辑可以对客户端的安全扫描技术隐藏起来,允许黑客从远端服务器上建立新的攻击。还有ajax也难以避免一些已知的安全弱点,诸如跨站点脚步攻击、SQL注入攻击和基于credentials的安全漏洞等。 3.对搜索引擎的支持比较弱。如果使用不当,AJAX会增大网络数据的流量,从而降低整个系统的性能。 应用场景: 场景 1. 数据验证 场景 2. 按需取数据 场景 3. 自动更新页面
8、如何判断一个数据是NaN
NaN 不是一个数字但数据类型为 number,而且不等于自身 可直接采用内置方法 isNaN function isNaN(n) { if (n !== n) { return true; } else { return false; }} 利用 NaN 是唯一一个不等于任何自身的特点 var a=NaN; a==a; //false object.is 方法 console.log(Object.is("a", NaN)); console.log(Object.is(1, NaN)); console.log(Object.is(NaN, NaN));
9、Js中null与undefined区别
相同点: if 判断语句中,两者都会被转换为 false 不同点: Number 转换的值不同,Number(null)输出为 0, Number(undefined) 输出为NaN null 表示一个值被定义了,但是这个值是空值 undefined 表示缺少值,即此处应该有值,但是还没有定义
10、什么是冒泡什么是捕获怎么实现
捕获(capture)和冒泡(bubble)是事件传播过程中的两个概念 在事件捕获阶段, 事件从最顶级的父元素逐层向内传递, 在冒泡阶段, 事件从事件发生的直接元素 , 逐层向父元素传递
11、闭包是什么有什么特性,对页面会有什么影响
简单来说闭包就是一个容器,储存着一些以键值对方式存在的数据,而从语法结构上看,闭包就是函数嵌套函数,被嵌套的函数就是闭包函数 • 闭包可以简单理解成“定义在一个函数内部的函数“。当其中一个内部函数在包含它们 的外部函数之外被调用时,就会形成闭包。 let fn = (function(){ //局部变量 var count = 0; return function(){ return ++count; }})() • 本质:外层函数嵌套一个内层函数,内层函数作为外层函数的 return 语句的返回 值。外层函数是自调用函数,并且将自身的返回值(也就是内层函数本身)赋给一 个变量。在 JS 执行环境上下文中调用该变量就等价于调用了内层函数,并且在内层 函数中可以访问到外层函数的局部变量又并且外层函数的局部变量不会被多次声 明,此时就形成了一种闭包的写法。 • 特点: o 函数嵌套函数。 o 函数内部可以引用外部的参数和变量。 o 参数和变量不会被垃圾回收机制回收。 • 用处: o 常驻内存会增大内存的使用量; o 读取函数内部的变量; o 这些变量的值始终保持在内存中,不会在外层函数调用后被自动清除。 • 优点: o 变量长期驻扎在内存中; o 避免全局变量的污染; o 私有成员的存在; • 缺点:会造成内存泄露 应用场景: 1、Ajax 异步请求的时候 2、类的设计----工厂模式 3、定时器 4、节流 5、防抖 函数嵌套层级多的时候使用 promise,优点在于,回调函数变成了链式写法,程序的 流程可以看得很清楚,而且有一整套的配套方法,可以实现许多强大的功能。
12、简述下async与await
async(额森可)用于申明一个function是异步的;而await则可以认为是 async await的简写形式,是等待一个异步方法执行完成的。 • async 用于声明一个 function 是异步的,而 await 用于等待一个异步方法执行完成, async 返回的是一个 Promise 对象。 • async 的主要作用是回调地狱的处理看起来比 promise 更美观,而且使用 async 来传参的时候比较方便。 • async 函数必须要等到方法体中所有的 await 声明 Promise 函数执行完后, async函数才会得到一个 resolve 状态的 Promise 对象。 • async/await 在遇到异步请求的情况下,能让代码以看似同步的方式来解决异步回调
13、如何便利对象?
1、使用Object.keys()遍历 2、使用for..in..遍历 3.Object.getOwnPropertyNames(obj),返回一个数组,包含对象自身的所有属性(不含Symbol属性,但是包括不可枚举属性). 4.Object.getOwnPropertySymbols(obj),返回一个数组,包含对象自身的所有Symbol属性. 5.Reflect.ownKeys(obj),返回一个数组,包含对象自身的所有属性,不管属性名是Symbol或字符串,也不管是否可枚举. 6.Reflect.enumerate(obj),返回一个Iterator对象,遍历对象自身的和继承的所有可枚举属性(不含Symbol属性),与for ... in 循环相同.
14、事件委托是什么?如何确定事件源
• 事件委托还有一个名字叫事件代理, JS 高程上讲:事件委托就是利用事件冒泡,只制定一个时间处理程序,就可以管理某一类型的所有事件。 • 将子元素的事情委托给它们的祖先级元素来干,然后使用 event.target(低版本 IE 用的是 event.srcElement)来代替已经混乱 this 关键字 o 解决动态元素(刚进入页面时,元素不在页面内)无法绑定事件问题 o 在极端情况下可以提升客户端性能
15、本地存储与cookie的区别
• Cookie 是小甜饼的意思。顾名思义, cookie 确实非常小,它的大小限制为 4KB 左 右。它的主要用途有保存登录信息,比如你登录某个网站市场可以看到“记住密码”, 这通常就是通过在 Cookie 中存入一段辨别用户身份的数据来实现的。 • localStorage 是 HTML5 标准中新加入的技术,它并不是什么划时代的新东西。早在 IE 6 时代,就有一个叫 userData 的东西用于本地存储, 而当时考虑到浏览器兼容 性,更通用的方案是使用 Flash。而如今, localStorage 被大多数浏览器所支持,如 果你的网站需要支持 IE6+,那以 userData 作为你方案是种不错的选择。 • sessionStorage 与 localStorage 的接口类似,但保存数据的生命周期与 localStorage 不同。做过后端开发的同学应该知道 Session 这个词的意思,直译过来 是“会话”。而 sessionStorage 是一个前端的概念,它只是可以将一部分数据在当前 会话中保存下来,刷新页面数据依旧存在。但当页面关闭后, sessionStorage 中的数 据就会被清空。 • cookie:兼容性很好,可以灵活的设置数据的生命周期,缺点是操作不方便,需要大 量的字符串处理 • localStorage: IE67 不认识,永久性存储,只要用户不删除或调用 clear 方法就永远 不会删,操作很方便 • sessionStorage:兼容性与 localStorage 一样,但是存储时间是会话(在当前标签页 无论跳转到该网站的哪一个页面都能获取到,但关闭浏览器就会销毁,并且在其他 标签页面中是获取不到的) 三者的异同
特 性 | Cookie | localStorage | sessionStorage |
---|---|---|---|
数 据 的 生 命 | 一般由服务器生成,可 设置失效时间。如果在 浏览器端生成 Cookie, 默认是关闭浏览器后失 效 | 除非被清除,否则永久 保存 | 仅在当前会话下有效, 关闭页面或浏览器后被 清除 |
存 放 数 据 大 小 | 4K 左右 | 一般为 5MB | 同左 |
与 服 务 器 端 通 信 | 每次都会携带在 HTTP 头中,如果使用 cookie 保存过多数据会带来性 能问题 | 仅在客户端(即浏览 器)中保存,不参与和 服务器的通信 | 同左 |
易 用 性 | 需要程序员自己封装, 源生的 Cookie 接口不 友好 | 源生接口可以接受,亦 可 再 次 封 装 来 对 Object 和 Array 有更 好的支持 | 同左 |
16、简述下浏览器缓存?
缓存读取原理:先从内存中查找相应得缓存,若有则读取,否则从硬盘中查找,若有则读取,反之重新网络请求。 一,作用 1,减少冗余得数据传输,节省了网络带宽。从而更快得加载页面; 2,降低了服务器得要求,从而服务器更快得响应。 二 ,资源文件缓存得位置(分为两个地方) 1,内存中(memory cache)退出进程数据被清除,读取速度比硬盘快,内存有限,一般存储脚本,字体,图片 2,硬盘中(disk cache)退出进程数据不会被清除 非脚本存储,如css; 三,两种缓存方式(强制缓存和协商缓存) 1,强制缓存:浏览器在加载资源的时候,会先根据本地缓存资源的header中的信息(Expires 和 Cache-Control)来判断是否需要强制缓存。 如果命中的话,则会直接使用缓存中的资源。否则的话,会继续向服务器发送请求。 2,协商缓存:客户端向服务器端发出请求,服务端会检测是否有对应的标识,如果没有对应的识,服务器端会返回一个对应的标识给客户端, 客户端下次再次请求的时候, 把该标识带过去,然后服务器端会验证该标识,如果验证通过了,则会响应304,告诉浏览器读取缓存。如果标识没有通过,则返回请求的资源
简单来说,浏览器缓存就是把一个已经请求过的Web资源(如html页面,图片,js,数据等)拷贝一份副本储存在浏览器中。缓存会根据进来的请求保存输出内容的副本。当下一个请求来到的时候,如果是相同的URL,缓存会根据缓存机制决定是直接使用副本响应访问请求,还是向源服务器再次发送请求。比较常见的就是浏览器会缓存访问过网站的网页,当再次访问这个URL地址的时候,如果网页没有更新,就不会再次下载网页,而是直接使用本地缓存的网页。只有当网站明确标识资源已经更新,浏览器才会再次下载网页。 为什么使用缓存: (1)减少网络带宽消耗 无论对于网站运营者或者用户,带宽都代表着金钱,过多的带宽消耗,只会便宜了网络运营商。当Web缓存副本被使用时,只会产生极小的网络流量,可以有效的降低运营成本。 (2)降低服务器压力 给网络资源设定有效期之后,用户可以重复使用本地的缓存,减少对源服务器的请求,间接降低服务器的压力。同时,搜索引擎的爬虫机器人也能根据过期机制降低爬取的频率,也能有效降低服务器的压力。 (3)减少网络延迟,加快页面打开速度 带宽对于个人网站运营者来说是十分重要,而对于大型的互联网公司来说,可能有时因为钱多而真的不在乎。那Web缓存还有作用吗?答案是肯定的,对于最终用户,缓存的使用能够明显加快页面打开速度,达到更好的体验。
17、ES6新特性
const 和 let 模板字符串 箭头函数 函数的参数默认值 对象和数组解构 for...of 和 for...in ES6 中的类 map()映射 set()集合
18、for...of 和 for...in有什么区别
for...of 遍历元素 for...in 遍历下标 1–for … of遍历获取的是对象的键值,for … in 获取的是对象的键名 2–for … in会遍历对象的整个原型链,性能非常差不推荐使用,而for … of只遍历当前对象不会遍历原型链 3–对于数组的遍历,for … in会返回数组中所有可枚举的属性(包括原型链上可枚举的属性),for … of只返回数组的下标对应的属性值
19、Let与var与const的区别
var 声明的变量会挂载在 window 上,而 let 和 const 声明的变量不会; var 声明变量存在变量提升, let 和 const 不存在变量提升; let 和 const 声明变量都没有函数作用域的概念,而是遵守块级作用域的概念; 同一作用域下 let 和 const 不能声明同名变量,而 var 可以; let 有暂存死区(在声明之前就使用变量,就会报错,这就是暂时性死区) let 和 const 关键字: let 和 const 声明变量都没有函数作用域的概念,而是遵守块级作用域的概念,并且没有变量提升的操作,不能重复声明。 const 是声明常量的 let, let 有暂时性死区的特性。
20、数组方法有哪些请简述
• push(新值) 向数组的尾端插入一个新的元素 • unshift(新值) 向数组的前端插入一个新的元素 • pop() 删掉数组中最后一个元素 • shift() 删掉数组中第一个元素 • splice(删除的下标,1) 从某一个下标上删除一个元素,有副作用 • splice(要插入的下标,0,要插入的数据) 从中间插入一个元素 • concat() 拼接数组,返回值为合并成的新数组,原数组不会改变 • join() 将数组转换为字符串,参数为分隔符,原数组不会改变 • reverse() 颠倒数组中元素的顺序,会改变原数组 • slice(start,end) 通过开始下标和结束下标截取数组元素,原数组不会发生改变 • toString() 将数组转换为字符串可以被 join 完美代替 • sort() 通过 Unicode 进行排序,在原数组上排序,不生成副本 var arr = [1, 5, 6, 1, 3, 4, 11, 2, 5] //排序固定写法升序 arr.sort(function(num1, num2) { return num1 - num2;}) console.log(arr); //排序固定写法降序 arr.sort(function(num1, num2) { return num2 - num1;}) console.log(arr); • arr.forEach(callback) 遍历数组,无 return 即使有 return,也不会返回任何值,并且会 影响原来的数组 • arr.map(callback) 映射数组(遍历数组),有 return 返回一个新数组。 • arr.filter(callback) 过滤数组,返回一个满足要求的数组
some()
some() 方法用于检测数组中的元素是否满足指定条件(函数提供)。
some() 方法会依次执行数组的每个元素:
-
如果有一个元素满足条件,则表达式返回true , 剩余的元素不会再执行检测。
-
如果没有满足条件的元素,则返回false。
注意: some() 不会对空数组进行检测。
注意: some() 不会改变原始数组
every
every() 方法用于检测数组所有元素是否都符合指定条件(通过函数提供)。
every() 方法使用指定函数检测数组中的所有元素:
-
如果数组中检测到有一个元素不满足,则整个表达式返回 false ,且剩余的元素不会再进行检测。
-
如果所有元素都满足条件,则返回 true。
注意: every() 不会对空数组进行检测。
注意: every() 不会改变原始数组。
21、数组怎么转换字符串?
数组方法 | 说明 |
---|---|
toString() | 将数组转换成一个字符串 |
toLocalString() | 把数组转换成本地约定的字符串 |
join() | 将数组元素连接起来以构建一个字符串 |
22、数组哪些方法会改变原始数据?
会改变原来数组的有: pop()---删除数组的最后一个元素并返回删除的元素。 push()---向数组的末尾添加一个或更多元素,并返回新的长度。 shift()---删除并返回数组的第一个元素。 unshift()---向数组的开头添加一个或更多元素,并返回新的长度。 reverse()---反转数组的元素顺序。 sort()---对数组的元素进行排序。 splice()---用于插入、删除或替换数组的元素。
23、数组哪些方法不会改变原始数据?
不会改变原来数组的有: concat()---连接两个或更多的数组,并返回结果。 filter()---检测数组元素,并返回符合条件所有元素的数组。 join()---把数组的所有元素放入一个字符串。 toString()---把数组转换为字符串,并返回结果。 lastIndexOf()---返回一个指定的字符串值最后出现的位置,在一个字符串中的指定位置从后向前搜索。 map()---通过指定函数处理数组的每个元素,并返回处理后的数组。 slice()---选取数组的的一部分,并返回一个新数组。 valueOf()---返回数组对象的原始值。 every()---检测数组元素的每个元素是否都符合条件。 some()---检测数组元素中是否有元素符合指定条件。 indexOf()---搜索数组中的元素,并返回它所在的位置。
24、数组filter与map与forEach区别?
方法 | 区别 | 语法 | 作用 | 返回值 | 是否改变原数组 |
---|---|---|---|---|---|
forEach | 遍历数组,无 return 即使有 return,也不会返回任何值,并且会影响原来的数组 | 数组.forEach(function (item, index, arr) {}) | 过滤原始数组中的数据,把满足条件的放在新数组里面 | 没有返回值 | 不改变原始数组 |
map | 映射数组(遍历数组),有 return 返回一个新数组 | 数组.map(function (item, index, arr) {}) | 定义在JavaScript的Array中,它返回一个新的数组,数组中的元素为原始数组调用函数处理后的值。 | 是一个新的数组 ,里面是对原始数组每一个数据的操作, 返回值数组,一定和原始数组长度一样 | 不改变原始数组 |
filter | 过滤数组,返回一个满足要求的数组 | 数组.filter(function (item, index, arr) {}) | 它是由原数组每一项调用一个过滤函数,由过滤函数返回的true或者false来决定该项是否可以到一个新的数组里面,同样它也是返回一个新的数组。 | 是一个新的数组,里面是所有原始数组中满足条件的项 | 不改变原始数组 |
25、字符串怎么转成数组?
1、split() 方法 2、展开运算符 ( ...) 允许在需要多个元素(如数组文字)的地方扩展诸如字符串之类的可迭代对象。 3、解构赋值:解构赋值语法可以将数组或可迭代对象中的值解包为不同的变量。 4、Array.from辅助创建从阵列状或迭代的对象的新数组。字符串既可迭代又类似于数组,因此,可以成功地将其转换为字符数组。
26、Json如何新增/删除键值对
• JSON 是什么: JSON (JavaScript Object Notation, JS 对象标记) 是一种轻量级的数 据交换格式。 • JSON 规则: 1.必须是字符 2.基础格式参考 js 中的对象(array 和 object) 3.对象格式的 key 部分必须放在双引号中,单引号不行 4.不允许出现没有意义的逗号 5.不能出现 undefined、 NaN,可以出现 null 6.不能出现单引号 • 字符串转 JSON(正解析): Var obj = JSON.parse(JSON 格式的字符串) • JSON 转字符串(反解析): Var str = JSON.stringify(对象) • 删除: delete json 对象["属性名"]; • 增加: json 对象["属性名"]=属性值例如: myObject[age]=10;//即可添加上 age 属 性
27、什么是面向对象请简述
• 面向对象就是将问题抽象成若干 object 对象,然后去对这些对象编程,将对象的属 性和操作封装到类中,让它们具有一定的功能。具有抽象性、封装性、继承性、多 态性的特点。 • 类是对象的抽象,对象是类的实例化 • 面向对象是把构成问题的的事物分解成各个对象,建立对象不是为了完成一个步 骤,而是为了描述某个事物在整个解决问题的过程中的行为。 • 优点:易维护、复用、扩展 • 缺点:性能低:因为在创建类的实例需要很大的开销。
28、普通函数和构造函数的区别
• 返回值类型的区别: 构造函数是没有返回值类型的 普通函数是有返回值类型的,即使函数没有返回值,返回值类型也要写上void。 • 函数名的区别: 构造函数的函数名必须要与类名一致,习惯首字母大写 普通函数的函数名只要符合标识符的命名规则即可。 • 调用方式的区别: 构造函数是在创建对象的时候由 new 关键字调用的 普通函数是由我们使用对象调用的,一个对象可以调用多次普通函数 • 作用上的区别: 构造函数用于初始化一个对象。 普通函数是用于描述一类事物的公共行为。
29、请简述原型/原型链/继承
事实上,js里完全依靠"原型链"(prototype chain)模式来实现继承。 __proto__:事实上就是原型链指针!! prototype:是指向原型对象的 ; 同时原型对象上也有一个__proto__属性; constructor:每一个原型对象都包含一个指向构造函数的指针,就是constructor 每个构造函数都拥有一个 prototype 属性,它指向构造函数的原型对象,这个原型对象中有一个 construtor 属性指回构造函数; 原型: 每个实例对象都有一个__proto__属性,当我们使用构造函数去创建实例时,实例的__proto__属性就会指向对应构造函数的原型对象。 原型链: 为了实现继承,__proto__属性会指向上一层的原型对象,而上一层的结构依然类似,那么就利用__proto__一直指向Object的原型对象上! Object.prototype.__proto__ = null;表示到达最顶端。如此形成了原型链继承。 继承:继承就是在子类构造函数中继承父类构造函数的私有属性和原型属性。我们 在子类构造函数中使用 call 或 apply 方法调用父类构造函数并改变其 this 指向为 子类构造函数的 this,此时子类的构造函数就继承了父类的私有属性和私有方法。 将父类的实例化对象赋值给子类的原型对象,此时子类就继承了父类的原型属性和 原型方法。
30、Promise的理解
a,什么是promise: 简单说是一个容器,里面保存着某个未来才会结束的事件的结果(通常是一个异步操作),从语法上说,promise是一个对象,从它可以获取异步操作的消息,promise提供了统一的API,各种异步操作都可以用同样的方法进行处理。 b,promise的作用: 将函数嵌套调用改为平级调用,增加代码可阅读性,避免了回调地狱 c,promise对象的特点 (1)对象的状态不受外界影响,promise对象代表一个异步操作,有三种状态,pending(进行中)、resolve(已成功)、rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态,这也是promise这个名字的由来“承若”; (2)一旦状态改变就不会再变,任何时候都可以得到这个结果,promise对象的状态改变,只有两种可能:从pending变为fulfilled,从pending变为rejected。这时就称为resolved(已定型)。如果改变已经发生了,你再对promise对象添加回调函数,也会立即得到这个结果,这与事件(event)完全不同,事件的特点是:如果你错过了它,再去监听是得不到结果的。 有了Promise对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。此外,Promise对象提供统一的接口,使得控制异步操作更加容易。 d,Promise也有一些缺点。 a,无法取消Promise,一旦新建它就会立即执行,无法中途取消。 b,如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。 c,当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。 Promise 是一个对象,它的内部其实有三种状态。 初始状态( pending )。 成功( resolve):resolve 方法可以使 Promise 对象的状态改变成成功 失败( reject ):reject 方法则是将 Promise 对象的状态改变为失败
31、Promise在哪里使用过
• Ajax 异步请求的时候 • 函数嵌套层级多的时候使用 promise,优点在于,回调函数变成了链式写法,程序的流程可以看得很清楚,而且有一整套的配套方法,可以实现许多强大的功能。
32、Promise.all与promise.race是什么
Promise.all和Promise.race都是有使用场景的。 有些时候我们做一个操作可能得同时需要不同的接口返回的数据,这时我们就可以使用Promise.all; 有时我们比如说有好几个服务器的好几个接口都提供同样的服务,我们不知道哪个接口更快,就可以使用Promise.race,哪个接口的数据先回来我们就用哪个接口的数据。
33、Promise怎么一直点then
34、浏览器内核有哪些?
1、Trident(揣登特) 元老级内核之一,由微软开发,并于1997年10月首次在ie 4.0中使用,凭借其windows垄断优势,Trident市场占有率一直很高。然而垄断并非,没有竞争就没有进步,长期以往,Trident内核一度停滞不前,更新缓慢,甚至一度与W3C标准脱节。2011年,从ie 9开始,Trident开始支持HTML5和CSS 3,因此我们也经常会看到有些网站在浏览时会提示用户(在Internet Explorer 9.0+以上浏览效果最佳)。前端程序员做浏览器兼容一般也不再会考虑ie 8之前的浏览器了。 由于该内核由微软开发出来供ie使用,因此这款内核一般也被称为“ie内核”。ie内核提供了开放的接口,可以供其他浏览器去包装该内核开发出自己的一套浏览器,如同包装Android原生系统开发出MIUI。国内很多浏览器厂商期初就是包装ie内核,如360安全浏览器,360极速浏览器,百度浏览器,猎豹浏览器等,后面经过不断地发展有的内核发生了变化,这个后面会提到。 2、Gecko(盖狗) 元老级内核之一,由Netscape公司Mozilla组织开发。1998年,Netscape在于IE浏览器竞争失利之后,成立了非正式组织Mozilla,由其开发新一代内核,后命名为“Gecko”。FireFox也是这班人开发出来了,因此这也就是FireFox一直使用的内核。 3、WebKit 这是苹果公司开发的内核,也是其旗下产品Ssfari浏览器使用的内核。Webkit引擎包含了WebCode排版引擎和JavaScriptCode解析引擎,分别是从KDE的KHTML和KJS衍生而来,它们都是自由软件,在GPL条约下授权,同时支持BSD系统开发。 Chrome、360极速浏览器以及搜狗高速浏览器也使用Webkit作为内核(在脚本理解方面,Chorome使用自己研发的V8引擎)。 4、Blink 这是由Google和Opera Software开发的浏览器排版引擎,Google计算将这个渲染引擎作为Chromium计划的一部分,并且在2013年4月公布了这一消息。这一渲染引擎是开源引擎Webkit中WebCore组件的一个分支,并且在Chrome(28及往后版本)、Opera(15及往后版本)和Yandex浏览器中使用。
35、请简述async的用法
• async 用于声明一个 function 是异步的,而 await 用于等待一个异步方法执行完成, async 返回的是一个 Promise 对象。 • async 的主要作用是回调地狱的处理看起来比 promise 更美观,而且使用 async 来传参的时候比较方便。 • async 函数必须要等到方法体中所有的 await 声明 Promise 函数执行完后, async函数才会得到一个 resolve 状态的 Promise 对象。 • async/await 在遇到异步请求的情况下,能让代码以看似同步的方式来解决异步回调 • 使用步骤: o 定义一个需要进行异步等待的方法,并在方法前加"async"关键字 o 在这个内部有异步请求的方法中用 await 等待相应的请求完成。 o 在这个异步请求的方法中返回一个 Promise 对象,并封装 resolve 和 reject 方法
36、jQuery相关的知识
• jQuery:类库(工具箱):宗旨是 write less do more,功能: DOM 操作, DOM 获取,动画,数据交互(ajax),链式调用 • jQuery 对象到底是啥? 是一个类数组。所有数组成员都是原生 JS 节点。 jQuery和原生 js 节点的属性和方法互不通用。是一个兼容多浏览器的 javascript 库(函数库),核心理念是 write less,do more(写的更少,做的更多)。 • 特点:是一个快速的简洁的 javascript 框架,可以简化查询 DOM 对象、处理时间、制作动画、处理 Ajax 交互过程 o 提供了强大的功能函数 o 解决浏览器兼容性问题 o 纠正错误的脚本知识 o 体积小,使用灵巧(只需引入一个 js 文件) o 易扩展、插件丰富 • 作用: o 程序员角度:简化 Javascript 和 Ajax 编程,能够使程序员从设计和书写繁杂的JS 应用中解脱出来,将关注点转向功能需求而非实现细节上,从而提高项目的 开发速度。 o 用户体验角度:改善了页面视觉效果,增强了与页面的交互性,体验更绚丽的网 页物资方便地选择页面元素(模仿 CSS 选择器更精确、灵活) 动态更改页面样式/页面内容(操作 DOM,动态添加、移除样式) 控制响应事件(动态添加响应事件) 提供基本网页特效(提供已封装的网页特效方法) 快速实现通信(ajax)。 o jQuery 获取方式: jQuery 库文件不需要安装,只需使用 <script>标签引入HTML 文件中,拿到 jQuery 的库文件后,就跟自己写的 JS 文件同样的引入方式 1.引入本地的 jQuery 2.引入 cdn 在线提供的库文件(稳定可靠高速)
37、Css预处理sass less是什么?为什么使用他们
• 首先 Sass 和 Less 都是 CSS 预处理器,是 CSS 上的一种抽象层,是一种特殊的语法/语言最终会编译成 CSS。 less 是一种动态样式语言,将 CSS 赋予了动态语言的特性,如变量,继承,运算,函数。 less 既可以在客户端上运行 (支持 IE 6+,Webkit, Firefox) 也可以在服务端运行(需要借助 Node.js)。 • 为什么使用: o 结构清晰,便于扩展 o 可以方便地屏蔽浏览器私有语法差异 o 减少无意义的机械劳动 - 可以轻松实现多重继承 o 完全兼容 CSS 代码,可以方便地应用到老项目中
38、Js中.call()与.apply()与bind()区别
1.他们都是改变this指向的函数对象的方法 2.bind()通常针对匿名函数,apply()和call()针对有名函数 3.call()和apply()的参数不同,apply()需要用数组包裹改变this指向的函数的参数 4.call()和apply()直接调用该函数,而bind()只是生成一个新的函数对象,不会调用该函数
39、为什么会造成跨域/请简述同源策略
• 造成跨域的原因: 因为浏览器的同源政策,协议、端口和域名有任意一个不同就会造成跨域。 比如说发送的异步请求是不同的两个源,就比如是不同的的两个端口或者不同的两个协议或者不同的域名。 • 同源策略: 同源策略就是浏览器保护浏览器安全的一种机制,它不允许客户端请求从 A 服务器请求过来的页面往 B 服务器去发送 Ajax 请求。两个页面地址中的协议、域名和端口号一致,则表示同源。 • 同源策略的数据 o 存储在浏览器中的数据,如 localStroage、 Cookie 和 IndexedDB 不能通过脚本跨域访问 o 不能通过脚本操作不同域下的 DOM o 不能通过 ajax 请求不同域的数据
40、This指向是哪里?怎么修改?
• 出现在一般函数中或者是全局作用域下, this 指向的 window 对象 a.当this出现在普通方法时,this代表调用当前方法的对象本身。 b.当this出现在事件中时,this代表触发当前事件的HTML元素本身。 c.当this与构造方法连用时,this代表 new 出来的对象 d.当this出现在箭头函数中时,this指向它的父级
41、请输出三种减少页面加载时间的方式
• 优化图片 • 图像格式的选择(GIF:提供的颜色较少,可用在一些对颜色要求不高的地方) • 优化 CSS(压缩合并 css,如 margin-top,margin-left...)34 • 网址后加斜杠(如 www.campr.com/目录,会判断这个“目录是什么文件类型,或者是目录。) • 标明高度和宽度(如果浏览器没有找到这两个参数,它需要一边下载图片一边计算大小,如果图片很多,浏览器需要不断地调整页面。这不但影响速度,也影响浏览体验。当浏览器知道了高度和宽度参数后,即使图片暂时无法显示,页面上也会腾出图片的空位,然后继续加载后面的内容。从而加载时间快了,浏览体验也更好了。) • 减少 http 请求(合并文件,合并图片)。
42、什么是jsonp工作原理是什么?他为什么不是真正的ajax
• JSONP:是一种解决跨域限制问题的一种方式 • 工作原理:前端使用一个 script 标签来创建一个 HTTP 请求,并且事先声明一个回调函数,该回调函数的名字由 callback 参数的参数值发送给后端。后端接收到来自前端的请求后利用 callback 参数的参数值和要给前端返回的数据拼接成一段 JS 执行函数的代码段,此时实参就是要返回给前端的数据。前端接收到后端返回的结果后,会自动的执行事先声明好的回调函数,此时函数的形参就代表了后端要返回的数据。 • 为什么不是真正的 ajax: JSONP(JSON with padding)可用于解决主浏览器的跨域数据访问的问题,与 JSON 没有关系,只是一种跨域访问的技巧。 ajax 的核心是通过 xmlHttpRequest 获取非本页内容, jsonp 的核心是动态添加 script 标签调用服务器提供的 js 脚本; jsonp 只支持 get 请求, ajax 支持 get 和 post 请求。
43、请掌握2种以上数组去重的方式
• 穷举法: function norepeat(arr){ var result=[]; //新数组 for(var i=0;i<arr.length;i++) { var isRepeat=false; //没有重复 for (var j=0;j<=result.length;j++){ if(arr[i]===result[j]){ isRepeat=true; }} • 数组下标判断法 var arr = [2,5,8,2,8,6,4] var newArr = []; for(var i=0;i<arr.length;i++){ if(arr.indexOf(arr[i]) === i){ newArr.push(arr[i]) } } Console.log(newArr) let arr = Array.from(new Set(arr)); • 利用 SET 数据结构(set 数据结构不允许有重复数据)
44、什么是栈 什么是堆?
栈(stack):栈会自动分配内存空间,会自动释放,存放基本类型,简单的数据段,占据固定大小的空间。 基本类型:String,Number,Boolean,Null,Undefined 堆(heap):动态分配的内存,大小不定也不会自动释放,存放引用类型,指那些可能由多个值构成的对象,保存在堆内存中,包含引用类型的变量,实际上保存的不是变量本身,而是指向该对象的指针 引用类型:Function,Array,Object
45、深浅拷贝是什么如何实现?
• 浅拷贝是什么:只拷贝引用地址,但是并未开辟空间 拷贝就是增加了一个指针指向已存在的内存(JavaScript 并没有指针的概念,这里只 是用于辅助说明),浅拷贝只是拷贝了内存地址,子类的属性指向的是父类属性的内 存地址,当子类的属性修改后,父类的属性也随之被修改。 • 深拷贝是什么:开辟空间且赋值 深拷贝就是增加一个指针,并申请一个新的内存,并且让这个新增加 的指针指向这个新的内存地址使用深拷贝,在释放内存的时候就不会像浅拷贝一样出 现释放同一段内存的错误,当我们需要复制原对象但又不能修改原对象的时候,深拷 贝就是一个,也是唯一的选择 。 • 如何实现:重新创建一个数组空间,将另一个空间中的元素循环复制到新空间中,这 实际是两个独立的空间,对一个空间中的元素进行操作,另一个空间中的元素不会受 到影响。 • 浅拷贝:通过展开运算符...来实现浅拷贝 let a ={age: 1 } let b = { ...a } a.age = 2 console.log(b.age) • 深拷贝 1. 可以通过 JSON.parse(JSON.stringify(object))来解决。 let a = { age: 1, } jobs: { first: 'FE' } let b = JSON.parse(JSON.stringify(a)) 2. 如果你所需拷贝的对象含有内置类型并且不包含函数,可以使用 MessageChannel function structuralClone(obj) { return new Promise(resolve => { const { port1, port2 } = new MessageChannel() port2.onmessage = ev => resolve(ev.data) port1.postMessage(obj) }) } var obj = { a: 1, b: { c: 2 } obj.b.d = obj.b // 注意该方法是异步的 // 可以处理 undefined 和循环引用对象 const test = async () => { const clone = await structuralClone(obj) console.log(clone) } test() 3. 使用 lodash 的深拷贝函数 function deepClone(obj) { function isObject(o) { return (typeof o === 'object' || typeof o === 'function') && o !== null36 } if (!isObject(obj)) { throw new Error('非对象') } let isArray = Array.isArray(obj) let newObj = isArray ? [...obj] : { ...obj } Reflect.ownKeys(newObj).forEach(key => { newObj[key] = isObject(obj[key]) ? deepClone(obj[key]) : obj[key] }) return newObj } let obj = { a: [1, 2, 3], b: { c: 2, d: 3 }} let newObj = deepClone(obj) newObj.b.c = 1 console.log(obj.b.c) // 2
46、为什么js是弱类型语言
弱类型语言是相对强类型语言来说的,在强类型语言中,变量类型有多种,例如 intchar float boolean 等,不同的类型相互转换有时需要强制转换,而 javascript 只有一种类型 var ,为变量赋值时会自动判断类型并进行转换,所以 javascript 是弱语言,就体现在变量定义类型 VAR 上了
47、怎么转换less为css
• 首先,你要确认你的电脑已经安装了 node。使用 npm 安装 lessc,命令行:npm install-gless • 然后,进入需要转换的 less 文件的目标位置。 • 最后,你只需输入以下两条命令: npm install -g less;lessc less 文件名.less 生成的 css 文件名.css
48、echarts使用最多的是什么
• Echarts 使用最多的一般是:有着丰富的可视化类型,可以实现多种数据格式无需转换直接使用,可以实现千万数据的前端展现,一般使用在大数据可视化平台。 • Echaets 是什么: ECharts 是百度开发的一个国内比较常用的网页图表工具,也算是它旗下不可多得的优秀工具之一。如果你看过其它的 js 图表工具就可以知道这玩意的强大之处了,相比其它 xxChart, ECharts 提供了基本上最完善的图表类型模板, api 接口和配置项,其次,它用起来比较方便,现成的模板非常易于使用,如果不需要一些高级特性,那么只需要一点前端知识就能完成数据的可视化。 • (ECharts(4.0)特性: 1、 丰富的可视化类型提供了常规的图,盒形图,用于地理数据可视化的图,用于关系数据可视化的图,多维数据可视化的平行坐标,并且支持图与图之间的混搭 多种数据格式无需转换直接使用 ECharts 内置的 dataset 属性(4.0+)通过简单的设置 encode 属性就可以完成从数据到图形的映射。37 2、 千万数据的前端展现 ECharts 同时提供了对流加载(4.0+)的支持,可以使用 WebSocket 或者对数据分块后加载,不需要漫长地等待所有数据加载完再进行绘制 移动端优化 例如移动端小屏上适于用手指在坐标系中进行缩放、平移。 PC 端也可以用鼠标在图中进行缩放(用鼠标滚轮)、平移等。 3、 多渲染方案,跨平台使用 不同的渲染方式提供了更多选择,使得 ECharts在各种场景下都有更好的表 现。 深度的交互式数据探索提供了图例、视觉映射、数据区域缩放、 tooltip、数据刷选等开箱即用的交互组件,可以对数据进行多维度数据筛取、视图缩放、展示细节等交互操作 4、 多维数据的支持以及丰富的视觉编码手段 ECharts 3 开始加强了对多维数据的支持。除了加入了平行坐标等常见的多维数据可视化工具外,对于传统的散点图等,传入的数据也可以是多个维度的。配合视觉映射组件 visualMap提供的丰富的视觉编码,能够将不同维度的数据映射到颜色,大小,透明度,明暗度等不同的视觉通道动态数据 ECharts 由数据驱动,数据的改变驱动图表展现的改变。因此动态数据的实现也变得异常简单,只需要获取数据,填入数据, ECharts 会找到两组数据之间的差异然后通过合适的动画去表现数据的变化。配合 timeline 组件能够在更高的时间维度上去表现数据的信息。 5、 绚丽的特效 ECharts 针对线数据,点数据等地理数据的可视化提供了吸引眼球的特效。、通过 GL 实现更多更强大绚丽的三维可视化提供了基于WebGL 的 ECharts GL,你可以跟使用 ECharts 普通组件一样轻松的使用ECharts GL 绘制出三维的地球,建筑群,人口分布的柱状图,在这基础之上还提供了不同层级的画面配置项,几行配置就能得到艺术化的画面。 6、 无障碍访问(4.0+)支持自动根据图表配置项智能生成描述,使得盲人可以在朗读设备的帮助下了解图表内容,让图表可以被更多人群访问。)
49、For循环与map循环有什么区别
• For 循环:在固定长度或者长度不计算的情况下 for 循环效率更高 • Map 循环:在不确定长度或者计算长度有损性能的时候用 map 比较方便,如果需要操作元素里面的每一个值并且返回一个新数组的话,那么 map 就是最好的选择, 数组中的元素为原始数组调用函数处理后的值。
50、请写出一个简单的类与继承
Person 类父类 function Person(name, age, sex) { // 私有属性和私有方法 this.name = name; this.age = age; this.sex = sex; } // 原型属性和原型方法 Person.prototype.type = "灵长类"; Person.prototype.sayName = function(){ alert(this.name) } let lxg = new Person("雷小盖",18,"女") // SuperMan 类子类38 function SuperMan(name, age, sex, skill) { // 继承了父类 Person 里面所有的特征(属性) // 此时只继承了私有属性和私有方法 Person.apply(this, [name, age, sex]); this.skill = skill; } // 将父类的实例化对象赋值给子类的原型对象 // 原型链继承 SuperMan.prototype = new Person(); // 子类的原始中独有的一个方法,父类的原型里应该没有 SuperMan.prototype.showSkill = function() { alert(this.skill) } let spiderMan = new SuperMan("蜘蛛侠", 18, "男", "爬墙"); //修复实例化对象的 constructor 指向问题 spiderMan.constructor = SuperMan;
51、同步与异步的区别/阻塞与非阻塞区别
• 同步与异步: 同步与异步是对应的,它们是线程之间的关系,两个线程之间要么是同步的,要么是异步的。 • 区别:同步就是由调用者主动等待这个调用的结果。而异步则是相反,调用在发出之后,这个调用就直接返回了,所以没有返回结果。同步就是在发出一个调用时,在没有得到结果之前,该调用就不返回。但是一旦调用返回,就得到返回值了。当一个异步过程调用发出后,调用者不会立刻得到结果。而是在调用发出后,被调用者通过状态、 来通知调用者,或通过回调函数处理这个调用。 • 阻塞与非阻塞:阻塞与非阻塞是对同一个线程来说的,在某个时刻,线程要么处于阻塞,要么处于非阻塞。 • 区别:阻塞调用是指调用结果返回之前,当前线程会被挂起。调用线程只有在得到结果之后才会返回。非阻塞调用指在不能立刻得到结果之前,该调用不会阻塞当前线程。
52、重绘和回流是什么
• 解析 HTML,生成 DOM 树,解析 CSS,生成 CSSOM 树,将 DOM 树和CSSOM 树结合生成渲染树(Render Tree) • Layout(回流):当渲染树中的一部分或者全部因为元素的尺寸、布局、隐藏等改变而需要重新构建的时候,这时候就会发生回流。根据生成的渲染树,进行回流(Layout),得到节点的几何信息(位置,大小) • Painting(重绘):在回流的时候,浏览器会使渲染树中受到影响的元素部分失效,并重新绘制这个部分的渲染树,完成回流以后,浏览器会重新绘制受到影响的部分元素到屏幕中,这个过程就是重绘。根据渲染树以及回流得到的几何信息,得到节点的绝对像素 • (什么时候会发生回流和重绘 o 添加或删除可见的 DOM 元素 o 元素的位置发生变化 o 元素的尺寸发生变化(包括外边距、内边框、边框大小、高度和宽度等)39 o 内容发生变化,比如文本变化或图片被另一个不同尺寸的图片所替代。 o 页面一开始渲染的时候(这肯定避免不了) o 浏览器的窗口尺寸变化(因为回流是根据视口的大小来计算元素的位置和大小的) o 回流一定会触发重绘,而重绘不一定会回流 • 如何减少回流,重绘? o 修改 html 元素中对应的 class 名,利用 class 替换样式 o csstext(利用 cssText 属性合并所有改变,然后一次性写入) o display:none(隐藏元素,应用修改,重新显示))
53、http是什么?有什么特点
• HTTP(HyperText Transfer Protocol 超文本传输协议)是用于从万维网服务器传输超文本到本地浏览器的传送协议。 • HTTP 基于 TCP/IP 协议模型来传递数据 • 特点:可靠传输、应用层协议、灵活可拓展、请求-应答、无状态。
54、HTTP协议和HTTPS区别
• HTTPS 和 HTTP 的区别主要如下 o https 协议需要到 ca 申请证书,一般免费证书较少,因而需要一定费用。 o http 是超文本传输协议,信息是明文传输, https 则是具有安全性的 ssl 加密传输协议。 o http 和 https 使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是 443。 o http 的连接很简单,是无状态的; HTTPS 协议是由 SSL+HTTP 协议构建的可进行加密传输、身份认证的网络协议,比 http 协议安全。 o HTTP:是互联网上应用最为广泛的一种网络协议,是一个客户端和服务器端请求和应答的标准(TCP),用于从 WWW 服务器传输超文本到本地浏览器的传输协议,它可以使浏览器更加高效,使网络传输减少。 o HTTPS:是以安全为目标的 HTTP 通道,简单讲是 HTTP 的安全版,即HTTP 下加入 SSL 层, HTTPS 的安全基础是 SSL,因此加密的详细内容就需要 SSL。 o HTTP 协议传输的数据都是未加密的,也就是明文的,因此使用 HTTP 协议传输隐私信息非常不安全,为了保证这些隐私数据能加密传输, 于是网景公司设计了 SSL(Secure Sockets Layer)协议用于对 HTTP 协议传输的数据进行加密,从而就诞生了 HTTPS。简单来说 HTTPS 协议是由 SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,要比 http 协议安全。
55、http状态码有哪些
2 开头的基本都是代表成功 200 OK 正常返回数据 3 开头的一般也是成功了,只不过中间做了一些额外处理 301 Moved Permanently 永久性转移/重定向,一般应用于网站域名更换,访问老域名,永久都跳转到新的域名上 302 Move Temporarily 临时转移 304 Not Modified 读取的是缓存中的数据,这个是客户端和服务器端共建的协商缓存(把不经常更新,请求过的资源文件做缓存,后期在访问这些资源直接走缓存数据,除非服务器端更新了此资源,或者客户端强制清缓存刷新等 307 Temporary Redirect 临时重定向,一般应用于服务器的负载均衡 4 开头的都是失败:失败的原因一般都是客户端(前端)的问题 400 Bad Request 请求参数错误 401 Unauthorized 无权限访问 404 Not Found 地址错误 405 Method Not Allowed 当前请求的方式服务器不支持 5 开头的都是失败:失败的原因一般都是服务器(后端)问题 500 Internal Server Error 未知服务器错误 503 Service Unavailable 服务器超负荷
56、原型和继承,prototype,call和apply继承的区别(第一个参数是相同的,第二个的区别在哪)
• 原型:每一个构造函数都有一个 prototype 属性,这个属性会在生成实例的时候,成为实例对象的原型对象。 javascript 的每个对象都继承另一个对象,后者称为“原型”(prototype)对象。40 • 继承:继承就是在子类构造函数中继承父类构造函数的私有属性和原型属性。我们在子类构造函数中使用 call 或 apply 方法调用父类构造函数并改变其 this指向为子类构造函数的 this,此时子类的构造函数就继承了父类的私有属性和私有方法。将父类的实例化对象赋值给子类的原型对象,此时子类就继承了父类的原型属性和原型方法。 • call 和 apply 的区别:每一个函数都有 call 和 apply 方法,都是帮助我们调用函数的,但是在调用的时候可以改变本次执行函数中的 this 指向。他们的不同点就在于 call 是无限多个参数,而 apply 有两个参数,第二个参数是数组,代表实参集合。一般来说我们也就是在用 JS 实现面向对象的继承特点时会使用到这个方法。
57、数组的方法,字符串的方法,要知道每个的含义,掌握排序和去重的方法
• 数组: o push(新值) 向数组的尾端插入一个新的元素 o unshift(新值) 向数组的前端插入一个新的元素 o pop() 删掉数组中最后一个元素 o shift() 删掉数组中第一个元素 o splice(删除的下标,1) 从某一个下标上删除一个元素,有副作用 o splice(要插入的下标,0,要插入的数据) 从中间插入一个元素 o concat() 拼接数组,返回值为合并成的新数组,原数组不会改变 o join() 将数组转换为字符串,参数为分隔符,原数组不会改变 o reverse() 颠倒数组中元素的顺序,会改变原数组 o slice(start,end) 通过开始下标和结束下标截取数组元素,原数组不会发生改变 o toString() 将数组转换为字符串可以被 join 完美代替 o sort() 通过 Unicode 进行排序,在原数组上排序,不生成副本 var arr = [1, 5, 6, 1, 3, 4, 11, 2, 5] //排序固定写法升序 arr.sort(function(num1, num2) { return num1 - num2; }) console.log(arr); //排序固定写法降序 arr.sort(function(num1, num2) { return num2 - num1; }) console.log(arr); • 字符串: o charAt() 根据下标查找字符 o concat() 字符串拼接,平时我们会用+运算代替 o indexOf() 根据字符查找对应的下标从一个字符串中检索某个字符的下标,如果没有找到对应的字符,则返回-1;如果要寻找的字符有多个,则默认返回第一个的下标 o lastIndexof() 根据字符查找对应的下标(从后往前找) o replace("原字符","新字符") 替换字符41 //惰性匹配用 m 替换 e console.log(str.replace("e", "m")); //全局匹配 console.log(str.replace(/c/g, "m")); o slice(start,end) 通过起始下标和终结下标截取一段字符串,结果中包含开始位但不包含结束位;如果省掉第二个参数则代表一直截取到结束为止 o substring() 同 slice 功能和参数都一致,不过第二个参数不允许传负数 o split() 根据所传参数的字符作为分隔将原字符切割为长度若干的一个数组 o substr() 通过起始下标和截取数量来截取一段字符串 o toLowerCase() 转换字符串为小写 o toUpperCase() 转换字符串为大写
58、数组的循环方式有哪些?
for循环 forEach循环 for in 循环 map 遍历 for of 遍历(ES6 support)
59、冒泡排序和选择排序方式是什么?
1.冒泡排序 原理: 相邻的两个单位,比较存储的数据。如果第一个单元的数据较大,就将两个相邻单元交换存储数据。 过程: 从起始单元开始比较,第一次循环,会选择出一个最大值,放在数组所有单元的最后; 之后,每次循环,都会比较出一个本次循环的最大值,放在当前参与比较单元的最后; 之前已经比较选出的单元,不会参与下一次比较。 优化: (1) 最后一个单元已经通过倒数第二个单元参与比较了,因此最后一个单元就不用参与单次循环了。 (2)之前比较出的最大值,不再参与下一次的比较 (3)n个单元只要循环比较n-1次就可以, 最后就一个单元时不用再循环比较。 核心: 交换存储的数据,两个相邻的单元比较数据大小,第一个单元数值较大就交换两个单元存储的数据。 var a = [6,5,4,7,3,8,2,9,1,0]; var t; for(var i=0; i<a.length-1; i++){ for(var j=0; j<a.length-i-1; j++){ if(a[j]>a[j+1]){ t = a[j]; a[j] = a[j+1]; a[j+1] = t; } } } 2. 选择排序 步骤: (1)先定义循环的起始位置默认为最小值所在位置,从起始位置下一个位置开始执行循环。 (2)如果有位置上的数值小于存储索引位置上的数值,就存储这个位置的索引值。 (3)循环结束后比较存储的索引是否是起始位置索引,如果不是就交换两个位置上的数值,会将本次循环的最小值,放置在循环的起始位置上。 (4)再执行多次循环完成排序。 核心 : 找到最小值的索引,再与起始位置交换数值。 优化 : (1)之前比较的数值不参与一次标记 (2)2 n个单元,只要比较n-1次 vra = [6,5,4,7,3,8,2,9,1,0]; var t; var k; for(var i=0; i<a.length-1; i++){ k = i; for(var j=i+1; j<a.length; j++){ if(a[k]>a[j]){ k = j; } } t = a[i]; a[i] = a[k]; a[k] = t; } console.log(a)
60、箭头函数与普通函数的区别
• 外形不同:箭头函数使用箭头定义,普通函数中没有。 • 箭头函数全都是匿名函数:普通函数可以有匿名函数,也可以有具名函数 • 箭头函数不能用于构造函数:普通函数可以用于构造函数,以此创建对象实例。 • 箭头函数中 this 的指向不同:在普通函数中, this 总是指向调用它的对象,如果用作构造函数,它指向创建的对象实例。 • 箭头函数不具有 arguments 对象:每一个普通函数调用后都具有一个arguments 对象,用来存储实际传递的参数。但是箭头函数并没有此对象。 • 其他区别:箭头函数不具有 prototype 原型对象。箭头函数不具有 super。箭头函数不具有 new.target。
61、什么是js内存泄露?
• 内存泄漏(Memory Leak)是指程序中已动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果。 • 避免内存泄漏: o 避免误建全局变量:在 JS 中使用未定义的变量,会在全局对象中定义一个新变量。在浏览器中,全局变量是 window o 注意定时器或回调函数的使用:使用定时器不可避免,但尽量少使用,尽量在使用完定时器后,使用 clearInterval 或者 clearTimeout。
62、Es6解构是深拷贝还是浅拷贝?
解构赋值,如果所解构的原对象是一维数组或对象,其本质就是对基本数据类型进行等号赋值,那它就是深拷贝; 如果是多维数组或对象,其本质就是对引用类型数据进项等号赋值,那它就是浅拷贝; 结论:解构赋值是浅拷贝(因为它确实不能对多维数组或对象达到深拷贝的作用);
63、ES6扩展运算符什么?有什么用?
扩展运算符(spread)是三个点(…),该运算符主要用于函数调用。但是也还有其他一些特别实用的功能。
数组传参
function add(x ,y){ console.log("你"+ x + ",我"+ y); } let arr = ["艾希","奶妈"]; add(...arr); //输出为你艾希,我奶妈
如果在ES5中,需要对应取值只能通过数据加下标一个个传进去,在ES6中,可以直接…数组直接传进去。
复制数组
let a = ["疾风剑豪"]; let b = [...a]; console.log(...b); //复制了数组a的值 console.log(a === b); //false
如果直接将数组a赋值给b,b得到的只是一个数组a的地址,并不能得到数组a里面的值。如果,采用…a 可以直接复制到数组a里面的值,但是,改变数组b里面的值,并不会影响数组a里面的值。
合并数组
let a1= ["暗夜猎手"]; let b1= ["澡子哥 UZI"]; console.log([...a1,...b1]); //["暗夜猎手","澡子哥 UZI"]
在ES5中,我们可以采用concat(a1,b1),将两个数组合并,在ES6中,我们就可以采用[…a1,…b1],将两个数组合并。
解构赋值
let a1= ["暗夜猎手"]; let b1= ["澡子哥 UZI"]; let arr = ["艾希","奶妈"]; let arr1 = [...a1,...b1,...arr]; // 将三个数组合并 let [aa1,...aa2] =arr1; // 采用解构赋值 console.log(aa1); //输出:暗夜猎手 console.log(aa2); //输出:["澡子哥 UZI","艾希","奶妈"]
在解构赋值中,它又相当于一个剩余运算符,那什么是解构运算符呢? 就是 :赋值运算符的扩展,专门对数组和对象进行模式匹配。 例如 let [a,b] = [2,1] ,此时a= 2, b = 1; 上面输出aa1 就是赋值运算符右边数组第一个,而…aa2则被赋值的是运算符右边数组剩下的元素。 不过该运算符在解构赋值中,只能放参数最后一位,不然会报错。
字符串转数组
console.log([..."hello"]); // [h,e,l,l,o]
类数组转真数组
let nodeList = document.querySelectorAll("div") let array = [...nodeList]
可以将获取的dom节点构成的类数组(数组类型为NodeList)转化为真数组。querySelectorAll方法返回的是一个NodeList对象。它不是数组,而是一个类似数组的对象。这时,扩展运算符可以将其转为真正的数组
64、你如何对网站的文件和资源进行优化?
• 利用浏览器缓存你的 js 和 CSS 文件 • 把你的 .js 库文件地址替换成 CDN 的地址 • 精简和优化 js 和 CSS • 使用 css sprites 合并图片(精灵图) • 优化网站图片 • 文件合并(相当于去重,把所用到的 css 样式或者 js 可以封装成一个公共类)目的是为了减少 http 的请求
65、请简述ajax的执行过程 以及常见的HTTP状态码
(1).创建 XMLHttpRequest 对象42 let http=new XMLHttpRequest(); (2).设置请求参数 //http.open("post 还是 get","发送给谁","是否异步"); http.open("get", "ajax.txt",true); (3).发送请求 http.send(); (4).设置回调函数 http.onreadystatechange=function(){ if(http.status==200 && http.readyState==4){ //http.responseText request 从后端接收的数据 (5).接收响应: http.responseText 或者 http.responseXML console.log(http.responseText); }} • 常见的 http 状态码 o 2 开头的基本都是代表成功 200 OK 正常返回数据 o 3 开头的一般也是成功了,只不过中间做了一些额外处理 301 Moved Permanently 永久性转移/重定向,一般应用于网站域名更换,访问老域名,永久都跳转到新的域名上 302 Move Temporarily 临时转移 304 Not Modified 读取的是缓存中的数据,这个是客户端和服务器端共建的协商缓存(把不经常更新,请求过的资源文件做缓存,后期在访问这些资源直接走缓存数据,除非服务器端更新了此资源,或者客户端强制清缓存刷新等 307 Temporary Redirect 临时重定向,一般应用于服务器的负载均衡 o 4 开头的都是失败:失败的原因一般都是客户端(前端)的问题 400 Bad Request 请求参数错误 401 Unauthorized 无权限访问 404 Not Found 地址错误 405 Method Not Allowed 当前请求的方式服务器不支持 o 5 开头的都是失败:失败的原因一般都是服务器(后端)问题 500 Internal Server Error 未知服务器错误 503 Service Unavailable 服务器超负荷
67、预加载和懒加载的区别,预加载在什么时间加载合适
• 预加载:提前加载图片,当用户需要查看时可直接从本地缓存中渲染。预加载是牺牲服务器前端性能,换取更好的用户体验,这样可以使用户的操作得到最快的反映。 • 懒加载也叫延迟加载:按照一定的条件或者需求等到满足条件的时候再加载对应的资源。懒加载页面加载速度快、可以减轻服务器的压力、节约了流量,用户体验好。 • 预加载使用场景:在网页全部加载之前,对一些主要内容进行加载,以提供给用户更好的体验,减少等待的时间。否则,如果一个页面的内容过于庞大,没有使用预加载技术的页面就会长时间的展现为一片空白,直到所有内容加载完毕。
68、JsDOM操作有哪些?
节点查找API document.getElementById :根据ID查找元素,大小写敏感,如果有多个结果,只返回第一个; document.getElementsByClassName :根据类名查找元素,多个类名用空格分隔,返回一个 HTMLCollection 。注意兼容性为IE9+(含)。另外,不仅仅是 document,其它元素也支持 getElementsByClassName 方法; document.getElementsByTagName :根据标签查找元素, * 表示查询所有标签,返回一个 HTMLCollection 。 document.getElementsByName :根据元素的name属性查找,返回一个 NodeList 。 document.querySelector :返回单个Node,IE8+(含),如果匹配到多个结果,只返回第一个。 document.querySelectorAll :返回一个 NodeList ,IE8+(含)。 节点创建API createElement创建元素: createTextNode创建文本节点: cloneNode 克隆一个节点: 节点修改API appendChild insertBefore insertAdjacentHTML removeChild用于删除指定的子节点并返回子节点 节点关系API parentNode :每个节点都有一个parentNode属性,它表示元素的父节点。 children :返回一个实时的 HTMLCollection ,子节点都是Element,IE9以下浏览器不支持; childNodes :返回一个实时的 NodeList ,表示元素的子节点列表,注意子节点可能包含文本节点、注释节点等; firstChild :返回第一个子节点,不存在返回null,与之相对应的还有一个 firstElementChild ; lastChild :返回最后一个子节点,不存在返回null,与之相对应的还有一个 lastElementChild ; previousSibling :节点的前一个节点,如果不存在则返回null。注意有可能拿到的节点是文本节点或注释节点,与预期的不符,要进行处理一下。 nextSibling :节点的后一个节点,如果不存在则返回null。注意有可能拿到的节点是文本节点,与预期的不符,要进行处理一下。 previousElementSibling :返回前一个元素节点,前一个节点必须是Element,注意IE9以下浏览器不支持。 nextElementSibling :返回后一个元素节点,后一个节点必须是Element,注意IE9以下浏览器不支持。 元素属性型API setAttribute 给元素设置属性 getAttribute 样式相关API
69、Jquery选择器有哪些
• 基础选择器 o id 选择器$('#brother').css('color','red'); o 标签选择器: $('a').css({'color':'green','font-size':'24px'}); o 类选择器: $('.li3').css('background','yellow'); o 通配符选择器:console.log($('')); $('').html(''); // 清空整个界面的 dom 元素 • 层级选择器 o 后代选择器: $('#box p').css('color','red'); o 子代选择器: $('#box>p').css('color','green'); o 毗邻选择器,匹配所有的紧接着选中元素的兄弟: $('#father+p').css('font-size','30px'); o 兄弟选择器 $('#father~p').css('background','gray'); • 过滤选择器 o 获取第一个 $('li:first').css('background','gray'); o 获取最后一个 $('li:last').css('background','yellow'); o 获取奇数 $('li:odd').css('color','red'); o 获取偶数 $('li:even').css('color','green'); o 选中索引值为 1 $('li:eq(1)').css('font-size','32px'); o 大于索引值 1 $('li:gt(1)').css('font-size','60px'); o 小于索引值 1 $('li:lt(1)').css('font-size','10px'); • 属性选择器 o $('li[id]').css('color','red'); o $('li[class=what]').css('font-size','30px'); o $('li[class!=what]').css('font-size','50px'); o $('input[name^=username]').css('background','gray'); o $('input[name$=222]').css('background','green'); o $('button[class*=danger]').css('background','orange'); o 解释: 1. 标签名【属性名】,查找所有含有 id 属性的该标签名的元素 2. 匹配给定的属性是 what 值【attr=value】匹配给定的属性是某个特定 值的元素 3. 没有 class 也会发生变化, [attr!=value]匹配所有不包含有特定的属 性,或者属性不等于特定值的元素 4. 匹配给定的属性是以某些值开始的元素 ^ 5. 匹配给定的属性是以某些值结尾的元素 $ 6. 匹配给定的属性是以包含某些值的元素 * • 筛选选择器 o $('span').eq(1).css('color','red'); o $('span').first().css('font-size','28px'); o $('span').last().css('color','greenyellow'); console.log($('span').parent()); o $('span').parent('.p1').css({'width':'300px',height:'400px','backgro und':'red'}); o $('.list').siblings('li').css('color','red'); o $('div').find('button').css('background','gray');44 o 解释: 1. 获取第 n 个元素数值从 0 开始 .eq() 2. 获取第一个元素 .first() 3. 获取最后一个元素 .last() 4. 获取父元素 .parent() 5. 选择所有的兄弟元素 .siblings() 6. 查找所有的后代元素 .find() o jQuery 的筛选器的分类 o 过滤筛选器如: $("li").eq(2) $("li").first() $("ul li").hasclass("test") o 查找筛选器如:查找子标签: $("div").children(".test") $("div").find(".test") o 向下查找兄弟标签: $(".test").next() $(".test").nextAll() $(".test").nextUntil() o 向上查找兄弟标签: $("div").prev() $("div").prevAll() $("div").prevUntil() o 查找所有兄弟标签: $("div").siblings() o 查找父标签: $(".test").parent() $(".test").parents() $(".test").parentUntil()
70、Jquery插入节点的方法
• before(): 在指定节点的前面添加要添加的节点 • insertBefore(): 把要插入节点插入到指定节点的前面 • after (): 在指定节点的后面添加要添加的节点 • insertAfter (): 把要插入的节点插入到指定节点的后面 • prepend (): 在指定父级里面的最前面添加指定节点 • prependTo (): 把指定节点添加到指定父级里面的最前面 • append (): 在指定父级里面的最后面添加指定节点 • appendTo (): 把指定节点添加到指定父级里面的最后面
71、Js的函数节流和函数防抖的区别
• 区别: o 函数节流是指一定时间内 js 方法只跑一次。比如人的眨眼睛,就是一定时间内眨一次。这是函数节流最形象的解释。 函数防抖是指频繁触发的情况下,只有足够的空闲时间,才执行代码一次。比如生活中的坐公交,就是一定时间内,如果有人陆续刷卡上车,司机就不会开车。只有别人没刷卡了,司机才开车。 o 函数防抖: 防抖就是指触发事件后在 n 秒内函数只能执行一次,如果在 n秒内又触发了事件,则会重新计算函数执行时间。 let box = document.getElementById('box'); let timer = 0 box.onclick = function () { clearTimeout(timer) timer = setTimeout(() => { console.log(1) }, 1000)}45 • 应用场景: o 函数防抖的应用场景,最常见的就是用户注册时候的手机号码验证和邮箱验证了。只有等用户输入完毕后,前端才需要检查格式是否正确,如果不正确,再弹出提示语。 o 函数节流:节流就是指连续触发事件但是在 n 秒中只执行一次函数。 let box = document.getElementById('box'); let timer = 0; box.onclick = function () { if (!timer) { timer = setTimeout(() => { timer = 0; console.log(1) }, 1000) }} o 函数节流应用的实际场景,多数在监听页面元素滚动事件的时候会用到。因为滚动事件,是一个高频触发的事件。
72、Get和post的区别
• get 请求参数是在 URL 中存在的, post 请求的参数是在请求主体中的 • post 的安全性要好于 get 请求 • get 请求会造成一次浏览器浏览记录,而 post 请求不会有浏览记录 • get 请求有长度限制, post 没有长度限制
73、什么是csrf攻击
• CSRF 攻击:中文名称:跨站请求伪造,可以理解为攻击者盗用了你的身份,以你的名义发送恶意请求,比如:以你名义发送邮件、发消息、购买商品,虚拟货币转账等。 • 防御手段: o 验证请求来源地址; o 关键操作添加验证码; o 在请求地址添加 token 并验证
74、Js数据类型的分类
• 基本数据类型: o 数值类型(number)包含数字 o 字符串类型(string)由单双引号包住的字符串内容会原样输出 o 布尔类型(boolean)只会输出 true , false o undefined 数值定义但未初始化 o null 空 o Symbol 表示独一无二的值(ES6 新增) • 引用类型: o object ,Array(数组), Date(日期), Functiion(函数), Regexp(正则) • 检测变量数值类型 o typeof 后面加变量名, typeof 本身是字符串类型,变量的数据类型取决于变量里保存的数据。 console.log(46 typeof 123, //"number" typeof 'dsfsf', //"string" typeof false, //"boolean" typeof [1,2,3], //"object" typeof {a:1,b:2,c:3}, //"object" typeof function(){console.log('aaa');}, //"function" typeof undefined, //"undefined" typeof null, //"object" typeof new Date(), //"object" typeof /^[a-zA-Z]{5,20}$/, //"object" typeof new Error() //"object" ); o instanceof instanceof 运算符需要指定一个构造函数,或者说指定一个特定的类型,它用来判断这个构造函数的原型是否在给定对象的原型链上 console.log( 123 instanceof Number, //false 'dsfsf' instanceof String, //false false instanceof Boolean, //false [1,2,3] instanceof Array, //true {a:1,b:2,c:3} instanceof Object, //true function(){console.log('aaa');} instanceof Function, //true undefined instanceof Object, //false null instanceof Object, //false new Date() instanceof Date, //true /^[a-zA-Z]{5,20}$/ instanceof RegExp, //true new Error() instanceof Error //true ) Number, String, Boolean 没有检测出他们的类型,但是如果使用下面的写法则可以检测出来: var num = new Number(123); var str = new String('dsfsf'); var boolean = new Boolean(false); 还需要注意 null 和 undefined 都返回了 false,这是因为它们的类型就是自己本身,并不是 Object 创建出来它们,所以返回了 false。 o toString() 为了每个对象都能通过 Object.prototype.toString() 来检测,需要 以 Function.prototype.call() 或者 Function.prototype.apply() 的形式来调用,传递要检查的对象作为第一个参数,称为 thisArg var toString = Object.prototype.toString; toString.call(123); //"[object Number]" toString.call('abcdef'); //"[object String]" toString.call(true); //"[object Boolean]" toString.call([1, 2, 3, 4]); //"[object Array]"47 toString.call({name:'wenzi', age:25}); //"[object Object]" toString.call(function(){ console.log('this is function'); }); //"[object Function]" toString.call(undefined); //"[object Undefined]" toString.call(null); //"[object Null]" toString.call(new Date()); //"[object Date]" toString.call(/^[a-zA-Z]{5,20}$/); //"[object RegExp]" toString.call(new Error()); //"[object Error]"
75、Js中手写一个深拷贝
• 乞丐版: var newObj = JSON.parse( JSON.stringify( someObj ) ); • 面试够用版: function deepCopy(obj){ //判断是否是简单数据类型, if(typeof obj == "object"){ //复杂数据类型 var result = obj.constructor == Array ? [] : {}; for(let i in obj){ result[i] = typeof obj[i] == "object" ? deepCopy(obj[i]) : obj[i]; } }else { //简单数据类型直接 == 赋值 var result = obj; } return result; }
万能版
function deepCopy(obj) { //判断是否是简单数据类型, if (typeof obj == "object") { //复杂数据类型 var result = obj.constructor == Array ? [] : {}; for (let i in obj) { result[i] = typeof obj[i] == "object" ? arguments.callee(obj[i]) : obj[i]; } } else { //简单数据类型直接 == 赋值 var result = obj; } return result; }
76、手写一个递归
function fun(num){ if(num<=1){ return 1; }else{ return num*arguments.callee(num-1); } }; alert(fun(5)); 输出的结果值为:120
77、什么时候用深拷贝 /浅拷贝
• 浅拷贝是什么:浅拷贝就是增加了一个指针指向已存在的内存(JavaScript 并没有指针的概念,这里只是用于辅助说明),浅拷贝只是拷贝了内存地址,子类的属性指向的是父类属性的内存地址,当子类的属性修改后,父类的属性也随之被修改。 • 深拷贝是什么:深拷贝就是增加一个指针,并申请一个新的内存,并且让这个新增加的指针指向这个新的内存地址使用深拷贝,在释放内存的时候就不会像浅拷贝一样出现释放同一段内存的错误,当我们需要复制原对象但又不能修改原对象的时候,深拷贝就是一个,也是唯一的选择。 • 什么时候用浅拷贝:从服务器 fetch 到数据之后我将其存放在 store 中,通过props 传递给界面,然后我需要对这堆数据进行修改,那涉及到的修改就一定有保存和取消,所以我们需要将这堆数据拷贝到其它地方。 • 什么时候用深拷贝:当你想使用某个对象的值,在修改时不想修改原对象,那么可以用深拷贝弄一个新的内存对象。像 es6 的新增方法都是深拷贝,所以推荐使用 es6 语法。
78、如何遍历一个多维数组
• 第一种 var arr = [ [1, 2, 3, 4], [2, 4, 6, 8], [6, 4, 9, 0] ] if (arr.length != 0) { //判断数组长度是否为 0 for (var i = 0; i < arr.length; i++) { //循环最外面的数组 for (var j = 0; j < arr[i].length; j++) { //循环里面的数组 document.write(arr[i][j]); document.write('<br/>') }}} • 第二种 var arr = [1,2,3,[4,5,[6,7,8,[9,10]]]]; Array.prototype.eachall = function(fn) { try{ //声明一个计数器 this.i || (this.i = 0) //判断数组存在且传的值是一个函数 if (this.length>0 && fn.constructor==Function) { //循环 while(this.i<this.length){ var e = this[this.i]; //判断当前值是不是数组如果是数组进行递归否则执行回调函数 if (e && e.constructor == Array) { e.eachall(fn); } else{ fn.call(e,e); }; this.i++; } //变量回收 this.i=null; }; }catch(err){ console.log("have error:"+err); }}; arr.eachall(function(item){ console.log(item); });
79、什么是事件循环(event loop)与宏任务微任务
Eventloop是什么? 先执行主线程同步的微任务,发现异步之后,放入到异步队列中,然后执行同步的宏任务,宏任务执行完毕执行刚才的异步任务。此顺序反复执行loop 宏任务:当前调用栈中执行的代码成为宏任务。(主代码快,定时器等等)。 微任务: 当前(此次事件循环中)宏任务执行完,在下一个宏任务开始之前需要执行的任务,可以理解为回调事件。(promise.then,proness.nextTick等等)。 宏任务中的事件放在callback queue中,由事件触发线程维护;微任务的事件放在微任务队列中,由js引擎线程维护。
80、什么是数组扁平化?把一个二维数组变成一维数组的方式有哪些
数组扁平化是指将一个多维数组变为一维数组 1. for-in 利用for-in的遍历机制,和递归调用 var newArr = [] function f(arr){ for(val of arr){ // console.log(val,"val") if(typeof(val)=='number'){ newArr.push(val) // console.log(val,"n") }else{ f(val) // console.log(val,"shuzu") } } return newArr } let res = f(a) console.log(res) [ 2, 3, 4, 5, 6, 7, 8, 9, 0 ] 2.reduce() function flatten2(arr) { return arr.reduce((result, item)=> { return result.concat(Array.isArray(item) ? flatten2(item) : item); }, []); reduce方法: 语法: array.reduce(function(total, currentValue, currentIndex, arr), initialValue) 参数: 参数 描述 function(total,currentValue, index,arr) 必需。用于执行每个数组元素的函数 initialValue 可选。传递给函数的初始值 回调函数参数: 参数 描述 total 必需。初始值, 或者计算结束后的返回值 currentValue 必需。当前元素 currentIndex 可选。当前元素的索引 arr 可选。当前元素所属的数组对象 concat方法: 作用:是数组的方法,用来给拼接数组。参数是数组时实现两个数组的拼接,参数是多个数字时是在原数组后拼接这些数字。 例:arr.concat([2,3])或arr.concat(2,3) 3.toString() function flatten3(arr) { return arr.toString().split(',').map((item)=>{ return Number(item) }) } toString()方法: 由于每个类型下面都重写了toString()方法,而Array下面的toString方法就可以把数组的元素转换成字符串,Array.prototype.toString()。 4.join() 类似于toString()方法,把数组先转化为字符串 function flatten4(arr) { return arr.join().split(',').map((item)=>{ return Number(item) }) } 5.解构 …arr可以将二维数组解构成一维数组。 判断数组中的元素是否还有数组,有的话就继续递归解构。 function flatten6(arr) { while(arr.some(item=>Array.isArray(item))) { arr = [].concat(...arr); } return arr; }
81、Js垃圾回收机制是什么?
垃圾回收机制:就是释放那些不再使用的变量。什么是不再使用?就是生命周期结束的变量,可能是全局的和局部的
82、怎么得到url中的参数?
方法一 ,split( )分解法。将URL中的字符按照?,&进行一层一层的分解,将分解得到的参数保存在一个数组中,如果其他地方需要某个参数,直接遍历这个数组,得到自己想要的参数。
function parseQueryString(ur1){ let obj = {} let str = url.slice(url.indexof("?")+1); let arr = str.split(('&')); arr.forEach(item=>{ let arr2 = item.split('='); obj[arr2[0]] = arr2[1] }); return obj } console.log(parseQuerystring("http://www.baidu.com?name=li&age=18"))
方法二,正则表达式分解法。将URL用正则表达式进行分解,直接得到想要的参数。
方法二,正则表达式分解法。将RL用正则表达式进行分解,直接得到想要的参数。 getparameterFromURL:function(url,para){ var reg = new RegExp("[?&]" + para + "\=([^&]+)","g"); var matcher = reg.exec(url); if (matcher != null) return matcher; } return""; }
83、http请求的三次握手四次挥手
1、TCP协议简介
TCP传输控制协议是一种面向连接的、可靠的、基于字节流的传输层通信协议。TCP用意在于适应并支持多网络应用的分层协议层次结构。
2、三次握手
这一场景在生活中可以描述为通话:
甲:你好,我是甲,你是乙吗;
乙:你好甲:我是乙;
甲:正好找你有点事情,身份确认:
-
第一次握手
客户端主动向服务器发起请求连接,请求报文中发送SYN=1,此时随机生成初始序列号seq=x,此时,客户端进程进入SYN-SENT同步已发送状态。
-
第二次握手
服务端收到请求报文后,确认客户的SYN,如果请求没有拒绝,则发出确认报文。报文中应该ACK=1,SYN=1,确认号是ack=x+1,同时自己也发送一个SYN包seq=y,此时,服务器进程进入SYN-RCVD同步收到状态。
-
第三次握手
客户端收到确认后,需要向服务器确认报文的ACK=1,ack=y+1,此时,TCP连接建立,客户端进入ESTABLISHED已建立连接状态。完成三次握手,客户端与服务器开始传送数据。
3、四次挥手
-
第一次挥手
客户端发送一个结束FIN,用来主动关闭和服务端的数据传输,释放连接且停止发送数据,报文首部:FIN=1,序列号seq=u;随后客户端进入终止等待1状态FIN-WAIT-1。
-
第二次挥手
服务端收到这个FIN,发出确认报文ACK=1,确认收到序号是收到的序号+1,即ack=u+1,且带上自己的序列号seq=v,和SYN一样,一个FIN将占用一个序号。如此,服务器通知应用进程,客户端已经没有数据要发送,如果服务器发送数据,客户端依然要接收,该状态会持续一段时间,服务端进入关闭等待状态CLOSE-WAIT。客户端收到服务器的确认请求后,进入终止等待2状态FIN-WAIT-2,等待服务器发送连接释放报文。
-
第三次挥手
服务器向客户端发送释放连接报文FIN=1,ack=u+1,此时服务端还处于半关闭状态,服务器可能还会发送一些数据,此时序列号为seq=w,如此,服务器进入最后确认状态LAST-ACK,等待客户端的确认。
-
第四次挥手
客户端收到服务器的连接释放报文后,回发确认,ACK=1,ack=w+1,序列号是seq=u+1,如此,客户端进入时间等待状态TIME-WAIT。此时TCP连接还没有释放,必须经过最长报文段寿命的时间后,才进入CLOSED状态。MSL:最长报文段寿命,一般2分钟,TCP连接释放时,主动方必须经过2MSL后才进入CLOSED状态,因此主动方关闭时间比较晚。
84、渐进增强和优雅降级
渐进增强 渐进增强(Progressive Enhancement):一开始就针对低版本浏览器进行构建页面,完成基本的功能,然后再针对高级浏览器进行效果、交互、追加功能达到更好的体验。 优雅降级 优雅降级(Graceful Degradation):一开始就构建站点的完整功能,然后再针对低版本浏览器进行兼容。比如一开始使用 CSS3 的特性构建了一个应用,然后逐步针对各大浏览器进行 hack 使其可以在低版本浏览器上正常浏览。
85、高阶函数
高阶函数:如果一个函数符合下面2个规范中的任何一个,那该函数就是高阶函数。
1.若A函数,接收的参数是一个函数,那么A就可以称之为高阶函数。
2.若A函数,调用的返回值依然是一个函数,那么A就可以称之为高阶函数。
常见的高阶函数有:Promise、setTimeout、arr.map()等等
86、函数的柯里化
函数的柯里化:通过函数调用继续返回函数的方式,实现多次接收参数最后统一处理的函数编码形式。
87、git指令
一、新建代码库 # 在当前目录新建一个Git代码库 $ git init # 新建一个目录,将其初始化为Git代码库 $ git init [project-name] # 下载一个项目和它的整个代码历史 $ git clone [url] 二、配置 Git的设置文件为.gitconfig,它可以在用户主目录下(全局配置),也可以在项目目录下(项目配置)。 # 显示当前的Git配置 $ git config --list # 编辑Git配置文件 $ git config -e [--global] # 设置提交代码时的用户信息 $ git config [--global] user.name "[name]" $ git config [--global] user.email "[email address]" 三、增加/删除文件 # 添加指定文件到暂存区 $ git add [file1] [file2] ... # 添加指定目录到暂存区,包括子目录 $ git add [dir] # 添加当前目录的所有文件到暂存区 $ git add . # 添加每个变化前,都会要求确认 # 对于同一个文件的多处变化,可以实现分次提交 $ git add -p # 删除工作区文件,并且将这次删除放入暂存区 $ git rm [file1] [file2] ... # 停止追踪指定文件,但该文件会保留在工作区 $ git rm --cached [file] # 改名文件,并且将这个改名放入暂存区 $ git mv [file-original] [file-renamed] 四、代码提交 # 提交暂存区到仓库区 $ git commit -m [message] # 提交暂存区的指定文件到仓库区 $ git commit [file1] [file2] ... -m [message] # 提交工作区自上次commit之后的变化,直接到仓库区 $ git commit -a # 提交时显示所有diff信息 $ git commit -v # 使用一次新的commit,替代上一次提交 # 如果代码没有任何新变化,则用来改写上一次commit的提交信息 $ git commit --amend -m [message] # 重做上一次commit,并包括指定文件的新变化 $ git commit --amend [file1] [file2] ... 五、分支 # 列出所有本地分支 $ git branch # 列出所有远程分支 $ git branch -r # 列出所有本地分支和远程分支 $ git branch -a # 新建一个分支,但依然停留在当前分支 $ git branch [branch-name] # 新建一个分支,并切换到该分支 $ git checkout -b [branch] # 新建一个分支,指向指定commit $ git branch [branch] [commit] # 新建一个分支,与指定的远程分支建立追踪关系 $ git branch --track [branch] [remote-branch] # 切换到指定分支,并更新工作区 $ git checkout [branch-name] # 切换到上一个分支 $ git checkout - # 建立追踪关系,在现有分支与指定的远程分支之间 $ git branch --set-upstream [branch] [remote-branch] # 合并指定分支到当前分支 $ git merge [branch] # 选择一个commit,合并进当前分支 $ git cherry-pick [commit] # 删除分支 $ git branch -d [branch-name] # 删除远程分支 $ git push origin --delete [branch-name] $ git branch -dr [remote/branch] 六、标签 # 列出所有tag $ git tag # 新建一个tag在当前commit $ git tag [tag] # 新建一个tag在指定commit $ git tag [tag] [commit] # 删除本地tag $ git tag -d [tag] # 删除远程tag $ git push origin :refs/tags/[tagName] # 查看tag信息 $ git show [tag] # 提交指定tag $ git push [remote] [tag] # 提交所有tag $ git push [remote] --tags # 新建一个分支,指向某个tag $ git checkout -b [branch] [tag] 七、查看信息 # 显示有变更的文件 $ git status # 显示当前分支的版本历史 $ git log # 显示commit历史,以及每次commit发生变更的文件 $ git log --stat # 搜索提交历史,根据关键词 $ git log -S [keyword] # 显示某个commit之后的所有变动,每个commit占据一行 $ git log [tag] HEAD --pretty=format:%s # 显示某个commit之后的所有变动,其"提交说明"必须符合搜索条件 $ git log [tag] HEAD --grep feature # 显示某个文件的版本历史,包括文件改名 $ git log --follow [file] $ git whatchanged [file] # 显示指定文件相关的每一次diff $ git log -p [file] # 显示过去5次提交 $ git log -5 --pretty --oneline # 显示所有提交过的用户,按提交次数排序 $ git shortlog -sn # 显示指定文件是什么人在什么时间修改过 $ git blame [file] # 显示暂存区和工作区的差异 $ git diff # 显示暂存区和上一个commit的差异 $ git diff --cached [file] # 显示工作区与当前分支最新commit之间的差异 $ git diff HEAD # 显示两次提交之间的差异 $ git diff [first-branch]...[second-branch] # 显示今天你写了多少行代码 $ git diff --shortstat "@{0 day ago}" # 显示某次提交的元数据和内容变化 $ git show [commit] # 显示某次提交发生变化的文件 $ git show --name-only [commit] # 显示某次提交时,某个文件的内容 $ git show [commit]:[filename] # 显示当前分支的最近几次提交 $ git reflog 八、远程同步 # 下载远程仓库的所有变动 $ git fetch [remote] # 显示所有远程仓库 $ git remote -v # 显示某个远程仓库的信息 $ git remote show [remote] # 增加一个新的远程仓库,并命名 $ git remote add [shortname] [url] # 取回远程仓库的变化,并与本地分支合并 $ git pull [remote] [branch] # 上传本地指定分支到远程仓库 $ git push [remote] [branch] # 强行推送当前分支到远程仓库,即使有冲突 $ git push [remote] --force # 推送所有分支到远程仓库 $ git push [remote] --all 九、撤销 # 恢复暂存区的指定文件到工作区 $ git checkout [file] # 恢复某个commit的指定文件到暂存区和工作区 $ git checkout [commit] [file] # 恢复暂存区的所有文件到工作区 $ git checkout . # 重置暂存区的指定文件,与上一次commit保持一致,但工作区不变 $ git reset [file] # 重置暂存区与工作区,与上一次commit保持一致 $ git reset --hard # 重置当前分支的指针为指定commit,同时重置暂存区,但工作区不变 $ git reset [commit] # 重置当前分支的HEAD为指定commit,同时重置暂存区和工作区,与指定commit一致 $ git reset --hard [commit] # 重置当前HEAD为指定commit,但保持暂存区和工作区不变 $ git reset --keep [commit] # 新建一个commit,用来撤销指定commit # 后者的所有变化都将被前者抵消,并且应用到当前分支 $ git revert [commit] # 暂时将未提交的变化移除,稍后再移入 $ git stash $ git stash pop 十、其他 # 生成一个可供发布的压缩包 $ git archive
88、各种兼容写法
1.滚动条事件兼容var _top = document.body.ScrollTop || document.documentElement.ScrollTop; 2.事件对象的兼容var e = e || event; 3.键盘事件兼容var key = e.keyCode || e.which || e.charCode; 4.阻止事件冒泡兼容
e.stopPropagation?e.stopPropagation():e.cancelBubble = true;
5.阻止浏览器默认行为兼容
e.preventDefault?e.preventDefault():e.returnValue = false;return false;
6.获取真实事件源var target = e.SrcElement || e.target 7.获取非行内样式兼容
function getStyle(obj,attr,value){ if(obj.currentStyle){ //针对ie获取非行间样式 return obj.currentStyle(attr); }else{ //标准浏览器 return getComputedStyle(obj,false)[attr]; } }
89、less和sass的区别
1.编译环境不一样 Sass的安装需要Ruby环境,是在服务端处理的,而Less是需要引入less.js来处理Less 代码输出css到浏览器,也可以在开发环节使用Less,然后编译成css文件,直接放到 项目中。 2.变量符不相同 less是@,而scss是$,而且它们的作用域也不一样,less是块级作用域 3.输出设置不一样 Less没有输出设置,sass提供4种输出选项,nested,compact,compressed和expanded nested: 嵌套缩进的css代码(默认) expanded:展开的多行css代码 compact:简洁格式的css代码 compressed:压缩后的css代码 4.sass支持条件语句,可以使用if{}else{},for{}循环等等,而less不行 5.引用外部css文件 sass引用外部文件必须以开头,文件名如果以下划线形状,sass会认为该文件是一个引用文件, 不会将其编译为css文件。less引用外部文件和css中的@import没什么差异。 6.sass和less的工具库不同 sass有工具库Compass, 简单说,sass和Compass的关系有点像Javascript和jQuery的关系, Compass是sass的工具库。在它的基础上,封装了一系列有用的模块和模板,补充强化了 sass的功能。 less有UI组件库Bootstrap,Bootstrap是web前端开发中一个比较有名的前端UI 组件库,Bootstrap的样式文件部分源码就是采用less语法编写。 总结: 不管是sass,还是less,都可以视为一种基于CSS之上的高级语言,其目的是使得CSS开发更 灵活和更强大,sass的功能比less强大,基本可以说是一种真正的编程语言了,less则相对 清晰明了,易于上手,对编译环境要求比较宽松。考虑到编译sass要安装Ruby,而Ruby官网在 国内访问不了,个人在实际开发中更倾向于选择less。
90、如何停止ajax的发送请求
1、 对于原生ajax来说,取消的ajax的关键是调用XHR对象的.abort()方法
2、 jQuery为我们封装了ajax请求接口,在jQuery中,取消ajax请求也是通过调用.abort()方法,只不过操作的对象不再是原生XHR对象, 取消ajax之后,jQuery封装的ajax对象就会执行error对应的函数
3、 vue等框架的话,就会使用axios发送ajax请求。在axios中取消ajax请求不同于上面两种形式,在axios中是通过axios.CancelToken.source()方法取消请求 (音译:堪嗖头肯)(音译:骚死)
91、jQuery链式调用的原理
jQuery的方法都是挂在原型的,那么如果我们每次在内部方法返回this,也就是返回实例对象,那么我们就可以继续调用原型上的方法了,这样的就节省代码量,提高代码的效率,代码看起来更优雅。
三、Vue
1、Vue的核心是什么
数据驱动和组件化
2、请简述你对vue的理解
• 定义: vue 是一套构建用户界面的渐进式的自底向上增量开发 MVVM 框架,只关注视图层,简单易学、上手快,结合第三方库实现大型单页面应用,支持 组件化 • 优点:轻量级、高效率、上手快、简单易学、文档全面而简洁 • 目的:解决数据绑定问题; Vue.js 主要的目的是为了开发大型单页面应用;支持 组件化,也就是可以把页面封装成为若干个组件,把组件进行拼装,这样是让页 面的复用性达到最高 • 核心思想:数据驱动、组件化 • 优势:简洁: HTML 模板 + Vue 实例 + JSON 数据;轻量: 17kb,性能好; 设计思想:视图与数据分离,无需操作 DOM;社区:大量的中文资料和开源案例
3、请简述vue的单向数据流
• 数据从父级组件传递给子组件,只能单向绑定。子组件内部不能直接修改从父级 传递过来的数据。所有的 prop 都使得其父子 prop 之间形成了一个单向下行 绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。每次父级 组件发生更新时,子组件中所有的 prop 都将会刷新为最新的值。这意味着你不 应该在一个子组件内部改变 prop。
4、Vue常用的修饰符有哪些
• 按键修饰符 .up,.down,.ctrl,.enter,.space 等等 语法: @click.修饰符='fn()' o 事件修饰符 prevent 修饰符:阻止事件的默认行为(submit 提交表单) stop 修饰符:阻止事件冒泡 capture 修饰符:与事件冒泡的方向相反,事件捕获由外到内 self:只会触发自己范围内的事件,不包含子元素 once:只会触发一次 sync:sync修饰符可以实现子组件与父组件的双向绑定,并且可以实现子组件同步修改父组件的值。 父组件:<Zi :isdata.sync="isShow"></Zi>; 子组件:this.$emit("update:事件名", 修改的值); 注意:修饰符可以串联使用
5、v-text与{{}}区别
• v-text 是操作网页元素中的纯文本内容, {{}}是它的另外一种写法, v-text 与{{}}等价, {{}}叫模板插值, v-text 叫指令,有一点区别就是,在渲染的数据比较多的时候,可能会把大括号显示出来,俗称屏幕闪动。 • 解决屏幕闪动的方法: o 使用 v-text 渲染数据; o 使用{{}}语法渲染数据,但是同时使用 v-cloak 指令(用来保持在元素上直到关联实例结束时候进行编译), v-cloak 并不需要添加到每个标签,只要在 el 挂载的标签上添加就可以,并且为[v-cloak]添加 css 样式为 display:none;
6、v-on可以绑定多个方法吗
可以绑定多个方法,中间用逗号隔开
7、Vue循环的key作用
• vue 中循环需加 :key=“唯一标识” ,唯一标识可以指 item 里面 id、 index 等,因为 vue 组件高度复用增加 key 可以标识组件的唯一性,为了更好地区别 各个组件, key 的作用主要是为了高效的更新虚拟 DOM • 为遍历数组或元素中的唯一标识,增加或删减元素时,通过这个唯一标识 key 判断是否是之前的元素, vue 会直接对已有的标签进行复用,不会整个的将所有 的标签全部重新删除和创建,只会重新渲染数据,然后再创建新的元素直到数据 渲染完为止
8、什么是计算属性
首先它是一种属性,其次它有“计算”这个特殊性质。每次取得它的值的时候,它不像 普通属性那样直接返回结果,而是经过一系列的计算之后再返回结果。同时只要在 它的当中引用了 data 中的某个属性,当这个属性发生变化时,计算属性会自动重新 执行。 计算属性 他是一个vue实例下的属性 这个属性是一个带有计算(data数据的)功能的 他会时时刻刻的盯着data中的数据 当data的数据改变了 他也会知道 重新计算并且在返回出计算之后的结果 **一条数据 在不同位置展示不同形态的时候 使用** 语法: computed:{ 你计算之后返回的数据变量(){ return 你处理数据的逻辑 } }
9、Vue单页面的优缺点
• 优点: 用户体验好,快,内容的改变不需要重新加载整个页面,对服务器压力较小。 前后端分离,比如 vue 项目 完全的前端组件化,前端开发不再以页面为单位,更多地采用组件化的思想,代 码结构和组织方式更加规范化,便于修改和调整; • 缺点: 不支持低版本浏览器 首次加载页面的时候需要加载大量的静态资源,这个加载时间相对比较长。 不利于 SEO(搜索引擎)优化,单页页面,数据在前端渲染,就意味着没有 SEO。 页面导航不可用,如果一定要导航需要自行实现前进、后退。(由于是单页面不 能用浏览器的前进后退功能,所以需要自己建立堆栈管理)
10、Vuex是什么?怎么使用?在那种场景下使用
• Vuex 是一个专为 Vue.js 应用程序开发中管理的一个模式。通过创建一个集中 的数据存储,方便程序中的所有组件进行访问。 • 使用: 在 store 下的 index.js 中 Vue.use(Vuex) 创建 store 实例 javascript export default new Vuex.Store({ state: {},//存放数据54 mutations: {},//修改数据的值 actions: {},//执行异步操作请求数据 modules: {},//让每一个模块拥有自己的 state、 mutation、 action、 getters, 使得 结构非常清晰,方便管理。 getters:{}//计算属性 }) • vuex 只能用于单个页面中不同组件(例如兄弟组件)的数据流通。
11、Vue中路由跳转方式(声明式/编程式)
• 使用 this.$router 全局路由的 push()方法进行路由跳转--称之为编程式跳转; • 使用 router-link 进行跳转路由--称之为声明式跳转
12、跨域的解决方式(具体到代码)
• 方法 1.后端解决跨域 CORS(跨域资源共享) (在 server.js 中添加) app.use("/", (req, res, next) => { res.header('Access-Control-Allow-Origin', '*'); res.header('Access-Control-Allow-Headers', 'Content-Type,Content-Length, Authorization, Accept, X-Requested-With , yourHeaderFeild'); res.header('Access-Control-Allow-Methods', 'PUT, POST, GET, DELETE,OPTIONS'); next() }) • 方法 2.使用 JQuery 提供的 jsonp o 网页中添加一个 script 元素,向服务器请求 json 数据,这种做法不受同源 策略的限制,服务器接收到请求后,把数据放在一个指定名字的回调函数里传递 回来 methods: { getData () { var self = this $.ajax({ url: 'http://f.apiplus.cn/bj11x5.json', type: 'GET', dataType: 'JSONP', success: function (res) { self.data = res.data.slice(0, 3) self.opencode = res.data[0].opencode.split(',') }})}} • 方法 3.利用devServer服务器代理的proxyTable 解决跨域(项目使用 vue-cli 脚手架搭建)在 vue.config.js 中中添写如下代码 proxy: { '/api': { target: 'http://localhost:3000/', //对应自己的接口 changeOrigin: true,55 ws: true, pathRewrite: { '^/api': '' }}} • 方法 4.使用nginx(音译:NG科斯)反向代理跨域 Nginx是一个。是一个**高性能的http服务器及反向代理服务器**。官方测试nginx能够支支撑5万并发链接,并且cpu、内存等资源消耗却非常低,运行非常稳定。 • 方法 5.使用otherWindow.postMessage 是html5引入的API, postMessage()方法允许来自不同源的脚本采用异步方式进行有效的通信,可以实现跨文本文档,多窗口,跨域消息传递.多用于窗口间数据通信,这也使它成为跨域通信的一种有效的解决方案.
13、Vue的生命周期请简述
Vue 实例从创建到销毁的过程,就是生命周期。也就是从开始创建、初始化数据、 编译模板、挂载 Dom→渲染、更新→渲染、卸载等一系列过程,我们称这是 Vue 的生命周期。
14、Vue生命周期的作用
生命周期中有多个事件钩子,让我们在控制整个 Vue 实例的过程时更容易完成指定 逻辑。每个 Vue 实例在被创建时都要经过一系列的初始化过程——例如,需要设置 数据监听、编译模板、将实例挂载到 DOM 并在数据变化时更新 DOM 等。同时在 这个过程中也会运行一些叫做生命周期钩子的函数,这给了用户在不同阶段添加自 己的代码的机会。(ps:生命周期钩子就是生命周期函数)例如,如果要通过某些插 件操作 DOM 节点,如想在页面渲染完后弹出广告窗,那我们最早可在 mounted 中进行。
15、DOM渲染在那个生命周期阶段内完成
DOM 渲染在 mounted 中就已经完成了,原因:在 created 的时候,视图中的 html 并没有渲染出来,所以此时如果直接去操作 html 的 dom 节点,一定找不到 相关的元素,而在 mounted 中,由于此时 html 已经渲染出来了,所以可以直接操 作 dom 节点。
16、Vue路由的实现
hash 模式和 history 模式 hash 模式:hash 模式 url 里面永远带着#号,我们在开发当中默认使用这个模式 history 模式:history 模式没有#号,是个正常的 url 适合推广宣传。
动态生成路由
利用 vue-router 的 addRoutes
方法可以动态添加路由。
router.addRoutes([ { path: '/login', name: 'login', component: () => import('../components/Login.vue') } ])
17、Vue路由模式hash和history,简单讲一下
• hash 模式: hash 模式 url 里面永远带着#号,我们在开发当中默认使用这个模 式 • history 模式: history 模式没有#号,是个正常的 url 适合推广宣传。 • 区别 o url 显示 o hash:有#,很 low o history:无#,好看 o 回车刷新 o hash:可以加载到 hash 值对应页面 o history:一般就是 404 刷新掉了 o 支持版本 hash:支持低版本浏览器和 IE 浏览器 history: HTML5 新推出的 API
18、Vue路由传参的两种方式,prams和query方式与区别
• params 方式 o 匹配参数(在路由规则中) o 动态路径参数 o 使用动态路由匹配中的动态路径参数来进行路由配置 o 注意:动态路径参数以冒号:开头 { path: '/info:aa',name: 'Info',component: Info} //在 router 下的 index.js 中,aa 表示随意绑定的参数 o 发送数据(绑定参数) o 声明式 <router-link :to="{name:'tema',params:{id:'参数 1',name:'参数 2'}}">index</router-link> o 编程式(推荐) this.$router.push({name:'tema',params:{id:'参数 1',name:'参数 2'}}) o 注意: params 只能通过路由配置中的 name 属性来引用路由 o 接收数据(获取路由传入参数) {{this.$route.params.id}} //在接收页面添加,id 指的是在路由规则里绑定的参数 • query 方式 o 路由参数不需要添加内容 o 发送数据(绑定参数) o 声明式 <router-link :to="/home?id=参数 1&name=参数 2">index</router-link> //通过 name 引用路由 <router-link :to="{name:'tema',query:{id:'参数 1',name:'参数 2'}}">index</router-link>(推荐) //通过 path 引用路由 <router-link :to="{path:'/home',query:{id:'参数 1',name:'参数 2'}}">index</router-link> • 编程式 this.$router.push("/home?id=参数 1&name=参数 2"); //通过 name 引用路由 this.$router.push({name:'tema',query:{id:'参数 1',name:'参数 2'}}); //通过 path 引用路由 this.$router.push({path:'/home',query:{id:'参数 1',name:'参数 2'}}); 接收数据(获取路由传入参数) {{this.$route.query.id}} //在接收页面添加,id 指的是在路由规则里绑定的参数 • prams 和 query 方式与区别 o 用法上的: query 可以用 name 也可以用 path 来引入, params 要用 name 来引入,接收参数都是类似的,分别是 this.$route.query.name 和 this.$route.params.name。57 o url 展示上: params 类似于 post, query 更加类似于我们 ajax 中 get 传 参,说的再简单一点,前者在浏览器地址栏中不显示参数,后者显示,所以 params 传值相对安全一些。
19、Vue数据绑定的几种方式
• 普通文本绑定:双大括号法/插值表达式 {{}}或者使用 v-text 指令绑定,以文本的形式输出 <h1 v-text="num"></h1> • 解释 HTML 标签的绑定:使用 v-html 绑定 <div v-html="newhtml"></div> newhtml:"<em>我是测试的</em>" • 将数据绑定到标签的属性上:使用 v-bind :属性名=“变量”来绑定
20、Vue注册一个全局组件
• 全局组件 o 作用域:全局范围内均可使用 o 建议:组件名(字母全小写且必须包含一个连字符) o 语法 Vue.component('name',{ template:'<div></div>' }) o 位置:创建实例前定义全局组件 template 的设置 template:'html 代码' template:'#template1' 引用 template 内容 o 数据的定义: data:function(){ return {a:1,b:2} } o 函数的定义: methods:{ o 函数名:function(){}
21、中央事件总线是什么?
1.什么是中央事件总线? 有时候两个非父子关系的组件,也需要通信。可以将一个空的vue实例作为两个组件通信的桥梁,这个vue实例就是中央事件总线。 import Vue from "vue" //创建空实例并且暴漏 export default new Vue 2.用到的api 监听事件触发:EventBus.$on(事件名,回调函数); 使得事件触发:EventBus.$emit(eventName, [...args]); 3.注意点 vm.$on(事件名,回调函数);不可被多次执行,否则,回调函数会被执行多次。 要注意在组件的beforeDestroy钩子中调用vm.$off()清除掉监听器
22、$on是什么?
监听当前实例上的自定义事件。事件可以由this.$emit触发。回调函数会接收所有传入事件触发函数的额外参数。
23、Vue响应式原理?
Vue 的响应式原理的核心是通过 ES5 的保护对象的 Object.defindeProperty 中的 get 和 set 方法,data 中声明的属性都被添加了访问器属性,当读取 data 中的数据时自动调用 get 方法,当修改 data 中的数据时,自动调用 set 方法,检测到数据的变化,会通知观察者 Wacher,观察者 Wacher自动触发重新render 当前组件(子组件不会重新渲染),生成新的虚拟 DOM 树,Vue 框架会遍历并对比新虚拟 DOM 树和旧虚拟 DOM 树中每个节点的差别,并记录下来,最后,加载操作,将所有记录的不同点局部修改到真实 DOM 树上。
24、Vue的路由钩子函数/路由守卫有哪些
• 全局前置守卫 o 当一个导航触发时,全局前置守卫(在进入组件之前)按照创建顺序调用。 o vue-router 提供的 router.beforeEach((to, from, next)=>{})可以方便地 实现全局前置导航守卫 to:即将要进入的目标路由对象 from:当前导航正要离开的路由 next:下一步执行 router.beforeEach((to,from,next)=>{ //根据用户的登录状态限制用户是否能跳转到首页面 if(to.path=="/login"||to.path=="/register"){ next() } else { alert("当前为付费页面请登录后访问! ")58 next("/login") }}) • 全局后置钩子 o 当一个导航触发时,全局后置钩子(在进入组件之后)调用。 o vue-router 提供的 router.afterEach((to,from)=>{})实现全局后置守卫 o to:即将要进入的目标路由对象 o from:当前导航正要离开的路由 router.afterEach((to,from)=>{ console.log("我是全局后置钩子"); }) • 路由独享的守卫 o 与全局前置守卫相比路由独享守卫只是对当前路由进行单一控制参数和全局 前置守卫相同 o 在路由配置上直接定义 beforeEnter 进行路由独享守卫定义 { path:'/shop', name:'Shop', component:Shop, beforeEnter:(to,from,next)=>{ //判断是否登录过 alert("当前页面是 vip 页面!请登录") next("/login") }} • 组件内的守卫(只对当前组件生效) o beforeRouteEnter 在进入组件前调用(不常用) o 在组件中使用 beforeRouteEnter(to,from,next){}来进行进入组建前的钩子 o beforeRouteLeave 离开路由之前(常用) o 在组件中使用 beforeRouteLeave(to,from,next){}来进行离开组件的钩子 beforeRouteLeave(to,from,next){ if(confirm("你确定要离开吗")){ next() }else{ //不进行下一步(也就是不从当前路由离开) next(false) }}
25、Vue中如何进行动态路由设置?有哪些方式?怎么获取传递过来的数据?
• params 方式 o 匹配参数(在路由规则中) o 动态路径参数 o 使用动态路由匹配中的动态路径参数来进行路由配置 o 注意:动态路径参数以冒号:开头59 { path: '/info:aa',name: 'Info',component: Info} //在 router 下的 index.js 中,aa 表 o 示随意绑定的参数 o 发送数据(绑定参数) o 声明式 <router-link :to="{name:'tema',params:{id:'参数 1',name:'参数 2'}}">index</router-link> o 编程式(推荐) this.$router.push({name:'tema',params:{id:'参数 1',name:'参数 2'}}) o 注意: params 只能通过路由配置中的 name 属性来引用路由 o 接收数据(获取路由传入参数) {{this.$route.params.id}} //在接收页面添加,id 指的是在路由规则里绑定的参 数 • query 方式 o 路由参数不需要添加内容 o 发送数据(绑定参数) o 声明式 <router-link :to="/home?id=参数 1&name=参数 2">index</router-link> //通过 name 引用路由 <router-link :to="{name:'tema',query:{id:'参数 1',name:'参数 2'}}">index</router-link>(推荐) //通过 path 引用路由 <router-link :to="{path:'/home',query:{id:'参数 1',name:'参数 2'}}">index</router-link> • 编程式 this.$router.push("/home?id=参数 1&name=参数 2"); //通过 name 引用路由 this.$router.push({name:'tema',query:{id:'参数 1',name:'参数 2'}}); //通过 path 引用路由 this.$router.push({path:'/home',query:{id:'参数 1',name:'参数 2'}}); o 接收数据(获取路由传入参数) {{this.$route.query.id}} //在接收页面添加,id 指的是在路由规则里绑定的参数
26、Elementui中的常用组件有哪些?请简述你经常使用的 并且他们的属性有哪些?
• Container 布局容器:用于布局的容器组件,方便快速搭建页面的基本结构 o <el‐container>:外层容器。当子元素中包含 <elheader> 或 <el‐footer> 时,全部子元素会垂直上下排列,否则会水平左右排列 o <el‐header>:顶栏容器 o <el‐aside>:侧边栏容器 o <el‐main>:主要区域容器 o <el‐footer>:底栏容器60 • Dropdown 下拉菜单:将动作或菜单折叠到下拉菜单中 o <el-dropdown split-button>:下拉按钮 o <el-dropdown-menu>下拉菜单 o <el-dropdown-item>下拉项 o divided 分隔 • NavMenu 导航菜单:为网站提供导航功能的菜单 o <el-menu>:导航菜单 o <el-submenu index="1">:导航按钮 o <template slot="title">标题和名称 - ```<i class="el-icon-menu">``` 图标 - ```<span slot="title">导航二</span>``` 导航标题 o <el-menu-item>导航项 • Table 表格:用于展示多条结构类似的数据,可对数据进行排序、筛选、 对比或 其他自定义操作 o <el-table :data="tableData" stripe>:表格\数据绑定对象\样式 o <el-table-column prop="date" label="日期">:表格行\数据绑定对象属性\表 头 o align="center":居中 o slot-scope:作用域插槽,可以获取表格数据 o cope:代表表格数据,可以通过 scope.row 来获取表格当前行数据, scope 不是固定写法 o <el-button type="primary" size="mini" o @click="handleUpdate(scope.row)">按钮\类型\大小\事件绑定 • Form 表单 o <el-form :model="ruleForm" :rules="rules" ref="ruleForm" >:表单/绑定数据模板/绑定校验 o <el-form-item label="活动名称" prop="name">表单项\显示内容\数据模板 属性绑定 o <el-input v-model="ruleForm.name">表单输入框/数据绑定 o <el-select v-model="ruleForm.region" placeholder="请选择活动区域">:下拉 框/数据绑定/提示 o <el-option label="区域一" value="shanghai"></el-option>:下拉项/数据项 o ref 绑定校验信息 o prop 对应 rules 中对应的校验规则字段名
27、Vue-cli中如何自定义指令与钩子?
• 自定义指令的钩子函数 o bind:绑定指令到元素上,只执行一次 o inserted:绑定了指令的元素插入到页面中展示时调用,基本上都是操作这 个钩子函数 o update:所有组件节点更新时调用 o componentUpdated:指令所在组件的节点及其子节点全部更新完成后调用 o unbind:解除指令和元素的绑定,只执行一次 direactives:{ 自定义指令的名字:{ 自定义指令的钩子函数(形参就是你绑定这个自定义指令的当前dom元素){ 你的逻辑 } }, } <template> <div class="about"> <h1 v-aa>自定义指令</h1> </div> </template> <script> export default { directives:{ "aa":{ // el 指向当前绑定的那个元素 inserted(el){ el.style.color="pink" }}}} </script>
28、Vue中指令有哪些
• v-model 指令主要是用于表单上数据的双向绑定 • v-show 指令控制切换一个元素的显示和隐藏 • v-on 指令为 HTML 元素绑定事件监听 • v-for 指令遍历 data 中的数据,并在页面进行数据展示 • v-bind 指令绑定 HTML 元素的属性 • v-if 指令判断是否加载固定的内容 • v-else 指令必须配合 v-if 使用否则无效,当 v-if 条件不成立的时候执行 • v-else-if 指令当有一项成立时执行 • v-text 指令操作网页元素中的纯文本内容 • v-html 指令输出真正的 HTML • v-once 指令当数据改变时,插值处的内容不会更新(会影响到该节点上的所有 属性)
29、Vue如何定义一个过滤器
• 全局过滤器 o 位置:创建实例之前 main.js o 语法 Vue.filter( '过滤器名称', function(val){//val 表示需要处理的值 return val + 4; //返回处理后的数据 } ) • 局部过滤器 o 只能在当前 vue 注册内容中使用 o 位置:在 vue 实例中与 el 属性 data 属性同级定义62 o 语法 filters: { "过滤器名字":function(val){ return 输出内容 }} • 过滤器的调用方法 o {{msg | 过滤器名称 }} o 注意事项 o 定义全局过滤器,必须放在 vue 实例化前面 o 在没有冲突的前提下,过滤器可以串联
30、对vue 中keep-alive的理解
• 我们不停的切换两个标签页的内容时候,会发现选择好的 内容,切换路由之后会 恢复初始化,也就是说之前的状态丢失。原因是每次切换路由的时候, Vue 都 创建了一个新的组件实例。解决这个问题,我们可以用一个 <keep-alive> 元素 将其路由出口包裹起来。在切换过程中将状态保留在内存中,防止重复渲染 DOM,减少加载时间及性能消耗,提高用户体验性。 • keep-alive 属性 include(包含的组件缓存) <keep-alive include="Democ"> <component :is="com"></component> </keep-alive> o exclude(排除的组件不缓存,优先级大于 include) o keep-alive 的钩子函数 (位置:和 data, methods 同级) o activated 类型: func 触发时机: keep-alive 组件激活时使用; export default { data(){ return{ text:"demoa" }}, activated() { console.log("进入到被 keepalive 管理的组件"); }, deactivated() { console.log("离开了被 keepalive 管理的组件"); }} o deactivated 类型: func 触发时机: keep-alive 组件停用时调用; o 这两个生命周期函数一定是要在使用了 keep-alive 组件之上。
31、如何让组件中的css在当前组件生效
为组件的 style 设置 scoped 属性,表示仅对当前组件设置样式
32、Vue生命周期一共几个阶段
• 它可以总共分为 8 个阶段:创建前/后,载入前/后,更新前/后,销毁前/销毁 后。 o beforeCreate:在 new 一个 vue 实例后,只有一些默认的生命周 期钩子和默认事件,其他的东西都还没创建。在 beforeCreate 生命 周期执行的时候, data 和 methods 中的数据都还没有初始化。不 能在这个阶段使用 data 中的数据和 methods 中的方法。 o created: data 和 methods 都已被初始化好了,如果要调用 methods 中的方法,或者操作 data 中的数据,最早可以在这个阶 段中操作。 o beforeMount:执行到这个钩子的时候,在内存中已经编译好了模板 了,但是还没有挂载到页面中,此时,页面还是旧的。 o mounted:执行到这个钩子的时候,就表示 Vue 实例已经初始化完 成了。此时组件脱离了创建阶段,进入到了运行阶段。如果我们想 要通过插件操作页面上的 DOM 节点,最早可以在这个阶段中进 行。 o beforeUpdate:当执行这个钩子时,页面中的显示的数据还是旧 的, data 中的数据是更新后的,页面还没有和最新的数据保持同 步。 o updated:页面显示的数据和 data 中的数据已经保持同步了,都是 最新的。 o beforeDestory: Vue 实例从运行阶段进入到了销毁阶段,这个时候 所有的 data 和 methods ,指令,过滤器 …… 都是处于可用状 态。还没有真正被销毁。 o destroyed:这个时候所有的 data 和 methods ,指令,过滤 器 ……都是处于不可用状态。组件已经被销毁了
33、Mvvm与mvc的区别
• MVVM 分为三部分:分别是 M(Model,模型层), V(View,视图 层), VM(ViewModel, V 与 M 连接的桥梁,也可以看作为控制器 MVC 的 C 层) o M:模型层,主要负责业务数据相关 o V:视图层,负责视图相关,细分下来就是 html+css 层 o VM: V 与 M 沟通的桥梁,负责监听 M 或者 V 的修改,是实现 MVVM 双向绑定的要点;因此开发者只需关注业务逻辑,不需要手 动操作 DOM,不需要关注数据状态的同步问题,复杂的数据状态维 护完全由 MVVM 来统一管理。 • MVC 封装与业务无关的重复代码,形成框架,是模型(model)-视图 (view)-控制器(controller)的缩写。 o 模型(Model)数据的储存和处理,再传递给视图层相应或者展示64 o 视图(View)前端的数据展示 o 控制器(Controller)对数据的接收和触发事件的接收和传递 • MVC 思想:一种将数据层与视图层进行分离的设计思想 • MVVM 思想: MVVM 的一个重要特性,双向绑定,意思就是当 M 层数 据进行修改时, VM 层会监测到变化,并且通知 V 层进行相应的修改, 反之相同 mvc 和 mvvm 都是一种设计思想。主要就是 mvc 中 Controller 演变成 mvvm 中的 viewModel。 mvvm 主要解决了 mvc 中 大量的 DOM 操作使页面渲染性能降低,加载速度变慢,影响用户体 验
34、Vue组件中的data为什么是函数
组件中的 data 写成一个函数,数据以函数返回值形式定义,这样每复用一 次组件,就会返回一份新的 data,防止组件在复用时产生数据关联关系,类似于给每个组件实例创建一个私有的 数据空间,让各个组件实例维护各自的数据。而单纯的写成对象形式,就使 得所有组件实例共用了一份 data,就会造成一个变了全都会变的结果
35、Vue双向绑定的原理
• 双向绑定原理: vue 数据双向绑定是通过数据劫持结合发布者-订阅者模 式的方式来实现的 O 数据劫持:当我们访问或设置对象的属性的时候,都会触发 Object.defineProperty()函数来拦截(劫持),然后再返回(get)或 设置(set)对象的属性的值,并且当数据发生改变的时候做出反应 O 发布者-订阅者模式:其定义对象间一种一对多的依赖关系,当一个 对象的状态发生改变时,所有依赖它的对象都将得到通知
36、Vue中组件怎么传值
• 父组件向子组件传值(正向传值) 父组件通过 props 向子组件传值, props 是你可以在组件上注册的一些自定义 特性。当一个值传递给一个 props 特性的时候,它就变成了那个组件实例的一 个属性。一个组件默认可以拥有任意数量的 props,任何值都可以传递给任何 props。 • 子组件向父组件传值(逆向传值) O 子组件通过触发事件给父组件的方式进行传值,调用内部的 $emit 方法并传入事件的名字,来向父级组件触发一个事件 O 首先要有事件触发一个函数(子) O 函数抛出自定义事件,携带着子组件的数据(子) O 子组件被调用的时候,使用 v-on 事件调用父组件的一个函数,但是父组件 函数不加()(父) O 父组件函数有一个形参 val,用来接收子组件抛出的数据(父) o 兄弟组件传值 O 创建一个事件总线,例如 demo 中的 eventBus,用它作为通信桥梁65 O 在需要传值的组件中用 bus.$emit 触发一个自定义事件,并传递参数(emit 前加美元符) O 在需要接收数据的组件中用 bus.$on 监听自定义事件,并在回调函数中处 理传递过来的参数
37、Bootstrap的原理
• 通过定义容器大小,平分 12 份(也有平分成 24 份或 32 份,但 12 份是最常 见的),再调整内外边距,最后结合媒体查询,就制作出了强大的响应式网格系 统。 Bootstrap 框架中的网格系统就是将容器平分成 12 份
38、Vue兄弟组件传值
• 传统方法:在需要传值的兄弟组件之上创建一个父组件, A 逆向给父组件,父 组件再正向给 B 组件 • 中央事件总线:在 src 下创建一个文件夹用来存放 xxx.js 文件,在其中只创建 一个新的 vue 实例,以后它就承担起了组件之间通信的桥梁了,也就是中央事 件总线。 O 创建一个事件总线,例如 demo 中的 eventBus,用它作为通信桥梁 O 在需要传值的组件中用 bus.emit 触发一个自定义事件,并传递参数(emit 前加美元符) O 在需要接收数据的组件中用 bus.$on 监听自定义事件,并在回调函数中处 理传递过来的参数
39、如果一个组件在多个项目中使用怎么办
• 方案一: npm 发布引用 公共组件编写完成后,将其发布到 npm。发布流程如下:在注 http://www.npmjs.com 册一个账号进入 common 的控制台,输入命令 npm login,按照提示输入刚注册的账号密码输入命令 npm publish 即可需要用该组 件的项目通过 npm install 命令将公共组件以 node_module 的方式引入。另 外,每次改动代码再次发布时,需要修改 package.json 文件中的版本号,不然 发布不成功。 • 方案二: npm link 首先进入公共包,在控制台输入 npm link 这会创建一个软连接,并保存到目录 C:\Users\Administrator\AppData\Roaming\npm\node_mo dules 下面。然后进入 使用该公共组件的项目,在控制台输入 npm link common • 方案三: npm 本地 file 引用(推荐) 进入使用该公共项目的文件夹,在控制台输入命令: npm install ../common/ 其 中…/common/是 common 的相对路径,这里也可以输入绝对路径这样就将 common 这个工程以 node_module 的方式引入到需要使用的项目中了。可以 正常使用公共项目在 index.js 中导出的组件了。命令执行完后, package.json 里会多一条记录
40、槽口请简述
• 它是一种内容分发机制,用来混合父组件的内容与子组件自己的模板(给组件设 置一个开口,让他在调用的时候可以在里面插入数据。 • 使用:数量相同、内容不同的时候组件使用 props,数量不同、内容也不相同的 时候使用 slot。
41、Watch请简述
watch 可以监听模型数据,当模型数据改变的时候就会触发。 watch 初始化 的时候不会运行,只有数据被改变之后才会运行。当需要在数据变化时执行 异步或开销较大的操作时, watch 这个方式是最有用的。 语法: watch:{ // newval 就是改变之后的值 oldval就是之前的旧数据 你要监听的数据(newval,oldval){ } }
42、Vantui请简述下
Vant 是一个轻量、可靠的移动端 Vue 组件库,通过 Vant,可以快速搭建出 风格统一的页面,提升开发效率。作为移动端组件库, Vant 一直将轻量化作 为核心开发理念。为了平衡日益丰富的功能和轻量化之间的矛盾关系, Vant 内部使用了很多的优化方式,包括支持组件按需加载、公共模块复用、组件 编译流程优化等。 Vant 不只是提供基础的 UI 组件,为了方便开发者快速构 建移动商城, Vant 增加了许多移动商城内常用的业务组件。
43、计算属性与watch区别
通俗来讲,既能用computed 实现又可以用 watch 监听来实现的功能,推荐用 computed,重点在于 computed 的缓存功能computed计算属性是用来声明式的描述一个值依赖了其它的值,当所依赖的值或者变量改变时,计算属性也会跟着改变; watch 监听的是已经在 data 中定义的变量,当该变量变化时,会触发 watch 中的方法; watch 监听一个data数据 当这个data数据改变的时候 watch就会触发一个函数完成一些指定的功能(异步操作 开销较大的逻辑) 计算属性 依赖一个data的数据 当这个数据改变了他会重新计算这个数据返回结果
44、Watch首次会触发吗?怎么让他第一次就触发?
首次加载执行函数需通过其immediate 属性进行配置,默认为false 监听数组值变化需通过其deep属性进行配置,默认为false watch:{ "aaa":{ immediate:true, // 首次加载的时候执行函数 deep:true, // 深入观察,监听数组值,对象属性值的变化 handler:function(){ } }
45、mvvm框架是什么?它和其它框架(jquery)的区别是什么?哪些场景适合?
• 定义: MVVM 分为三部分:分别是 M(Model,模型层), V(View,视图 层), VM(ViewModel, V 与 M 连接的桥梁,也可以看作为控制器 MVC 的 C 层) M:模型层,主要负责业务数据相关, V:视图层,负责视图相关,细分下 来就是 html+css 层, VM: V 与 M 沟通的桥梁,负责监听 M 或者 V 的修 改,是实现 MVVM 双向绑定的要点;因此开发者只需关注业务逻辑,不需要手 动操作 DOM,不需要关注数据状态的同步问题,复杂的数据状态维护完全由 MVVM 来统一管理。 • 区别: vue 数据驱动,通过数据来显示视图层而不是节点操作。 • 场景:数据操作比较多的场景,更加便捷
46、Vue首屏加载慢的原因,怎么解决的,白屏时间怎么检测,怎么解决白屏问题
• 加载慢的原因:因为路由的项目在第一次加载的时候会默认把所有的组件页面都 进行渲染,如果页面多的话,加载太多,造成用户在进入项目的时候等待时间过 久,出现白屏。 • 检测白屏: • 解决:白屏时间指的是浏览器开始显示内容的时间。因此我们只需要知道是浏览 器开始显示内容的时间点,即页面白屏结束时间点即可获取到页面的白屏时间。 我们通常认为浏览器开始渲染 <body> 标签或者解析完 <head> 标签的时刻就 是页面白屏结束的时间点。 因此白屏时间则可以这样计算出:67 O 可使用 Performance API 时 O 白屏时间 = firstPaint - performance.timing.navigationStart; O 不可使用 Performance API 时 O 白屏时间 = firstPaint - pageStartTime; • 路由懒加载 ES 中的 import(推荐) { path: '/', name: 'Home', //路由懒加载 component: () => import ('../views/Home.vue') } vue 异步组件懒加载-- resolve:主要是使用了 Promise.resolve()的异步机制,用 require 代替了 import, 实现按需加载 • gzip 压缩:方法一:使用 Nginx 反向代理,配置 nginx.conf 文件;方法二: 使用 node 压缩,需要使用 compression 库; • 使用 webpack 的 externals 属性把不需要打包的库文件分离出去,减少打包后 文件的大小 • 使用 vue 的服务端渲染(ssr) ssr 优点是 seo 优化,以及加快首屏加载 路由懒加载 1. import导入 component: () => import('你要显示路由的页面路径') 2. 异步组件 component: (resolve) => require(['你要显示的路由页面路径即可'], resolve),
47、Vue双向数据绑定过程中,这边儿数据改变了怎么通知另一边改变
使用 Object.defineProperty()来定义属性的 set 函数,属性被赋值的时候,修改 Input 的 value 值,然后监听 input 的 keyup 事件,修改对象的属性值,即可实现 这样的一个简单的数据双向绑定。
48、Vuex流程
• 在 vue 组件里面,通过 this.$store.dispatch 来触发 actions 执行异步操作获取 数据。 • 然后再通过 store.commit 来触发 mutations 来修改数据。 • mutations 接收到 commit 的请求,就会自动修改 state(数据中心里面的数据 状态)里面的数据。 • 最后由 store 触发每一个调用它的组件进行更新
49、Vuex怎么请求异步数据
• 在 store 文件中引入 import axios from "axios" • 通过事件触发 active <button @click="fun()">点我发送请求</button> export default { methods: { fun(){ this.$store.dispatch("ajaxdemo")68 }},} • 创建 actions 并进行异步请求,并且调用 Mutations 修改 state 数据 mutations: { uparr(state, payload) { state.arr = payload }}, actions: { ajaxdemo(store) { axios({ url:"http://api.artgoer.cn:8084/artgoer/api/v1/user/324380/v3/topic/top icHomeByLabel?pageIndex=1&token=b544cd63-6d42-46fe-a96c-3cf96b ae3113&topicId=62187", method: "get" }).then((ok) => { console.log(ok); store.commit("uparr", ok.data.data.commentList)
50、Vuex中action如何提交给mutation的
vuex 的 acions 创建一个方法进行异步操作,他的形参就是 store 对象,把请求来 的数据通过 commit()传递给 mutations actions: { axioslink(store) { demoapi.demo().then((ok) => { console.log(ok.data.data.commentList); // 把请求来的数据给 mutations 进行 state 的修改 store.commit("uparr", ok.data.data.commentList) })}}
51、Route与router区别
• $router 是 VueRouter 的一个对象, router 的实例对象,这个对象是一个全局 的对象,他包含了所有的路由包含了许多关键的对象和属性。举例: history 对 象 • $route 是一个跳转的路由对象,每一个路由都会有一个 route 对象,是一个局 部的对象,可以获取对应的 name,path,params,query 等
52、vuex有哪几种状态和属性
有五种,分别是 State , Getter , Mutation , Action , Module (就是 mapAction)
53、vuex的State特性是?
• state 就是存放数据的地方,类似一个仓库 , 特性就是当 mutation 修改了 state 的数据的时候,他会动态的去修改所有的调用这个变量的所有组件里面的 值(若是 store 中的数据发生改变,依赖这个数据的组件也会发生更新) • state: vuex 中的数据源 state,我们需要保存的数据就保存在这里(用来存 储数据)69 O 使用: 1. 可以使用$store.state.xx 调用 {{this.$store.state.name}} 2. 使用数据的组件中使用计算属性调用 this.$store.state.xxx computed:{ obj(){ return this.$store.state.obj }} O state 里面存放的数据是响应式的, Vue 组件从 store 中读取数据,若是 store 中的数据发生改变,依赖这个数据的组件也会发生更新 O 它通过 mapState 把全局的 state 和 getters 映射到当前组件的 computed 计算属性中
54、vuex的Getter特性是?
• getters:相当于之前组件中学习的计算属性,getters 属性主要是对于 state 中数 据的一种过滤 O 使用场景:在项目开发中,有时候希望对 state 中的某个属性在多个组件中 展示出不同状态 O 与使用 state 相同在组件中的计算属性当中使用 this.$store.getters.xxx 来 进行调用 O 语法 getters: { nameone(state) { return state.name.toUpperCase() }, nametwo(state) { return state.name.substr(0, 2) }} <p>{{this.$store.getters.nameone}}</p> <p>{{this.$store.getters.nametwo}}</p>
55、vuex的Mutation特性是?
• mutations:里面装着一些改变数据方法的集合,就是把处理数据逻辑方法全部放 在 mutations 里面,当触发事件的时候想改变 state 数据的时候使用 mutations(在 vuex 中如果想进行数据的修改,必须在 mutations 中进行操 作) O 语法 mutations: { upone(state) { //创建一个方法,且必须有一个形参,对应要修改的那个 数据 state state.name = "haha" }} O 不能直接调用一个 mutations 中的处理函数要使用 this.$store.commit()来 进行调用。70 methods:{ fun(){ //调用 mutations 的 commit()函数 this.$store.commit("upone") }} O 之前的只是一个简单的修改 state 中的属性,在实际项目中往往会有值传递 给 mutations,给 store.commit 传一个附加参数,他就叫做 mutation 的载 荷,一般使用 payload mutations: { uptwo(state, payload) { state.name = payload }} methods:{ funb(){ // this.$store.commit("uptwo",把要传递给 mutations 的数据放到这里) this.$store.commit("uptwo",this.inputval) }} O 如果要传多个参数,可以传递一个对象 this.$store.commit('add',{'name':'lxg','num':20...})
56、vuex的actions特性是?
actions:进行异步操作(异步请求) 语法 actions: { axioslink(store) { demoapi.demo().then((ok) => { console.log(ok.data.data.commentList); // 把请求来的数据给 mutations 进行 state 的修改 store.commit("uparr", ok.data.data.commentList) })}}, methods:{ func(){ //调用 actions 来进行异步请求 this.$store.dispatch("axioslink") } } mutations: { uparr(state, payload) { state.arr = payload }}
57、vuex 是什么?怎么使用?哪种功能场景使用它
• Vuex 是一个专为 Vue.js 应用程序开发中管理的一个模式。通过创建一个集中 的数据存储,方便程序中的所有组件进行访问。 • 使用: 在 store 下的 index.js 中 Vue.use(Vuex) 创建 store 实例 javascript71 export default new Vuex.Store({ state: {}, mutations: {}, actions: {}, modules: {} }) • vuex 只能用于单个页面中不同组件(例如兄弟组件)的数据流通。
58、vuex的优势
• 解决了非父子组件的消息传递(将数据存放在 state 中) o 减少了 AJAX 请求次数,有些情景可以直接从内存中的 state 获取 • 双向绑定,使用 commit 修改一处状态后,所有引用的地方自动更新,不需要 传值
59、Vue路由懒加载(按需加载路由)
• 懒加载简单来说就是延迟加载或按需加载,即在需要的时候进行加载。为给客户 更好的客户体验,首屏组件加载速度更快,解决白屏问题,当构建的项目比较大 的时候,懒加载可以分割代码块,提高页面的初始加载效率。 • 使用 component O vue 异步组件懒加载:主要是使用了 Promise.resolve()的异步机制,用 require 代替了 import,实现按需加载: resolve=>(require(["引用的组件路径"], O ES 中的 import(推荐): const HelloWorld = () =>import(' 需要加载的模块地址')
60、Vuex数据修改刷新丢失怎么解决?
办法一:将vuex中的数据直接保存到浏览器缓存中(sessionStorage、localStorage、cookie) 办法二:在页面刷新的时候再次请求远程数据,使之动态更新vuex数据 办法三:在父页面向后台请求远程数据,并且在页面刷新前将vuex的数据先保存至sessionStorage(以防请求数据量过大页面加载时拿不到返回的数据)
61、Vue与react区
1、监听数据变化的实现原理不同 Vue 通过 getter/setter 以及一些函数的劫持,能精确知道数据变化,不需要特别的优化就能达到很好的性能 React 默认是通过比较引用的方式进行的,如果不优化(PureComponent/shouldComponentUpdate)可能导致大量不必要的VDOM的重新渲染 为什么 React 不精确监听数据变化呢? 这是因为 Vue 和 React 设计理念上的区别,Vue 使用的是可变数据,而React更强调数据的不可变。所以应该说没有好坏之分,Vue更加简单,而React构建大型应用的时候更加鲁棒。 因为一般都会用一个数据层的框架比如 Vuex 和 Redux,所以这部分不作过多解释,在最后的 vuex 和 redux的区别 中也会讲到。 2、数据流的不同 大家都知道Vue中默认是支持双向绑定的。在Vue1.0中我们可以实现两种双向绑定: 父子组件之间,props 可以双向绑定 组件与DOM之间可以通过 v-model 双向绑定 在 Vue2.x 中去掉了第一种,也就是父子组件之间不能双向绑定了(但是提供了一个语法糖自动帮你通过事件的方式修改),并且 Vue2.x 已经不鼓励组件对自己的 props 进行任何修改了。 所以现在我们只有 组件 <--> DOM 之间的双向绑定这一种。 然而 React 从诞生之初就不支持双向绑定,React一直提倡的是单向数据流,他称之为 onChange/setState()模式。 不过由于我们一般都会用 Vuex 以及 Redux 等单向数据流的状态管理框架,因此很多时候我们感受不到这一点的区别了。 3、HoC 和 mixins 在 Vue 中我们组合不同功能的方式是通过 mixin,而在React中我们通过 HoC (高阶组件)。 React 最早也是使用 mixins 的,不过后来他们觉得这种方式对组件侵入太强会导致很多问题,就弃用了 mixinx 转而使用 HoC,关于mixin究竟哪里不好,可以参考React官方的这篇文章 Mixins Considered Harmful 而 Vue 一直是使用 mixin 来实现的。 为什么 Vue 不采用 HoC 的方式来实现呢? 高阶组件本质就是高阶函数,React 的组件是一个纯粹的函数,所以高阶函数对React来说非常简单。 但是Vue就不行了,Vue中组件是一个被包装的函数,并不简单的就是我们定义组件的时候传入的对象或者函数。比如我们定义的模板怎么被编译的?比如声明的props怎么接收到的?这些都是vue创建组件实例的时候隐式干的事。由于vue默默帮我们做了这么多事,所以我们自己如果直接把组件的声明包装一下,返回一个高阶组件,那么这个被包装的组件就无法正常工作了。 推荐一篇很棒的文章讲的是vue中如何实现高阶组件 探索Vue高阶组件 4、组件通信的区别 其实这部分两个比较相似。 在Vue 中有三种方式可以实现组件通信: 父组件通过 props 向子组件传递数据或者回调,虽然可以传递回调,但是我们一般只传数据,而通过 事件的机制来处理子组件向父组件的通信 子组件通过 事件 向父组件发送消息 通过 V2.2.0 中新增的 provide/inject 来实现父组件向子组件注入数据,可以跨越多个层级。 另外有一些比如访问 $parent/$children等比较dirty的方式这里就不讲了。 在 React 中,也有对应的三种方式: 父组件通过 props 可以向子组件传递数据或者回调 可以通过 context 进行跨层级的通信,这其实和 provide/inject 起到的作用差不多。 可以看到,React 本身并不支持自定义事件,Vue中子组件向父组件传递消息有两种方式:事件和回调函数,而且Vue更倾向于使用事件。但是在 React 中我们都是使用回调函数的,这可能是他们二者最大的区别。 5、模板渲染方式的不同 在表层上, 模板的语法不同 React 是通过JSX渲染模板 而Vue是通过一种拓展的HTML语法进行渲染 但其实这只是表面现象,毕竟React并不必须依赖JSX。 在深层上,模板的原理不同,这才是他们的本质区别: React是在组件JS代码中,通过原生JS实现模板中的常见语法,比如插值,条件,循环等,都是通过JS语法实现的 Vue是在和组件JS代码分离的单独的模板中,通过指令来实现的,比如条件语句就需要 v-if 来实现 对这一点,我个人比较喜欢React的做法,因为他更加纯粹更加原生,而Vue的做法显得有些独特,会把HTML弄得很乱。举个例子,说明React的好处: react中render函数是支持闭包特性的,所以我们import的组件在render中可以直接调用。但是在Vue中,由于模板中使用的数据都必须挂在 this 上进行一次中转,所以我们import 一个组件完了之后,还需要在 components 中再声明下,这样显然是很奇怪但又不得不这样的做法。 6、Vuex 和 Redux 的区别 从表面上来说,store 注入和使用方式有一些区别。 在 Vuex 中,$store 被直接注入到了组件实例中,因此可以比较灵活的使用: 使用 dispatch 和 commit 提交更新 通过 mapState 或者直接通过 this.$store 来读取数据 在 Redux 中,我们每一个组件都需要显示的用 connect 把需要的 props 和 dispatch 连接起来。 另外 Vuex 更加灵活一些,组件中既可以 dispatch action 也可以 commit updates,而 Redux 中只能进行 dispatch,并不能直接调用 reducer 进行修改。 从实现原理上来说,最大的区别是两点: Redux 使用的是不可变数据,而Vuex的数据是可变的。Redux每次都是用新的state替换旧的state,而Vuex是直接修改 Redux 在检测数据变化的时候,是通过 diff 的方式比较差异的,而Vuex其实和Vue的原理一样,是通过 getter/setter来比较的(如果看Vuex源码会知道,其实他内部直接创建一个Vue实例用来跟踪数据变化) 而这两点的区别,其实也是因为 React 和 Vue的设计理念上的区别。React更偏向于构建稳定大型的应用,非常的科班化。相比之下,Vue更偏向于简单迅速的解决问题,更灵活,不那么严格遵循条条框框。因此也会给人一种大型项目用React,小型项目用 Vue 的感觉。
62、简述下$set
出现的场景是 如果我们在vue中向data定义的数组获取对象中添加新的属性的时候 就会出现数据变了但是视图没有发生改变 原因 :因为双向绑定中 依赖数据劫持(object.defineProperty()) 数据劫持有一个非常大的bug **他只会劫持初始化的时候data有的数据** 但是当程序运行之后 在给data的属性插入新的内容的时候 由于数据劫持劫持不到 就没有双向绑定了 没有双向绑定了 当然数据变了视图不会发生改变 $set的使用 所以我们为了解决这种数据变视图不发生改变的问题 我们使用$set来解决 语法: this.$set( 你要操纵的数据,新增的key,新增的val ) fun(){ // this.obj.age=18 // $set来进行添加新属性 this.$set(this.obj,"age",666) console.log(this.obj.age); }
63、v-for与v-if优先级
首先不要把 v-if 与 v-for 用在同一个元素上,原因: v-for 比 v-if 优先,如果每一 次都需要遍历整个数组,将会影响速度,尤其是当之需要渲染很小一部分的时候, v-for 比 v-if 具有更高的优先级
64、Vue nextTick是什么?
会在dom加载完毕之后 立即执行的一个方法 为了在数据变化之后等待 Vue 完成更新 DOM 可以在数据变化之后立即使用 Vue.nextTick(callback)。这样回调函数在 DOM 更新完成后就会调用。在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后 的 DOM。 在 Vue 生命周期的 created()钩子函数进行 DOM 操作一定要放到 Vue.nextTick()的 回调函数中。 created()钩子函数执行的时候, DOM 其实并未进行任何渲染。所以 此处一定要将 DOM 操作的 js 代码放进 Vue.nextTick()的回调函数中。在数据变化 后要执行的某个操作,而这个操作需要使用随数据改变而改变的 DOM 结构的时 候,这个操作都应该放进 Vue.nextTick()的回调函数中 created(){ // console.log(this.$refs.demoh.innerText); this.$nextTick(()=>{ console.log(this.$refs.demoh.innerText); }) },
65、Vue 项目如何性能优化
路由懒加载 路由懒加载就是按需加载,不会让项目刚开始运行速度就很慢,能大大的优化用户体验 图片懒加载插件(安装插件vue-lazyload) <img v-lazy="1.jpg"> 代码优化 O 封装组件和函数,提高代码复用率 O 减少本地存储的使用 O 减少 watch 使用:watch 监听大量状态时会让浏览器出现卡顿 O 使用 v-if 代替 v-show :用户体验优化 O 添加 loading(等待动画):当用户需要等待时间较长时,必须添加等待 loading O 路由逻辑 O 样式统一 O 滚动组件的使用
66、打包上线的流程?
1.npm run build命令打包 但是会发现打包之后资源路径有问题 2.修改静态资源路径 publicPath module.exports={ // 注意位置 // 注意位置 publicPath:"./", devServer:{ open:true,//自动开启浏览器 port:8888, //修改端口 proxy:{ "/api":{ target:"http://www.weather.com.cn", changeOrigin:true, "pathRewrite":{ "^/api":"/" } } }, } } 3.修改路由模式为hash 服务器上线流程 服务器购买与连接 1. 在ECS实例列表页面,选择实例的所属地域。 2. 找到目标实例,然后在操作列选择**【**更多**】**> **【**密码/密钥**】** > 【重置实例密码**】**,然后在弹出的对话框设置ECS实例的登录密码 3. 在弹出的页面,单击【立即重启】使新密码生效。 4. 在ECS实例列表页面,复制ECS实例的公网IP地址。 5. 连接远程桌面
67、路由的更多属性
我们给路由的规则中添加一个meta的对象 那么就可以在其中存储一些信息 在页面进行使用
{ path: '/phone', name: 'phone', component: () => import('../views/phone.vue'), // meta元信息 meta:{ text:"我是路由中的meta信息" } }
在当前页面中使用这个meta信息
this.$route.meta.xxx
在组件内获取路由全部规则
this.$router.options.routes
68、父子组件钩子函数执行先后顺序
加载渲染过程 父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父mounted 子组件更新过程 父beforeUpdate->子beforeUpdate->子updated->父updated 父组件更新过程 父beforeUpdate->父updated 销毁过程 父beforeDestroy->子beforeDestroy->子destroyed->父destroyed
69、v-if 和 v-show 的区别
区别
v-if 在编译过程中会被转化成三元表达式,条件不满足时不渲染此节点。
v-show 会被编译成指令,条件不满足时控制样式将此节点隐藏(display:none)
使用场景
v-if 适用于在运行时很少改变条件,不需要频繁切换条件的场景。
v-show 适用于需要非常频繁切换条件的场景。
扩展补充:display:none 、 visibility:hidden 和 opacity:0 之间的区别?
三者公共点都是隐藏。
不同点:
-
一、是否占据空间。 display:none,隐藏之后不占位置;visibility:hidden、opacity:0,隐藏后任然占据位置。
-
二、子元素是否继承。 display:none --- 不会被子元素继承,父元素都不存在了,子元素也不会显示出来。 visibility:hidden --- 会被子元素继承,通过设置子元素 visibility:visible 来显示子元素。 opacity:0 --- 会被子元素继承,但是不能设置子元素 opacity:0 来先重新显示。
-
三、事件绑定。 display:none 的元素都已经不存在了,因此无法触发他绑定的事件。 visibility:hidden 不会触发他上面绑定的事件。 opacity:0 元素上面绑定的事件时可以触发的。
-
四、过度动画。 transition对于display是无效的。 transition对于visibility是无效的。 transition对于opacity是有效的。
70、Proxy 与 Object.defineProperty 优劣对比
1.Proxy 可以直接监听对象而非属性; 2.Proxy 可以直接监听数组的变化; 3.Proxy 有多达 13 种拦截方法,不限于 apply、ownKeys、deleteProperty、has 等等是 Object.defineProperty 不具备的; 4.Proxy 返回的是一个新对象,我们可以只操作新的对象达到目的,而 Object.defineProperty 只能遍历对象属性直接修改; 5.Proxy 作为新标准将受到浏览器厂商重点持续的性能优化,也就是传说中的新标准的性能红利; 6.Object.defineProperty 的优势如下: 兼容性好,支持 IE9,而 Proxy 的存在浏览器兼容性问题,而且无法用 polyfill 磨平,因此 Vue 的作者才声明需要等到下个大版本( 3.0 )才能用 Proxy 重写。
71、vue2和vue3比较
一.vue3新特性:
1.数据响应重新实现(ES6的proxy代替Es5的Object.defineProperty)
2.源码使用ts重写,更好的类型推导
3.虚拟DOM新算法(更快,更小)
4.提供了composition api,为更好的逻辑复用与代码组织
5.自定义渲染器(app、小程序、游戏开发)
6.Fragment,模板可以有多个根元素
二.vue2 vue3响应原理对比
1.vue2使用Object.defineProperty方法实现响应式数据
2.缺点:
无法检测到对象属性的动态添加和删除
无法检测到数组的下标和length属性的变更
3.解决方案:
vue2提供Vue.$set动态给对象添加属性
Vue.$delete动态删除对象属性
重写数组的方法,检测数组变更
------------------------------------------------------------------------------------
1.vue3使用proxy实现响应式数据
2.优点:
可以检测到代理对象属性的动态新增和删除
可以见到测数组的下标和length属性的变化
3.缺点:
es6的proxy不支持低版本浏览器 IE11
回针对IE11出一个特殊版本进行支持
四、React
1、请简述你对react的理解
• 定义: React 起源于 Facebook; React 是一个用于构建用户界面的 javascript 库。 React 拥有较高的性能,代码逻辑非常简单,越来越多的人已开始关注和使 用它
• | 特点 |
---|---|
O | 声明式设计 -React 采用声明范式,可以轻松描述应用。(开发者只需要声 明显示内容, react 就会自动完成) |
O | 高效 -React 通过对 DOM 的模拟,最大限度地减少与 DOM 的交互。 |
O | 灵活 -React 可以与已知的库或框架很好地配合组件 - 通过 React 构建组件,使得代码更加容易得到复用,能够很好的应用在大项目的开发中。(把页面的功能拆分成小模块--每个小模块就是组件) |
O | 单向数据流 -React 是单向数据流,数据主要从父节点传递到子节点(通过 props)。如果顶层(父级)的某个 props 改变了, React 会重渲染所有的 子节点 |
• | 核心: |
O | React 的核心就是组件:组件的设计目的是提高代码复用率,降低测试难度和代码的复杂程度 |
• | 优点 |
---|---|
O | 它提高了应用的性能 |
O | 可以方便地在客户端和服务器端使用 |
O | 由于 JSX,代码的可读性很好 |
O | React 很容易与 Meteor, Angular 等其他框架集成 |
O | 使用 React,编写 UI 测试用例变得非常容易 |
O | React 推荐在 React 中使用 JSX 来描述用户界面。当遇到<>, JSX 就当 HTML 解析,遇到{}就当 JavaScript 解析 |
2、State与props区别
O | state: |
---|---|
O | state 就是状态,它只是用来控制这个组件本身自己的状态,我们可以用 s tate 来完成对行为的控制、数据的更新、界面的渲染,由于组件不能修改传 入的 props,所以需要记录自身的数据变化 要想修改 state 中的数据,可以使用 setState(),setState() 是异步的会自动触发 render 函数的重新渲染 |
props: | |
---|---|
O | props 是组件对外的接口,使用 props 就可以从外部向组件内部进行数据 传递完成父组件传值给子组件 props 对于使用它的组件来说,是只读的。 |
O | 一旦赋值不能修改。也就是说 props 的值是不可变的,只能在渲染的时候传入,无法动态赋值。 |
3、组件之间的数据传递
• 正向传值--使用 props |
---|
父组件发送数据在子组件中使用 this.props.xxx 来接收数据,如果父级的某个 props 改变了, React 会重渲染所有的子节点 |
•逆向传值---函数传值 |
O 子组件通过事件调用函数传递 |
O 在子组件中使用 this.props.调用的函数名绑定发送数据 |
O 在父组件中进行函数传递 |
O 父组件中必须要有一个形参用来接收子组件发送过来的数据 |
• | 同级传值---pubsub-js |
---|---|
O | 在第一个要传值的组件中进行数据抛出 PubSub.publish("事件名","数据") |
O | 在第二个要接收数据的组件中接收 PubSub.subscribe("监听的事件",(事件,数 据)=>{}) |
• | 跨组件传值---context |
O | context 上下文对象,无需为每一层组件手动添加 props,就能在组件数间 进行数据传递的方法 使用 createContext()方法提供了两个对象 - Provider 对象生产者---->用来 生产数据 - Consumer 对象消费者---->用来使用数据 |
4、Vue与react区别
• | 相似之处 |
---|---|
O | 他们都是 JavaScript 的框架,专注于创造前端的数据应用。 不同于早期的 JavaScript 框架“功能齐全”, Reat 与 Vue 只有框架的骨架, 其他的功能如路由、状态管理等是框架分离的组件。 |
O | 都使用了虚拟 DOM, Virtual DOM 是一个映射真实 DOM 的 JavaScript 对象,如果需要改变任何元素的状态,那么是先在 Virtual DOM 上进行改变,而不是直接改变真实的 DOM。当有变化产生时,一个新的 VirtualDOM 对象会被创建并计算新旧 Virtual DOM 之间的差别,之后这些差别会应用在真实的 DOM 上。 |
O | 组件化 React 与 Vue 都鼓励组件化应用 |
---|---|
O | Props React 和 Vue 都有'props'的概念, props 在组件中是一个特殊的属 性,允许父组件往子组件传送数据。 |
O | 构建工具 React 和 Vue 都有自己的构建工具, 你可以使用它快速搭建开发 环境。 |
O | 区别 |
O | 数据 |
O | vue:双向数据绑定和单向数据流。双向数据绑定: DOM 元素绑定的 data 值,当发生改变后, vue 的响应式机制会自动监听 data 的变化重新 渲染。单向数据流:当父组件给子组件传递数据的时候,子组件只可以读取 而不能修改数据。可以用 watch 监听数据的更改,再赋给父组件的变量。 |
react:单向数据流。 DOM 元素依赖于 state,但改变 state 不会改变渲染 好的 DOM,通过 setState() 才能重新渲染。父组件传值到子组件,如果顶 级的 props 变了,会重新渲染所有的子组件。 |
O | 虚拟 DOM |
---|---|
O | vue:计算出虚拟 DOM 的差异,在渲染的过程中跟踪每个组件的依赖关 系,不会重新渲染整个组件树 react:当应用的状态改变时,重新渲染全部子组件,可以通过 s houldComponentUpdate 生命周期进行优化 模板和 jsx: |
O | vue:具有单文件组件,可以把 html、 css、 js 写在一个 vue 文件里---- MVVM 框架 |
O | react:依赖于 jsx,在 JavaScript 中创建 DOM---视图层框架 |
5、请简述虚拟dom与diff算法
简述 | |
---|---|
虚拟 dom | 虚拟 dom 相当于在 js 和真实 dom 中间加了一个缓存。基于React 进行开发时所有的 DOM 构造都是通过虚拟 DOM 进行,每当数据变化时, React 都首先重新构建整个 DOM 树(减少页面更新次数),然后 React 将当前整个 DOM 树和上一次的 DOM 树进行对比(DOM Diff 算法-最小化页面重绘),得到 DOM 结构的区别,然后仅仅将需要变化的部分进行实际的浏览器DOM 更新 |
diff 算法 | diff 算法是调和的具体实现,将 Virtual(虚拟)DOM 树转换成actual(真实)DOM 树的最少操作的过程称为调和, diff 算法的作用计算出虚拟DOM 中真正变化的部分,并只针对该部分进行原生 DOM 操作,而非重新渲染整个页面 |
6、你对组件的理解
React 的核心就是组件:组件的设计目的是提高代码复用率,降低测试难度和代码的复杂程度。 | |
---|---|
o | 提高代码复用率:组件将数据和逻辑进行封装。 |
o | 降低测试难度:组件高内聚低耦合(各个元素高集成度低关联性),很容易对单个组件进行测试。 |
o | 代码的复杂程度:直观的语法,可以极大提高可读性 |
7、调用 setState 之后发生了什么?
在代码中调用 setState 函数之后, React 会将传入的参数对象与组件当前的状态合并,然后触发所谓的调和过程(Reconciliation)。 经过调和过程, React 会以相对高效的方式根据新的状态构建 React 元素树并且着手重新渲染整个 UI 界面。在 React得到元素树之后, React 会自动计算出新的树与老树的节点偏差,然后根据差异对界面进行最小化重渲染。在差异计算算法中, React 能够相对精确地知道哪些位置发生了改变以及应该如何改变,这就保证了按需更新,而不是全部重新渲染。
8、SetState是同步还是异步的?怎么拿到最新修改的值?
能紧随其后拿到结果的可以认为同步(简单理解哈,一些场景暂不考虑,就像有一些属于异步的但是异步任务刚好都结束了,直接拿到了对应的结果等) 至于异步,他添加在异步队列,不影响同步任务的执行,在所有的同步任务执行完它才会按照顺序开始执行队列里面的任务,有一个等待的过程 想要拿到我们改变后的值可以利用setState第二个传入的回调函数获取 add () { this.setState({ count:10 },()=>{ // 这里是可以拿到的 console.log(this.state.count) }) }
9、循环中的key为什么不建议用便利的下标
用index作为key可能会引发的问题: 1. 若对数据进行:逆序添加、逆序删除等破坏顺序操作: 会产生没有必要的真实DOM更新 ==> 界面效果没问题, 但效率低。 2. 如果结构中还包含输入类的DOM: 会产生错误DOM更新 ==> 界面有问题。 3. 注意!如果不存在对数据的逆序添加、逆序删除等破坏顺序操作, 仅用于渲染列表用于展示,使用index作为key是没有问题的。
10、React创建组件的方式有哪些?
函数式定义的无状态组件 es5原生方式React.createClass定义的组件 es6形式的extends React.Component定义的组件
详见:React创建组件的三种方式及其区别 - wonyun - 博客园
11、函数组件与类组件的区别?
1. 语法上的区别: 函数式组件是一个纯函数,它是需要接受props参数并且返回一个React元素就可以了。类组件是需要继承React.Component的,而且class组件需要创建render并且返回React元素,语法上来讲更复杂。 2. 调用方式 函数式组件可以直接调用,返回一个新的React元素;类组件在调用时是需要创建一个实例的,然后通过调用实例里的render方法来返回一个React元素。 3. 状态管理 函数式组件没有状态管理,类组件有状态管理。 4. 使用场景 类组件没有具体的要求。函数式组件一般是用在大型项目中来分割大组件(函数式组件不用创建实例,所有更高效),一般情况下能用函数式组件就不用类组件,提升效率。
12、Props与state的区别?
• | State 是一种数据结构,用于组件挂载时所需数据的默认值。 State 可能会随着时间的推移而发生突变,但多数时候为用户事件行为的结果。 |
---|---|
• | Props(properties 的简写)则是组件的配置。 props 由父组件传递给子组件,并且就子组件而言, props 是不可变的(immutable)。组件不能改变自身的 props,但是可以把其子组件的 props 放在一起(统一管理)。 Props 也不仅仅是数据-回调函数也可以通过 props 传递。 |
13、react 生命周期函数
• | React 生命周期分为三种状态:挂载阶段、更新阶段、卸载阶段 |
---|---|
o | 始化阶段: |
o | getDefaultProps:获取实例的默认属性 |
o | getInitialState:获取每个实例的初始化状态 |
o | componentWillMount: 组件即将被装载、渲染到页面上 |
o | render:组件在这里生成虚拟的 DOM 节点 |
o | componentDidMount:组件真正在被装载之后 |
• | 运行中状态: |
---|---|
o | componentWillReceiveProps:组件将要接收到属性的时候调用 |
o | shouldComponentUpdate:组件接受到新属性或者新状态的时候(可以返回 false,接收数据后不更新,阻止 render 调用,后面的函数不会被继续执行了) |
o | componentWillUpdate:组件即将更新不能修改属性和状态 o render:组件重新描绘 |
o | componentDidUpdate:组件已经更新 |
• | 销毁阶段 |
---|---|
o | componentWillUnmount:组件即将销毁 |
14、高阶组件HOC是什么 什么地方使用过?
• 参数是组件同时返回值也是组件 • 作用:封装可以在组件中高度复用的代码 • 高阶组件 HOC 接收 props o 如果组件是被高阶组件导出的那么在正向传值的时候需要在高阶组件中进行 传递 • 反向继承 o 作用:渲染劫持,按照条件选择性的给用户输出想要的内容 o super.render()是调用父类的 render()渲染
15、为什么虚拟 dom 会提高性能?(必考)
• 虚拟 dom 相当于在 js 和真实 dom 中间加了一个缓存,利用 dom 的 diff 算法避免了没有必要的 dom 操作,从而提高性能。 • 用 JavaScript 对象结构表示 DOM 树的结构;然后用这个树构建一个真正的DOM 树,插到文档当中,当状态变更的时候,重新构造一棵新的对象树。然后用新的树和旧的树进行比较,记录两棵树差异把 2 所记录的差异应用到步骤 1 所构建的真正的 DOM 树上,视图就更新了。
16、shouldComponentUpdate 是做什么的
判定组件是否要更新 html 主要用于性能优化(部分更新)唯一用于控制组件重新渲染的生命周期,由于在 react 中, setState 以后, state 发生变化,组件会进入重新渲染的流程,在这里 return false 可以阻止组件的更新
17、react diff 原理
• 把树形结构按照层级分解,只比较同级元素。 • 给列表结构的每个单元添加唯一的 key 属性,方便比较。 • React 只会匹配相同 class 的 component(这里面的 class 指的是组件的名字) • 合并操作,调用 component 的 setstate 方法的时候, React 将其标记为 dirty到每一个事件循环结束, React 检查所有标记 dirty 的 component 重新绘制 • 选择性子树渲染。开发人员可以重写 shouldComponentUpdate 提高 diff 的性 能。
18、何为受控组件什么是非受控组件
受控组件
React 负责渲染表单的组件,同时仍然控制用户后续输入时所发生的变化,值是来自 于 state 控制的输入表单元素称为“受控组件” <1> 通过在初始state中设置表单的默认值 <2> 每当表单的值发生变化时,调用onChange事件处理器 <3> 事件处理器通过合成对象e拿到改变后的状态,并更新应用的state <4> SetState触发视图的重新渲染,完成表单组件值的更新
非受控组件
1、如果一个表单组件没有value prop就可以称为非受控组件 2、非受控组件是一种反模式,它的值不受组件自身的state或props控制 3、通常需要为其添加ref prop来访问渲染后的底层DOM元素
19、(组件的)状态(state)和属性(props)之间有何不同
• State 是一种数据结构,用于组件挂载时所需数据的默认值。 State 可能会随着 时间的推移而发生突变,但多数时候为用户事件行为的结果。 • Props(properties 的简写)则是组件的配置。 props 由父组件传递给子组件,并且 就子组件而言, props 是不可变的(immutable)。组件不能改变自身的 props,78 但是可以把其子组件的 props 放在一起(统一管理)。 Props 也不仅仅是数据-回 调函数也可以通过 props 传递。
20、调用 super(props) 的目的是什么
• super 调用父类的构造方法,此时组件才有自己的 this,在组件的全局中都可以使用 this 关键字,否则如果只是 constructor 而不执行 super() 那么以后的 this 都是错 的, super()继承父组件的 this
21、React 中构建组件的方式
• 函数组件/无状态组件
function 函数名(组件名 但是名字首字母必须必须必须必须 必须 大写){ return ( jsx ) }
• class 类组件
class 类名(当前组件名首字母大写) extends React.Component{ render(){ render方法也叫做渲染方法 他的作用就是渲染当前的jsx return( jsx ) } }
22、简述下redux
redux 是一个专门用于做状态管理的JS库(不是react插件库),学过vue框架的应该知道和vuex差不多。 它可以用在react,angular,vue等项目中,但基本与react配合使用。 作用: 集中式管理react应用中多个组件共享的功能。 单一数据源 整个应用的state被存储在一个对象树中, 并且这个对象树只存在一个唯一的store State是只读的 唯一改变state的方法简书触发action, 让action去修改state, action是一个用于描述已发生事件的普通对象 这样就确保了视图和网络请求都不能直接的修改state, 让所以的修改都被集中化处理 使用纯函数来执行修改 为了描述 action 如何改变 state tree ,你需要编写 reducers Reducer 只是一些纯函数,它接收先前的 state 和 action,并返回新的 state。刚开始你可以只有一个 reducer,随着应用变大,你可以把它拆成多个小的 reducers,分别独立地操作 state tree 的不同部分,因为 reducer 只是函数,你可以控制它们被调用的顺序,传入附加数据,甚至编写可复用的 reducer 来处理一些通用任务,如分页器。 Redux成员及数据流 actions actions其实是描述操作的对象,我们调用dispatch时需要传入此对象。 store store是整个应用的数据存储仓库,把我们全局管理的状态数据存储起来。 reducers reducers接收actions并更新store
23、React常见的hooks
24、Reducer有哪些方法
1. createStore(reducer, [initState, enhancer])------redux中的方法
-
作用:创建一个Redux store来存放应用中所有的state,一个应用只能有个store。函数返回store对象。
-
参数:
-
reducer(Function):两个参数:state和action,返回一个state。 不要对参数state进行修改,需要返回一个新的对象。
-
initStatate:初始state。如果不为空,需要和reducer中处理的state结构一致
-
enhancer:一个中间件,如logger等。
-
2. Store
Store是用来维持应用所有state树的一个对象。改变state的唯一方法是store dispatch一个action。 Store不是类,而只是一个有几个方法的对象,可以采用createStore进行创建。
-
getState() 返回应用当前的 state 树。它与 store 的最后一个 reducer 返回值相同。
-
dispatch(action) 分发action,这是改变state的唯一方法。
-
subscribe(listener) 添加一个变化监听器,每当 dispatch action 的时候就会执行,state 树中的一部分可能已经变化。你可以在回调函数里调用 getState() 来拿到当前 state。函数返回一个解绑的函数。可以参考counter-vanilla
-
replaceReducer(nextReducer) 替换Reducer,用处较少。
3. combineReducers(reducers)
combineReducers辅助函数的作用是,把一个由多个不同 reducer 函数作为 value 的 object,合并成一个最终的 reducer 函数,然后就可以对这个 reducer 调用 createStore。 多个子reducer函数合并后,相当于整体函数会为state特定字段进行映射产生特定的reducer函数。 如页面中的例子;todos和counter只会处理对应字段过来的action。
4. applyMiddleware(...middlewares)
输入一个middlewares数组,返回一个函数,函数以createStore为参数
5. bindActionCreators(actionCreators,dispatch)
经过bindActionCreators处理的actions,直接调用函数而不需调用dispatch即可触发state的改变。 可以参考文章。
6. compose(...functions)
从右到左来组合多个函数。 这是函数式编程中的方法,为了方便,被放到了 Redux 里。 当需要把多个 store 增强器 依次执行的时候,需要用到它。 参考文章:文章
7. <Provider store>和connect([mapStateToProps], [mapDispatchToProps],[mergeProps], [options])
<Provider store>使组件层级中的 connect()方法都能够获得 Redux store。正常情况下,你的根组件应该嵌套在 <Provider>中才能使用 connect()方法。
25、React常见的优化方式是什么?
26、Fetch与axios与ajax的区别
• 传统 Ajax 指的是 XMLHttpRequest(XHR),最早出现的发送后端请求技术,隶属于原始 js 中,核心使用 XMLHttpRequest 对象,多个请求之间如果有先后关系的话,就会出现回调地狱。 JQuery ajax 是对原生 XHR 的封装 • axios 是一个基于 Promise ,本质上也是对原生 XHR 的封装,只不过它是Promise 的实现版本,符合最新的 ES 规范, • fetch 不是 ajax 的进一步封装,而是原生 js,没有使用 XMLHttpRequest 对 象。
27、UseEffect作用是什么?
useEffect是什么? • 副作用钩子:用于处理组件中的副作用,用来取代生命周期函数。 useEffect可以做什么? • 挂载阶段: 从上向下执行函数,如果碰到 useEffect 就执行并将 useEffect 传入的副作用函数推入一个队列(链表),在组件挂载完成之后,将队列(链表)中的副作用函数执行,并将副作用函数的返还函数,推入一个新的队列(链表) • 更新阶段 - !!! 更新阶段不同于其他阶段对应的函数是否要执行,取决于依赖参数: 从上向下执行函数,如果碰到 useEffect 就执行并将 useEffect 传入的副作用函数推入一个队列(链表),在组件更新完成之后,找出之前的返回函数队列,依次准备执行,在执行前会判断该 useEffect 的依赖参数,如果依赖参数改变就执行,否则跳过当前项去看下一项,然后再执行副作用队列,执行时同样判断依赖是否变化,来决定其是否执行,如果执行,就重新获取其对应的返回函数。 • 卸载阶段: 组件即将卸载时,找出其对应的返回函数队列,依次执行
28、什么是 TypeScript
• TypeScript 是一种由微软开发的自由和开源的编程语言。它是 JavaScript 的一个超集,而且本质上 TypeScript 扩展了 JavaScript 的语法解决 JavaScript 的“痛点”:弱类型和没有命名空间,导致很难模块化 • 优点:开源、简单、兼容性好 • 与 js 相比的优势 o TypeScript 工具使重构更变的容易、快捷。 o TypeScript 引入了 JavaScript 中没有的“类”概念。 o TypeScript 中引入了模块的概念,可以把声明、数据、函数和类封装在模块中类型安全功能能在编码期间检测错误,这为开发人员创建了一个更高效的编码和调试过程
29、React 中 Keys 的作用是什么
Keys 可以在 DOM 中的某些元素被增加或删除的时候帮助 React 识别哪些元素发生了变化。因此要给数组中的每一个元素赋予一个确定的标识。一个元素的 key 最好是这个元素在列表中拥有的一个独一无二的字符串
30、React 事件处理中如何修改 this 指向?
• 通过 bind 方法进行原地绑定,从而改变 this 指向 funa(){ this.setState({ text:"我变了 1" })} <button onClick={this.funa.bind(this)}>方式 1:通过 bind 方法进行原地绑定, 从而改变 this 指向</button> • 通过创建箭头函数 funb=()=>{ this.setState({ text:"我变了 2" })} <button onClick={this.funb}>方式 2:通过创建箭头函数</button> • 在 constructor 中提前对事件进行绑定 func(){ this.setState({ text:"我变了 3"})} <button onClick={this.func}>方式 3:在 constructor 中提前对事件进行绑定 </button> • 将事件调用的写法改为箭头函数的形式 fund(){ this.setState({ text:"我变了 4"})} <button onClick={(e)=>{this.funb("参数 1","参数 2",e)}}>通过箭头函数传递 </button>
31、什么是 React 状态提升
• 定义:多个组件需要反映相同的变化数据,提升到它们最近的父组件上,在父组件上改变这个状态然后通过 props 分发给子组件 • 使用场景:两个子组件需要利用到对方的状态的话,那么这个时候我们就需要使用到状态提升
32、什么是 Webpack
WebPack 可以看做是模块打包机:它做的事情是,分析你的项目结构,找到 JavaScript 模块以及其它的一些浏览器不能直接运行的拓展语言(Scss, TypeScript 等),并将其转换和打包为合适的格式供浏览器使用。
## 33、Webpack 的组成
webpack 分成四个部分,其中最核心的就是入口(entry)和出口(output),当然在入口 和出口配置的同时我们还需要一些加载器(Loaders)和插件(plugin),这就是我们所谓 的 webpack 配置文件。 这个配置文件我们习惯把其命名为 webpack.config.js ,还 有 webpackfile.js
34、Webpack 打包原理
webpack 是把项目当作一个整体,通过给定的一个主文件, webpack 将从这个主 文件开始找到你项目当中的所有依赖的文件,使用 loaders 来处理它们,最后打包 成一个或多个浏览器可识别的 js 文件
35、webpack 的工作过程
• 解析配置参数,合并从(npm install 类似的命令)和 webpack.config.js 文件的配置信息,输出最终的配置信息; o 册配置中的插件,做出对应的反应; • 解析配置文件中的 entry 入口文件,并找出每个文件依赖的文件,递归下去; • 在递归每个文件的过程中,根据文件类型和配置文件中的 loader 找出对应的loader 对文件进行转换; • 递归结束后得到每个文件最终的结果,根据 entry 配置生成代码;