前端面试基础
一.HTML
1.html语义化
使页面内容结构化,即使丢失样式也能使页面呈现清晰的结构
有利于SEO,搜索引擎根据标签确定上下文和关键字的权重有利于开发和维护
语义化更具有可读性,代码更好维护
方便其他设备解析,如配合盲人阅读器渲染页面易于用户阅读,
如:header 定义头部内容
nav 定义导航区域
main 定义主要文档内 容
article 表示文章、博客等内容
aside 侧边内容
footer 尾部
div、article、section
div、article、section是语义从无到有,逐渐增强的。
div无任何语义,仅仅用作样式化或脚本的标签。
对于一段主题性的内容,则适用于section元素。
对于可脱离上下文,作为一段完整独立内容的,适用于article。
article元素代表文档、页面或应用程序中独立的、完整的、可以独自被外部引用的内容。它可以是一篇博客或报刊中的文章、一篇论坛帖子、一段用户评论或独立的插件,或其他任何独立的内容。除了内容部分,一个article元素通常有它自己的标题(一般放在一个header元素里面),有时还有自己的脚注
section元素的作用是对页面上的内容进行分块,或者说对文章进行分段;一个section元素通常由内容及其标题组成,通常不推荐为那些没有标题的内容使用section元素
2.HTML5新标签
<header> <footer> <nav> <aside> <aduio> <video> <canvas>
3.html5语义化
表示选择合适的标签(语义化标签)便于开发者阅读和写出更优雅的代码
4.html5新特性
HTML5新特性有哪些?
语义化标签
音视频处理
canvas / webGL
history API
requestAnimationFrame
地理位置
webSocket
5.对WEB标准和W3C的理解认识
个人理解:
html - 表示人的光身体 ---结构
css - 表示给人穿的衣服 ---表现
js - 表示人的行为,走路等 ---行为
web简单来说可以分为结构、表现和行为。
- 其中结构主要是由HTML标签组成。
- 表现是指css样式表,可用通过css使页面标签更具美感。
- 行为是指用户和页面有一定的交互,同时结构和表现也会发生变化,主要由js组成
web标准一般是将该三部分独立分开,使其更具有模块化。但一般产生行为时,就会有结构或者表现的变化,也使这三者的界限并不那么清晰。
W3C对web标准提出了规范化的要求,也就是在实际编程中的
一些代码规范:
1.对于结构要求(标签规范可以提高搜索引擎对页面的抓取率,对seo很有帮助):
标签要小写
标签要闭合
标签不能随意嵌套
2.对于css和js来说:
使用外链css和js,使结构、表现、行为三者分离。
提高页面渲染速度,提高用户体验
尽量少使用行内样式,使结构和表现分离,标签的id和class要见文知意,标签越少,加载越快,用户体验越高
不需要变动页面内容,便可提供打印版本而不需要复制内容,提高网站易用性。
6.什么是DOCTYPE及作用
DTD(document type definition,文档类型定义)是一系列的语法规则,用来定义XML或(X)HTML的文件类型。浏览器会使用它来判断文档类型,决定使用何种协议来解析以及切换浏览器模式。(DTD告诉浏览器我是什么文档类型,浏览器会根据这个来判断用什么引擎来解析和渲染他们)
DOCTYPE是用来声明文档类型和DTD规范的,一个主要的用途便是文件的合法性验证。如果文件代码不合法,那么浏览器解析时会出一些错误。(DOCTYPE告诉浏览器当前是哪个文档类型)
作用:
告诉浏览器用哪种HTML版本的规范来解析HTML文档
二.CSS
1.盒模型
- 组成:border+padding+content+margin
- 标准盒模型:width: content box-sizing: content-box
- 怪异盒模型/IE:width: content+padding+border box-sizing:border-box
2.rem和em的区别
rem是根据根元素的font-size变化,em是根据父元素的font-size变化
- rem:相对于根元素html的font-size,假如html为font-size:12px,那么,在其当中的div设置为font-size:2rem,就是当中的div为24px
- em:相对于当前对象内文本的字体大小计算,假如某个p元素为font-size:12px,在它内部有个span标签继承p元素字体大小,设置font-size:2em,那么,这时候的span字体大小为:12*2=24px
3.常见单位
- px:绝对单位,页面按精确像素展示
- em:相对单位,基准点为当前对象内文本的字体大小,整个页面内1em不是一个固定的值
- rem:相对单位,可理解为”root em”, 相对根节点html的字体大小来计算,CSS3新加属性,chrome/firefox/IE9+支持
- vw:viewpoint width,视窗宽度,1vw等于视窗宽度的1%
- vh:viewpoint height,视窗高度,1vh等于视窗高度的1%
- vmin:vw和vh中较小的那个
- vmax:vw和vh中较大的那个
- %:百分比
4.移动端视口配置
<meta name="viewport" content="width=device-width,
initial-scale=1.0,minimum-scale=1.0,
maximum-scale=1.0,user-scalable=no">
initial-scale:初始的缩放比例
minimum-scale:允许用户缩放到的最小比例
maximum-scale:允许用户缩放到的最大比例
user-scalable:用户是否可以手动缩放
5.渐进增强与优雅降级的理解及区别
渐进增强(Progressive Enhancement):一开始就针对低版本浏览器进行构建页面,完成基本的功能,然后再针对高级浏览器进行效果、交互、追加功能达到更好的体验。
优雅降级(Graceful Degradation):一开始就构建站点的完整功能,然后针对浏览器测试和修复。比如一开始使用 CSS3 的特性构建了一个应用,然后逐步针对各大浏览器进行hack 使其可以在低版本浏览器上正常浏览。
两者区别?
1、广义:
其实要定义一个基准线,在此之上的增强叫做渐进增强,在此之下的兼容叫优雅降级
2、狭义:
渐进增强一般说的是使用CSS3技术,在不影响老浏览器的正常显示与使用情形下来增强体验,而优雅降级则是体现html标签的语义,以便在js/css的加载失败/被禁用时,也不影响用户的相应功能
6.cookie、sessionStorage、localStorage区别
相同点:
- 都是保存在浏览器端、且同源的
不同点:
cookie数据始终在同源的http请求中携带(即使不需要),即cookie在浏览器和服务器间来回传递,而sessionStorage和localStorage不会自动把数据发送给服务器,仅在本地保存。cookie数据还有路径(path)的概念,可以限制cookie只属于某个路径下
存储大小限制也不同,cookie数据不能超过4K,同时因为每次http请求都会携带cookie、所以cookie只适合保存很小的数据,如会话标识。sessionStorage和localStorage虽然也有存储大小的限制,但比cookie大得多,可以达到5M+
cookie设置的过期时间之前一直有效;localStorage永久存储,浏览器关闭后数据不丢失除非主动删除数据;sessionStorage数据在当前浏览器窗口关闭后自动删除
cookie的数据会自动的传递到服务器;sessionStorage和localStorage数据保存在本地
作用域不同,sessionStorage在不同的浏览器窗口中不共享,即使是同一个页面;localstorage在所有同源窗口中都是共享的;cookie也是在所有同源窗口中都是共享的
7.css选择器
常用css选择器
id选择器 #header
类选择器 .header
元素选择器 div
通配符 *
后代选择器 div p, p a
儿子选择器 div > span
兄弟选择器 div + p, h2 ~ h3
伪类选择器 a:hover
属性选择器 input[type=”text”]
伪元素选择器 p::before p::first-linecss选择器权重
!important > id > class > 元素和伪元素 > * > 继承 >默认
8.css3新特性
- transition 过渡
- transform 旋转 倾斜 移动 缩放
- animation 动画
- shadow 阴影
- grdient 渐变
- border-radius 圆角
9.行内元素和块级元素
行内元素(display: inline):
- 设置宽高无效,宽度和高度由内容决定
- 设置margin左右有效,上下无效,padding都有效
- 不会自动换行
- 有span,img,input,a,b,sub,sup,i
块级元素(display:block):
- 可以设置宽高
- margin和padding都有效
- 自动换行
- 多个块元素写一起,排列从上到下
- 由div,p,nav,h,footer,main,header等
行内块元素(display:inline-block)
- 能够设置宽高
- margin/padding都有效
- 不会自动换行
- 默认排列方式从左到右
10.css的position的定位
relative absolute fixed static
- 绝对定位: absolute和fiexed统称为绝对定位
- 相对定位: relative
- 默认值:static
相对定位和绝对定位的区别: - relative:
相对于自身位置定位,仍处于文档流中,元素的宽高不变,设置偏移量也不会影响其他元素的位置,如果最外层设置relative,在没有设置宽度情况,元素宽度是整个浏览器的宽度 - absolute:
相对于离自己最近的设置了相对或绝对定位的父元素定位,如果没有父元素设置相对和绝对定位,则相对于跟元素html定位,设置了绝对定位的元素脱离了文档流,如果没有设置宽高由元素内容决定,脱离后元素位置是空的下面的元素会占据 - fixed:
相对于浏览器窗口定位,如果没有设置宽高由元素内容决定。
11.Flex布局
Flexbox为Flexible box缩写,“弹性布局”,任何一个元素都能设置弹性布局包含两部分,一个为容器,一个为项目
水平的主轴(main axis)和垂直的交叉轴(cross axis)
主轴的排列方式:从左到右;交叉轴的排列方式:从上到下;
容器的属性:
- flex-direction:主轴的方向-row/row-reverse/column/column-reverse
- flex-wrap:项目排列方式是否换行–nowrap/wrap/wrap-reverse
- flex-flow:direction和wrap的缩写
- justify-content:项目在主轴排列方式–flex-start/flex-end/center/space-between/space-around
- align-items:项目在交叉轴的如何对齐-flex-start/flex-end/center/baseline/stretch
项目属性:
- order:number (数值越小越靠前,默认为0)项目排列顺序
- flex-grow :number(默认0,如果有剩余空间也不放大,值为1放大,2是1的双倍大小,此类推)定义项目放大比例
- flex-shrink :number (默认为1,如果空间不足则会缩小,值为0不能缩小)项目缩小比例
- flex-basis :number/auto (默认auto,可设置固定的值50px/50%)定义项目自身的大小
- flex:属性是flex-grow,flex-shrink ,flex-basis的简写,默认值为0、1、auto
- align-self :auto | flex-start | flex-end | center | baseline | stretch项目自身对齐
12.display有哪些值?说明他们的作用?
- inline(默认)–内联
- none–隐藏
- block–块显示
- table–表格显示
- list-item–项目列表
- inline-block-内联块
13.BFC
BFC块格式化上下文,是Web页面的可视CSS渲染的一部分.是块盒子的布局过程发生的区域,也是浮动元素与其他元素交互的区域。
下列方式会创建块格式化上下文
根元素html
浮动元素(元素的float不是none)
绝对定位元素(元素的display为absolute或fixed)
行内块元素(display:inline-block)
表格单元格(display:table-cell)
表格标题(display:table-caption)
匿名表格单元格元素(display:table/table-row/table-row-group/table-header-group/table-footer-group或inline-table)
overflow计算值不为visible的块元素
display值为flow-root的元素
contain值为layout/content/paint的元素
弹性元素(display为flex或inline-flex 元素的直接子元素)
网格元素(display为grid或inline-grid 元素的直接子元素)
多列容器(元素的column-count或column-width部位auto)
column-span为all的元素始终会创建一个新的BFC,即使该元素没有包裹一个多列容器中。
BFC布局规则:
内部的box会在垂直方向,一个一个排列
Box垂直方向的距离由margin决定,同一个BFC内相邻的两个box的margin值会重叠
每个元素的margin box的左边与border box的左边相接触,即使浮动也如此
BFC区域不和float box区域重叠
BFC是页面上一个独立的容器,内部子元素不回对外部元素产生影响
计算BFC高度时,浮动元素也参与计算
BFC的使用场景?
去除边距重叠现象
清除浮动(让父元素的高度包含子浮动元素)
避免某元素被浮动元素覆盖
避免多列布局由于宽度计算四舍五入而自动换行
14.水平垂直居中
水平居中: margin:0 auto;text-align:center;flex:justify-content
垂直居中:line-height;flex:align-items
水平垂直居中:flex;absolute+margin负;absolute+translate负
15.Sass、Less、Stylus区别
什么是CSS预处理器?
CSS预处理器是一种语言用来为CSS增加一些编程的特性,无需考虑浏览器兼容问题,例如你可以在CSS中使用变量,简单的程序逻辑、函数等在编程语言中的一些基本技巧,可以让CSS更加简洁,适应性更强,代码更直观等诸多好处
基本语法区别
Sass是以.sass为扩展名,Less是以.less为扩展名,Stylus是以.styl为扩展名变量的区别
Sass 变量必须是以$开头的,然后变量和值之间使用冒号(:)隔开,和css属性是一样的。
Less 变量是以@开头的,其余sass都是一样的。
Stylus 对变量是没有任何设定的,可以是以$开头或者任意字符,而且变量之间可以冒号,空格隔开,但是在stylus中不能用@开头
三种预处理器都有:嵌套、运算符、颜色函数、导入、继承、混入。Stylus还有一些高级特性。例如循环、判断等
16.display: none与visibility: hidden的区别
display:none 不显示对应的元素,在文档布局中不再分配空间(回流+重绘)
visibility:hidden 隐藏对应元素,在文档布局中仍保留原来的空间(重绘)
17.重绘 & 回流
浏览器渲染过程如下:
- 解析HTML,生成DOM树,解析CSS,生成CSSOM树
- 将DOM树和CSSOM树结合,生成渲染树(Render Tree)
- Layout(回流):根据生成的渲染树,进行回流(Layout),得到节点的几何信息(位置,大小)
- Painting(重绘):根据渲染树以及回流得到的几何信息,得到节点的绝对像素
- Display:将像素发送给GPU,展示在页面上
通过构造渲染树,我们将可见DOM节点以及它对应的样式结合起来,可是我们还需要计算它们在设备视口(viewport)内的确切位置和大小,这个计算的阶段就是回流
我们通过构造渲染树和回流阶段,我们知道了哪些节点是可见的,以及可见节点的样式和具体的几何信息(位置、大小),那么我们就可以将渲染树的每个节点都转换为屏幕上的实际像素,这个阶段就叫做重绘节点。
何时发生回流重绘
- 添加或删除可见的DOM元素
- 元素的位置发生变化
- 元素的尺寸发生变化(包括外边距、内边框、边框大小、高度和宽度等)
- 内容发生变化,比如文本变化或图片被另一个不同尺寸的图片所替代。
- 页面一开始渲染的时候(这肯定避免不了)
- 浏览器的窗口尺寸变化(因为回流是根据视口的大小来计算元素的位置和大小的)
注意:回流一定会触发重绘,而重绘不一定会回流根据改变的范围和程度,渲染树中或大或小的部分需要重新计算,有些改变会触发整个页面的重排,比如,滚动条出现的时候或者修改了根节点。
当你获取布局信息的操作的时候,会强制队列刷新
最小化重绘和重排:
批量修改DOM:
使元素脱离文档流
对其进行多次修改
将元素带回到文档中。
有三种方式可以让DOM脱离文档流:
隐藏元素,应用修改,重新显示
使用文档片段(document fragment)在当前DOM之外构建一个子树,再把它拷贝回文档。
将原始元素拷贝到一个脱离文档的节点中,修改节点后,再替换原始的元素。
18.防抖(debounce)
防抖就是在触发事件n秒内函数只执行一次,如果在n秒内又触发了事件,就重新计时
如下,鼠标移动时,计数:
1 | <div id="content" style="height:150px;line-height:150px;text-align:center; color: #fff;background-color:#ccc;font-size:80px;"></div> |
防抖函数分为非立即执行版和立即执行版
非立即执行版:
1 | function debounce(func,wait){ |
在触发事件后函数 1 秒后才执行,而如果我在触发事件后的 1秒内又触发了事件,则会重新计算函数执行时间
content.onmousemove = debounce(count,1000);
let context = this;
let args = arguments;
防抖函数的代码使用这两行代码来获取 this 和参数,是为了让 debounce 函数最终返回的函数 this指向不变以及依旧能接受到 e 参数
立即执行版:
1 | function debounce(func,wait){ |
触发事件后函数会立即执行,然后 n 秒内不触发事件才能继续执行函数的效果。
19.节流(throttle)
连续触发函数在n秒内只执行一次,稀释了函数的执行频率
时间戳版:
1 | function throttle(func,wait){ |
在持续触发事件的过程中,函数会立即执行,并且每 1s 执行一次
定时器版:
1 | function throttle(func,wait){ |
在持续触发事件的过程中,函数不会立即执行,并且每1s 执行一次,在停止触发事件后,函数还会再执行一次。
时间戳版的函数触发是在时间段内开始的时候,而定时器版的函数触发是在时间段内结束的时候。
20.获取盒子宽高的几种方式及区别
dom.style.width/height
这种方式只能取到dom元素内联样式所设置的宽高,也就是说如果该节点的样式是在style标签中或外联的CSS文件中设置的话,通过这种方法是获取不到dom的宽高的dom.currentStyle.width/height
获取渲染后的宽高。但是仅IE支持window.getComputedStyle(dom).width/height
与2原理相似,但是兼容性,通用性更好一些dom.getBoundingClientRect().width/height
计算元素绝对位置,获取到四个元素left,top,width,height
扩展:获取浏览器高度和宽度的兼容性写法:
1 | var w = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth |
21.link和import区别
1 | <style type="text/css"> |
- import是css提供的语法规则,只有导入样式表的作用,link是html的标签,不仅可以加载样式还可以设置rel type等属性
- import是css2才引入等,只支持ie5+,而link没有兼容问题
- import在页面加载完毕才引入,link在加载页面时引入
- link可用dom操作引入link加载样式
22.多行元素省略号
overflow : hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical
三.JS
1.JS的基本数据类型
Number
String
Boolean
Null
undefined
新增Symbol
2.几种判断数据类型的优缺点
一、typeof
1 | console.log(typeof 1); // number |
优点:能够快速区分基本数据类型 缺点:不能将Object、Array和Null区分,都返回object
二、instanceof
instanceof用来检测构造函数的prototype属性是否存在某实例对象的原型链上
语法:object instanceof constructor
参数:
object:某个实例对象
constructor:某个构造函数
描述:二、instanceof用来检测constructor.prototype属性是否存在在object的原型链上。
1 | console.log(1 instanceof Number); // false |
优点:能够区分Array、Object和Function,适合用于判断自定义的类实例对象 缺点:Number,Boolean,String基本数据类型不能判断
三、Object.prototype.toString.call()
1 | var toString = Object.prototype.toString; |
优点:精准判断数据类型 缺点:写法繁琐不容易记,推荐进行封装后使用
3.null和undefined的区别
undefined是访问一个未初始化的变量时返回的值,而null是访问一个尚未存在的对象时所返回的值。
undefined看作是空的变量,而null看作是空的对象
4.对象深浅拷贝
一、深拷贝
- 1.1 最简单的方法就是JSON.parse(JSON.stringify())
但是这种拷贝方法不可以拷贝一些特殊的属性(例如正则表达式,undefine,function) - 1.2 用递归去复制所有层级属性
1 | function deepCopyTwo(obj) { |
二、浅拷贝
1 | Object.assign(target, ...sources) |
5.数组基本方法
push():将参数逐个添加到数组尾部,返回修改后的数组长度
unshift():将参数逐个添加到数组前端,返回修改后的数组长度
pop():移除数组中的最后一项,返回移除的项
shift():移除数组中的第一项,返回移除的项
push pop shift unshift 都会直接改变原数组
map: 遍历数组,返回回调返回值组成的新数组
forEach: 无法break,可以用try/catch中throw new Error来停止
filter: 过滤
some: 有一项返回true,则整体为true
every: 有一项返回false,则整体为false
join: 通过指定连接符生成字符串
concat: 连接数组,不影响原数组, 浅拷贝
slice(start, end): 返回截断后的新数组,不改变原数组
splice(start, number, value…):返回删除元素组成的数组,value 为插入项,改变原数组
indexOf / lastIndexOf(value, fromIndex): 查找数组项,返回对应的下标
reduce / reduceRight(fn(prev, cur), defaultPrev): 两两执行,prev 为上次化简函数的return值,cur 为当前值(从第二项开始)
map和forEach的区别:
1.都用来遍历数组,map速度比forEach快
2.map返回回调返回值组成的新数组,不会对原数组产生影响,forEach没有返回值,不能return或者break
3.map返回数组,所以可以链式调用
6.js有那些内置对象
Object是JavaScript中所有对象的父对象
数据封装对象:Object、Array、Boolean、Number和String
其他对象:Function、Arguments、Math、Date、RegExp、Error
7.get请求传参长度的误区
- HTTP 协议 未规定 GET 和POST的长度限制
- GET的最大长度显示是因为 浏览器和 web服务器限制了 URI的长度
- 不同的浏览器和WEB服务器,限制的最大长度不一样
- 要支持IE,则最大长度为2083byte,若只支持Chrome,则最大长度 8182byte
补充get和post请求在缓存方面的区别
- get请求类似于查找的过程,用户获取数据,可以不用每次都与数据库连接,所以可以使用缓存
- post不同,post做的一般是修改和删除的工作,所以必须与数据库交互,所以不能使用缓存。因此get请求适合于请求缓存。
8.同步任务和异步任务
同步任务:在主线程上执行的任务,只有前一个任务执行完,才能执行下一个任务
异步任务:不进入主线程而进入“任务队列”的任务,只有任务队列通知主线程,某个任务可以执行了,该任务才会进入主线程执行。
异步执行的运行机制如下。(同步执行也是如此,因为它可以被视为没有异步任务的异步执行。):
1)所以同步任务都在主线程执行,形成一个执行栈
2)主线程之外,还有一个任务队列,只要异步任务有了执行结果,就在任务队列放置一个事件
3)一旦执行栈中的所有同步任务执行完毕,系统就会读取任务队列,看看有哪些事件,对应的事件就结束等待状态,进入执行栈进行执行
4)主线程不断重复第三步主线程从“任务队列”中读取事件,这个事件是循环不断的,又称为事件循环(Event loop)
9.事件和回调函数
“任务队列”就是一个事件的队列,当IO设备完成一项任务,就在“任务队列”中添加一个事件,表示相关的异步任务可以进入执行栈了,主线程读取“任务队列”,就是读取有哪些事件
“回调函数”(callback)就是被主线程挂起来的代码。异步任务必须指定回调函数,主线程执行异步任务就是执行对应的回调函数。
10.定时器
定时器功能主要由setTimeout()和setInterval()这两个函数来完成,它们的内部运行机制完全一样,区别在于前者指定的代码是一次性执行,后者则为反复执行
1 | console.log(1); |
上面代码的执行结果是1,3,2,因为setTimeout()将第二行推迟到1000毫秒之后执行。
如果将setTimeout()的第二个参数设为0,就表示当前代码执行完(执行栈清空)以后,立即执行(0毫秒间隔)指定的回调函数。
1 | setTimeout(function(){console.log(1);}, 0); |
上面代码的执行结果总是2,1,因为只有在执行完第二行以后,系统才会去执行”任务队列”中的回调函数。
setTimeout(fn,0)的含义是,指定某个任务在主线程最早可得的空闲时间执行,也就是说,尽可能早得执行
HTML5标准规定了setTimeout()的第二个参数的最小值(最短间隔),不得低于4毫秒,如果低于这个值,就会自动增加.需要注意的是,setTimeout()只是将事件插入了”任务队列”,必须等到当前代码(执行栈)执行完,主线程才会去执行它指定的回调函数。要是当前代码耗时很长,有可能要等很久,所以并没有办法保证,回调函数一定会在setTimeout()指定的时间执行
除了setTimeout和setInterval这两个方法,Node.js还提供了另外两个与”任务队列”有关的方法:process.nextTick和setImmediate。
process.nextTick方法可以在当前”执行栈”的尾部—-下一次Event Loop(主线程读取”任务队列”)之前—-触发回调函数。也就是说,它指定的任务总是发生在所有异步任务之前。setImmediate方法则是在当前”任务队列”的尾部添加事件,也就是说,它指定的任务总是在下一次EventLoop时执行,这与setTimeout(fn, 0)很像
process.nextTick和setImmediate的一个重要区别:多个process.nextTick语句总是在当前”执行栈”一次执行完,多个setImmediate可能则需要多次loop才能执行完
另外,由于process.nextTick指定的回调函数是在本次”事件循环”触发,而setImmediate指定的是在下次”事件循环”触发,所以很显然,前者总是比后者发生得早,而且执行效率也高(因为不用检查”任务队列”)。
11.进程和线程
进程和线程是操作系统的基本概念
单个cpu一次只能运行一个任务,任一时刻,CPU总是运行一个进程,其他进程处于非运行状态
- 一个进程可用包含多个线程
- 一个进程的内存空间是共享的,每个线程都可以使用这些共享内存。
- 一个线程使用某些共享内存时,其他线程必须等它结束,才能使用这一块内存。”互斥锁”(Mutual exclusion,缩写 Mutex),防止多个线程同时读写某一块内存区域。
某些内存区域,只能供给固定数目的线程使用。”信号量”(Semaphore),用来保证多个线程不会互相冲突
操作系统的设计,因此可以归结为三点:
(1)以多进程形式,允许多个任务同时运行;
(2)以多线程形式,允许单个任务分成不同的部分运行;
(3)提供协调机制,一方面防止进程之间和线程之间产生冲突,另一方面允许进程之间和线程之间共享资源
12.axios在vue.js中应用和特点
axios是基于promise的http请求客户端,可用在浏览器和node。js中使用
使用场景:结合vue.js发送请求,拦截请求
特点:
1.基于promise
2.拦截请求和响应
3.转换请求和响应的数据
4.可在node.js中使用
安装:
1 | npm install --save axios |
结合Vue.js的请求响应拦截器:
1 | // 请求拦截 |
13.HTTP中定义请求方式
get
post
put
delete
trace
options
head
1.get
get请求只是查询数据,不对数据库进行删改操作;请求会把参数放在url后面;http协议对url长度没有限制,有限制的是浏览器和服务器
2.post
post请求一般是对服务器的数据做改变,比如数据的提交,新增操作,请求参数放在请求体中
3.put
put和post一样都是对服务器数据对修改,但是put侧重于对数据的修改,而post是对数据的新增
4.delete
用来请求删除服务器的资源,但有可能删除不成功(取消delete请求)
5.options
options请求属于浏览器的预检请求,查看服务器是否接受请求,预检通过后,浏览器才会去发get,post,put,delete等,响应报文包含一个 Allow 首部字段,该字段的值表明了服务器支持的所有 HTTP 方法:
1 | HTTP/1.1 200 OK |
在 CORS 中,可以使用 OPTIONS 方法发起一个预检请求,以检测实际请求是否可以被服务器所接受。预检请求报文中的 Access-Control-Request-Method首部字段告知服务器实际请求所使用的 HTTP方法;Access-Control-Request-Headers首部字段告知服务器实际请求所携带的自定义首部字段。服务器基于从预检请求获得的信息来判断,是否接受接下来的实际请求
1 | OPTIONS /resources/post-here/ HTTP/1.1 |
服务器所返回的 Access-Control-Allow-Methods 首部字段将所有允许的请求方法告知客户端。该首部字段与 Allow 类似,但只能用于涉及到 CORS 的场景中。
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
6.head
与GET方法的行为很类似,但服务器在响应中只返回实体的主体部分
7.trace
会在目的服务器端发起一个“回环”诊断。这样客户端就可以查看HTTP请求报文在发送的途中,是否被修改过了
14.get和post区别
GET参数通过URL传递,POST放在Request body中。
GET请求会被浏览器主动cache,而POST不会,除非手动设置
GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留
Get 请求中有非 ASCII 字符,会在请求之前进行转码,POST不用,因为POST在Request body中,通过 MIME,也就可以传输非 ASCII 字符
一般我们在浏览器输入一个网址访问网站都是GET请求,HTTP的底层是TCP/IP。HTTP只是个行为准则,而TCP才是GET和POST怎么实现的基本。GET/POST都是TCP链接。GET和POST能做的事情是一样一样的。但是请求的数据量太大对浏览器和服务器都是很大负担。所以业界有了不成文规定,(大多数)浏览器通常都会限制url长度在2K个字节,而(大多数)服务器最多处理64K大小的url。
GET产生一个TCP数据包;POST产生两个TCP数据包。对于GET方式的请求,浏览器会把http header和data一并发送出去,服务器响应200(返回数据);而对于POST,浏览器先发送header,服务器响应100 continue,浏览器再发送data,服务器响应200 ok(返回数据)
在网络环境好的情况下,发一次包的时间和发两次包的时间差别基本可以无视。而在网络环境差的情况下,两次包的TCP在验证数据包完整性上,有非常大的优点。但并不是所有浏览器都会在POST中发送两次包,Firefox就只发送一次
15.http中content-type
MediaType,即是Internet Media Type,互联网媒体类型;也叫做MIME类型,在Http协议消息头中,使用Content-Type来表示具体请求中的媒体类型信息
常见的媒体格式类型如下:
- text/html : HTML格式
- text/plain :纯文本格式
- text/xml : XML格式
- image/gif :gif图片格式
- image/jpeg :jpg图片格式
- image/png:png图片格式
以application开头的媒体格式类型:
- application/xhtml+xml :XHTML格式
- application/xml : XML数据格式
- application/atom+xml :Atom XML聚合格式
- application/json : JSON数据格式
- application/pdf :pdf格式
- application/msword : Word文档格式
- application/octet-stream : 二进制流数据(如常见的文件下载)
- application/x-www-form-urlencoded :
另外一种常见的媒体格式是上传文件之时使用的:
- multipart/form-data : 需要在表单中进行文件上传时,就需要使用该格式
16.import和require区别
加载方式
require:运行时加载,所以require理论上可以运用在代码的任何地方
import:编译时加载,import是编译时调用,所以必须放在文件开头遵循规范
require 是 AMD规范引入方式
import是es6的一个语法标准,如果要兼容浏览器的话必须转化成es5的语法本质
require是赋值过程,其实require的结果就是对象、数字、字符串、函数等,再把require的结果赋值给某个变量import是解构过程,但是目前所有的引擎都还没有实现import,我们在node中使用babel支持ES6,也仅仅是将ES6转码为ES5再执行,import语法会被转码为require
1 | const fs = require('fs') |
17.ajax
ajax是异步javascript和xml;
Ajax是一种用于创建快速动态网页的技术。
ajax的使用及实现步骤:
1.创建XMLHttpRequest对象,也就是创建一个异步调用对象.
1 | var xmlHttp; |
2.创建一个新的HTTP请求,并指定该HTTP请求的方法、URL及验证信息
1 | xmlhttp.open(method,url,async); |
3.设置响应HTTP请求状态变化的函数
1 | xmlHttp.onreadystatechange()=>{ |
//服务器响应
responseText:获得字符串形式的响应数据。
responseXML:获得 XML 形式的响应数据。
readyState:存有 XMLHttpRequest 的状态。从 0 到 4 发生变化。
0: 请求未初始化
1: 服务器连接已建立
2: 请求已接收
3: 请求处理中
4: 请求已完成,且响应已就绪
status:
200: "OK"
404: 未找到页面
当 readyState 等于 4 且状态为 200 时,表示响应已就绪:
ajax步骤:
创建XMLHttpRequest对象。
设置请求方式。
调用回调函数。
发送请求。
18.闭包
函数A 里面包含了 函数B,而 函数B 里面使用了 函数A 的变量,那么 函数B 被称为闭包。
又或者:闭包就是能够读取其他函数内部变量的函数
1 | function A() { |
特征:
- 函数内再嵌套函数
- 内部函数可以引用外层的参数和变量
- 参数和变量不会被垃圾回收制回收
闭包的理解:使用闭包主要是为了设计私有的方法和变量。闭包的优点是可以避免全局变量的污染,缺点是闭包会常驻内存,会增大内存使用量,使用不当很容易造成内存泄露。
在js中,函数即闭包,只有函数才会产生作用域的概念
闭包 的最大用处有两个,一个是可以读取函数内部的变量,另一个就是让这些变量始终保持在内存中
- 好处:能够实现封装和缓存等
- 坏处:消耗内存,使用不当造成内存泄漏;在退出函数之前,将不使用的局部变量全部删除
1 | for(var i = 0; i < 3; i++) { |
答案:3个3
解析:首先,for 循环是同步代码,先执行三遍 for,i变成了 3;然后,再执行异步代码 setTimeout,这时候输出的 i,只能是 3 个 3 了
解决方法:
1.使用let i=0;每个 let 和代码块结合起来形成块级作用域,当 setTimeout() 打印时,会寻找最近的块级作用域中的 i,所以依次打印出 0 1 2
2.立即执行函数:
1 | for(let i = 0; i < 3; i++) { |
19.js作用域和作用域链
1.作用域
在JavaScript中,作用域分为 全局作用域 和 函数作用域
- 全局作用域:
代码在程序的任何地方都能被访问,window 对象的内置属性都拥有全局作用域 - 函数作用域:
在固定的代码片段才能被访问
作用域最大的用处就是隔离变量,不同作用域下同名变量不会有冲突。
变量取值:到创建 这个变量 的函数的作用域中取值
2.作用域链
一般情况下,变量取值到 创建 这个变量 的函数的作用域中取值。
但是如果在当前作用域中没有查到值,就会向上级作用域去查,直到查到全局作用域,这么一个查找过程形成的链条就叫做作用域链
20.组件化和模块化
1.组件化
- 为什么要组件化?
有时候页面代码量太大,逻辑太多或者同一个功能组件在许多页面均有使用,维护起来相当复杂,这个时候,就需要组件化开发来进行功能拆分、组件封装,已达到组件通用性,增强代码可读性,维护成本也能大大降低
- 组件化开发的优点
很大程度上降低系统各个功能的耦合性,并且提高了功能内部的聚合性,降低了开发成本
组件化开发的准则:
专一
可配置性
标准
复用性
可维护性
2.模块化
- 为什么要模块化?
早期的javascript版本没有块级作用域、没有类、没有包、也没有模块,这样会带来一些问题,如复用、依赖、冲突、代码组织混乱等,随着前端的膨胀,模块化显得非常迫切
模块化的好处
提高代码可复用性
避免变量污染,命名冲突
提高可维护性
方便依赖关系管理模块化的几种方法:
1)函数封装:
1 | var myModule = { |
总结:这样避免了变量污染,只要保证模块名唯一即可,同时同一模块内的成员也有了关系
缺陷:外部可以睡意修改内部成员,这样就会产生意外的安全问题
2)立即执行函数表达式(IIFE):
1 | var myModule = (function(){ |
总结:这样在模块外部无法修改我们没有暴露出来的变量、函数
缺点:功能相对较弱,封装过程增加了工作量,仍会导致命名空间污染可能、闭包是有成本的
21.图片的预加载和懒加载
- 预加载:提前加载图片,当用户需要查看时可直接从本地缓存中渲染
- 懒加载:懒加载的主要目的是作为服务器前端的优化,减少请求数或延迟请求数
两种技术的本质:两者的行为是相反的,一个是提前加载,一个是迟缓甚至不加载。预加载则会增加服务器前端压力,懒加载对服务器有一定的缓解压力作用。
22.mouseover和mouseenter的区别
- mouseover:当鼠标移入元素或其子元素都会触发事件,所以有一个重复触发,冒泡的过程。对应的移除事件是mouseout
- mouseenter:当鼠标移入元素本身(不包含元素的子元素)会触发事件,也就是不会冒泡,对应的移除事件是mouseleave
解决异步回调地狱:promise、generator、async/await
23.对This对象的理解
this总是指向函数的直接调用者(而非间接调用者)
如果有new关键字,this指向new出来的那个对象
在事件中,this指向触发这个事件的对象,特殊的是,IE中的attachEvent中的this总是指向全局对象Window
this表示当前对象,this的指向是根据调用的上下文来决定的,默认指向window对象,指向window对象时可以省略不写
全局环境: this始终指向的是window对象
局部环境: 在全局作用域下直接调用函数,this指向window 对象函数调用,哪个对象调用就指向哪个对象 使用new实例化对象,在构造函数中的this指向实例化对象 使用call或apply改变this的指向
总结:this始终指向最后一个调用它的函数的对象
24.ES6其他常用功能
- let/const
- 多行字符串/模板变量
- 解构赋值
- 块级作用域
- 函数默认参数
- 箭头函数
25.bind、call、apply用法及区别
相同点: 三个函数的作用就是改变this的指向,将函数绑定到上下文中; 不同点: 三个函数的语法不同
1 | fun.call(thisArg[, arg1[, arg2[, ...]]]) |
26.目前JS解决异步的方案有哪些
回调函数
事件监听
发布-订阅
Promise
Generator
Async/Await
27.创建对象有几种方法
1 | // 第一种:字面量 |
四.Vue
vue的生命周期:就是vue实例从创建到销毁的过程,也就是从开始创建,初始化数据,编译模版,挂载Dom,渲染更新,卸载等过程
1.Vue生命周期的作用是什么?
它的生命周期中有多个事件钩子,让我们在控制整个Vue实例的过程时更容易形成好的逻辑
2.Vue生命周期总共有几个阶段?
它可以总共分为8个阶段:创建前/后, 载入前/后,更新前/后,销毁前/销毁后
3.DOM渲染在哪个周期中就已经完成?
DOM 渲染在 mounted 中就已经完成了
4.每个生命周期适合哪些场景?
生命周期钩子的一些使用方法:
beforecreate : 可以在这加个loading事件,在加载实例时触发
created : 初始化完成时的事件写在这里,如在这结束loading事件,异步请求也适宜在这里调用
mounted : 挂载元素,获取到DOM节点
updated : 如果对数据统一处理,在这里写上相应函数
beforeDestroy : 销毁实例前做收尾清除工作
nextTick : 更新数据后立即操作dom
5.关于vue的keep-alive需要条件性缓存的解决
A>B不缓存,C>B需要缓存
在路由里面加上了
1 | { |
在app.vue写了
1 | <keep-alive> |
A页面写了
1 | beforeRouteLeave(to, from, next) { |
C页面写了
1 | beforeRouteLeave(to, from, next) { |
meta.keepAlive=true这种方法,解决不了条件缓存问题
原因:在keep-alive源码中,include和exclude是被watch的 ,当发生变化时,keep-alive会去校验cache里是否匹配,匹配不上的会被删除。也就是说,官方是为这种情况做了处理的。而meta这种方法,因为没有存在某种类似于watch的方法,导致这种方法天然是和实际cache里面的内容有出入的,所以可定会存在各种奇怪的bug
利用include,动态添加”B”
1、在app.vue下增加keep-alive
1 | <keep-alive :include="catchList"> |
catchList,是vuex维护的需要缓存的组件名的一个数组
2、在路由中加入
1 | router.beforeEach((to,next,from)=>{ |
3、在b.vue中加入(A>B不缓存,C>B缓存)
1 | beforeRouteLeave((to,next,from)=>{ |
在vuex中mutation是
1 | keepAlive(state, component) { |
只要是B的组件,都缓存。只有当从A>B的时候,才让B不缓存。
6.Vue 路由懒加载
Vue项目中实现路由按需加载(路由懒加载)的3中方式:
一、Vue异步组件技术:
1 | { |
二、es6提案的import()
1 | const Home = () => import('path路径') |
三、webpack提供的require.ensure()
1 | { |
7.Proxy与Object.defineProperty()的对比
Proxy的优点:
1. 可以直接监听对象而非属性,并返回一个新对象
2. 可以直接监听数组的变化
3. 可以劫持整个对象,并返回一个新对象
Proxy的缺点:
Proxy是es6提供的新特性,兼容性不好,所以导致Vue3一致没有正式发布让让广大开发者使用,IE9以下不兼容
Object.defineProperty的优点:
IE8以下的版本不兼容
Object.defineProperty的缺点:
只能劫持对象的属性,我们需要对每个对象的每个属性进行遍历,无法监控到数组下标的变化,导致直接通过数组的下标给数组设置值,不能实时响应
Proxy代理整个对象,Object.defineProperty只代理对象上的某个属性。
如果对象内部要全部递归代理,则Proxy可以只在调用时递归,而Object.defineProperty需要在一开始就全部递归,Proxy性能优于Object.defineProperty。
对象上定义新属性时,Proxy可以监听到,Object.defineProperty监听不到。
数组新增删除修改时,Proxy可以监听到,Object.defineProperty监听不到。
Proxy不兼容IE9以下,Object.defineProperty不兼容IE8及以下。
8.v-show与v-if区别
v-show是css切换,v-if是完整的销毁和重新创建
使用 频繁切换时用v-show,运行时较少改变时用v-if
v-if=’false’ v-if是条件渲染,当false的时候不会渲染
9.vue有哪些指令
v-model //在表单控件或者组件上创建双向绑定
v-if //根据表达式的值的 truthiness 来有条件地渲染元素。在切换时元素及它的数据绑定 / 组件被销毁并重建
v-else-if
v-else
v-text //更新元素的 textContent
v-show //根据表达式之真假值,切换元素的 display CSS property。
v-html://更新元素的 innerHTML。注意:内容按普通 HTML 插入 - 不会作为 Vue 模板进行编译。如果试图使用 v-html 组合模板,可以重新考虑是否通过使用组件来替代。
v-on:绑定事件监听器
v-bind //动态地绑定一个或多个 attribute,或一个组件 prop 到表达式。
v-for //基于源数据多次渲染元素或模板块
v-cloak //这个指令保持在元素上直到关联实例结束编译。和 CSS 规则如 [v-cloak] { display: none } 一起用时,这个指令可以隐藏未编译的 Mustache 标签直到实例准备完毕
v-once //只渲染元素和组件一次
v-pre //跳过这个元素和它的子元素的编译过程。可以用来显示原始 Mustache 标签。跳过大量没有指令的节点会加快编译。
v-slot //提供具名插槽或需要接收 prop 的插槽
绑定class的数组用法
对象方法: v-bind:class="{'orange': isRipe, 'green': isNotRipe}"
数组方法: v-bind:class="[class1, class2]"
行内: v-bind:style="{color: color, fontSize: fontSize+'px' }"
10.组件之间的传值通信
父组件给子组件传值:props
子组件向父组件通信:父组件向子组件传递事件方法,子组件通过$emit触发事件,回调给父组件
非父子,兄弟组件之间通信:
可以通过实例一个vue实例Bus作为媒介,要相互通信的兄弟组件之中,都引入Bus,然后通过分别调用Bus事件触发和监听来实现通信和参数传递
1 | <template> |
另一个组件也import Bus.js 在钩子函数中监听on事件
1 | import Bus from '../common/js/bus.js' |
11.子组件调用父组件的方法函数
- 直接在子组件中通过this.$parent.event来调用父组件的方法
- 在子组件里用$emit向父组件触发一个事件,父组件监听这个事件就行了
- 父组件把方法传入子组件中,在子组件里直接调用这个方法
12.路由跳转方式
<router-link to='home'>
router-link标签会渲染为<a>
标签
另一种是编程是导航 也就是通过js跳转 比如 router.push(‘/home’)
13.mvvm
M - Model,Model 代表数据模型,也可以在 Model 中定义数据修改和操作的业务逻辑
V - View,View 代表 UI 组件,它负责将数据模型转化为 UI 展现出来
VM - ViewModel,ViewModel 监听模型数据的改变和控制视图行为、处理用户交互,简单理解就是一个同步 View 和 Model 的对象,连接 Model 和 View之间的桥梁,绑定数据到viewmodel层并自动更新渲染到页面上,视图变化通知到viewmodel层去更新数据
14.computed和watch有什么区别?
computed:
- computed是计算属性,也就是计算值,它更多用于计算值的场景
- computed具有缓存性,computed的值在getter执行后是会缓存的,只有在它依赖的属性值改变之后,下一次获取computed的值时才会重新调用对应的getter来计算
- computed适用于计算比较消耗性能的计算场景
watch:
- 更多的是「观察」的作用,类似于某些数据的监听回调,用于观察props $emit或者本组件的值,当数据变化时来执行回调进行后续操作
- 无缓存性,页面重新渲染时值不变化也会执行
小结:
- 当我们要进行数值计算,而且依赖于其他数据,那么把这个数据设计为computed
- 如果你需要在某个数据变化时做一些事情,使用watch来观察这个数据变化
15.key
key是为Vue中的vnode标记的唯一id,通过这个key,我们的diff操作可以 更准确、更快速
准确:
如果不加key,那么vue会选择复用节点(Vue的就地更新策略),
导致之前节点的状态被保留下来,会产生一系列的bug快速:
key的唯一性可以被Map数据结构充分利用
预期:number | string
key 的特殊属性主要用在 Vue 的虚拟 DOM 算法,在新旧 nodes 对比时辨识 VNodes。如果不使用 key,Vue 会使用一种最大限度减少动态元素并且尽可能的尝试就地修改/复用相同类型元素的算法。而使用 key 时,它会基于 key的变化重新排列元素顺序,并且会移除 key 不存在的元素。
有相同父元素的子元素必须有独特的 key。重复的 key 会造成渲染错误。
最常见的用例是结合 v-for:
1 | <ul> |
它也可以用于强制替换元素/组件而不是重复使用它。当你遇到如下场景时它可能会很有用:
- 完整地触发组件的生命周期钩子
- 触发过渡
1 | <transition> |
当 text 发生改变时,<span>
总是会被替换而不是被修改,因此会触发过渡
16.组件中的data为什么是函数?
组件可以被多次复用,创建多个实例,这些实例本质是同一个构造函数,如果data是对象,对象是引用类型,修改对象会影响所有实例,因此data是一个函数
17.Class 与 Style 如何动态绑定?
1)class
对象语法:
1 | <div v-bind:class="{ 'active': isActive, 'text-danger': hasError }"></div> |
数组语法:
1 | <div v-bind:class="[isActive ? activeClass : '', errorClass]"></div> |
2)style:
对象语法:
1 | <div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"></div> |
数组语法:
1 | <div v-bind:style="[styleColor, styleSize]"></div> |
18.vue的单向数据流
所有的 prop都使得其父子prop之间形成了一个单向下行绑定:
父级 prop的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外改变父级组件的状态,从而导致你的应用的数据流向难以理解
额外的,每次父级组件发生更新时,子组件中所有的 prop 都将会刷新为最新的值。
这意味着你不应该在一个子组件内部改变prop。如果你这样做了,Vue 会在浏览器的控制台中发出警告。
子组件想修改时,只能通过 $emit派发一个自定义事件,父组件接收到后,由父组件修改
有两种常见的试图改变一个 prop 的情形 :
1)这个 prop 用来传递一个初始值:
这个子组件接下来希望将其作为一个本地的 prop 数据来使用,在这种情况下,最好定义一个本地的 data属性并将这个 prop 用作其初始值:
1 | props: ['initialCounter'], |
2)prop 以一种原始的值传入且需要进行转换:
1 | props: ['size'], |
19.keep-alive
keep-alive 是 Vue 内置的一个组件,可以使被包含的组件保留状态,避免重新渲染 ,其有以下特性:
一般结合路由和动态组件一起使用,用于缓存组件;
提供 include 和 exclude 属性,两者都支持字符串或正则表达式, include表示只有名称匹配的组件会被缓存,exclude表示任何名称匹配的组件都不会被缓存 ,其中 exclude的优先级比 include 高;
对应两个钩子函数 activated 和 deactivated ,当组件被激活时,触发钩子函数 activated,当组件被移除时,触发钩子函数 deactivated。
20.v-model 的原理
vue 项目中主要使用 v-model 指令在表单 input、textarea、select 等元素上创建双向数据绑定,我们知道 v-model 本质上不过是语法糖,v-model在内部为不同的输入元素使用不同的属性并抛出不同的事件:
- text 和 textarea 元素使用 value 属性和 input 事件;
- checkbox 和 radio 使用 checked 属性和 change 事件;
- select 字段将 value 作为 prop 并将 change 作为事件
1 | <input v-model='something'> |
如果在自定义组件中,v-model 默认会利用名为 value 的 prop 和名为 input 的事件
21.nextTick()
在下次DOM更新循环结束之后执行延迟回调。在修改数据之后,立即使用的这个回调函数,获取更新后的DOM
22.vue插槽
单个插槽:
当子组件模板只有一个没有属性的插槽时,
父组件传入的整个内容片段将插入到插槽所在的 DOM 位置,
并替换掉插槽标签本身命名插槽:
solt元素可以用一个特殊的特性name来进一步配置如何分发内容。
多个插槽可以有不同的名字。 这样可以将父组件模板中 slot 位置,
和子组件 slot 元素产生关联,便于插槽内容对应传递作用域插槽:
可以访问组件内部数据的可复用插槽(reusable slot)
在父级中,具有特殊特性 slot-scope 的<template>
元素必须存在,
表示它是作用域插槽的模板。slot-scope 的值将被用作一个临时变量名,
此变量接收从子组件传递过来的 prop 对象
23.导航守卫
vue-router提供的导航守卫主要通过跳转或取消的方式守卫导航
参数或查询的改变不会触发进入/离开的导航守卫
你可以通过观察 $route 对象来应对这些变化,或使用beforeRouteUpdate 的组件内守卫
- 全局前置守卫:
1 | const router = new VueRouter({ ... }) |
守卫是异步解析执行,此时导航在所有守卫 resolve 完之前一直处于 等待中
to: Route: 即将要进入的目标 路由对象
from: Route: 当前导航正要离开的路由
next: Function: 一定要调用该方法来 resolve这个钩子。执行效果依赖 next 方法的调用参数。
确保要调用 next 方法,否则钩子就不会被 resolved
- 路由独享的守卫
1 | const router = new VueRouter({ |
- 组件内的守卫
1 | const Foo = { |
vue-router有哪几种导航钩子
第一种:是全局导航钩子:router.beforeEach(to,from,
next),作用:跳转前进行判断拦截
第二种:组件内的钩子:beforeRouteEnter/beforeRouteUpdate/beforeRouteLeave
第三种:单独路由独享组件:beforeEnter
24.vuex是什么?
vuex是专门为vuejs应用程序开发的状态管理插件,集中存储管理组件状态,通过显式提交mutation改变组件状态
vuex 就是一个仓库,仓库里放了很多对象。其中 state就是数据源存放地,对应于一般 vue 对象里面的 data
state 里面存放的数据是响应式的,vue 组件从 store 读取数据,若是 store 中的数据发生改变,依赖这相数据的组件也会发生更新
它通过 mapState 把全局的 state 和 getters 映射到当前组件的 computed 计算属性
Vuex有5种属性: 分别是 state、getter、mutation、action、module;
state
Vuex 使用单一状态树,即每个应用将仅仅包含一个store 实例,但单一状态树和模块化并不冲突。存放的数据状态,不可以直接修改里面的数据mutations
mutations定义的方法动态修改Vuex 的 store 中的状态或数据getters
类似vue的计算属性,主要用来过滤一些数据actions
actions可以理解为通过将mutations里面处里数据的方法变成可异步的处理数据的方法,简单的说就是异步操作数据。view 层通过 store.dispath 来分发 actionmodules
由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得复杂时,store对象就变得臃肿。为了解决以上问题,vuex允许将store分隔成模块。每个模块有自己的state/getter/mutation/action,甚至是嵌套子模块。
总结
vuex 一般用于中大型 web 单页应用中对应用的状态进行管理,对于一些组件间关系较为简单的小型应用,使用 vuex 的必要性不是很大,因为完全可以用组件 prop属性或者事件来完成父子组件之间的通信,vuex 更多地用于解决跨组件通信以及作为数据中心集中式存储数据
vuex解决了什么?
多个组件依赖同一个状态,多层组件间传值
来自不同的组件的行为需要变更同一个状态
25.优化SPA首屏加载速度
缩小webpack或者其他打包工具生成的包的大小
用webpack-bundle-analyzer的分析工具哪个模块占空间大
第三方UI组件按需引入
使用服务端渲染方式(基于vue的nuxt.js开发)
使用预渲染的方式
在打包时会预先运行一次js代码,将一部分静态页面直接渲染成html写在生成的index.html中,在加载完index.html后页面就能展示,无需等待加载js缺点是在需要预渲染的页面较多时,build打包的时间会十分漫长
使用gzip减小网络传输的流量大小
HTTP协议上的gzip编码是一种用来改进web应用程序性能的技术,web服务器和客户端(浏览器)必须共同支持gzip,使用gzip可以将原静态文件压缩到30%,效果很明显,对于优化首屏加载时间非常适合在nginx中配置
http{
gzip on;
}组件懒加载
26.你有对 Vue 项目进行哪些优化?
1)代码层面的优化
- v-if 和 v-show 区分使用场景
- computed 和 watch 区分使用场景
- v-for 遍历必须为 item 添加 key,且避免同时使用 v-if
- 长列表性能优化
- 事件的销毁
- 图片资源懒加载
- 路由懒加载
- 第三方插件的按需引入
- 优化无限列表性能
- 服务端渲染 SSR or 预渲染
- 减少data中数据
- SPA采用keep-alive缓存组件
2)Webpack 层面的优化
- Webpack 对图片进行压缩
- 减少 ES6 转为 ES5 的冗余代码
- 提取公共代码
- 模板预编译
- 提取组件的 CSS
- 优化 SourceMap
- 构建结果输出分析
- Vue 项目的编译优化
- 压缩代码
- tree shaking
- cdn加载第三方模块
- sourcemap优化
3)基础的 Web 技术的优化
- 开启 gzip 压缩
- 浏览器缓存
- CDN 的使用
- 使用 Chrome Performance 查找性能瓶颈
五.ES6
1.var let const区别
let、const声明的变量仅在块级作用域内有效,var声明变
量是全局的,没有块级作用域功能
let 、const 不存在变量提升 , var 存在变量提升
let 、const不能在同一块级作用域内重复申请
1 | var a = 10; |
通过 var 声明的变量有初始值 undefined,而通过 let声明的变量直到定义的代码被执行时才会初始化。在变量初始化前访问变量会导致 ReferenceError
2.解构赋值
1)数组解构
1 | let [a, b, c] = [1, 2, 3] //a=1, b=2, c=3 |
2)对象解构:
1 | let {a, b} = {a: 'aaaa', b: 'bbbb'} //a='aaaa' b='bbbb' |
函数参数的定义
1 | function personInfo(name, age, address, gender) { |
上面这个例子在对用户信息的时候需要传递四个参数,且需要一一对应,这样就会极易出现参数顺序传错的情况,从而导致bug,接下来来看es6解构赋值是怎么解决这个问题的:
1 | function personInfo({name, age, address, gender}) { |
交换变量的值
1 | let a=1, b=2; |
函数默认参数
es5:
1 | function saveInfo(name, age, address, gender) { |
es6:
1 | function saveInfo({name= 'william', age= 18, address= 'changsha', gender= 'man'} = {}) { |
3.forEach、for in、for of三者区别
forEach更多的用来遍历数组,无法return或break
for in 一般常用来遍历对象或json,循环遍历的值都是数据结构的键值,也遍历数组
for of数组对象都可以遍历,遍历对象需要通过和Object.keys()一起使用
它是ES6中新增加的语法,用来循环获取一对键值对中的值
一个数据结构只有部署了 Symbol.iterator 属性, 才具有 iterator接口可以使用 for of循环
以下数据结构部署了 Symbol.iteratoer属性:- 数组
- Map
- Set
- String
- Nodelist
- arguments对象
如果想让对象可以使用 for of循环怎么办?使用 Object.keys() 获取对象的 key值集合后,再使用 for of
或者使用内置的Object.values()方法获取对象的value值集合再使用for of
for in循环出的是key,for of循环出的是value
4.使用箭头函数应注意什么?
- 1、用了箭头函数,this就不是指向window,而是父级(指向是可变的)
- 2、不能够使用arguments对象
- 3、不能用作构造函数,这就是说不能够使用new命令,否则会抛出一个错误
- 4、不可以使用yield命令,因此箭头函数不能用作 Generator 函数
5.Set、Map的区别
应用场景Set用于数据重组,Map用于数据储存
- Set:
1,成员不能重复
2,只有键值没有键名,类似数组
3,可以遍历,方法有add, delete,has - Map:
1,本质上是健值对的集合,类似集合
2,可以遍历,可以跟各种数据格式转换
6.Ajax
1.创建一个XmlHttpRequest对象,也就是创建一个异步调用对象
2.创建一个发送请求到方法,设置http请求方法,url和验证信息
3.设置请求状态变化到方法
4.发送请求
5.获取异步调用返回的数据
6.使用js和dom实现局部刷新
7.同步和异步的区别
- 同步:
按照一定的顺序去执行,执行完一个才能执行下一个浏览器访问服务器请求,用户看得到页面刷新,重新发请求,等请求完,页面刷新,新内容出现,用户看到新内容,进行下一步操作 - 异步:
浏览器访问服务器请求,用户正常操作,浏览器后端进行请求。等请求完,页面不刷新,新内容也会出现,用户看到新内容执行顺序是不确定的,由触发条件决定,什么时间执行也是不确定的,即使是定时器(下面做解释),异步处理可以同时执行多个。
8.ajax的优点和缺点
ajax的优点
1、无刷新更新数据(在不刷新整个页面的情况下维持与服务器通信)
2、异步与服务器通信(使用异步的方式与服务器通信,不打断用户的操作)
3、前端和后端负载均衡(将一些后端的工作交给前端,减少服务器与宽度的负担)
4、界面和应用相分离(ajax将界面和应用分离也就是数据与呈现相分离)ajax的缺点
1、ajax不支持浏览器back按钮
2、安全问题 Aajax暴露了与服务器交互的细节
3、对搜索引擎的支持比较弱
4、破坏了Back与History后退按钮的正常行为等浏览器机制
9.get和post的区别
1、get和post在HTTP中都代表着请求数据,其中get请求相对来说更简单、快速,效率高些
2、get相对post安全性低
3、get有缓存,post没有
4、get体积小,post可以无限大
5、get的url参数可见,post不可见
6、get只接受ASCII字符的参数数据类型,post没有限制
7、get请求参数会保留历史记录,post中参数不会保留
8、get会被浏览器主动catch,post不会,需要手动设置
9、get在浏览器回退时无害,post会再次提交请求
10.什么时候使用post?
post一般用于修改服务器上的资源,对所发送的信息没有限制。比如
1、无法使用缓存文件(更新服务器上的文件或数据库)
2、向服务器发送大量数据(POST 没有数据量限制)
3、发送包含未知字符的用户输入时,POST 比 GET 更稳定也更可靠
11.同源策略
同源策略是浏览器的一个安全功能,不同源的客户端脚本在没有明确授权的情况下,不能相互读取对方资源
同源策略限制了一个源的文档和脚本和另一个源的资源进行交互,是一个隔离潜在恶意文件攻击的安全机制
不受同源策略限制的:
1.页面中的连接,重定向和表单提交
2.第三方js的引入不受限制,但不能js读写加载的内容,script,link,img,iframe
12.如何解决跨域问题?
跨域的概念:协议、域名、端口都相同才同域,否则都是跨域
解决跨域问题:
1、 通过jsonp跨域
2、 document.domain + iframe跨域
3、 location.hash + iframe
4、 window.name + iframe跨域
5、 postMessage跨域
6、 跨域资源共享(CORS)
7、 nginx代理跨域
8、 nodejs中间件代理跨域
9、 WebSocket协议跨域
六.浏览器
1.主流浏览器
IE Google Chrome Firefox Opera Safari
2.浏览器内核
渲染引擎和js引擎
渲染引擎:用来解释网页语法并渲染到网页上
浏览器内核决定了如何显示网页内容和格式化的信息
Trident:IE、360
Gecko:火狐
Presto:Opera
Blink:Opera,Googlechrome
webkit:Safari
3.浏览器兼容
1.不同浏览器默认内外边距不同:*{margin:0;padding:0}
2.图片默认有间距:img设置float
3. IE6双边距bug:块属性标签float后,又有横行的margin情况下,在IE6显示margin比设置的大。hack:display:inline;将其转化为行内属性。
4. 设置较小高度标签(一般小于10px),在IE6,IE7中高度超出自己设置高度。hack:给超出高度的标签设置overflow:hidden;或者设置行高line-height 小于你设置的高度。
5. Chrome 中文界面下默认会将小于 12px 的文本强制按照 12px 显示,可通过加入 CSS 属性 -webkit-text-size-adjust: none; 解决。
6. 超链接访问过后hover样式就不出现了,被点击访问过的超链接样式不再具有hover和active了。解决方法是改变CSS属性的排列顺序:L-V-H-A ( love hate ): a:link {} a:visited {} a:hover {} a:active {}
七.其他
1.前端组件化和模块化
组件化:组件化是具体的,按照一些功能的通用性和复用性来抽象组件侧重于UI部分,比如弹窗按钮
模块化:模块化是抽象的,按照项目业务划分的大块侧重于数据数据的封装
对于组件来说,其主要是提高代码的复用性,功能单一独立模块是将同一类型的代码整合在一起,例如用户信息,设置等,所以模块等功能相当复杂,但都同属于同一业务(提高内聚降低耦合)
2.什么是Ajax和JSON,它们的优点和缺点
Ajax:
Ajax是异步JavaScript和XML,用于在Web页面中实现异步数据交互
Ajax优点:
异步请求响应快,用户体验好;页面无刷新、数据局部更新;按需取数据,减少了冗余请求和服务器的负担;
Ajax缺点:
异步回调问题、this指向问题、路由跳转back问题;对搜索引擎的支持比较弱,对于一些手机还不是很好的支持JSON:
是一种轻量级的数据交换格式,看着像对象,本质是字符串
JSON优点:
轻量级、易于人的阅读和编写,便于js解析,支持复合数据类型
JSON缺点:
没有XML格式这么推广的深入人心和使用广泛, 没有XML那么通用性。
3.Github
git常用的命令
从远程库克隆到本地:git clone 网站上的仓库地址
新增文件的命令:git add .
提交文件的命令:git commit –m或者git commit –a
查看工作区状况:git status –s
拉取合并远程分支的操作:git fetch/git merge或者git pull
查看提交记录命令:git reflog
4.webpack
webpack打包原理:
webpack只是一个打包模块的机制,只是把依赖的模块转化成可以代表这些包的静态文件。webpack就是识别你的入口文件。识别你的模块依赖,来打包你的代码。至于你的代码使用的是commonjs还是amd或者es6的import。webpack都会对其进行分析。来获取代码的依赖。webpack做的就是分析代码,转换代码,编译代码,输出代码。webpack本身是一个node的模块,所以webpack.config.js是以commonjs形式书写的(node中的模块化是commonjs规范的)
webpack 核心概念
1.entry
入口起点(entry point)指示 webpack 应该使用哪个模块,来作为构建其内部依赖图的开始. 进入入口起点后,webpack 会找出有哪些模块和库是入口起点(直接和间接)依赖的。 每个依赖项随即被处理,最后输出到称之为 bundles 的文件中。
2.output
output 属性告诉 webpack 在哪里输出它所创建的bundles,以及如何命名这些文件,默认值为 ./dist。 基本上整个应用程序结构,都会被编译到你指定的输出路径的文件夹中。
3.Module 模块
在 Webpack 里一切皆模块,一个模块对应着一个文件。Webpack 会从配置的 Entry 开始递归找出所有依赖的模块
4.chunk 代码块
一个 Chunk 由多个模块组合而成,用于代码合并与分割。
5.loader
loader 让 webpack 能够去处理那些非 JavaScript 文件(webpack 自身只理解 JavaScript)。 loader 可以将所有类型的文件转换为 webpack能够处理的有效模块,然后你就可以利用 webpack 的打包能力,对它们进行处理。 本质上,webpack loader将所有类型的文件,转换为应用程序的依赖图(和最终的 bundle)可以直接引用的模块。
6.Plugin
loader 被用于转换某些类型的模块,而插件则可以用于执行范围更广的任务。 插件的范围包括,从打包优化和压缩,一直到重新定义环境中的变量。插件接口功能极其强大,可以用来处理各种各样的任务。
模块热更新
模块热更新是webpack的一个功能,他可以使代码修改过后不用刷新就可以更新,是高级版的自动刷新浏览器
devServer中通过hot属性可以控制模块的热替换
1 | const webpack = require('webpack'); |
webpack的优点
专注于处理模块化的项目,能做到开箱即用,一步到位
可通过plugin扩展,完整好用又不失灵活
使用场景不局限于web开发
社区庞大活跃,经常引入紧跟时代发展的新特性,能为大多数场景找到已有的开源扩展
良好的开发体验
webpack的缺点
webpack的缺点是只能用于采用模块化开发的项目
5.微信小程序
- onLoad():页面加载时触发。
- onReady():页面初次渲染完成时触发。
- onShow():页面显示/切入前台时触发。
- onHide():页面隐藏/切入后台时触发。
- onUnload():页面卸载时触发。
小程序运行环境分为渲染层和逻辑层,其中wxml和wxss工作在渲染层,js工作在逻辑层
小程序的渲染层和逻辑层分别由两个线程来管理:渲染层的界面使用webview来管理,逻辑层使用jscore来运行js脚本,一个小程序存在多个界面,所以渲染层有多个webview,两个线程通过微信客户端做中转,逻辑层请求网络经由客户端转发
6.微信小程序支付流程
- 1.wx.login用code换取openid
- 2.生成商户订单
- 3.调用支付统一下单api,返回预付单信息prepay_id
- 4.将组合数据再次签名,返回5个参数和sign
- 5.小程序获取参数后,鉴权调起支付
- 6.返回支付结果给小程序,推送支付结果给商户,修改订单状态
7.微信网页授权流程
前置条件:
公众平台设置授权回调域名,在域名内页面可进行OAuth2.0鉴权
关于网页授权的两种scope的区别说明
1.以snsapi_base为scope发起的网页授权,是用来获取进入页面的用户的openid的,并且是静默授权跳转到回调页面的
2.snsapi_userinfo为scope发起的网页授权,是用来获取用户基本信息的,但是需要用户手动同意,由于用户同意过所以无需关注就可获取用户基本信息
3、用户管理类接口中的“获取用户基本信息接口”,是在用户和公众号产生消息交互或关注后事件推送后,才能根据用户OpenID来获取用户基本信息。这个接口,包括其他微信接口,都是需要该用户(即openid)关注了公众号后,才能调用成功的。
网页授权流程分为四步:
1.引导用户进入授权页面,同意授权,获取code
2.通过code换取网页授权access_token
3.如果需要,刷新access_token
4.通过access_token和opened获取用户基本信息
8.小程序登录流程
1.wx.login()获取code,传给开发者服务器
2.开发者服务器用appid,appsecret,code调用登录凭证校验
( auth.code2Session )向微信服务器获取openid和sessionkey
3.发者服务器可以根据用户标识来生成自定义登录态,用于后
续业务逻辑中前后端交互时识别用户身份。
9.小程序授权
如果用户未接受或拒绝过此权限,会弹窗询问用户,用户点击同意后方可调用接口;
如果用户已授权,可以直接调用接口;
如果用户已拒绝授权,则不会出现弹窗,而是直接进入接口fail 回调。请开发者兼容用户拒绝授权的场景。(wx.openSetting引导用户进行授权)
开发者可以使用 wx.getSetting 获取用户当前的授权状态。
微信小程序分为两个部分:webview 和 appService。其中 webview 主要用来展示 UI,appService 用来处理业务逻辑、数据及接口调用。它们在两个进程中进行,通过系统层 JSBridge 实现通信,实现 UI 的渲染、事件的处理
10.网络协议
网络分层
目前网络分层可分为两种:OSI 模型和 TCP/IP 模型
OSI模型
应用层(Application)
表示层(Presentation)
会话层(Session)
传输层(Transport)
网络层(Network)
数据链路层(Data Link)
物理层(Physical)
TCP/IP模型
应用层(Application)
传输层(Host-to-Host Transport)
互联网层(Internet)
网络接口层(Network Interface)
11.HTTP/HTTPS
1、https协议需要到ca申请证书,一般免费证书较少,因而需要一定费用
2、http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议
3、http和https使用的是完全不同的连接方式,用的端口也不一样,默认前者是80,后者是443
4、http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。
12.从输入URL到页面加载到过程?
1.浏览器地址栏输入URL并回车
2.通过DNS将域名解析成IP地址。在解析过程中,按照浏览器缓存、系统缓存、路由器缓存、ISP(运营商)DNS缓存、根域名服务器、顶级域名服务器、主域名服务器的顺序,逐步读取缓存,直到拿到IP地址。(应用层)
3.根据获取IP进行tcp连接(三次握手)(传输层)
4.发送http请求
5.服务器处理请求,浏览器接收http的响应
6.渲染页面,构造dom树
7.关闭tcp连接(四次挥手)
13.HTTP状态码
区分状态码
1××开头 - 临时响应
2××开头 - 请求成功
3××开头 - 请求被重定向
4××开头 - 请求错误
5××开头 - 服务器错误
常见状态码
200 - 请求成功,Ajax 接受到信息了
400 - 服务器不理解请求
403 - 服务器拒绝请求
404 - 请求页面错误
500 - 服务器内部错误,无法完成请求
14.性能优化
HTML优化
1、避免 HTML 中书写 CSS 代码,因为这样难以维护。
2、使用 Viewport 加速页面的渲染。
3、使用语义化标签,减少 CSS 代码,增加可读性和 SEO。
4、减少标签的使用,DOM 解析是一个大量遍历的过程,减少不必要的标签,能降低遍历的次数。
5、避免 src、href 等的值为空,因为即时它们为空,浏览器也会发起 HTTP 请求。CSS优化
1、优化选择器路径:使用 .c {} 而不是 .a .b .c {}。
2、选择器合并:共同的属性内容提起出来,压缩空间和资源开销。
3、精准样式:使用 padding-left: 10px 而不是 padding: 0 0 0 10px。
4、雪碧图:将小的图标合并到一张图中,这样所有的图片只需要请求一次。
5、避免通配符:.a .b {} 这样的选择器,根据从右到左的解析顺序在解析过程中遇到通配符 {} 会遍历整个 DOM,性能大大损耗。
6、少用 float:float 在渲染时计算量比较大,可以使用 flex 布局。
7、为 0 值去单位:增加兼容性。
8、压缩文件大小,减少资源下载负担。JavaScript优化
1、尽可能把<script>
标签放在 body 之后,避免 JS 的执行卡住 DOM 的渲染,最大程度保证页面尽快地展示出来
2、尽可能合并 JS 代码:提取公共方法,进行面向对象设计等……
3、CSS 能做的事情,尽量不用 JS 来做,毕竟 JS 的解析执行比较粗暴,而 CSS 效率更高。
4、尽可能逐条操作 DOM,并预定好 CSs 样式,从而减少 reflow 或者 repaint 的次数。
5、尽可能少地创建 DOM,而是在 HTML 和 CSS 中使用 display: none 来隐藏,按需显示。
6、压缩文件大小,减少资源下载负担。