大家好,这里是 lionLoveVue,基础知识决定了编程思维,学如逆水行舟,不进则退。金三银四,为了面试也还在慢慢积累知识,Github上面可以直接查看所有前端知识点梳理, github传送门,觉得不错,点个Star★,好运连连,Offer终究鼠于你,持续更新中。另外,也可以关注微信公众号: 小狮子前端Vue,源码以及资料今后都会放在里面。
一直想着成为一个up主,正值时间挺多的,4月份左右面试的面经我会制作视频去分享,赶快捧个场吧。 哔哩哔哩:一百个Chocolate
假设高度已知,请写出三栏布局,其中左、右栏宽度各为300px,中间自适应
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Layout</title>
<style>
html *{
padding: 0;
margin: 0;
}
.layout{
margin-top: 20px;
}
.layout article div{
min-height: 100px;
}
</style>
</head>
<body>
<!-- 浮动解决方式 -->
<section class="layout float">
<style>
.layout.float .left{
float: left;
width: 300px;
background: red;
}
.layout.float .right{
float: right;
width: 300px;
background: blue;
}
.layout.float .center{
background: yellow;
}
</style>
<article class="left-right-center">
<div class="left"></div>
<div class="right"></div>
<div class="center">
<h1>浮动解决方式</h1>
1.这是三栏布局的正中间部分
2.这是三栏布局的正中间部分
</div>
</article>
</section>
<!-- 绝对定位解决方式 -->
<section class="layout absolute">
<style>
.layout.absolute .left-center-right>div{
position: absolute;
}
.layout.absolute .left{
left: 0;
width: 300px;
background: red;
}
.layout.absolute .center{
left: 300px;
right: 300px;
background: yellow;
}
.layout.absolute .right{
right: 0;
width: 300px;
background: blue;
}
</style>
<article class="left-center-right">
<div class="left"></div>
<div class="center">
<h1>绝对定位解决方式</h1>
1.这是三栏布局的正中间部分
2.这是三栏布局的正中间部分
</div>
<div class="right"></div>
</article>
</section>
<!-- flexbox解决方式 -->
<section class="layout flexbox">
<style>
.layout.flexbox{
margin-top: 140px;
}
.layout.flexbox .left-center-right{
display: flex;
}
.layout.flexbox .left{
width: 300px;
background: red;
}
.layout.flexbox .center{
flex: 1;
background: yellow;
}
.layout.flexbox .right{
width: 300px;
background: blue;
}
</style>
<article class="left-center-right">
<div class="left"></div>
<div class="center">
<h1>flexbox解决方式</h1>
1.这是三栏布局的正中间部分
2.这是三栏布局的正中间部分
</div>
<div class="right"></div>
</article>
</section>
<!-- 表格布局 -->
<section class="layout table">
<style>
.layout.table .left-center-right{
width: 100%;
display: table;
height: 100px;
}
.layout.table .left-center-right>div{
display: table-cell;
}
.layout.table .left{
width: 300px;
background: red;
}
.layout.table .center{
background: yellow;
}
.layout.table .right{
width: 300px;
background: blue;
}
</style>
<article class="left-center-right">
<div class="left"></div>
<div class="center">
<h1>表格解决方式</h1>
1.这是三栏布局的正中间部分
2.这是三栏布局的正中间部分
</div>
<div class="right"></div>
</article>
</section>
<!-- 网格布局 -->
<section class="layout grid">
<style>
.layout.grid .left-center-right{
display: grid;
width: 100%;
grid-template-rows: 100px;
grid-template-columns: 300px auto 300px;
}
.layout.grid .left{
background: red;
}
.layout.grid .center{
background: yellow;
}
.layout.grid .right{
background: blue;
}
</style>
<article class="left-center-right">
<div class="left"></div>
<div class="center">
<h1>网格解决方式</h1>
1.这是三栏布局的正中间部分
2.这是三栏布局的正中间部分
</div>
<div class="right"></div>
</article>
</section>
</body>
</html>
上述5中解决方式是比较常见的,但是我们不能只局限于为了问答而问答,我们应该从此基础上升华一下问题。
答完了这5种常见方式,并不代表我们页面布局这一话题就结束了,面试官可能还会延伸我们的问题,比如:
高度已知
条件去掉,考虑纵向,那么对于中间内容过多,导致中间格子撑开,此时需要左右跟着撑开,以上5种方式哪几种还能使用?那么,接下来就来围绕这三个问题来讲解:
① 对于浮动:
优点
兼容性比较好,把清除浮动和其它浮动周边元素的关系处理好的话,那么它的兼容性是挺不错的。
缺点
设置浮动之后,脱离了文档流,处理不好的话,会带来很多问题,这是它本身的局限性。
② 对于绝对定位:
优点
快捷,不容易出问题
缺点
本身脱离了文档流,就会导致子元素跟着脱离文档流。因此,导致绝对定位的有效性
、可使用性
比较差。
③ 对于flexbox
css3中推出的flex布局,就是为了解决上述两种方式不足而出现的,算是比较完美的一种方式,尤其是对于移动端
④ 对于表格布局
优点
尽管多数人吐槽表格布局,但其实,表格布局在很多场景都适用的。比如上文写的三栏布局设计当中,表格布局是不是很轻松就实现了呢?
同时,表格布局的兼容性是非常好的,当用flex
解决不了问题的时候,对于PC端 IE8
是不支持flex
的,此时就可以尝试表格布局
缺点
除开历史上一些诟病外,还有一个:
比如我们把三栏理解成为三个小单元格,那么当其中某一个单元格高度超出的时候,其余两侧也会跟着调整,于是对于有些场景是不合适的。因此,对于不同场景,我们可以在flex
和表格
布局进行选优操作
⑤ 对于网格布局
这一块的话,算是新热点,也是经历了一段时间的演变,从上文代码来看的话,通过网格布局我们能让代码更加简单、方便实现逻辑。在面试的时候提到也可以说明你比较关注新的事物,主动学习能力不错。
当然,以上表述有部分个人思考,也有现常说的优缺点,读者可以根据研究布局方式进行深入思考,学习更多的使用场景以及优缺点,其次,欢迎提出新的解决方案及相关知识点,后续进行补充。
这里,我们就采用增加高度方式来看看,还有哪些布局能使用。(中间区域增加几个p标签)
源代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Layout</title>
<style>
html *{
padding: 0;
margin: 0;
}
.layout{
margin-top: 20px;
}
.layout article div{
min-height: 100px;
}
</style>
</head>
<body>
<!-- 浮动解决方式 -->
<section class="layout float">
<style>
.layout.float .left{
float: left;
width: 300px;
background: red;
}
.layout.float .right{
float: right;
width: 300px;
background: blue;
}
.layout.float .center{
background: yellow;
}
</style>
<article class="left-right-center">
<div class="left"></div>
<div class="right"></div>
<div class="center">
<h1>浮动解决方式</h1>
1.这是三栏布局的正中间部分
2.这是三栏布局的正中间部分
<p>增加高度</p>
<p>增加高度</p>
<p>增加高度</p>
<p>增加高度</p>
<p>增加高度</p>
</div>
</article>
</section>
<!-- 绝对定位解决方式 -->
<section class="layout absolute">
<style>
.layout.absolute .left-center-right>div{
position: absolute;
}
.layout.absolute .left{
left: 0;
width: 300px;
background: red;
}
.layout.absolute .center{
left: 300px;
right: 300px;
background: yellow;
}
.layout.absolute .right{
right: 0;
width: 300px;
background: blue;
}
</style>
<article class="left-center-right">
<div class="left"></div>
<div class="center">
<h1>绝对定位解决方式</h1>
1.这是三栏布局的正中间部分
2.这是三栏布局的正中间部分
<p>增加高度</p>
<p>增加高度</p>
<p>增加高度</p>
<p>增加高度</p>
<p>增加高度</p>
</div>
<div class="right"></div>
</article>
</section>
<!-- flexbox解决方式 -->
<section class="layout flexbox">
<style>
.layout.flexbox{
margin-top: 140px;
}
.layout.flexbox .left-center-right{
display: flex;
}
.layout.flexbox .left{
width: 300px;
background: red;
}
.layout.flexbox .center{
flex: 1;
background: yellow;
}
.layout.flexbox .right{
width: 300px;
background: blue;
}
</style>
<article class="left-center-right">
<div class="left"></div>
<div class="center">
<h1>flexbox解决方式</h1>
1.这是三栏布局的正中间部分
2.这是三栏布局的正中间部分
<p>增加高度</p>
<p>增加高度</p>
<p>增加高度</p>
<p>增加高度</p>
<p>增加高度</p>
</div>
<div class="right"></div>
</article>
</section>
<!-- 表格布局 -->
<section class="layout table">
<style>
.layout.table .left-center-right{
width: 100%;
display: table;
height: 100px;
}
.layout.table .left-center-right>div{
display: table-cell;
}
.layout.table .left{
width: 300px;
background: red;
}
.layout.table .center{
background: yellow;
}
.layout.table .right{
width: 300px;
background: blue;
}
</style>
<article class="left-center-right">
<div class="left"></div>
<div class="center">
<h1>表格解决方式</h1>
1.这是三栏布局的正中间部分
2.这是三栏布局的正中间部分
<p>增加高度</p>
<p>增加高度</p>
<p>增加高度</p>
<p>增加高度</p>
<p>增加高度</p>
</div>
<div class="right"></div>
</article>
</section>
<!-- 网格布局 -->
<section class="layout grid">
<style>
.layout.grid .left-center-right{
display: grid;
width: 100%;
grid-template-rows: 100px;
grid-template-columns: 300px auto 300px;
}
.layout.grid .left{
background: red;
}
.layout.grid .center{
background: yellow;
}
.layout.grid .right{
background: blue;
}
</style>
<article class="left-center-right">
<div class="left"></div>
<div class="center">
<h1>网格解决方式</h1>
1.这是三栏布局的正中间部分
2.这是三栏布局的正中间部分
<p>增加高度</p>
<p>增加高度</p>
<p>增加高度</p>
<p>增加高度</p>
<p>增加高度</p>
</div>
<div class="right"></div>
</article>
</section>
</body>
</html>
展示效果
这里,图片可能不是特别清楚,读者可以跑一遍上述代码,在浏览器打开使用会更好一点嗷~
总结
从上述显示效果来看的话,改变了高度,用flex
和表格
布局还能继续使用。
对于第一块,也就是浮动布局那一块,我们还可以进行知识拓展:
为什么会有两段文字跑到最左边去了呢?
答:因为向左浮动的原因,上面文字被左边红色部分挡住了,当内容超过高度后,就会往左边移动了。
那你怎么将多余的两段文字接着上述文字显示,而不是向左移动?
答:这就扯到了BFC的问题,清楚浮动等等,这里就不再进行拓展了,不然这篇文章没法完结啦。。。
三栏布局
两栏布局
谈谈你对CSS盒模型的认识
基本概念:标准模型+IE模型
标准模型和IE模型的区别
CSS如何设置这两种盒模型
JS如何设置获取盒模型对应的宽和高
实例题(根据盒模型解释边距重叠)
BFC(边距重叠解决方案)
以上内容知识点由浅入深,知识点理论从CSS->JS->CSS
推荐阅读:这一次,彻底看懂 CSS 盒模型(图文并茂)
标准盒模型、怪异盒模型(IE盒模型)和flex弹性伸缩盒模型以及多列布局
content = width+padding+border
附完美回答方式:
标准盒子模型,即box-sizing content-box,浏览器默认模型,我们所写的width和height并不是最终盒子的宽高,而是content的,盒子的宽高由我们的content+padding+border来组成的,但是这样在做项目时可能会遇到小问题,假如我想构建一个100x100的盒子大小,但是我发现我写的是width和height是100,于是我需要加上padding及border,但是加上去之后,盒子也会相应变大,这就造成改动麻烦。
后面css3中提供了IE盒子模型,能够直接控制盒子的大小。于是项目中大多数用上了IE盒子模型,以及我看过bootstrap以及element-ui源码中大部分也是用的IE盒子模型
以上回答方式,请读者可以好好体会一下,挖掘其中的亮点!
关于这里可以参考阮一峰老师的文章
参考:Flex 布局教程:语法篇
读者可以适当了解一下,这里就不加以说明了
①dom.style.width / height
这种方法,有一定局限性,只能取内联样式的宽高。
②dom.currentStyle.width / height
这种方法,也是有一定局限性,不过我们三种常用css样式都能获取。但是只支持IE
,其它浏览器不支持
③ window.getComputedStyle(dom).width / height
支持所有浏览器,兼容性好
④ dom.getBoundingClientRect().width / height
这种方法,一般用于计算元素的绝对位置,根据视窗左上角的点来算的。可以拿到四个元素值:left
、top
、width
、height
如下图,有两个盒子,深色的定为父元素,浅色的定位子元素,子元素的高度为100px
,与父元素的上边距为10px
,请问父元素实际高度是多少?
结合这个标题的情况,你可能会说是100px,但你也可能就是直接相加,觉得是110px,但都不是面试官觉得满意的回答,因为要看父元素的盒模型是如何设置的,下面来探讨这个问题:
我们在界面里来写一个父子元素的盒子
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>CSS盒模型</title>
<style>
html *{
padding: 0%;
margin: 0;
}
</style>
</head>
<body>
<section id="sec">
<style>
#sec{
background: #f00;
}
.children{
height: 100px;
margin-top: 10px;
background: yellow;
}
</style>
<article class="children">
</article>
</section>
</body>
</html>
我们父级元素貌似没看到,打开开发者工具(按下F12
)
此时,我们看一下计算属性 Computed
那是不是就是100px
呢?在回答之前,接着来如下操作,我们修改一个地方:
在父元素样式里设置 overflow: hidden;
此时,我们再次查看content,变成了110px
。
此时,就有疑问了,为什么之前是100px
,而当我们加了overflow: hidden;
之后变成了110px
了呢?
补充知识点:
我们常见的边距重叠,有两种情况:
margin-top
和margin-bottom
补充完后,接着回答上一个问题,为什么加了overflow: hidden;
之后变成了110px
了呢?
其实,是给父级元素创建了一个BFC
,这里我们在下文继续讨论。
BFC基本概念:块级格式化上下文
与之并列的一个是IFC(内联格式化上下文)这个不常考,就提一下。
BFC的原理(渲染规则)
① 在BFC这个元素的垂直方向
边距会发生重叠
② BFC的区域不会与浮动元素的box重叠,可用来清除
浮动布局
③ BFC是一个独立
的容器,外面的元素不会影响里面的元素,同时,里面的元素不会影响外面的元素。
④ 计算BFC元素高度的时候,浮动元素也会参与计算
怎么创建BFC?
① float
值不为none,因为CSS默认为none,只要设置了浮动,当前元素就设置了BFC
② static:静态定位。它是position
的默认值,一般不设置position属性时,元素会按照正常的文档流进行排列。那么,只要position不为默认值static也是设置了BFC
③ display
属性,table、table-cell等table相关的,都是设置了BFC
④ overflow
: auto / hidden
BFC使用场景
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>CSS盒模型</title>
<style>
html *{
padding: 0%;
margin: 0;
}
</style>
</head>
<body>
<section id="sec">
<style>
#sec{
background: #f00;
}
.children{
height: 100px;
margin-top: 10px;
background: yellow;
}
</style>
<article class="children">
</article>
</section>
<!-- BFC垂直方向边距重叠 -->
<section id="margin">
<style>
#margin{
background: pink;
overflow: hidden;
}
#margin>p{
margin: 5px auto 25px;
background: red;
}
</style>
<p>a</p>
<p>b</p>
<p>c</p>
</section>
</body>
</html>
如下图所示,a的顶部只有5px,而b的顶部用到了a的底部25px,因此就造成了边距重叠问题
如何消除上述情况?
给子元素创建父元素,让父元素设置BFC
如下图所示,仅需加一个div,然后设置overflow: hidden
即可
效果
接下来,来一个左边固定,右边自适应的例子。
<!-- BFC不予float重叠 -->
<section id="layout">
<style>
#layout{
margin-top: 10px;
background: red;
}
#layout .left{
float: left;
width: 100px;
height: 100px;
background: pink;
}
#layout .right{
height: 110px;
background: #ccc;
}
</style>
<div class="left"></div>
<div class="right"></div>
</section>
效果
从上图可以看到,右边因为宽度设置的高一点,经过浮动重叠到了左边一部分,此时,我们仅需一行代码即可overflow: auto;
#layout .right{
height: 110px;
background: #ccc;
overflow: auto;
}
计算BFC元素高度的时候,浮动元素也会参与计算
怎么理解这个概念呢?比如下面代码:
<!-- BFC子元素即使是float也会参与高度计算 -->
<section id="float">
<style>
#float{
background: green;
}
#float .float{
float: left;
font-size: 30px;
}
</style>
<div class="float">I am 浮动元素</div>
</section>
效果
我们从上面图片发现,没有父级元素,于是检查一下,发现父级高度为0,因为子元素设置了浮动,高度没有算进去
解决办法,父级元素设置清除浮动,于是形成了一个BFC,然后就会加上子级元素的高度
#float{
background: green;
overflow: hidden;
}
从门再次打开开发者工具(F12),可以看到,父级元素已经有了高度
基本概念:DOM事件的级别
DOM事件模型
DOM事件流
描述DOM事件捕获的具体流程
Event对象的常见应用
自定义事件
DMO事件类 | 事件级别 |
---|---|
DOM0 | element.οnclick=function(){} |
DOM2 | element.addEventListener(‘click’, function(){} , false) |
DOM3 | element.addEventListener(‘keyup’, function(){} , false) |
为啥没有DOM1呢?
答:因为DOM1制定的时候,没有设计与事件相关的东西,但不代表DOM1标准不存在
DOM3也是一种事件定义方式,相对来说事件类型增加了,比如鼠标键盘事件等
最后一个boolean
值表示事件模型是捕获还是冒泡,默认为false
冒泡,为true
表示捕获。
分为捕获(从上到下)和冒泡(从目标元素往上)
如上图所示,这就是一个事件流,一个完整的事件流
分为三个阶段:
event.preventDefault()
(阻止默认,例如链接等)event.stopPropagation()
(阻止冒泡)event.stopImmediateProgation()
(事件响应优先级,例如给一个按钮添加两个事件A和B,你想要只执行A,不执行B,就在A的响应函数里添加这个方法,就会阻止B事件的执行)event.currentTarget
(表示当前所绑定的事件,如下面所述,指向的就是父级元素)event.target
(与事件委托相关,把子元素的事件全都转到父级元素上,进行优化,只需绑定一次事件,然而作响应的时候,需要区别是哪个子元素被点击,该方法就可以绑定当前被点击的元素)var eve = new Event('custome');
ev.addEventListener('custome',function(){
console.log('custome');
});
ev.dispatchEvent(eve);
CustomEvent
是为了解决Event事件不能传数据的问题
上文讲述了相关知识点,下面我们通过代码来简单实现,让抽象的知识更加具体化
DOM事件捕获的具体流程实例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<div id="ev">
<style>
#ev{
width: 300px;
height: 100px;
color: #fff;
text-align: center;
line-height: 100px;
background: red;
}
</style>
目标元素
<script type="text/javascript">
var ev=document.getElementById('ev');
//DOM2中定义事件 window
window.addEventListener('click',function(){
console.log('window capture')
},true)
//document
document.addEventListener('click',function(){
console.log('document capture')
},true)
//html
document.documentElement.addEventListener('click',function(){
console.log('html capture')
},true)
//body
document.body.addEventListener('click',function(){
console.log('body capture')
},true)
//目标元素
ev.addEventListener('click',function(){
console.log('ev capture')
},true)
/* 自定义事件 */
var eve = new Event('test');
ev.addEventListener('test',function(){
console.log('test dispatch')
},true)
setTimeout(function(){
ev.dispatchEvent(eve);
},2000)
</script>
</div>
</body>
</html>
HTTP协议的主要特点
HTTP报文的组成部分
HTTP方法
POST和GET的区别
HTTP状态码
什么是持久连接
什么是管线化
同理,响应报文
请求示例
以上第一行就是请求行,包含GET
方法 / 表示首页 HTTP/1.1
表示HTTP协议版本
后面内容都是请求头,都是key-value
键值对
空行在这里没有显示出来,然后对于请求体就是一些数据部分了。
第一行是状态行,包含HTTP协议版本,协议状态码200
下面就是响应头了,也是键值对的形式
下面会有一个空行,类似下面这种效果(下面这条分割横线)
方法 | 作用 |
---|---|
GET | 获取资源 |
POST | 传输资源 |
PUT | 更新资源 |
DELETE | 删除资源 |
HEAD | 获取报文首部 |
get在浏览器回退时是无害的,而post会再次提交请求
get请求会被浏览器主动缓存,而post不会,除非手动设置
get请求参数会被完整保留在浏览器历史记录里,而post中的参数不会被保留
get请求在URL中传送的参数是有长度限制的,而POST没有限制
get参数通过URL传递,post放在Request body中
get请求只能进行url编码,而post支持多种编码方式
对参数的数据类型,get只接受ASCALL字符,而post没有限制
get比post更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息
get产生的URL地址可以被收藏,而post不可以
一般答完上述基本ok了,如果问的详细一点的话,就多加一点知识上去:
200 OK
:客户端请求成功206 Partial Content
:客户发送了一个带有Range(范围)头的GET请求,服务器完成了它(比如客户端请求0-1w字节,服务器就会返回206,常见播放视频和音频地址,文件过大时一般返回206)301 Moved Permanently
:所请求的页面已经转移至新的URL302 Found
:所请求的页面已经临时
转移至新的URL304 Not Modified
:客户端有缓冲
的文档并发出一个条件性的请求,服务器告诉客户,原来缓冲的文档还可以继续使用400 Bad Request
:客户端请求有语法错误,不能被服务器所理解401 Unauthorized
:请求未经授权,这个状态码必须和WWW-Authenticate
报头域一起使用403 Forbidden
:请求访问的页面被禁止(比如页面只能通过服务端去访问)404 Not Found
:请求资源不存在500 Internal Server Error
:服务器发生不可预料的错误但原来缓冲的文档还可以继续使用503 Server Unavailable
:请求未完成,服务器临时过载或当机,一段时候后可能恢复正常HTTP协议采用“请求-应答”模式,当使用普通模式,即非 Keep-Alive
模式时,每个请求 / 应答客户和服务器都要新建一个连接,完成之后立即断开连接(HTTP协议为无连接的协议)
当使用 Keep-Alive
模式(又称持久连接、连接重用)时,Keep-Alive
功能使客户端到服务端的连接持续有效,当出现对服务器的后续请求时,Keep-Alive
功能避免了建立或者重新建立连接
PS:只有HTTP 1.1 版本才支持持久连接,1.0不支持。
在使用持久连接的情况下,某个连接上消息的传递类似于
请求1->响应1->请求2->响应2->请求3->响应3
某个连接上的消息类似变成了这样:
请求1->请求2->请求3->响应1->响应2->响应3
(将请求打包一起发送,然后服务器一起打包回来响应)
拓展知识:
HTTP / 1.1
支持此技术(重点)get
和head
请求可以进行管线化,而 post
有所限制(重点)HTTP /1.1
版本的协议(重点)HTTP / 1.1
要求服务器端支持管线化,但并不要求服务器端也对响应进行管线化处理,只是要求对于管线化的请求不失败即可Chrome
和 Firefox
默认并未开启管线化支持var o1 = {name:'o1'};
var o11 = new Object({name:'o11'});
var M = function(){this.name='o2'};
var o2 = new M();
var P = {name:'o3'};
var o3 = Object.create(P);
var M = function(name){this.name=name}; //构造函数
var o2 = new M('o2'); //实例
实例和构造函数的关系
原型链:通过原型链的方式,找到原型对象,原型对象的方法是被不同实例所共有的。例如Object上有toString()方法,因此其它所有的实例都共有这个方法。
instanceof
原理就是判断当前实例是不是当前构造函数的实例对象,判断依据就是实例对象的__proto__
和构造函数的prototype
是否指向相同的引用,只要在一条原型链上,instanceof
就会返回true
。
很抽象是吧,下面我们还是举上文的例子:
var M = function(name){this.name=name};
var o2 = new M('o2');
因此,instanceof
判断不严谨,比如m继承了a、b、c,我怎么判断是继承了哪一个呢?用instanceof
判断都返回true
。
下面就来,介绍constructor
判断方式
一个新对象被创建。它继承自foo.prototype
构造函数foo被执行。执行的时候,相应的参数会被传入,同时上下文(this)会被指定为这个新实例。new foo
等同于 new foo()
,只能用在不传递任何参数的情况
如果构造函数返回一个“对象”,那么这个对象会取代整个new出来的结果。如果构造函数没有返回对象,那么new出来的结果为步骤1创建的对象
类与实例
类与继承
<body>
<script>
/* 类的声明 */
function Animal(){
this.name='aaa';
}
/* ES6中的class的声明 */
class Animal2{
constructor(){
this.name = 'bbb';
}
}
/* 实例化一个类 */
console.log(new Animal(),new Animal2());
</script>
</body>
方法一:借助构造函数来实现继承
/* 借助构造函数来实现继承 */
function fruit(){
this.name = 'fruit';
}
function apple(){
fruit.call(this);
this.type='apple';
}
console.log(new apple);
上述这种方式,是通过改变fruit
构造函数运行时this指向,指向了apple
上,但是fruit
原型链上的东西并没有被继承。
/* 借助构造函数来实现继承 */
function fruit(){
this.name = 'fruit';
}
fruit.prototype.eat = function(){
console.log('吃水果啦!');
}
function apple(){
fruit.call(this);
this.type='apple';
}
console.log(new apple().eat());
因此,通过构造函数来实现的继承,只能继承父类构造函数的属性,如果原型prototype
上面还有方法甚至原型链上的方法,不会继承。
方法二:借助原型链实现继承
/* 借助原型链实现继承 */
function fruit(){
this.name = 'fruit';
}
function apple(){
this.type='apple';
}
apple.prototype = new fruit();
console.log(new apple());
掌握之前原型链相关的知识,下面的等式应该就比较容易理解了
但这种继承方式也是有缺点的,下文来探讨这个问题:
/* 借助原型链实现继承 */
function fruit(){
this.name = 'fruit';
this.arr = [1,2,3];
}
function apple(){
this.type='apple';
}
apple.prototype = new fruit();
var app1 = new apple();
var app2 = new apple();
app1.arr.push(4);
console.log(app1,app2);
从上述结果来看,当我们修改某一个对象时,该函数的所有新出的实例对象都会跟着改变,这就造成了污染
问题,肯定不是我们面向对象思想所想要的。(因为它们引用的是同一个父类实例对象)
方式三:组合方式实现继承
这种方式就是结合前两种的优点,弥补它们的缺点。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>面向对象</title>
</head>
<body>
<script>
/* 关于继承的几种方式
**使用方法:
**读者按需将对应模块注释取消掉即可
*/
/* 借助原型链实现继承 */
/*function fruit(){
this.name = 'fruit';
this.arr = [1,2,3];
}
function apple(){
this.type='apple';
}
apple.prototype = new fruit();
var app1 = new apple();
var app2 = new apple();
app1.arr.push(4);
console.log(app1,app2);*/
/* 组合方式实现继承 */
/**
*此方法的缺点:new fruit() 父类构造函数执行了两次,可以但没必要
*/
function fruit(){
this.name = 'fruit';
this.arr = [1,2,3];
}
function apple(){
fruit.call(this);
this.type='apple';
}
apple.prototype = new fruit(); //这里拿的是父类的实例,没有自己的constructor
var app1 = new apple();
var app2 = new apple();
app1.arr.push(4);
//console.log(app1,app2);
//console.log(app1.constructor,app2.constructor)
/* 组合方式实现继承优化1 */
function fruit1(){
this.name = 'fruit';
this.arr = [1,2,3];
}
function apple1(){
fruit.call(this);
this.type='apple';
}
apple1.prototype = fruit1.prototype; //这里拿的是父类的原型对象,但依旧没有自己的constructor
var app3 = new apple1();
var app4 = new apple1();
app3.arr.push(4);
//console.log(app3,app4);
//判断实例
//console.log(app3 instanceof apple1);
//console.log(app3 instanceof fruit1); //这里无法判断当前对象是由父类产生的实例对象还是由子类产生的实例对象
//判断构造函数
//console.log(app3.constructor);
//console.log(app4.constructor); //因为和父类的原型对象是一个对象,导致constructor也是指向的父类的constructor,无法判断自己
/* 组合方式实现继承优化2 */
function fruit2(){
this.name = 'fruit';
this.arr = [1,2,3];
}
function apple2(){
fruit.call(this);
this.type='apple';
}
apple2.prototype = Object.create(fruit2.prototype); //这里使用Object.create()方法,和之前直接用fruit2.prototype来说,它创建了一个中间对象,和父类不是指向同一个区域了
//这样就能区分父类和子类的原型对象了,达到父类和子类原型对象的隔离效果
apple2.prototype.constructor = apple2; //由于隔离了父类子类的原型对象,我们就可以指定子类自己的constructor
var app5 = new apple2();
var app6 = new apple2();
app5.arr.push(4);
console.log(app5,app6);
//判断实例
console.log(app5 instanceof apple2);
console.log(app5 instanceof fruit2); //因此,这里可以判断当前对象是由父类产生的实例对象还是由子类产生的实例对象
//判断构造函数
console.log(app5.constructor); //指向的是自己的constructor
</script>
</body>
</html>
同源策略限制从一个源加载的文档或脚本如何与来自另一个源的资源进行交互。
这是一个用于隔离潜在恶意文件的关键的安全机制。
源包括协议、域名、端口
JSONP实现原理:
根据script标签异步加载而来
很关键一点是会向服务端发送一个callbackName
,然后服务器就会响应如下内容(下面那个script里的内容)利用callbackName
作为函数名来返回,而且本地必须有这个函数名的函数。
Hash与postMessage实现原理
WebSocket实现原理
浏览器回拦截Ajax
请求,如果觉得是跨域的,就会在请求头上加上origin
。
CSRF
基本概念和缩写
攻击原理
防御措施
XSS
基本概念和缩写
CSRF,通常称为跨站请求伪造,英文名(Cross-site request forgery)缩写CSRF
CSRF攻击原理
CSRF防御措施
基本概念和缩写
跨域脚本攻击(cross-site scripting)
攻击原理
比如可以在你的提交区里面写上script标签,即用一些渠道向你的页面注入js脚本
防御措施
让插入的js不可执行
CSRF是利用本身的漏洞自动执行接口,依赖于用户登录网站
XSS是向页面注入js,js函数体里面做想做的事
PS:由于文章篇幅所限,并且算法这一块需要的是自己平时的积累,这里就不作长文加载了,关于算法这一块我会在github里有相应专栏,记录题库。因此,在这里就给大家分享一些比较好的文章提供学习。
推荐:【再也不怕面试官要你手写排序算法】一文详细解读前后端之各种排序算法及知识拓展(附图示) JS / C / C++
参考:JS中的数据结构与算法
参考:JS中的递归
参考:波兰式、逆波兰式与表达式求值
参考:源码
首先,对于前端来说,算法要求没有后端那么严格,考察的一般不会很刁专,一般就是看下你的思考能力。如果一开始就考察算法题,如果你回答不了的话,也很正常,或许这不是一个关于前端的部门…可能招的是算法工程师,算法这一块问的话,多半是中间时间段。算法这一块的话,在于平时积累,如果时间充裕的话,可以深入了解一点,这也是面试加分点,如果时间紧迫的话,把上文提到的部分专题弄懂已经不错了。
PS:这里要记住html5该如何声明,以及4.0版本有严格模式和传统模式,具体区别如上图下划线所示
简单快速回答:
第一步,HTML经过HTML解析器解析成为DOM Tree
第二步,CSS通过CSS解析器形成样式规则
第三步,将两个DOM结合形成Render Tree,这里就类似于告诉浏览器渲染树结构基本出来了,此时有一个平行操作,Layout,经过这个,就能知道元素具体应该显示在屏幕在哪个位置(宽、高、颜色等)
最后一步,浏览器通过GUI画图,呈现页面内容,最后Display显示页面
下面通过几个比较好理解的图形来将抽象具体化:
DOM Tree
CSSOM Tree
Render Tree
Layout
定义
DOM结构中的各个元素都有自己的盒子(模型),这些都需要浏览器根据各种样式来计算并根据计算结果将元素放到它该出现的位置,这个过程称之为reflow
触发Reflow
DOM
结点时,会导致 Reflow
或 Repaint
DOM
的位置,或是搞个动画的时候CSS
样式的时候Resize
窗口的时候(移动端没有这个问题),或是滚动的时候定义
当各种盒子的位置、大小以及其他属性,例如颜色、字体大小等确定下来后,浏览器于是便把这些元素都按照各自的特性绘制了一遍,于是页面的内容出现了,这个过程称之为repaint
。即页面需要呈现的内容,一起画到屏幕上。
触发Repaint
(重点)如何尽量减小Repaint?
比如页面有一个计算器,用户在输入框输入一些计算表达式,最后显示计算结果,然后把输入给隐藏掉。这里就有两个交互,先是用户输入,将输入隐藏掉,然后将结果显示出来。这两个交互呈现内容不一样,当然就需要Repaint,那怎么做少画点东西?
好像是有一个documentFrame这个东西,把n个节点创建成一个片段,向浏览器一次添加这个片段。
(这里我的朋友考察过,遗留一下这个问题,可以帮助我完善这个问题,谢谢!)
关于这一专题,我之前的文章也是写的挺多的了。
推荐阅读:【金三银四】一个问题就知道你会不会JS了 阿里、头条真题解析
推荐阅读:【金三银四】 一文弄懂 js 数据类型、堆栈内存、作用域(链)、闭包知识拓展 (一)
下面就例举几个经典题,读者可以好好体会一下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>js运行机制</title>
</head>
<body>
<script>
console.log(1);
setTimeout(function(){
console.log(3);
},0);
console.log(2);
</script>
</body>
</html>
for(var i=0;i<4;i++){
setTimeout(function(){
console.log(i);
},1000)
}
以上三个问题的详细表述:
推荐阅读:【金三银四】 一文弄懂 js 数据类型、堆栈内存、作用域(链)、闭包知识拓展 (一)
学过JS,不对,听过JS的同学应该都知道,JS是单线程的,而浏览器是多线程的,分配的时间内js只能干一件事情
分同步任务和异步任务
为了解决同步和异步问题,浏览器提供了一个事件队列 Event Queue,根据特征不同,分为微任务和宏任务队列
执行顺序是:主线程代码 > 微任务 > 宏任务
宏任务:
定时器例如setTimeout(异步)、事件绑定
微任务:
await(异步,执行x函数并等待返回结果,有结果再执行下面代码)
resolve() / reject() 执行的时候把 then / catch 中的代码执行
promise、async
特殊情况:
new Promise(同步)会立即执行
提升页面性能的方法有哪些?
<meta http-equiv="x-dns-prefetch-control" content="on"> //打开a标签dns预解析
//有些https默认关了dns预解析,使用上述可以打开(加分点)
<link rel="dns-prefetch" href="//host_name_to_prefetch.com">
1、异步加载的方式
2、异步加载的区别
(1)defer
是在HTML解析完之后才会执行,如果是多个,按照加载的顺序依次执行
(2)async
是在加载完之后立即执行,如果是多个,执行顺序和加载顺序无关
1、缓存的分类
① 强缓存(不用任何请求,拿过来就用,如果两个都下发,以第二个Cache
为准)
Expires(过期时间-服务器绝对时间) Expires:Thu,21 Jan 2017 23:39:02 GMT
(会导致客户端时间和服务器时间之间时间差问题)
Cache-Control(客户端相对时间,单位秒) Cache-Control:max-age=3600
② 协商缓存(浏览器发现本地有这个副本,但是不确定用不用它,于是得向服务器问一下,这个副本要不要用)
Last-Modified(拿到某个资源文件时,通过这个字段服务器下发一个时间) If-Modified-Since (当下次请求这个资源是否发生变化时,是用这个key
值,对比两个时间)
Last-Modified: Web,26 Jan 2017 00:35:11 GMT
(上述方式会存在问题,例如我可能时间上修改了,但是内容并没有修改)
Etage(解决上述问题,服务器给Etage值,当过了强缓存时间,浏览器请求是否可用副本时,会在http请求头中用 If-None-Match 当做key值,加上value
,此value就是Etage的值)
PS:(面试真题-鹅厂)你知道浏览器与缓存相关的http头有哪些?
答案就是上述加粗字体
问法:如何检测JS错误,如何保证你的产品质量?
即时运行错误:代码错误
资源加载错误
即时运行错误的捕获方式
(1) try…catch
(2)window.onerror(无法捕获资源加载错误,理由如下)
资源加载错误(上述原因:因为资源加载错误不会冒泡)
(1)object.onerror
(节点上绑定onerror
事件)
(2)performance.getEntries()
(获得目前已加载的资源,例如图片,然后用document.getElementsByTagName(‘img’)来获取需要加载的图片,然后用总的去减已加载的,就能知道未加载的有多少了)
(3)Error
事件捕获(之前说不能冒泡,但可以捕获)
延伸:跨域的js运行错误可以捕获吗,错误提示什么,应该怎么处理?
crossorigin
属性1、采用Ajax通信的方式上报
2、利用Image对象上报(重点,加分点)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>利用Image对象上报</title>
</head>
<body>
<script>
(new Image()).src='http://baidu.com/test?name=123';
</script>
</body>
</html>
此时,我们查看Nerwork
,可以发现,我们的请求已经发出去了(比Ajax简单,不用借用任何第三方库)
如若本文有瑕疵需修改的地方,请提出来,谢谢您的贡献!
欢迎关注微信公众号:小狮子前端Vue
谢谢您的支持!✿✿ヽ(°▽°)ノ✿
学如逆水行舟,不进则退