前端面试知识点小盘点
总结的一些知识点
1 SEO优化思路
SEO,全称Search Engine Optimization,即搜索引擎优化,指利用搜索引擎的搜索规则,采取优化策略或程序,提高网站的权重。
- 页面应该具有合理的title、description、keywords
- 语义化的HTML代码
- 重要的HTML代码放在最前面
- 重要内容不用JS输出,爬虫不执行JS获取内容
- 少用iframe,爬虫不爬取iframe内容
- 非装饰性图片必须添加alt
- 提高网站速度
2 html语义化
2.1 什么是html语义化
简单来说,html的语义化就是使正确的标签做该做的事情,便于开发者阅读和写出更优雅的代码,也能使得爬虫解析变得方便,使网站权重提高。
2.2 如何做html的语义化
坚持一个原则:HTML告诉我们一块内容应该是什么,不关心样式,样式是CSS要做的,具体如下:
h1~h6:作为标题使用,依据重要性递减 p:段落标记,其中不需要包含换行符 ul ol li :无序列表 em strong用作强调 q:引用 ...
2.3 为什么要进行html语义化
- 去掉样式,页面结构也很清晰
- 盲人使用读屏器更好地阅读
- 搜索引擎更好的理解页面,有利于收录
- 团队合作也更方便
3 BFC详解
BFC,全称block formatting context,块级格式化上下文,简单地说,BFC是通过CSS样式定义的独立的一块区域,这个区域的渲染不会影响到其它地方,与外部不相干。
创建的规则:
- HTML根元素
- 浮动元素:float为left或right
- 绝对定位元素(position为absolute或fixed)
- display为inline-block、table-cell,table-caption,flex,inline-flex,grid,inline-grid
- overflow不为visible
作用:
- 包含浮动元素
- 防止div高度坍缩
4 CSS水平居中、垂直居中
4.1 水平居中
- 块级元素:margin : 0 auto
- 行内元素:text-align : center
- 绝对定位结合transform
- flex布局结合justify-content:center
4.2 垂直居中
- 绝对定位结合transform
- flex布局结合align-items : center
- line-height : height
- 父div display:table,子div display : table-cell, vertical-align: middle
4.3 水平竖直居中
- flex布局结合justify-content和align-items
- 绝对定位结合transform
5 清除浮动
结合一个例子讲述为什么需要清除浮动:
<div class="box"> <div class="float">float element</div> <p>sjsjahdjkahdsjkah</p> </div> <style> .float { float: left; width: 200px; height: 200px; border: 1px darkblue solid; } .box { border: 2px darkorange solid; } </style>
运行结果为:
回答一开始的问题:当我们不想让一个元素的旁边出现浮动元素时,需要进行清除浮动。
方法1:clear属性
.float { float: left; width: 200px; height: 200px; border: 1px darkblue solid; } .box p { /*注意这里:清除左边的浮动*/ clear: left; } .box { border: 2px darkorange solid; /*BFC*/ overflow: auto; }
将style改成如上,运行结果即变为:
成功。
方法2:注意:方法1中,p元素在浮动元素之后,因此我们可以应用上述方法,但如果p元素在浮动元素之前,会变成这样:
此时不论对不对p元素设置clear属性都没什么作用,因为此时p元素旁边并没有浮动元素。
所以此时我认为已经不是一个清除浮动的问题了,我更倾向于认为这是父元素高度坍缩问题,因此将父元素变为BFC即可。
如果非要当作清除浮动问题,只需要在浮动元素下box之中添加一个空元素然后为空元素添加clear:both属性即可。当然也可以使用伪类,为伪类同样添加clear:both属性。
如下:
<style> .float { float: left; width: 200px; height: 200px; border: 1px darkblue solid; } .box { border: 2px darkorange solid; } .blank { clear: both; } </style> <div class="box"> <p>sjsjahdjkahdsjkah</p> <div class="float">float element</div> <div class="blank"></div> </div>
运行结果:
或者:
<style> .float { float: left; width: 200px; height: 200px; border: 1px darkblue solid; } .box { border: 2px darkorange solid; } .f::after { display: block; content: ""; clear: both; } </style> <div class="box f"> <p>sjsjahdjkahdsjkah</p> <div class="float">float element</div> </div>
结果和上面一样。
6 盒模型
页面渲染时,dom元素所采用的布局模型可使用box-sizing属性进行设置,有如下选择:
- content-box(W3C标准盒模型)
- border-box
- padding-box
上一个图:
7 CSS选择器优先级
!important > 行内样式 > #id > .class > tag > * > 继承 > 默认
8 展示顺序
层叠等级:
background -> z-index<0 -> block -> float -> inline -> z-index=0/auto -> z-index>0
9 rem em px pt
rem:CSS3
新增的单位,1rem
等于html
根元素的字体大小
em:1em
等于元素的父元素的字体大小
px(像素):像素与显示设备相关,对于屏幕显示,通常是一个设备像素(点)的显示。对于打印机和高分辨率的屏幕,一个px
意味着多个设备像素
pt(磅):1pt = (1 / 72)in
1in
= 96px
,3pt = 4px
,25.4mm
=96px
10 link vs @import
- link可以加载css、icon等,但@import只能用于加载css
- link被解析时即加载CSS,@import所引用的css在页面加载完毕后再被加载
- @import不能使用js动态引入
11 CSS动画
pass
12 DOCTYPE
<!DOCTYPE>声明位于HTML文档的头部,用于告诉浏览器当前HTML的版本
在 HTML4.01 中<!doctype>
声明指向一个 DTD,由于 HTML4.01 基于 SGML,所以 DTD 指定了标记规则以保证浏览器正确渲染内容。HTML5 不基于 SGML,所以不用指定 DTD
常见的DOCTYPE:
- HTML4.01 strict:不允许使用表现性、废弃元素(如 font)以及 frameset。声明:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
- HTML4.01 Transitional:允许使用表现性、废弃元素(如 font),不允许使用 frameset。声明:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
- HTML4.01 Frameset:允许表现性元素,废气元素以及 frameset。声明:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">
- XHTML1.0 Strict:不使用允许表现性、废弃元素以及 frameset。文档必须是结构良好的 XML 文档。声明:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
- XHTML1.0 Transitional:允许使用表现性、废弃元素,不允许 frameset,文档必须是结构良好的 XMl 文档。声明:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
- XHTML 1.0 Frameset:允许使用表现性、废弃元素以及 frameset,文档必须是结构良好的 XML 文档。声明:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
- HTML 5:
<!doctype html>
13 HTML全局属性
- accesskey:设置快捷键
- class
- contenteditable:指定元素内容是否可编辑
- contextmenu:自定义鼠标右键弹出菜单的内容
- data-*:为元素增加自定义属性
- dir:设置元素文本方向
- draggable:设置元素拖放类型
- hidden:表示一个元素是否显示
- id
- lang:语言
- spellcheck
- style
- title
- tabindex
14 如何显示<div></div>这个字符
<div></div>
15 placehoder属性
placeholder 属性提供可描述输入字段预期值的提示信息(hint)
16 CSS伪类 vs 伪元素
伪元素:::after ::before ::first-letter ::first-line
伪类:
- :active
- :focus
- :hover
- :link
- :visited
- :first-child
- :lang
针对作用选择器的效果,伪类需要添加类来达到效果,而伪元素需要增加元素tag,所以一个叫伪类,另外一个叫伪元素。
17 CSS属性继承
display属性不继承,visibility属性继承
18 块级元素 行内元素
块级元素:block element,每个块级元素默认占一行高度,一行内添加一个块级元素后无法添加其他元素(float浮动后除外)。块级元素一般作为容器出现,用来组织结构。
行内元素:inline element,行内元素一般是基于语义级的基本元素,只能容纳文本或其它内联元素。
常见块级元素:
- address
- blockquote
- center
- dir
- div
- dl
- fieldset
- form
- h1
- h2
- h3
- h4
- h5
- h6
- hr
- menu
- noscript
- ol
- p
- pre
- table
- ul
常见行内元素:
- a
- abbr
- b
- big
- br
- cite
- code
- em
- font
- i
- img
- input
- kbd
- label
- q
- s
- samp
- select
- small
- span
- strike
- strong
- sub
- sup
- textarea
- tt
- u
19 line-height:2 VS line-height:200%
line-height为2时,子元素继承父元素line-height属性,会根据子元素的字体大小动态计算出行高。而line-height为200%时,父元素的行高为200%时,会根据父元素的字体大小先计算出行高值然后再让子元素继承。
20 JS 基本数据类型
六种基本数据类型:boolean string number undefined null Symbol(ES6)
var a = 1, b = "s", c, d = true, e = null, f = Symbol() console.log(typeof (a), typeof (b), typeof (c), typeof (d), typeof (e), typeof (f))// number string undefined boolean object symbol
21 JS 原型链
继承是OO语言中的一个最为人津津乐道的概念.许多OO语言都支持两种继承方式: 接口继承 和 实现继承 .接口继承只继承方法签名,而实现继承则继承实际的方法.由于js中方法没有签名,在ECMAScript中无法实现接口继承.ECMAScript只支持实现继承,而且其
实现继承
主要是依靠原型链来实现的.by JavaScript高级程序设计
构造函数、实例对象和原型之间的关系:每个构造函数有一个原型对象(constructor.prototype),原型对象包含一个指向构造函数的指针,实例都包含一个指向原型对象的内部指针(instance.__proto__)。
如果试图引用对象(实例instance)的某个属性,会首先在对象内部寻找该属性,直至找不到,然后才在该对象的原型(instance.prototype)里去找这个属性.
function Father() { this.name = "baba" } Father.prototype.getFatherName = function () { return this.name } function Son() { this.sonName = "son" } // 继承 Son.prototype = new Father() Son.prototype.getSonName = function () { return this.name } var son = new Son() console.log(son.getFatherName()) // baba
在这个例子中,我们将子类Son的原型对象初始化为Father,此时调用son.getFatherName()方法就会首先在son内部寻找,发现找不到,于是去son.__proto__即Son.prototype中去找,Son.prototype是指Father实例,寻找不到,又到了Father实例的原型中去寻找,就找到了
这种搜索的轨迹,形似一条长链, 又因prototype在这个游戏规则中充当链接的作用,于是我们把这种实例与原型的链条称作 原型链 。
使用 instanceof 操作符, 只要用这个操作符来测试实例(instance)与原型链中出现过的构造函数,结果就会返回true. 以下几行代码就说明了这点.
alert(instance instanceof Object);//true alert(instance instanceof Father);//true alert(instance instanceof Son);//true
son -> Son.prototype(father) -> Father.prototype -> Object.prototype
使用 isPrototypeOf() 方法, 同样只要是原型链中出现过的原型,isPrototypeOf() 方法就会返回true, 如下所示。
alert(Object.prototype.isPrototypeOf(instance));//truealert(Father.prototype.isPrototypeOf(instance));//truealert(Son.prototype.isPrototypeOf(instance));//true
用图像进一步说明。来源于https://github.com/mqyqingfeng/blog/issues/2
这条蓝色的线就是原型链。
22 闭包
闭包是JavaScript中十分重要也很难理解的概念。
变量作用域分为 全局作用域 函数作用域 块级作用域 词法作用域及动态作用域
在JavaScript中,函数内部可以直接读取全局作用域的变量。
var n = 999; function f() { console.log(n) } f() // 999
函数外部无法读取函数内部的局部变量,因为是局部变量处于函数作用域。
function f1(){ var n=999; } console.log(n); // error
但由于种种原因,我们想要读取函数内部的变量,因此便引出了闭包。可以首先建立一个概念,闭包就是在函数中定义子函数,在子函数中获取函数的内部变量并返回,如下。
function f2() { var n = 999 function f3() { console.log(n) } return f3 } f2()()//999
f3函数便是一个闭包。阮一峰定义闭包为“能够读取其他函数内部变量的函数”,闭包就是将函数内部和函数外部链接的一座桥梁。
1)由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。
2)闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。
23 CORS
CORS用于解决ajax跨域问题,全称跨域资源共享。
首先,何为跨域?协议不同,域名不同,端口不同都会导致跨域。
解决方法主要有jsonp和CORS。
其中jsonp只能适用于get请求,且需要有后台支持,后台主要负责数据的封装,利用了script src不受跨域问题的干扰的特点衍生而出,前台负责数据的处理。而CORS适用于所有请求,对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样,实现CORS通信的关键是服务器,只要服务器实现了CORS接口,就可以实现跨源通信。
浏览器将CORS请求分为两类:简单请求和非简单请求。
简单请求:
HEAD GET POST (2)HTTP的头信息不超出以下几种字段: Accept Accept-Language Content-Language Last-Event-ID Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain
对于简单请求,浏览器发出跨域请求之后,会在头信息之中增加一个Origin字段(这是浏览器自动进行的),Origin
字段用来说明,本次请求来自哪个源(协议 + 域名 + 端口),然后服务器会根据这个值,按自己的配置决定是否同意请求。如果Origin
指定的域名在许可范围内,服务器返回的响应,会多出几个头信息字段。
Access-Control-Allow-Origin: http://api.bob.com Access-Control-Allow-Credentials: true Access-Control-Expose-Headers: FooBar Content-Type: text/html; charset=utf-8
(1)Access-Control-Allow-Origin
该字段是必须的。它的值要么是请求时Origin
字段的值,要么是一个*
,表示接受任意域名的请求。
(2)Access-Control-Allow-Credentials
该字段可选。它的值是一个布尔值,表示是否允许发送Cookie。默认情况下,Cookie不包括在CORS请求之中。设为true
,即表示服务器明确许可,Cookie可以包含在请求中,一起发给服务器。这个值也只能设为true
,如果服务器不要浏览器发送Cookie,删除该字段即可。
(3)Access-Control-Expose-Headers
该字段可选。CORS请求时,XMLHttpRequest
对象的getResponseHeader()
方法只能拿到6个基本字段:Cache-Control
、Content-Language
、Content-Type
、Expires
、Last-Modified
、Pragma
。如果想拿到其他字段,就必须在Access-Control-Expose-Headers
里面指定。上面的例子指定,getResponseHeader('FooBar')
可以返回FooBar
字段的值。
所以对于简单请求,我们的思路就很明确了,如果项目有后台,就让后台指定Access-Control-Allow-Origin为*就行了。
对于复杂请求,比如请求方法是PUT
或DELETE
,或者Content-Type
字段的类型是application/json
。会在正式通信之前,增加一次HTTP查询请求,称为"预检"请求(preflight)。浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段。只有得到肯定答复,浏览器才会发出正式的XMLHttpRequest
请求,否则就报错。如:
var url = 'http://api.alice.com/cors'; var xhr = new XMLHttpRequest(); xhr.open('PUT', url, true); xhr.setRequestHeader('X-Custom-Header', 'value'); xhr.send();
上面代码中,HTTP请求的方法是PUT
,并且发送一个自定义头信息X-Custom-Header
。
浏览器发现,这是一个非简单请求,就自动发出一个"预检"请求,要求服务器确认可以这样请求。下面是这个"预检"请求的HTTP头信息。
OPTIONS /cors HTTP/1.1 Origin: http://api.bob.com Access-Control-Request-Method: PUT Access-Control-Request-Headers: X-Custom-Header Host: api.alice.com Accept-Language: en-US Connection: keep-alive User-Agent: Mozilla/5.0...
除了Origin
字段,"预检"请求的头信息包括两个特殊字段。
(1)Access-Control-Request-Method
该字段是必须的,用来列出浏览器的CORS请求会用到哪些HTTP方法,上例是PUT
。
(2)Access-Control-Request-Headers
该字段是一个逗号分隔的字符串,指定浏览器CORS请求会额外发送的头信息字段,上例是X-Custom-Header
。
服务器收到"预检"请求以后,检查了Origin
、Access-Control-Request-Method
和Access-Control-Request-Headers
字段以后,确认允许跨源请求,就可以做出回应。
HTTP/1.1 200 OK Date: Mon, 01 Dec 2008 01:15:39 GMT Server: Apache/2.0.61 (Unix) Access-Control-Allow-Origin: http://api.bob.com Access-Control-Allow-Methods: GET, POST, PUT Access-Control-Allow-Headers: X-Custom-Header Content-Type: text/html; charset=utf-8 Content-Encoding: gzip Content-Length: 0 Keep-Alive: timeout=2, max=100 Connection: Keep-Alive Content-Type: text/plain
(1)Access-Control-Allow-Methods
该字段必需,它的值是逗号分隔的一个字符串,表明服务器支持的所有跨域请求的方法。注意,返回的是所有支持的方法,而不单是浏览器请求的那个方法。这是为了避免多次"预检"请求。
(2)Access-Control-Allow-Headers
如果浏览器请求包括Access-Control-Request-Headers
字段,则Access-Control-Allow-Headers
字段是必需的。它也是一个逗号分隔的字符串,表明服务器支持的所有头信息字段,不限于浏览器在"预检"中请求的字段。
(3)Access-Control-Allow-Credentials
该字段与简单请求时的含义相同。
(4)Access-Control-Max-Age
该字段可选,用来指定本次预检请求的有效期,单位为秒。上面结果中,有效期是20天(1728000秒),即允许缓存该条回应1728000秒(即20天),在此期间,不用发出另一条预检请求。
如在SpringBoot中配置CORS。
@Configuration public class CORSConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry corsRegistry) { corsRegistry.addMapping("/**") .allowedOrigins(ALL) .allowedMethods(ALL) .allowedHeaders(ALL) .allowCredentials(true); } }
以上结合阮一峰老师文章跨域资源共享CORS详解写成。
24 HTTP状态码
- 1xx:信息状态码
- 100 continue 客户端应当继续发送请求,该响应用于通知客户端请求已被服务器接收,且仍未被拒绝,客户端应当继续发送请求的剩余部分,或者如果请求已经完成,忽略这个响应。
- 101 指服务器将按照其上的头信息变为一个不同的协议
- 2xx:成功状态码
- 200 OK 请求成功
- 201 Created
- 202 Accepted 告诉客户端请求正在被执行,但还没有处理完
- 203 Non-Authoritative Information
- 204 No Content
- 205 Reset Content
- 206 Partial Content
- 3xx:重定向
- 300 多选择
- 301 永久重定向
- 302 临时重定向
- 303 参见其他信息
- 304 修正
- 305 使用代理
- 307 临时重定向,和302类似
- 4xx:客户端错误
- 400 错误的请求
- 401 未授权
- 403 禁止
- 404 未找到
- 405 方法不允许
- 406 无法访问
- ...
- 5xx:服务端错误
- 500 Internal Server Error
- 501 未实现
- 502 错误的网关
- 503 服务无法获得
- 504 网关超时
- 505 不支持的HTTP版本
25 函数防抖 函数节流
用于在时间轴上控制函数的执行次数。
函数防抖:指在事件被触发n秒后再执行回调,如果在这n秒内又被触发,则重新计时。
26 TCP 三次握手
第一次握手(SYN=1, seq=x):
客户端发送一个 TCP 的 SYN 标志位置1的包,指明客户端打算连接的服务器的端口,以及初始序号 X,保存在包头的序列号(Sequence Number)字段里。
发送完毕后,客户端进入
SYN_SEND
状态。第二次握手(SYN=1, ACK=1, seq=y, ACKnum=x+1):
服务器发回确认包(ACK)应答。即 SYN 标志位和 ACK 标志位均为1。服务器端选择自己 ISN 序列号,放到 Seq 域里,同时将确认序号(Acknowledgement Number)设置为客户的 ISN 加1,即X+1。 发送完毕后,服务器端进入
SYN_RCVD
状态。第三次握手(ACK=1,ACKnum=y+1)
客户端再次发送确认包(ACK),SYN 标志位为0,ACK 标志位为1,并且把服务器发来 ACK 的序号字段+1,放在确定字段中发送给对方,并且在数据段放写ISN的+1
发送完毕后,客户端进入
ESTABLISHED
状态,当服务器端接收到这个包时,也进入ESTABLISHED
状态,TCP 握手结束。