[搞定一面] 快速搞定一面~技术面
前端面试总结
- 一、HTML模块
- 如何理解HTML语义化
- 常见的块级元素和内联元素
- 二、CSS模块
- 1. 盒模型宽度计算
- 2. margin 纵向重叠问题
- 3. inline-block中的元素之间的空格是什么引起的?
- 4. margin 负值问题
- 5. BFC概念?如何使用?
- Formatting context
- Box
- 1. BFC的布局规则
- 2. 如何创建BFC,形成BFC的条件
- 3. BFC常见的应用
- 手写clearfix
- 6. float布局
- 圣杯布局
- 双飞翼布局
- 7. flex 布局
- 8. absolute、relative定位(子绝父相)
- 9. 使元素水平居中对齐
- 10.使元素垂直居中对齐
- 11. 让未知宽高的Div垂直水平居中
- 12. line-height 继承问题
- 10. 响应式布局
- 第一种,用 @media 和 rem 实现的
- 第二种,用vh\vw
- 11. CSS3 动画
- Vue中scoped原理? 怎么穿透scoped?
- 12. DOM
- DOM是什么?
- DOM有什么用?
- DOM与JS的关系
- 优化DOM渲染
- 13. BOM
- 1. 什么是BOM?
- 2. Window对象
- window尺寸
- window方法
- 3. navigator对象
- navigator.userAgent
- 4. screen对象
- 5. location对象
- 6. history对象
- 三、JS基础模块
- 1. JS有几种类型数据( 值类型和引用类型的区别)
- 2. typeof 能判断哪些类型?
- 3. 判断数据类型有哪些方法
- 4. 什么时候用`===` 何时使用 `==`
- if 条件
- 逻辑判断
- 5. `Object.is()`与`===` ,`==`有什么区别?
- 6. 深拷贝与浅拷贝
- - 手写深拷贝
- 7. JS内置对象有哪些?
- 四、JS原型、原型链
- 1. Class
- 2. 继承
- 3. [原型与原型链](https://blog.csdn.net/xiaoermingn/article/details/80745117)
- 4 .请问JS中 new 一个对象发生了什么?
- 五、作用域及闭包
- 1. 作用域
- 2. 作用域链
- 3. 闭包是什么?如何利用闭包实现私有变量
- this指向问题
- 箭头函数与普通函数的区别
- 六、异步
- 单线程及异步
- 同步和异步的区别是什么?
- 前端使用异步的场景
- Promise解决回调地狱
- 手写用Promise加载一张图片
- 面试题
- 七、ES6
- require与import的区别
- 八、HTTP协议
- 1. 什么是HTTP协议、TCP协议,两者关系
- HTTP协议(Hyper Text Transfer Protocol)
- TCP协议
- UDP协议
- websocket协议
- 2. HTTP状态码分类
- 3. 常见的状态码
- 4. HTTP 请求头headers
- Request Headers
- Response Headers
- 5. methods分类
- GET 和 POST 有什么区别?
- 6. Restful API
- Restful API 特点
- 7. HTTP与HTTPS的区别
- 8. HTTP2的特点
- 二进制分帧
- 压缩头部
- 多路复用
- 请求优先级
- 服务器推送
- 服务器提示
- 9. 浏览器缓存
- 10.HTTP缓存 [(浏览器缓存机制)](https://www.jianshu.com/p/54cc04190252)
- 缓存位置
- 缓存过程
- 缓存分类
- 强缓存
- 协商缓存
- 缓存机制
- 缓存策略的实际场景应用
- 用户行为对浏览器缓存的影响
- 11. [JS GC垃圾回收机制](https://blog.csdn.net/qq_17550381/article/details/81126809)
- 什么是内存泄漏?
- JS垃圾回收机制原理:
- 标记清除
- 引用计数
- 三、防抖 (debounce)
- 四、节流(throttle)
- 1. 共同点
- 2. 区别
- 五、undefined与null 有什么区别
- 什么时候给变量赋值为null?
- 六、[浏览器是如何渲染页面的?](https://cloud.tencent.com/developer/article/1495980)
- 回流(重排)与重绘
- 减少回流(重排)、重绘:
- 八、浅谈MVC模式与MVVM模式的区别
- 九、什么是 Virtual DOM?
- 十、前端路由原理?两种实现方式有什么区别?
- Hash 模式
- History 模式
- 两种模式对比
- 十一、Vue 生命周期
- keep-alive 生命周期
- 组件通信
- computed 和 watch 区别
- v-show 与 v-if 区别
- 组件中 data 什么时候可以使用对象
- Vue.extend 的使用
- mixin 和 mixins 区别
- Vue响应式原理
- Vue2.0
- vue3.0
- `Object.defineProperty`与`Proxy`的对比
- Vue模板编译过程
一、HTML模块
如何理解HTML语义化
HTML语义化:HTML本身就是标记语言,根据内容的结构化,选择合适的标签便于开发者阅读和写出更优雅的代码的同时让浏览器的爬虫和机器很好地解析
语义化的好处:
- 语义化增加代码可读性,便于团队开发和维护。
- 有利于SEO:和搜索引擎建立良好沟通,有助于爬虫抓取更多的有效信息:爬虫依赖于标签来确定上下文和各个关键字的权重
常见的块级元素和内联元素
display :block / table ;
有 div、h1、h2、table、ul、ol、p
dispaly :inline-block / inline
有 span、img、input、button、
二、CSS模块
CSS盒模型本质上是一个盒子,封装周围的HTML元素,它包括:外边距(margin)、边框(border)、内边距(padding)、实际内容(content)四个属性。
1. 盒模型宽度计算
box-sizing属性可以指定盒子模型种类
- 默认,W3C(标准盒模型):
box-sizing : content-box
,width
值不包括border
和padding
- IE盒子模型(怪异盒模型):
box-sizing : border-box
,width
值就包括了border
和padding
,即真实的width
变小了
总结:
- 一个元素的布局宽度,
offsetWidth=(width+padding+border)
,无margin
请问 div 的offsetWidth
是多大?
#div{width:100px;padding:10px;border:1px solid #ccc;margin:10px;
}
首先offsetWidth =(width+padding+border)
,无margin
所以offsetWidth = 100px+10px*2+1px*2=122px
如果要使offsetWidth 为100px,需要加上box-sizing:border-box;
,这时中间的width
由100px变成了78px
2. margin 纵向重叠问题
- 相邻元素的
margin-top
和margin-bottom
会发生重叠 - 空白内容的
<p></p>
也会重叠
问AAA
与BBB
之间的距离? 答案:15px
中间三个空的P标签不渲染,AAA的下边距15px,BBB的上边距为10px,两者重叠,取最大的15px
3. inline-block中的元素之间的空格是什么引起的?
元素被当成行内元素排版的时候,元素之间的空白符(空格、回车换行等)都会被浏览器处理,根据white-space
的处理方式(默认是normal,空白会被浏览器忽略),HTML代码中的回车换行被转成一个空白符,在字体不为0的情况下,空白符占据一定宽度,所以inline-block
的元素之间就出现了空隙。
解决办法:
- 删除元素之间的空白符
<div class="box1">box1</div><div class="box2">box2</div>
- 在父元素中设置
font-size: 0
,在子元素上重新设置正确的font-size
- 为
inline-block
元素添加样式float:left
4. margin 负值问题
margin-top
和margin-left
负值,元素会向上、向左移动margin-right
负值,其右侧元素会左移,自身不受影响。margin-bottom
负值,其下方元素上移,自身不受影响。
5. BFC概念?如何使用?
BFC:Block formatting context
,块级格式化上下文,如果一个元素符合了成为BFC的条件,该元素内部元素的布局和定位就和外部元素互不影响(除非内部的盒子建立了新的 BFC),是一个隔离了的独立容器,它涉及两个概念:
Formatting context
属于 W3C CSS2.1
,它是页面中的一块渲染区域,并且有一套渲染规则,它决定了其子元素将如何定位,以及和其他元素的关系和相互作用。
Block fomatting context
(BFC)Inline formatting context
(IFC)
Box
Box 是 CSS 布局的对象和基本单位, 一个页面是由很多个 Box 组成的。元素的类型和 display 属性,决定了这个 Box 的类型。
block-level box
:display:block|list-item|table
,会生成block-level box
,并且参与block fomatting context;
inline-level box
:display:inline|inline-block|inline-table
,会生成inline-level box
,并且参与inline formatting context;
run-in box
: css3中才有, 这儿先不讲了
1. BFC的布局规则
BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素,反之也如此。
内部的Box会在垂直方向,一个接一个地放置。
Box垂直方向的距离由margin决定。属于同一个BFC的两个相邻Box的margin会发生重叠(margin-top、margin-bottom为什么会重叠)。
每个盒子(块盒与行盒)的
margin box
的左边,与包含块border box
的左边相接触(对于从左往右的格式化,否则相反)。即使存在浮动也是如此。BFC的区域不会与
float box
重叠(清除浮动)。计算BFC的高度时,浮动元素也参与计算。
2. 如何创建BFC,形成BFC的条件
- 浮动元素,float除了none之外的值
- 绝对定位元素,position(absolute、fixed)
- overflow 除了visible之外的值(hidden、auto、scroll)
- display的值是inline-block、table-cell、flex、table-caption或者inline-flex
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>BFC</title>
</head>
<style>*{margin: 0;padding: 0;}body {width: 100%;position: relative;}.left {width: 100px;height: 150px;float: left; /* 1.设置浮动 */background: rgb(139, 214, 78);text-align: center;line-height: 150px;font-size: 20px;}.right {overflow: hidden; /* 2.触发BFC */height: 300px;background: rgb(170, 54, 236);text-align: center;line-height: 300px;font-size: 40px;}
</style>
<body><div class="left">LEFT</div><div class="right">RIGHT</div>
</body>
</html>
3. BFC常见的应用
- 清除浮动,外层div设置
overflow:hidden;
- 防止垂直 margin 上下重叠:给其中一个元素外面套上一个div,把这个div变成BFC
- 自适应两栏布局:侧边栏浮动,重要内容区域变成BFC
手写clearfix
.clearfix:after{content:'';display:table;clear:both;
}
6. float布局
圣杯布局
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>圣杯布局实现</title><style>#header{background-color: #fa1717;height:100px;} .column{float: left; /*第一步,设置左浮动*/}#left{background-color: #ee8037;width: 200px;height:100px;/* 第三步,利用margin-left: -100% 使得left与center在同一行 负值使left 向左移动100% */margin-left: -100%;}#right{/* 第四步,利用相对定位将right 移到右边*/position: relative;right: 150px;background-color: #377dee;width: 150px;height:100px;margin-right:-150px;}#center{background-color: #999;width: 100%;height:100px;text-align: center;}#footer{clear: both; /* 第二步清除 footer的浮动 */background-color: palevioletred;height:100px;}</style>
</head>
<body><div><div id="header"> header</div><div id="container"><div id="center" class="column">center</div><div id="left" class="column">left</div><div id="right" class="column">right</div></div><div id="footer">footer</div></div>
</body>
</html>
双飞翼布局
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>双飞翼布局</title><style>body{min-width: 500px;}.column{float: left;/* 第一步 设置浮动 */}#main{background-color: #999;width: 100%;height:200px;}#main-warp{/* 第二步,设置外边距 */margin: 0 200px 0 200px;}#left{background-color: #ee8037;width: 200px;height:200px;/* 第三步,设置margin-left,使左边放到main 的左边 */margin-left: -100%;}#right{width: 200px;height:200px;background-color: #377dee;/* 第四步,设置right到对应的位置 */margin-left: -200px;}</style>
</head>
<body><div><div id="main" class="column"><div id="main-warp">main</div></div><div id="left" class="column">left</div><div id="right" class="column">right</div></div>
</body>
</html>
7. flex 布局
- flex-direction
- justify-content
- align-items
- flex-warp
- align-self
常见问题: flex:1 0 auto 代表什么?
flex: [ flex-grow ] [ flex-shrink ] [ flex-basis ]
flex-grow
:定义了项目的放大比例,默认为0,即如果存在剩余空间,也不放大
flex-shrink
:定义了项目的缩小比例,默认为1,即如果空间不足,该项目将缩小。
flex-basis
:定义了在分配多余空间之前,项目占据的主轴空间(main
size),浏览器根据这个属性,计算主轴是否有多余空间。它的默认值为auto,即项目的本来大小
8. absolute、relative定位(子绝父相)
- relative 相对定位,相对于自身定位
- absolute 绝对定位,依据最近一层的定位元素定位
9. 使元素水平居中对齐
- inline元素 :
text-align:center
- block元素:
margin:auto
- absolute元素:
left:50%;margin-left 负值(-宽度/2)
10.使元素垂直居中对齐
- inline 元素 :
line-height 值 = height 值
- absolute元素:
top:50%;margin-top 负值(-高度/2)
- absolute元素:
transform:translate(-50%,-50%)
- absolute元素:
top、left、bottom、right=0 ; margin:auto
11. 让未知宽高的Div垂直水平居中
- flex
- transform
- table-cell
- 父容器设置
display:flex;
display: flex;
justify-content: space-around;
align-items: center;
- 父容器设置
position: relative;
,子容器如下
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
- 父容器设置
dispaly:table-cell;
display: table-cell;
text-align: center;
vertical-align: middle;
子容器设置vertical-align: middle;
12. line-height 继承问题
如下代码,p的行高将会是多少?
body{font-size:20px;line-height:200%;
}
p{font-size:16px;
}
答案是40px
- line-height 为具体数值,如line-height:30px,则直接继承为30px
- line-height 为比例时,如 line-height:1.5,则继承该比例,即16px1.5=24px ,用自身的字体大小比例
- line-height 为百分比时,如line-height:200%,则继承父标签计算20px*200%=40px的结果
10. 响应式布局
- px :绝对长度单位
- em:相对长度单位,相对于父元素
- rem : 相对长度单位,相对于根元素(html),常用与响应式布局
第一种,用 @media 和 rem 实现的
@media only screen and (max-width:374px){ /**/ iphone 5 及更小尺寸
}@media only screen and (min-width:375px) and (max-width:413px){/*iPhone 6、7、8 、iPhone X*/
}
@media only screen and (min-width:414px) {/*iPhone 6P 或更大尺寸*/
}
rem 的弊端,“阶梯”性
第二种,用vh\vw
先来看下三个概念
window.screen.height
手机屏幕高度,手机型号不同,高度不一致window.innerHeight
可视窗口高度,去掉浏览器头尾,不同浏览器的header和footer不一致document.body.height
body 的高度,取决于整体内容的高度
vh
网页视口高度的1/100
vw
网页视口高度的1/100
vmax
取两者最大值,vmin
取两者最小值
当手机竖着,vmax
为vh
,vmin
为vw
当手机横屏,vmax
为vw
,vmin
为vh
div{width:10vmax;height:20vmin
}
11. CSS3 动画
/* 定义动画 */
@keyframes example{from {background-color:red}to {background-color:blue}
}div{width:100px;height:100px;background-color:red;animation-name:example;animation-duration:4s;}
animation 属性是一个简写属性,用于设置六个动画属性:
默认:animation :none 0 ease 0 1 normal
- animation-name 规定需要绑定到选择器的 keyframe 名称。。
- animation-duration 规定完成动画所花费的时间,以秒或毫秒计。
- animation-timing-function 规定动画的速度曲线。
- animation-delay 规定在动画开始之前的延迟。
- animation-iteration-count 规定动画应该播放的次数。
- animation-direction 规定是否应该轮流反向播放动画。
Vue中scoped原理? 怎么穿透scoped?
Vue在编译的时候通过在DOM元素以及css样式上加上唯一标记,实现样式私有化,不污染全局样式
穿透scoped:深度选择器
>>>
/deep/
::v-deep
12. DOM
DOM是什么?
DOM(document Object Model )即文档对象模型,它允许脚本(js)控制Web页面、窗口和文档,是HTML和XML文档的编程接口API
W3C(万维网联盟)把DOM标准分为三个部分:
- 核心 DOM,针对任何结构化文档的标准模型
- XML DOM,针对XML文档的标准模型
- HTML DOM,针对HTML文档的标准模型
DOM有什么用?
DOM把一份文档(HTML为例),表示为一棵树,文档是由各种节点构成的集合,而节点有不同的类型,常说的就是HTML DOM树 ,由不同的节点组成的,比如文档节点、元素节点、属性节点、文本节点、注释节点,DOM可以操作HTML中的元素
DOM基本功能:
- 查询某个元素,元素集合
- 查询某个元素的祖先、兄弟以及后代元素
- 获取、修改元素的属性
- 获取、修改元素的内容
- 创建、插入、删除元素
const div=document.getELementById('div')//获取元素
const divList=document.getElementsByTagName('div')//获取div元素列表
console.log(divList[0])const pList=doument.querySelectorAll('p')//集合
const p1=pList[0];
//property 形式,对DOM元素的js变量进行修改,修改对象属性,不会体现在html结构中
p1.style.width='100px';//修改高度属性
console.log(p1.className)//获取class
p1.className='red';//修改 class //获取nodeName、nodeType
console.log(p1.nodeName)//获取nodeName ,打印 p
console.log(p1.nodeType)//获取nodeType , 打印 1
//attribute形式,对DOM节点属性进行修改,修改html属性,会改变html结构
p1.getAttribute('data-name')
p1.setAttribute('data-name','hh')
p1.getAttribute('style')
p1.setAttribute('style','font-size:30px')
两者都有可能引起DOM重新渲染
const newP=decument.createElement('p')// 创建元素
newP.innerHTML='this is newP'div1.appendChild(newP)//插入节点//移动现有的节点
const p1=document.getElementByID('P1')
div2.appendChild(p1)//获取父元素
console.log(p1.parentNode)//获取子元素列表
const div1ChildNodes=div1.childNodes;
const div1ChildNodesP=Array.prototype.slice.call(div1ChildNodes).filter(child=>{if(child.nodeType===1){return true}return fasle
})console.log(div1ChildNodesP)const child=document.getElementById('div1').childNodes
div1.removeChild(child[0])//删除节点
DOM与JS的关系
使用JS对网页进行的操作,是通过DOM来进行的
优化DOM渲染
- DOM查询做缓存 (
const div=document.getElementById('mydiv')
) - 将频繁操作改为一次性操作(
appendChild
)
13. BOM
http://c.biancheng.net/js/bom/
1. 什么是BOM?
BOM(Browser Object Model) 是指浏览器对象模型,是用于描述这种对象与对象之间层次关系的模型,浏览器对象模型提供了独立于内容的、可以与浏览器窗口进行互动的对象结构。
BOM由多个对象组成,其中代表浏览器窗口的Window对象是BOM的顶层对象,其他对象都是该对象的子对象。
- window:客户端 JavaScript 顶层对象。每当
<body>
或<frameset>
标签出现时,window 对象就会被自动创建。 - navigator:包含客户端有关浏览器信息。
- screen:包含客户端屏幕的信息。
- history:包含浏览器窗口访问过的 URL 信息。
- location:包含当前网页文档的 URL 信息。
- document:包含整个 HTML 文档,可被用来访问文档内容及其所有页面元素
2. Window对象
- 所有浏览器都支持 window 对象,它表示浏览器窗口
- 所有 JavaScript 全局对象、函数以及变量均自动成为 window 对象的成员
- 全局变量是 window 对象的属性,全局函数是 window 对象的方法,甚至 HTML DOM 的 document 也是 window 对象的属性之一
window尺寸
window.innerHeight - 浏览器窗口的内部高度(包括滚动条)
window.innerWidth - 浏览器窗口的内部宽度(包括滚动条)
window方法
window.open() - 打开新窗口
window.close() - 关闭当前窗口
window.moveTo() - 移动当前窗口
window.resizeTo() - 调整当前窗口的尺寸
3. navigator对象
navigator 对象存储了与浏览器相关的基本信息,如名称、版本和系统等。通过 window.navigator 可以引用该对象,并利用它的属性来读取客户端基本信息。
navigator.userAgent
BOM 在 navigator 对象中定义了 userAgent 属性,利用该属性可以捕获客户端 user-agent 字符串信息。
var s = window.navigator.userAgent;
// var s = navigator.userAgent;//简写方法console.log(s); //返回类似信息:Mozilla/5.0 (Windows NT 10.0; Win64;x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36
user-agent 字符串包含了 Web 浏览器的大量信息,如浏览器的名称和版本。
4. screen对象
screen 对象存储了客户端屏幕信息,这些信息可以用来探测客户端硬件配置。利用 screen 对象可以优化程序的设计,提升用户体验。
不同浏览器在解析 screen 对象的 width 和 height 属性时存在差异。
screen.width
screen.height
5. location对象
location 对象存储了当前文档位置(URL)相关的信息,简单地说就是网页地址字符串。
举例说明:
http://www.123.cn:80/news/index.asp?id=123&name=location#top
console.log(location.href) //url地址 http://www.123.cn:80/news/index.asp?id=123&name=location#top
console.log(location.protocol) //协议 http:
console.log(location.host) //主机及端口 www.123.cn:80
console.log(location.hostname) //主机名称 www.123.cn
console.log(location.port) //端口 80
console.log(location.pathname) // URL的路径部分 /news/index.asp
console.log(location.search) // URL 的查询部分,包括前导问号(?)。 ?id=123&name=location
console.log(location.hash) // URL 中锚部分,包括前导符(#) #top
location 对象属性
属性 | 说明 |
href | 声明了当前显示文档的完整 URL,与其他 location 属性只声明部分 URL 不同,把该属性设置为新的 URL 会使浏览器读取并显示新 URL 的内容 |
protocol | 声明了 URL 的协议部分,包括后缀的冒号。例如:“http:” |
host | 声明了当前 URL 中的主机名和端口部分。例如:“www.123.cn:80” |
hostname | 声明了当前 URL 中的主机名。例如:“www.123.cn” |
port | 声明了当前 URL 的端口部分。例如:“80” |
pathname | 声明了当前 URL的路径部分。例如:“news/index.asp” |
search | 声明了当前 URL 的查询部分,包括前导问号。例如:“?id=123&name=location” |
hash | 声明了当前 URL 中锚部分,包括前导符(#)。例如:“#top”,指定在文档中锚记的名称 使用 location 对象,结合字符串方法可以抽取 URL 中查询字符串的参数值。 |
6. history对象
history 对象存储了库互动浏览器的浏览历史,通过 window 对象的 history 属性可以访问该对象,实际上 history 属性仅存储最近访问的、有限条目的 URL 信息。
history.back()//后退
history.forword()//前进
移动到指定的历史记录点
window.history.go(-1); //相当于调用 back()
window.history.go(1); //相当于调用forward()
HTML5 新增
history.pushState() //添加历史记录条目,pushState() 方法永远不会触发 hashchange 事件。
history.replaceState() //修改历史记录条目
pushState() 是在 history 栈中添加一个新的条目,replaceState() 是替换当前的记录值。
每当激活的历史记录发生变化时,都会触发 popstate 事件。
当页面重新加载时,页面会触发 onload 事件,但不会触发 popstate 事件。
三、JS基础模块
- 值类型 vs 引用类型
- typeof 运算符
- 深拷贝
1. JS有几种类型数据( 值类型和引用类型的区别)
JS主要分值类型数据
和 引用类型数据
基本数据类型:
- undefined
- string
- boolean
- number
- Symbol
值类型数据以栈
的形式存储在内存中
引用数据类型:
- Object
- Array
- Function
- null (特殊的引用类型,指针指向空地址)
引用类型数据以栈
和堆
的形式存储在内存中
栈:变量名:内存地址
堆:内存地址:变量的值
比如我们定义一个引用类型变量 a={age:20}
,首先在堆中申请一个地址,把值{age:20}
放在堆中,这时堆会给出 {age:20}
在堆中的地址,变量a存在栈中,值为 {age:20}
在堆中的内存地址。
//值类型
let a=100;
let b=a;
a=200;
console.log(b) //100
//引用类型
let a={age:20}
let b=a
a.age=21
console.log(b.age)//21
2. typeof 能判断哪些类型?
- 识别所有的值类型
- 识别函数
- 判断是否是引用类型(不可再细分)
- 返回值有:
'object'、'function'、'undefined'、'string'、'number'、'boolean'、'symbol'
3. 判断数据类型有哪些方法
- typeof(用于判断数据类型,返回值为6个字符串,分别为
string、Boolean、number、function、object、undefined
,缺点判断数组Array
,结果为"object"
,引用类型不可再细分) - instanceof(对象运算符,判断该对象是谁的实例,判断方法是根据对象的原型链依次向下查询,返回
Boolean
类型) - Object.propotype.toString.call(a) 使用Object原型对象上的
toString
方法,用call
或者apply
改变this指向,原理是所有类在继承Object的时候,改写了toString()方法,而Object原型上的toString
方法是可以输出数据类型的,所以我们要改变this指向,使用Object上的toString方法
4. 什么时候用===
何时使用 ==
- 除了判断
==null
, 其他都要用===
==
会强制进行类型转换,会出现0==' '
,结果为true
if 条件
const obj={x:100}
if(obj.a==null){}
//相当于
if(obj.a==null||obj.a===undefined){}
逻辑判断
- 注意类型转换的问题 ,if 判断语句、逻辑运算中,truly变量(
!!变量===true
)、falsly 变量(!!变量===false
)
console.log(10&&0) //0 ,10 不是falsly变量,继续运算
console.log(0&&10) //0 ,0 是falsly变量,直接返回
console.log(''&&'abc') //''
console.log('abc'||'') //'abc',!!'abc'===true ,||运算返回turly变量
5. Object.is()
与===
,==
有什么区别?
Object.is()
方法判断两个值是否为同一个值。如果满足以下条件则两个值相等:
- 都是 undefined
- 都是 null
- 都是 true 或 false
- 都是相同长度的字符串且相同字符按相同顺序排列
- 都是相同对象(意味着每个对象有同一个引用)
- 都是数字且
- 都是 +0
- 都是 -0
- 都是 NaN 或都是非零而且非 NaN 且为同一个值
与==
运算不同。 ==
运算符在判断相等前对两边的变量(如果它们不是同一类型) 进行强制转换 (这种行为的结果会将"" == false
判断为 true), 而 Object.is
不会强制转换两边的值。
与===
运算也不相同。 ===
运算符 (也包括==
运算符) 将数字-0
和 +0
视为相等 ,而将Number.NaN
与NaN
视为不相等.
6. 深拷贝与浅拷贝
- 浅拷贝,只拷贝引用,修改新对象的值,原对象会受影响,例如,使用ES6 浅拷贝
object.assign(o,obj)
- 深拷贝,复制原内存空间中的数据给新对象,为其开辟一个新的内存空间,对新对象属性进行修改时,原对象不受干扰,递归方式实现,通过 JSON 对象实现深拷贝
//通过js的内置对象JSON 来进行数组对象的深拷贝
function deepClone(obj) {var _obj = JSON.stringify(obj),objClone = JSON.parse(_obj);return objClone;
}
- 手写深拷贝
- 注意判断值类型与引用类型,值类型直接返回,引用类型要遍历递归
- 注意判断是数组还是对象,定义返回值
- 注意递归前判断是否是自己的属性,
result[key]=deepClone(obj[key])
/*** 深拷贝* @param {object} obj 要拷贝的对象*/function deepClone(obj={}){//1. 判断是否不是对象或者是null,如果符合,直接返回if(typeof obj!=='object'||obj==null){return obj}let result // 2. 定义返回值if (obj instanceof Array) { //判断是否是数组result =[]}else{result={}}for (const key in obj) {if (obj.hasOwnProperty(key)) { //key 不是原型prototype的属性result[key]=deepClone(obj[key]); }} return result;}
7. JS内置对象有哪些?
基本对象是定义或使用其他对象的基础。基本对象包括一般对象、函数对象和错误对象。
- Object
- Function
- Boolean
- Symbol
数字和日期对象
- Number
- BigInt
- Math
- Date
字符串
- String
- RegExp
可索引的集合对象
- Array
使用键的集合对象
- Map
- Set
- WeakMap
- WeakSet
结构化数据
- ArrayBuffer
- JSON
控制抽象对象
- Promise
- Generator
反射
- Reflect
- Proxy
四、JS原型、原型链
1. Class
class Student{constructor(name,age){this.name=name;this.age=age;}sayHi(){console.log(`My name is ${this.name},I'm ${this.age} years old`) }
}let huahua=new Student('花花',23)console.log(huahua);huahua.sayHi();
typeof Student// "function"
Student=== Student.prototype.constructor // true
由此可见,类class的数据类型就是函数,类本身就指向构造函数,类是构造函数的语法糖,上面代码等同于
// 等同于
Student.prototype = {constructor(name,age) {},sayHi() {}
};
在类的实例上面调用方法,其实就是调用原型上的方法。
2. 继承
现实中的继承:子承父业,比如我们都继承父亲的姓氏
程序中的继承:子类可以继承父类的一些属性和方法
语法:使用 extends 关键字
- super ,用于访问和调用对象父类上的函数,可以调用父类的构造函数,也可以调用父类的普通函数。
class People {constructor(name, age) {this.name = name;this.age = age;}sayHi() {console.log(`My name is ${this.name},I'm ${this.age} years old`) }}
class Father extends People {constructor(name, age, job) {super(name, age) ; //调用了父类中的构造函数this.job = job}goToWork() {console.log('Dad has to go to work every day~~!my job is' + this.job);}}class Son extends People {constructor(name, age, school) {super(name, age)this.school = school}goToSchool() {console.log('Son has to go to school every day~~!my school is' + this.school);}}
let pp = new Father('爸爸', 45, 'programming');
pp.goToWork();let ss = new Son('儿子', 18, '人大附中');
ss.goToSchool();console.log(pp, ss);
3. 原型与原型链
原型可分为
- 显式原型
prototype
- 隐式原型
__proto__
- 每一个引用类型都有一个
__proto__
(隐式原型)属性,是一个普通的对象 - 每一个函数里都有的一个
prototype
(显式原型)属性,是一个普通的对象 - 引用类型的
__proto__
属性指向它构造函数的prototype
构造函数与原型对象、实例对象之间的关系
原型是每一个构造函数里都有的一个原型对象prototype
- 每个实例对象中都有一个
__proto__
,__proto__
指向构造函数的原型对象prototype
prototype
中有一个属性constructor
指向回构造函数,prototype
中也有一个属性__proto__
- 如果这个构造函数(类class)没有继承其他的类,那么
prototype.__proto__
指向Object.prototype
,Object.prototype.__proto__
指向null
原型链:当访问一个对象的某个属性时,会先在这个对象本身属性上查找,如果没有找到,则会去它的__proto__隐式原型上查找,即它的构造函数的prototype,如果还没有找到就会再在构造函数的prototype的__proto__中查找,这样一层一层向上查找就会形成一个链式结构,我们称为原型链。
4 .请问JS中 new 一个对象发生了什么?
- new 执行的函数,函数内部生成一个空对象
var obj = new Object();
- 将函数内部的
this
默认指向objvar result = Person.call(obj);
- 设置原型链,将
obj
的__proto__
成员指向了Person函数对象的prototype
成员对象obj.__proto__ = Person.prototype;
- 判断函数Person的返回值类型,如果是值类型,返回obj。如果是引用类型,就返回这个引用类型的对象
return typeof(result)=="object"? result : obj
五、作用域及闭包
1. 作用域
作用域(Scope):表示代码的执行环境,作用域分为全局作用域和局部作用域、块级作用域(ES6)
全局作用域
——在 Web 浏览器中,全局执行环境被认为是 window 对象,所有全局变量和函数都是作为 window 对象的属性和方法创建的。
- 所有末定义直接赋值的变量自动声明为拥有全局作用域
variable = "未定义直接赋值的变量";
- 所有window对象的属性拥有全局作用域
- 全局作用域中的弊端,污染全局命名空间, 容易引起命名冲突
局部作用域
——函数执行都会形成一个局部作用域块级作用域
——块级作用域通过ES6命令let和const声明
- 所声明的变量在指定块的作用域外无法被访问。
- 块级作用域,第一可在一个函数内部创建;二可在一个代码块(由一对花括号包裹)内部创建
- 块级作用域声明变量不会提升到代码块顶部
- 禁止重复声明
- 循环中的绑定块作用域的妙用
作用域最大的用处就是隔离变量,不同作用域下同名变量不会有冲突。
2. 作用域链
自由变量:未在函数中定义但是使用该变量,要到别的作用域去找的(变量跨作用域查找)都叫自由变量(当前作用域没有定义的变量)。
自由变量的值要到父执行环境中找,所谓的父执行环境,指的是创建函数时候的父执行环境,而不是调用时的父执行环境
作用域链:查找自由变量时,如果父级也没有定义,再一层一层向上寻找,直到找到全局作用域还是没找到,就宣布放弃。这种一层一层的关系,就是 作用域链 。
https://www.jianshu.com/p/cc79f22b99fe
var x = 10;
function fn() {console.log(x); // x 是自由变量
}function show(f) {var x = 20;(function () { // 立即执行匿名函数f();})();
}show(fn); // 10
在调用 show(fn)时,里面有一个立即执行匿名函数,执行了 fn()。那么 fn()里面有一个自由变量 x。x 取调用时父作用域的值,结果就是20;x 取创建函数时候的父作用域的值,结果就是 10。
3. 闭包是什么?如何利用闭包实现私有变量
变量分为:全局变量和局部变量
var a = 1; //全局变量a,在全局或者函数内部都可以访问到
function keith() {return a;var b = 2; //函数内部(局部作用域)定义的局部变量b}console.log(keith()); //1console.log(b); //ReferenceError: b is not defined//函数外部是无法访问的函数内部定义的b
那么如果我们想在函数外部(全局作用域下)访问函数内部的变量,该咋办呢?
function keith(){var a=1;function closure(){//在函数内部再定义一个函数return a; //内层函数返回上层函数的局部变量a}return closure;//将函数作为返回值}var result=keith();console.log(result()); //1
两者写法相同,唯一区别就是内部函数是否使用匿名函数
function keith(){var a=1;return function(){return a;};}var result=keith();console.log(result()) //1
闭包:有权访问另一个函数作用域中变量的函数(能够读取其他函数内部变量的函数),外层函数的局部变量被内层函数所引用,调用外层函数返回内层函数,上面的closure
函数就是闭包。
闭包的特点:
1. 在一个函数内部定义另外一个函数,并且返回内部函数或者立即执行内部函数。
2. 内部函数可以读取外部函数定义的局部变量
3. 让局部变量始终保存在内存中。也就是说,闭包可以使得它诞生环境一直存在,。
为什么会用到闭包?
函数外部无法访问函数内部的局部变量,但函数内部的函数可以访问本函数内的局部变量,故通过闭包实现在函数外部访问函数内部局部变量。但容易造成内存泄漏,应当谨慎使用。
闭包的实际应用
- 封装对象的私有属性和私有方法
闭包实现私有变量,只提供API
这里是利用构造函数,创建私有变量、私有方法
function privateVariable() {var value;this.setValue = function(newValue) {value= newValue;};this.getValue = function() {return value;};}
var x = new privateVariable();
x.setValue("abcd");console.log(x.value); //undefined
console.log(x.getValue ()); //abcd
this指向问题
分类 | this指向 |
---|---|
普通函数执行 | this指向定义时的环境 window |
箭头函数执行 | this指向上一层环境 |
对象方法执行 | this指向该方法所属对象 |
构造函数、class | this指向实例对象 |
call、apply、bind()执行 | this指向传入的执行上下文 |
箭头函数与普通函数的区别
- 箭头函数都是匿名函数,普通函数有匿名、具名
- 箭头函数不能用于构造函数,不能使用new,不具有super
- 箭头函数本身不创建this,但是在声明时可以捕获其上下文的this供自己使用,普通函数,this指向函数定义的地方,或者构造函数中指向实例对象
- 箭头函数不具有原型
prototype
六、异步
单线程及异步
- JS是单线程语言,同一时间只能做一件事儿
- 浏览器和Nodejs已支持JS启动进程,如Web Worker
- JS和DOM渲染共用一个线程,因为JS可修改DOM结构
同步和异步的区别是什么?
- 同步和异步,是基于JS是单线程语言的本质出现的
- 同步任务,按顺序执行,遇到
alert()
,会阻塞代码执行 - 异步任务,通过回调函数实现,不会阻塞代码的执行
前端使用异步的场景
- 网络请求,如
ajax
、图片加载img.οnlοad=function(){} - 定时任务,如
setTimeout
、setInterval
Promise解决回调地狱
$.get(url1,(data1)=>{//获取第一份数据console.log(data1)$.get(url2,(data2)=>{//获取第二份数据console.log(data2)$.get(url3,(data3)=>{//获取第三份数据console.log(data3)})})
})
function getData(url){return new Promise(function(resolve,reject)=>{$.ajax({url,success(data){resolve(data)},error(err){reject(err)}})})
}getData(url1).then(data1=>{console.log(data1)return getData(url2)
}).then(data2=>{console.log(data2)return getData(url3)
}).then(data3=>{console.log(data3)
}).catch(err=>{console.error(err)
})
手写用Promise加载一张图片
const url1='https://pics6.baidu.com/feed/9e3df8dcd100baa1c92ee995ab9c801ac8fc2e36.jpeg?token=e8fe2ad2c923748490586c27c85bc358';const url2='https://img-home.csdnimg.cn/images/20201124032511.png';function loadImg(url){return new Promise((resolve,reject)=>{ const img=document.createElement('img') img.onload=function(){resolve(img)} img.onerror=function(){reject(new Error(`图片加载失败!`))} img.src=url})
}loadImg(url1).then(img1=>{console.log(img1.width) document.getElementById('ss').appendChild(img1); return img1
}).then(img1=>{console.log(img1.height)return loadImg(url2)
}).then(img2=>{console.log(img2.width);document.getElementById('ss').appendChild(img2);
}).catch(err=>{console.log(err) //Error: 图片加载失败! at HTMLImageElement.img.onerror (loadImgUsePromise.html:26)
})
面试题
如题,请问结果输出什么?
console.log(1)
setTimeout(function(){console.log(2)
},1000)
console.log(3)
setTimeout(function(){console.log(4)
},0)
console.log(5)
答案:1、3、5、4、2
七、ES6
require与import的区别
执行环境不同,前者是在node环境下,后者是在浏览器上
八、HTTP协议
1. 什么是HTTP协议、TCP协议,两者关系
HTTP协议(Hyper Text Transfer Protocol)
HTTP协议是超文本传输协议,属于OSI模型中应用层的协议,定义的是传输数据内容的规范。它是一个基于TCP/IP通信协议来传递数据
HTTP协议采用了请求/响应模型。客户端向服务器发送一个请求报文,请求报文包含
请求的方法、URL、协议版本、请求头部和请求数据
。服务器以一个状态行作为响应,响应的内容包括协议的版本、成功或者错误代码、服务器信息、响应头部和响应数据
。
HTTP工作原理
- 客户端连接到Web服务器端
- 发送HTTP请求
- 服务器端接收请求,并返回Http响应
- 释放连接TCP连接
- 客户端浏览器解析HTML内容
TCP协议
TCP协议是一种面向连接的、可靠的,属于OSI模型中的传输层协议,定义的是数据传输及连接方式的规范
UDP协议
UDP协议是一种无连接、不可靠的,属于OSI模型中的传输层协议,定义的是
websocket协议
websocket 是一种网络通信协议,是HTML5 开始提供的一种在单个 TCP 连接上进行全双工通信的协议.
相比http 协议来说,http 协议是一种无状态的、无连接的、单向的应用层协议,通信请求只能由客户端发起,服务端对请求做出应答处理。http 协议无法实现服务器主动向客户端发起消息,
Websocket 连接允许客户端和服务器之间进行全双工通信,以便任一方都可以通过建立的连接将数据推送到另一端。WebSocket 只需要建立一次连接,就可以一直保持连接状态。
2. HTTP状态码分类
状态码 | 含义 |
---|---|
1XX | 服务器接收到请求 |
2XX | 请求成功 |
3XX | 重定向 |
4XX | 客户端错误 |
5XX | 服务器错误 |
3. 常见的状态码
状态码 | 含义 |
---|---|
200 | 请求成功 |
204 | No content,表示请求成功,但响应报文不含实体的主体部分,没有body数据 |
301 | 永久重定向(配合location,浏览器自动处理),域名到期,永久重定向到新的域名 |
302 | 临时重定向(服务器在response Headers中配合location,返回临时重定向的地址)下一次客户端还是访问原地址,常见的搜索引擎,搜索出来的地址 |
304 | 协商缓存被命中,之前向服务器端请求过的资源未被修改,未到期,告诉浏览器从缓存中找 |
403 | Forbidden - 服务器拒绝访问,没有权限访问此站,角色权限方面使用,对请求资源的访问被服务器拒绝 |
404 | Not Found-资源未找到,在服务器上没有找到请求的资源 |
405 | Method Not Allowed-请求方法不被服务器允许 |
500 | Internal Server Error-服务器出现未知错误 |
502 | Bad Gateway- 服务器自身是正常的,但访问的时候出错了,啥错误咱也不知道 |
503 | service unavailable-表明服务器暂时处于超负载或正在停机维护,无法处理请求,暂时无法响应服务 |
504 | 网关超时,比如数据库连接超时啥的 |
4. HTTP 请求头headers
HTTP 请求头主要分为两类
Request Headers
Response Headers
Request Headers
Accept
浏览器可接收的数据格式*/*
Accept-Encoding
浏览器可接收的压缩算法,如gzip
Accept-Languange
浏览器可接收的语言,如zh-CN
Connection:keep-alive
一次TCP连接重复使用Cookie
同域都会带上Host
域名User-Agent (简称UA)
浏览器信息Content-type
发送数据的格式 ,如application/json
Response Headers
Content-type
返回数据格式,如application/json
Content-length
返回数据的大小,多少字节Content-Encoding
返回数据的压缩算法,如gzipSet-Cookies
5. methods分类
- GET: 通常用来获取资源
- HEAD: 获取资源的元信息
- POST: 提交数据,即上传数据
- PUT: 修改数据
- DELETE: 删除资源(几乎用不到)
- CONNECT: 建立连接隧道,用于代理服务器
- OPTIONS: 列出可对资源实行的请求方法,用来跨域请求
- TRACE: 追踪请求-响应的传输路径
GET 和 POST 有什么区别?
首先最直观的是语义上的区别。
- 从缓存的角度,GET 请求会被浏览器主动缓存下来,留下历史记录,而 POST 默认不会。
- 从编码的角度,GET 只能进行 URL 编码,只能接收 ASCII 字符,而 POST 没有限制。
- 从参数的角度,GET 一般放在 URL 中,因此不安全,POST 放在请求体中,更适合传输敏感信息。
- 从幂等性的角度,GET是幂等的,而POST不是。(幂等表示执行相同的操作,结果也是相同的)
- 从TCP的角度,GET 请求会把请求报文一次性发出去,而 POST 会分为两个 TCP 数据包,首先发 header 部分,如果服务器响应 100(continue), 然后发 body 部分。(火狐浏览器除外,它的 POST 请求只发一个 TCP 包)
6. Restful API
- 传统的API:把URL当做一个功能
- Restful API :把URL当做唯一的资源
Restful API 特点
- 尽量不用 url 参数
- 用 method 表示操作类型
7. HTTP与HTTPS的区别
https://www.cnblogs.com/wqhwe/p/5407468.html
超文本传输协议HTTP协议被用于在Web浏览器和网站服务器之间传递信息,HTTP协议以明文方式发送内容,不提供任何方式的数据加密,如果攻击者截取了Web浏览器和网站服务器之间的传输报文,就可以直接读懂其中的信息,因此,HTTP协议不适合传输一些敏感信息,比如:信用卡号、密码等支付信息。
为了解决HTTP协议的这一缺陷,需要使用另一种协议:安全套接字层超文本传输协议HTTPS,为了数据传输的安全,HTTPS在HTTP的基础上加入了SSL协议,SSL依靠证书来验证服务器的身份,并为浏览器和服务器之间的通信加密。
8. HTTP2的特点
二进制分帧
压缩头部
多路复用
请求优先级
服务器推送
服务器提示
- 二进制分帧
在应用层跟传送层之间增加了一个二进制分帧层,从而能够达到在不改动HTTP的语义,HTTP方法,状态码,URI以及首部字段的情况下,突破HTTP 1.1的性能限制,改进传输性能,实现低延迟和高吞吐量。
HTTP 2.0会将所有传输的信息分割为更小的消息和帧,并对它们采用二进制格式的编码,其中HTTP 1.1的首部信息会被封装到Headers帧,而request body被封装到图中所示的DATA帧。相当于把部分数据塞进了二进制分帧层里,改进传输性能。
- 压缩头部
HTTP 2.0在客户端和服务端使用首部表来跟踪和存储之间发送的键-值对,对相同请求而言不需要再次发送请求和相应发送,通信期间几乎不会改变的通用键值,如user-Agent和content-Type值发送一次,相当于做了一层缓存。
如果请求不包含首部,如:对同一资源的轮询请求,那首部开销为零字节
如果首部发生变化,那只需发送变化的数据在Headers帧里面,新增或修改的首部帧会被追加到首部表
- 多路复用
- CSS雪碧图合并-减少请求
- 合并压缩CSS跟JS代码-减少请求
- CSS代码放在header头部里面,JS代码放到body结束之前,因为JS代码执行会阻塞
对HTTP 1.1而言,浏览器通常有并行连接的限制,即最多几个并行链接。而多路复用允许通过单一的HTTP 2.0连接发起多重的请求-相应消息 ,这意味着HTTP 2.0的通信都在一个连接上完成了,这个连接可以承载任意数量的双向数据流,直观来说,就是上面我们所做的优化已经不需要了。
- 请求优先级
所有资源可以并行交错发送, 那想要优先拿到CSS和JS而不是图片怎么办,在每个HTTP 2.0的流里面有个优先值,这个优先值确定着客户端跟服务器处理不同的流采取不同的优先级策略,高优先级优先发送,但这不是绝对的(绝对等待会导致队头阻塞问题)
- 服务器推送
服务端可以在发送页面HTML时主动推送其它资源,而不用等到浏览器解析到相应位置,发起请求再响应。例如服务端可以主动把JS和CSS文件推送给客户端,而不需要客户端解析HTML时再发送这些请求。
服务端可以主动推送,客户端也有权利选择是否接收。如果服务端推送的资源已经被浏览器缓存过,浏览器可以通过发送RST_STREAM帧来拒收。主动推送也遵守同源策略,服务器不会随便推送第三方资源给客户端。
- 服务器提示
HTTP 2.0新增加服务器提示,可以先于客户端检测到将要请求的资源,提前通知客户端,服务器不发送所有资源的实体,只发送资源的URL,客户端接到提示后会进行验证缓存,如果真需要这些资源,则正式发起请求(服务器主动更新静态资源)
9. 浏览器缓存
Cookies
:4KB,用于用户信息的存储,Cookie的内容会在请求时被传递给服务器,安全性低LocalStorage
:数据将一直保存在浏览器内,直到用户清除浏览器缓存数据为止。SessionStorage
:数据保存于当前session会话中,当标签页被关闭时,数据会被清除。
10.HTTP缓存 (浏览器缓存机制)
缓存位置
从缓存位置上来说分为四种,并且各自有优先级,当依次查找缓存且都没有命中的时候,才会去请求网络
Service Worker Cache
(传输协议必须为 HTTPS,可自由控制缓存,实现离线缓存)Memory Cache
(内存缓存,主要包含的是当前中页面中已经抓取到的资源,例如页面上已经下载的样式、脚本、图片,一旦关闭 Tab 页面,内存中的缓存也就被释放了)Disk Cache
(硬盘缓存,读取速度慢点,通过对Cache-Control、expires 等字段控制的缓存)Push Cache
(推送缓存,HTTP/2内容,它只在会话(Session)中存在,一旦会话结束就被释放,并且缓存时间也很短暂 )
如果以上四种缓存都没有命中的话,那么只能发起请求来获取资源了。
缓存过程
- 浏览器每次发送请求,都会先在浏览器缓存中查找该请求的结果以及缓存标识
- 浏览器每次拿到返回的请求结果,都将会把结果和缓存标识存入浏览器缓存中
缓存分类
通常浏览器缓存分为两种,一种是强缓存
、一种是协商缓存
,并且缓存策略都是通过设置HTTP Header
来实现的。
浏览器对于缓存的处理是根据第一次请求资源时返回的响应头来确定的
强缓存
- 不会向服务器发送请求,直接从缓存中读取资源
- 请求返回
200
状态码,Size
显示from memory cache
或from disk cache
- 强缓存通过设置两种
HTTP Header
中服务器响应消息头字段实现:Expires
缓存过期时间 /Cache-Control
控制网页缓存
Expires:max-age + 请求时间,需要和Last-modified结合使用,在响应http请求时告诉浏览器在过期时间前浏览器可以直接从浏览器缓存取数据,而无需再次请求。受限于本地时间,如果修改了本地时间,可能会造成缓存失效。
Cache-Control:主要用于控制网页缓存。比如当Cache-Control:max-age=300时,则代表在这个请求正确返回时间(浏览器也会记录下来)的300秒,即5分钟内再次加载资源,就会命中强缓存。
两者同时存在的话,
Cache-Control
优先级高于Expires
;Expires
受限于本地时间,如果修改了本地时间,可能会造成缓存失效。
cache-control
:
max-age=300
,5分钟内再次加载资源,就会命中强缓存。s-maxage=31536000
,用于表示 cache 服务器上(比如 cache CDN)的缓存的有效时间,**仅在代理服务器中生效,**客户端中我们只考虑max-agepublic
,既可以被浏览器缓存,也可以被代理服务器缓存private
,只能被浏览器缓存no-cache
,绕开浏览器,每一次请求都不会去问浏览器的缓存情况,直接向服务器确认该资源是否过期(走协商缓存)
-no-store
,不使用任何缓存策略,只允许直接向服务器发送请求、并下载完整的响应。
协商缓存
协商缓存就是强缓存失效后,浏览器携带缓存标识向服务器发送请求,由服务器根据缓存标识来判断,是否使用缓存的过程,主要有以下两种情况:
协商缓存生效,返回304和
Not Modified
,表示服务器资源无更新,可以从浏览器缓存中获取。协商缓存无效,返回200和请求结果,表示服务器资源已更新,重新返回请求结果和200,之后再将请求结果和缓存标识存入浏览器缓存中
协商缓存可以通过设置两种
HTTP Header
中服务器响应消息头字段实现:Last-Modified
和Etag
Last-Modified
:表示资源在服务器上的最后修改时间,浏览器接收后,缓存文件和Header
再次请求时,浏览器检测到
Last-Modified
,于是添加If-Modified-Since
字段,值为Last-Modified
中的值,服务器再次收到时,比对if-Modified-since
与last-Modified
的值,如果相等,返回304和空响应体,如果if-Modified-since
时间小于服务器中这个资源的最后修改时间,说明文件有更新,于是返回新的资源文件和200
Etag
:服务器响应请求时,返回当前资源文件的一个唯一标识(由服务器生成),只要资源有变化,都会生成新的ETag值。
再次请求时,浏览器把上一次返回的
Etag
值放在if-None-Match
里面,服务器只需要比较客户端传来的if-None-Match
和自己服务器上的该资源的Etag
是否一致,如果不一致,返回新的资源及200,如果一致,返回304和空响应体,通知客户端直接使用本地缓存。
从精确度及优先级上,服务器校验优先考虑
Etag
,因为If-Modified-Since
只能检查到以秒为最小计量单位的时间差,服务器并没有正确感知文件的变化。
缓存机制
- 强缓存优先于协商缓存
- 若强制缓存(Expires/Cache-control)生效则直接使用缓存
- 若强缓存不生效,则进行协商缓存(
Last-Modified/if-Modified-Since
和Etag/if-None-Match
)。 - 若协商缓存成功,返回304,继续使用缓存
- 若协商缓存失效,返回200,新的资源和缓存标识,再次存入浏览器中。
缓存策略的实际场景应用
1.频繁变动的资源
Cache-Control: no-cache
对于频繁变动的资源,首先需要使用Cache-Control: no-cache
使浏览器每次都请求服务器,然后配合 ETag
或者 Last-Modified
来验证资源是否有效。这样的做法虽然不能节省请求数量,但是能显著减少响应数据大小。
2.不常变化的资源
Cache-Control: max-age=31536000
通常在处理这类资源时,给它们的 Cache-Control
配置一个很大的 max-age=31536000
(一年),这样浏览器之后请求相同的 URL 会命中强制缓存。
而为了解决更新的问题,就需要在文件名(或者路径)中添加 hash, 版本号等动态字符,之后更改动态字符,从而达到更改引用 URL 的目的,让之前的强制缓存失效 (其实并未立即失效,只是不再使用了而已)。
在线提供的类库 (如 jquery-3.3.1.min.js, lodash.min.js 等) 均采用这个模式
用户行为对浏览器缓存的影响
所谓用户行为对浏览器缓存的影响,指的就是用户在浏览器如何操作时,会触发怎样的缓存策略。主要有 3 种
打开网页,地址栏输入地址:查找
Disk Cache
中是否有匹配,如有则使用,没有则发送网络请求普通刷新(F5):Tab没有关闭,因此
memory cache
是可用的,会被优先使用memory cache
(匹配到的话),其次才是Disk cache
强制刷新(Ctrl+F5):浏览器不使用缓存,因此发送的请求头部均带有
Cache-control:no-cache
,服务器直接返回200和最新结果
11. JS GC垃圾回收机制
什么是内存泄漏?
对于持续运行的服务进程,必须及时释放内存,否则,内存占用越来越高,轻则影响系统性能,重则导致进程崩溃。
不再用到的内存,没有及时释放,就叫做内存泄漏。
JS垃圾回收机制原理:
解决内存的泄露,垃圾回收机制会定期(周期性)找出那些不再用到的内存(变量),然后释放其内存。
现在各大浏览器通常采用的垃圾回收机制有两种方法:标记清除,引用计数
。
标记清除
标记清除
:给每个变量标记进入环境或者离开环境,当变量离开执行环境时,变量被回收。
引用计数
引用计数
:语言引擎中有一张引用表,保存了内存里所有的资源的引用次数,如果一个值的引用次数为0,则将这块内存释放。
三、防抖 (debounce)
防抖 :当调用动作过n豪秒后,才会执行该动作,若在这n毫秒内,又调用此动作,则将重新计算执行时间
使用场景:
- 输入框打字搜索查询时,节约请求资源
- window对象的resize事件
- 拖拽时的mousemove事件
const debounce = (func, wait = 50) => { // func是用户传入需要防抖的函数 wait是等待时间let timer = 0 return function(...args) {//每次用户实际调用的防抖函数if (timer) clearTimeout(timer) // 如果已经设定过定时器了就清空上一次的定时器timer = setTimeout(() => { // 开始一个新的定时器,延迟执行用户传入的方法func.apply(this, args)}, wait)}
}
四、节流(throttle)
含义:预先设定一个执行周期,当调用动作的时刻大于等于n则执行该动作,n豪秒内只会执行一次,然后进入下一个新周期
使用场景:
- 节流常应用于鼠标不断点击触发、监听滚动事件。
const throttle = (fn,time)=>{let flag=true;return function(){if(!flag) return;flag=false;setTimeout(()=>{fn.apply(this,arguments)flag=true},time)}
}
使用:
window.onscroll = throttle(function(){console.log('正在加载中~')
},3000)
1. 共同点
函数节流(throttle)与 函数防抖(debounce)都是为了限制函数的执行频次,以优化函数触发频率过高导致的响应速度跟不上触发频率,出现延迟,假死或卡顿的现象。
2. 区别
防抖debounce
像是搜索框的查询,等待用户完成操作再执行,避免打字期间就不断的查询。当调用动作过n豪秒后,才会执行该动作,若在这n毫秒内,又调用此动作,则将重新计算执行时间。节流throttle
像是按钮的冷却时间,防止用户疯狂点击按钮提交表单不断的调用接口,我们限制 2 秒才发一次请求,不管你点击多少次;预先设定一个执行周期,当调用动作的时刻大于等于n则执行该动作,n豪秒内只会执行一次,然后进入下一个新周期
五、undefined与null 有什么区别
undefined
:定义但未赋值
null
:定义且已赋值,值为null
什么时候给变量赋值为null?
- 初始赋值,表明变量类型将会是引用类型,如对象object
- 结束操作,该对象需要被垃圾回收时
六、浏览器是如何渲染页面的?
渲染引擎首先解析HTML文档,生成DOM树)
- 解析CSS文件构建 CSSOM树 (CSS Object Model层叠样式表模型)
CSS文件并生成CSS规则树,在过程中,每个CSS文件都会被分析成StyleSheet对象,每个对象都包括CSS规则,CSS规则对象包括对应的选择器和声明对象以及其他对象。
- 构建渲染Render树
根据DOM树与CSSOM树生成另外一棵用于渲染的树
- 布局渲染Render树
计算每一个渲染树节点的位置和大小,此过程被称为reflow。(对渲染树的每个节点进行布局处理,确定其在屏幕上的显示位置)
- 绘制Render树,最后遍历渲染树,并调用操作系统的Native GUI API完成绘制(repain)
回流(重排)与重绘
https://www.cnblogs.com/ShuiNian/p/12098325.html
回流,也叫重排(Layout):当页面的布局和几何属性发生改变的时候,就需要进行重排
- 添加和或者删除可见的DOM元素
- 元素的位置发生变化
- 元素的尺寸发生变化(包括:外边距,内边距,边框厚度,宽度,高度等属性发生改变)
- 内容发生变化(例如:内容增加引起高度变化或者是图片被另外一个不同尺寸的图片所替换)
- 页面渲染器进行初始化的
- 浏览器窗口尺寸发生改变
由于每次的重排都会产生计算消耗,大多数浏览器通过队列化
修改并批量来优化重排过程。
重绘(Painting):当改变vidibility、outline、背景色等属性导致样式的变化,使浏览器需要根据新的属性进行绘制
重绘不一定导致回流(重排),但回流(重排)一定会导致重绘。
需要注意的是,display:none
会触发 reflow
,而visibility: hidden
属性则并不算是不可见属性,它的语义是隐藏元素,但元素仍然占据着布局空间,它会被渲染成一个空框,这在我们上面有提到过。所以visibility:hidden
只会触发 repaint
,因为没有发生位置变化。
https://www.imooc.com/article/40004
减少回流(重排)、重绘:
- 合并对DOM的多次修改
- 批量修改DOM ,使元素脱离文档流
- DOM的离线化:一旦我们给元素设置
display:none
时,元素不会存在于渲染树中,相当于将其从页面“拿掉”,我们之后的操作将不会触发重排和重绘,这叫做 - 使用虚拟DOM
八、浅谈MVC模式与MVVM模式的区别
MVC模式
- M:Model(数据模型),用于存放数据
- V:View(视图),也就是用户界面
- C:Controller是Model和View的协调者,Controller把Model中的数据拿过来给View使用。
缺点:
所有业务逻辑都在Controller里操作,逻辑复杂且不利于维护
大量的DOM 操作使页面渲染性能降低,加载速度变慢,影响用户体验。
当 Model 频繁发生变化,需要主动更新到View,当用户的操作导致Model发生变化,同样需要将变化的数据同步到Model中, 这样的工作不仅繁琐,而且很难维护复杂多变的数据状态。
MVVM模式:
核心是提供对View 和 ViewModel的双向数据绑定,View和Model之间并没有直接的联系,而是通过ViewModel进行交互,View的变动,自动反映在ViewModel上,反之亦然,这样就保证视图和数据的一致性。
- M:Movel(数据模型)
- V:View
- VM:ViewModel 是一个同步View 和 Model的对象。
View 和 Model 之间并没有直接的联系,而是通过ViewModel进行交互。
ViewModel 通过双向数据绑定把 View 层和 Model 层连接了起来,而View 和 Model 之间的同步工作完全是自动的,无需人为干涉,因此开发者只需关注业务逻辑,不需要手动操作DOM, 不需要关注数据状态的同步问题,复杂的数据状态维护完全由 MVVM 来统一管理。
九、什么是 Virtual DOM?
所谓的virtual dom,也就是虚拟节点。它通过JS的Object对象模拟DOM中的节点, 那么相较于 DOM 来说,操作 JS 对象会快很多,并且我们也可以通过 JS 来模拟 DOM
const ul = {tag: 'ul',props: {class: 'list'},children: {tag: 'li',children: '1'}
}
上述代码对应的 DOM 就是
<ul class='list'><li>1</li>
</ul>
那么既然 DOM 可以通过 JS 对象来模拟,反之也可以通过 JS 对象来渲染出对应的 DOM。通过 JS 来模拟 DOM 并且渲染对应的 DOM 只是第一步,难点在于如何判断新旧两个 JS 对象的最小差异并且实现局部更新 DOM。
十、前端路由原理?两种实现方式有什么区别?
前端路由实现起来其实很简单,本质就是监听 URL 的变化,然后匹配路由规则,显示相应的页面,并且无须刷新页面。目前前端使用的路由就只有两种实现方式
- Hash 模式
- History 模式
Hash 模式
www.test.com/#/
就是 Hash URL
,当 #
后面的哈希值发生变化时,可以通过 hashchange
事件来监听到 URL 的变化,从而进行跳转页面,并且无论哈希值如何变化,服务端接收到的 URL 请求永远是 www.test.com
window.addEventListener('hashchange', () => {// ... 具体逻辑
})
History 模式
History 模式是 HTML5 新推出的功能,主要使用 history.pushState
和 history.replaceState
改变 URL。
通过 History 模式改变 URL 同样不会引起页面的刷新,只会更新浏览器的历史记录。
// 新增历史记录
history.pushState(stateObject, title, URL)// 替换当前历史记录
history.replaceState(stateObject, title, URL)
当用户做出浏览器动作时,比如点击后退按钮时会触发 popState
事件
window.addEventListener('popstate', e => {// e.state 就是 pushState(stateObject) 中的 stateObjectconsole.log(e.state)
})
两种模式对比
Hash 模式只可以更改 # 后面的内容,History 模式可以通过 API 设置任意的同源 URL
History 模式可以通过 API 添加任意类型的数据到历史记录中,Hash 模式只能更改哈希值,也就是字符串
Hash 模式无需后端配置,并且兼容性好。History 模式在用户手动输入地址或者刷新页面的时候会发起 URL 请求,后端需要配置 index.html 页面用于匹配不到静态资源的时候
十一、Vue 生命周期
beforeCreate()
:获取不到props
获者data
中的数据,因为数据的初始化还在initState
中created()
:已完成数据观测 (data observer),property 和方法的运算,watch/event 事件回调,组件还没被挂载,看不到组件beforeMount()
:在挂载开始之前被调用,相关的 render 函数首次被调用。 该钩子在服务器端渲染期间不被调用。mounted()
:实例被挂载后调用,这时 el 被新创建的根 DOM 元素vm.$el
替换了。如果根实例挂载到了一个文档内的元素上,当mounted
被调用时根 DOM 元素vm.$el
也在文档内。该钩子在服务器端渲染期间不被调用。beforeUpdate()
:数据更新前调用updated()
:数据更新后会调用beforeDestroy()
:适合移除事件、定时器等等,否则可能会引起内存泄露的问题destroyed
:实例销毁后调用。该钩子被调用后,对应 Vue 实例的所有指令都被解绑,所有的事件监听器被移除,所有的子实例也都被销毁。
keep-alive 生命周期
用 keep-alive 包裹的组件在切换时不会进行销毁,而是缓存到内存中,并执行 deactivated 钩子函数,命中缓存渲染后会执行 activated 钩子函数。
activated
:被 keep-alive 缓存的组件激活时调用。deactivated
:被 keep-alive 缓存的组件停用时调用。
组件通信
组件通信一般分为以下几种情况:
- 父子组件通信:
props/$emit
、$parent/$children
- 兄弟组件通信:
this.$parent.$children
- 跨多层级组件通信:
provide / inject
- 任意组件:
Vuex、Event Bus
computed 和 watch 区别
computed
是计算属性,依赖其他属性计算值,并且 computed 的值有缓存,只有当计算值变化才会返回内容。
watch
监听到值的变化就会执行回调,在回调中可以进行一些逻辑操作
应用场景:
computed
:需要依赖别的属性来动态获得值用watch
:对于监听到值的变化需要做一些复杂业务逻辑的情况使用
v-show 与 v-if 区别
v-show
只是在 display: none
和 display: block
之间切换。只是切换 CSS,DOM 还是一直保留着的。 v-show
在初始渲染时有更高的开销,但是切换开销很小,更适合于频繁切换的场景。
v-if 的话就得说到 Vue 底层的编译了。当属性初始为 false 时,组件就不会被渲染,直到条件为 true,并且切换条件时会触发销毁/挂载组件,所以总的来说在切换时开销更高,更适合不经常切换的场景。
并且基于 v-if 的这种惰性渲染机制,可以在必要的时候才去渲染组件,减少整个页面的初始渲染开销。
组件中 data 什么时候可以使用对象
组件复用时所有组件实例都会共享 data,如果 data 是对象的话,就会造成一个组件修改 data 以后会影响到其他所有组件
,所以需要将 data 写成函数,每次用到就调用一次函数获得新的数据。
当我们使用 new Vue()
的方式的时候,无论我们将 data 设置为对象还是函数都是可以的,因为 new Vue() 的方式是生成一个根组件,该组件不会复用,也就不存在共享 data 的情况了。
Vue.extend 的使用
扩展组件生成一个构造器,通常会与 $mount
一起使用
// 创建组件构造器
let Component = Vue.extend({template: '<div>test</div>'
})
// 挂载到 #app 上
new Component().$mount('#app')
// 除了上面的方式,还可以用来扩展已有的组件
let SuperComponent = Vue.extend(Component)
new SuperComponent({created() {console.log(1)}
})
new SuperComponent().$mount('#app')
mixin 和 mixins 区别
mixin 用于全局混入,是用来分发 Vue 组件中可复用功能的,会影响到每个组件实例,通常插件都是这样做初始化的。
Vue.mixin({beforeCreate() {// ...逻辑// 这种方式会影响到每个组件的 beforeCreate 钩子函数}
})
mixins 应该是我们最常使用的扩展组件的方式了。如果多个组件中有相同的业务逻辑,就可以将这些逻辑剥离出来,通过 mixins 混入代码,比如上拉下拉加载数据这种逻辑
Vue响应式原理
Vue2.0
Vue 内部使用 Object.defineProperty()
将 Data 中的每一个成员都转换为 getter / setter
的形式。
getter
用来依赖收集,setter
用来派发更新。而模板内容,最终会被编译为 render
函数。
在 render 函数中,我们能发现 _v(_s(message)) message
被访问了,就会触发 getter 来进行依赖收集。
而在代码中的点击事件中,一旦事件处理程序被触发执行,那么 message 则会被修改,就会触发 setter
来进行派发更新。
var data = { name: 'yck' }
observe(data)
let name = data.name // -> get value
data.name = 'yyy' // -> change valuefunction observe(obj) {// 判断类型if (!obj || typeof obj !== 'object') {return}Object.keys(obj).forEach(key => {defineReactive(obj, key, obj[key])})
}function defineReactive(obj, key, val) {// 递归子属性observe(val)Object.defineProperty(obj, key, {// 可枚举enumerable: true,// 可配置configurable: true,// 自定义函数get: function reactiveGetter() {console.log('get value')return val},set: function reactiveSetter(newVal) {console.log('change value')val = newVal}})
}
obj.defineProperty
弊端:
- 无法检测 property 的添加或移除。
set、delete
方法 - 不能检测以下数组的变动,不能很好的实现对数组下标的监控。set 、splice
vue3.0
Proxy 实现原理
使用 Proxy
实现的响应式代码,要比使用 defineProperty
的代码简单得多。
<div id="app">hello</div><script>// 模拟 Vue 中的 data 选项let data = {msg: 'hello',count: 0}// 模拟 Vue 实例const vm = new Proxy(data, {// 执行代理行为的函数// 当访问 vm 的成员会执行get (target, key) {console.log('get, key: ', key, target[key])return target[key]},// 当设置 vm 的成员会执行set (target, key, newValue) {console.log('set, key: ', key, newValue)if (target[key] === newValue) {return}target[key] = newValuedocument.querySelector('#app').textContent = target[key]}})// 测试vm.msg = 'Hello World'console.log(vm.msg)
</script>
Object.defineProperty
与Proxy
的对比
Object.defineProperty
只能监听对象里的某个属性,而Proxy
可以监听整个对象Object.defineProperty
直接修改原对象的属性,而Proxy
只是代理了原对象外层属性,递归代理对象内部的对象,并返回一个新的代理proxy对象,没有修改原对象。- 对象上定义新属性时,Proxy可以监听到,Object.defineProperty监听不到。
- 数组新增删除修改时,Proxy可以监听到,Object.defineProperty监听不到。
- Proxy不兼容IE,Object.defineProperty不兼容IE8及以下。
Vue模板编译过程
- 将模板解析为 AST(抽象语法树)
- 优化 AST
- 将 AST 转换为 render 函数
[搞定一面] 快速搞定一面~技术面相关推荐
- 教你一招超级简单的方法快速搞定grub.conf文件的丢失及损坏
教你一招超级简单的方法快速搞定grub.conf文件的丢失及损坏 实验环境: GRUB是大多数Linux系统默认使用的引导程序,当"/boot/grub/grub.conf"配置文 ...
- 一行代码快速搞定Flowable断点下载(下)
一行代码快速搞定Flowable断点下载(下) 其实这个主题对应的三篇文章真的真的非常难写,首先是感觉非常多人对于函数式编程不太熟悉,然后又有一些人对于kotlin不太熟悉.这就导致了,写这三篇文章的 ...
- 一行代码快速搞定Flowable断点下载(中)
一行代码快速搞定Flowable断点下载(中) 感觉上一篇家常聊了太多,这一篇就直接进入正题,首先来看一下,通过存储化以及方法拓展技术将mComposableDisposable的相关逻辑也从抽象Ac ...
- 一行代码快速搞定Flowable断点下载(上)
一行代码快速搞定Flowable断点下载(上) 之前我们大致讲了讲,到底怎么完全将disposable相关代码完全隐藏. 然后到了这里,可能有些杠精就会说了,你那个方式,我们不是完全不能拿到Flowa ...
- 白话经典算法系列之六 快速排序 快速搞定
快速排序由于排序效率在同为O(N*logN)的几种排序方法中效率较高,因此经常被采用,再加上快速排序思想----分治法也确实实用,因此很多软件公司的笔试面试,包括像腾讯,微软等知名IT公司都喜欢考这个 ...
- 怎么做95置信区间图_这种动态的OD图怎么做?简单3步快速搞定
之前在视频号中发过一个单车的出行数据可视化效果. 动态展示了某天单车不同时段的运行情况,这种动态的OD可视化效果是如何制作的呢?使用的是kepler.gl进行制作的,其实非常简单,3步即可快速搞定. ...
- 【转载】白话经典算法系列之六 快速排序 快速搞定
原文地址:http://blog.csdn.net/morewindows/article/details/6684558 快速排序由于排序效率在同为O(N*logN)的几种排序方法中效率较高,因此经 ...
- 水墨特效怎么做?两种方法快速搞定!大神都在用的超美视频画面效果
想在视频里用高大上的水墨特效,却不知道怎么做?一般做这种唯美好看的效果,在一些特效软件里需要自己去设计.渲染,这一步就难倒了很多新手.那像视频大神一样的水墨特效就没办法制作了吗? 今天就教大家快速搞定 ...
- 计算机设计图片教程,电脑如何抠图?教你一招快速搞定
电脑抠图是使用软件进行图片处理,去除照片背景得到一张透明背景的图片,便于进行设计创作,抠图对于ps大神是非常简单的事情,可对于一窍不通的新手小白来说用电脑抠图是很困难的事情,但小编今天给大家分享一个抠 ...
最新文章
- 未来的计算机老素描画,考试这么无聊?学生把手画成“平面”,老师:未来的“美术大师”...
- StaticLinkList
- VTK修炼之道68:体绘制讨论_梯度不透明度传输函数
- OpenCV简单的过滤器平滑的实例(附完整代码)
- 聊聊CTR预估算法DeepFM
- 分解 python_面试官:如何用Python实现将一个整数分解成质因数?
- IE浏览器网页无法缩放怎么办 解决IE浏览器网页无法缩放的方法
- python修饰符的理解_python函数修饰符@的使用方法解析
- fabric 启动peer_Hyperledger Fabric Peer 常用命令总结
- LeetCode题目总结-滑窗法
- 反编译获取线上任何微信小程序源码(转)
- excel统计填充色单元格数
- 用python发邮件为什么接收不了_如何使用python发送邮件和接收邮件?
- Java父亲节贺卡,2018父亲节贺卡内容怎么写?父亲节贺卡写什么好
- 华为服务器新版bios修改IPMI,华为服务器ipmi设置
- c语言打印字母金字塔图形,C程序打印金字塔和图案
- Qt MetaObject sysmtem 详解之三:QMetaObject接口实现
- 白月黑羽教python之pytest:课后练习
- Java获取收件箱邮件
- 按拼音首字母排序并分组