2021春招前端面试总结

前端面试总结


word文档原文百度网盘:
链接:https://pan.baidu.com/s/1BZEfduhC8_lS_vlsRS-BgA
提取码:st42

笔试注意点

JS V8牛客网ACM模式输入

while(line=readline()){
var lines=line.split(’ ');
var a=parseInt(lines[0]);
var b=parseInt(lines[1]);
print(a+b);
}
输出用print或console.log()

Node中控制台输入输出

var readline = require(‘readline’);
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
rl.on(‘line’, function(line){
var tokens = line.split(’ ');
console.log(parseInt(tokens[0]) + parseInt(tokens[1]));
});

HTML+CSS

bgcolor是HTML,bgColor是JScript,backgroundColor是javascript

盒模型

盒模型、盒子模型、框模型(box model)
- CSS将页面中的所有元素都设置为了一个矩形的盒子
- 将元素设置为矩形的盒子后,对页面的布局就变成将不同的盒子摆放到不同的位置
- 每一个盒子都由一下几个部分组成:
内容区(content)
内边距(padding)
边框(border)
外边距(margin)

css引入方式和权重计算

引入方式:
行间样式:

我是p标签


页面级css,在head里面添加style标签
外部css文件,Link标签引入 导入样式

链接和导入的区别
链接:属于XHTML,优先加载css文件到页面
导入:属于css2,先加载HTML结构再加载CSS文件

权重:
行内样式>内部样式和外部样式
内部样式和外部样式是就近原则,即谁离显示位置最进即显示哪种样式,即style如果在link下就显示style,反之。

优先级:
!important>行间样式>id>class|属性>标签选择器>通配符

权重的计算(2进制)

权重相同的选择器谁在下面,执行谁(样式的覆盖)

a标签的全部作用

超链接
百度
Href微指向页面的url,target为打开方式
1: _blank 代表在新窗口中打开页面的链接地址;
2: _self 代表在自身窗口打开页面链接,默认为self;
3: _parent 代表是在父窗口中打开此网页;
4: _top 代表的是在整个窗口中打开此网页,测试的效果与self相同;

锚点
定位相应的位置,快速找到目标
第6个
表示跳转id为demo6的区域

打电话,发邮件
给郭xx打电话
给郭xx发邮箱

协议限定符,强制使用js代码
你点我试试啊!
结果陷入一个死循环,不断弹出’让你手欠‘的框框
可以实现a标签点击响应js事件

元素种类的划分

分类一:
行内元素
会在水平方向排列,宽度高度设置无效,占据对应标签的空间,不能包含块级元素,元素之间默认有间距,常用的有:a,span,textarea,input,button,label,em,i,b,small,strong,select,img
块级元素
占用一行,可以设置宽度高度,内部可以包含行内元素和其他块级元素,常用的div,p,h1,ol,ul,dl,table,form,header,footer,aside,nav,section,arctile
行内块元素
可以设置宽度有可以和其他行内元素一行排列,即包含了以上两个的特性

分类2:
替换元素
内容为空,即img,input,select,video,audio,canvas,iframe,textarea等
非替换元素
内容不为空,html大部分都是非替换元素

定位方式及其区别(文档流)

将窗体自上而下分成一行一行,并在每行中按从左至右依次排放元素,称为文档流,也称为普通流。
文档流是相对于盒子模型讲的,而文本流是相对于HTML中的文字段落来讲的。
脱离文档流:
元素脱离文档流之后,将不再在文档流中占据空间,而是处于浮动状态(可以理解为漂浮在文档流的上方)。脱离文档流的元素的定位基于正常的文档流,当一个元素脱离文档流后,依然在文档流中的其他元素将忽略该元素并填补其原先的空间。

脱离文档流的方式:直接默认不存在了
浮动float。块级元素看不到浮动
Position:absolute
Position:fixed

半脱离文档流:默认你原来位置,而不是你改变后的位置
Position:relative,其他元素默认你原来的位置,但是你已经通过relative浮动到其他位置

margin塌陷及合并问题

margin塌陷问题
父子嵌套元素在垂直方向的margin,父子元素是结合在一起的,他们两个的margin会取其中最大的值.(即父子同时设置margin-top)
正常情况下,父级元素应该相对浏览器进行定位,子级相对父级定位.
但由于margin的塌陷,父级相对浏览器定位.而子级没有相对父级定位,子级相对父级,就像坍塌了一样.
解决方法:
1可以给父级设置边框或者内边距(不推荐使用)
2触发bfc(块级格式上下文),改变父级渲染规则,给父级盒子添加
(1)position:absolute/fixed
(2)display:inline-block;
(3)float:left/right
(4)overflow:hidden
这四种方法都能触发bfc,但是使用的时候都会带来不同的麻烦,具体使用中还需根据具体情况选择没有影响的来解决margin塌陷
Margin合并
两个兄弟结构的元素在垂直方向上的margin是合并的,即margin-bottom: 100px; margin-top: 100px;并没有200px,两个兄弟结构元素仅仅只有100pox间距
解决方法:也可以用bfc解决
可以在兄弟元素加一个父级元素,并且在兄弟元素上添加overflow:hidden,
或者两个兄弟元素都添加父级元素

但是这两种方法都改变了html结构,开发中并不会这么用,而是直接设置一个,即200px即可,不会使用bfc

浮动模型及清除浮动的方法

块级元素看不到浮动的元素,但是产生了bfc的元素和文本类属性inline-block元素以及文本元素可以看到
清除浮动方法:
clear:both
使用伪元素清除浮动:
.box::after {
content: “”; // 伪元素独有的属性,这里将伪元素的内容设置为空
display: block; // 伪元素天生就是行级元素,在清楚浮动的时候要改变该属性
clear: both;
}
使用bcf清除浮动
overflow:hidden
display: inline-block
position: absolute
position: absolute; float: left / right 的元素,它们会自动变成inline-block 元素。

CSS定位属性

Position:static(静态定位),absolute(绝对定位),relative(相对定位),fixed(固定定位)
Static:默认值,始终处于文档流给予的位置
Inherit:继承父元素的position,任何版本的IE都不支持inherit
Fixed:定位相对于浏览器的指定坐标,通过left,top,bottom,right属性进行规定,不论串口滚动与否,元素都会留在那个位置。但是当祖先元素具有transform属性且不为none时,就会相对于祖先元素指定坐标而不是浏览器窗口
Absolute:相对于距离该元素最近的非static元素进行定位,通过left,top,bottom,right属性进行规定
Relative:相对于该元素在文档中的初始位置进行定位,通过left,top,bottom,right属性进行规定

用CSS画三角形

等腰三角形
.a{
width: 0px;
height: 0px;
border-bottom: 50px solid red;
border-left: 50px solid transparent;
border-right: 50px solid transparent;
}
等腰梯形
.b{
width: 50px;
height: 0px;
border-bottom: 50px solid red;
border-left: 50px solid transparent;
border-right: 50px solid transparent;
}
扇形
.c{
width: 0px;
height: 0px;
border-bottom: 50px solid red;
border-left: 50px solid transparent;
border-right: 50px solid transparent;
border-radius: 50%;
}

.d{
width: 50px;
height: 50px;
background-color: blue;
border-radius: 25px;//50% 边框半径为宽高的50%
}
半圆
.e{
width: 100px;
height: 50px;
background-color: blue;
border-top-left-radius: 50px;
border-top-right-radius: 50px;
/* border-bottom-left-radius: 50px; */
}

未知宽高元素水平垂直居中(方案及比较)

使用flex布局水平垂直居中:
表示class为center的div内部居中
使用表格居中:
item类在wrap类中央
元素宽高都知:
content类在box类中央
宽度高度都未知:
content类在box类中央
内联元素:
center类内部元素水平居中
块级元素:
center类在out类中央

盒子模型及其理解

盒子模型(Box Modle)可以用来对元素进行布局,由实际内容(content)、内边距(padding)、边框(border)与外边距(margin)这几个部分组成。
盒模型也称为框模型,就是从盒子顶部俯视所得的一张平面图,用于描述元素所占用的空间。它有两种盒模型,W3C盒模型和IE盒模型(IE6以下,不包括IE6以及怪异模式下的IE5.5+)
理论上两者的主要区别是二者的盒子宽高是否包括元素的边框和内边距。当用CSS给给某个元素定义高或宽时,
IE盒模型中内容的宽或高将会包含内边距和边框,而W3C盒模型并不会。
解决两种盒模型的兼容性问题:
不要给元素添加具有指定宽度的内边距,而是尝试将内边距或外边距添加到元素的父元素和子元素。
Css3指定盒模型的种类:
box-sizing属性可以指定盒子模型种类,content-box指定盒子模型为W3C(标准盒模型),border-box为IE盒子模型(怪异盒模型)

display及相关属性

行级元素(内联元素)inline:
内容决定元素所占位置;
不可以通过CSS改变宽高。
常见标签有:span , strong , em , a , del
块级元素block:
独占一行;
可以通过CSS改变宽高。
常见标签有:div , p , ul , li , ol , form , address
行级块元素inline-block:
内容决定大小;
可以通过CSS改变宽高。
常见标签有:img
凡是带有inline的元素,都有文字特性
多个img中间有空隙,去掉空隙的方法:去掉多个img标签之间的空格(即把多个img标签写在一行)

IFC与BFC

BFC
Block Formatting Context 块级格式化上下文。
bfc是什么
由css2提出,具有规定的渲染,定位等规则的块级元素;大家都知道盒子box,一个布局中,可以同时存在很多的盒子boxes,而盒子只是容器而已,这也是其不同之处,可以说成是其升级版,具有一些规则和渲染方式之后就可以变成一个BFC,当然也只有块级元素能参与转化成BFC。
BFC布局规则
内部的Box会在垂直方向,一个接一个的放置
同一个BFC内,垂直方向的盒子上下margin会重叠
每个元素的margin box的左边,与包含块border box的左边连接(对于从右往左的布局,则相反)即使存在浮动也是如此
子BFC的区域不会与float box重叠
BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素,反之也如此。
计算BFC的高度时,浮动元素也参与计算(故也可以达到所谓清除浮动的效果,只要将包裹层转变为BFC)
如何将块级元素转换成BFC
(1)根元素(body)
(2)浮动元素(float属性不为none)
(3)定位元素(position为absolute或fixed)
(4)行内元素(display为inline-block,table-cell,table-caption,flex,inline-flex)
(5)overflow不为visible。
(除非该值已经传播到视口,入html body会将overflow的值传播到视口,故此情况下,该属性不能建立BFC)
BFC作用:
清除浮动:可以在浮动元素的父元素添加overflow:hidden清除浮动
自适应两栏布局:可以在没有实现两栏布局的那个div添加overflow:hidden
防止垂直margin合并:在第二个套一个div添加overflow:hidden
IFC
Inline Formatting Context 内联格式化上下文。(inline inline-block)
ifc是什么——一个块级元素内部都是inline或者inline-block元素
1.行内框(inline box)
每个行内元素会形成一个行内框,行内框是浏览器渲染模型中的一个概念,无法显示出来,在没有其他因素(padding等)影响的时候,行内框等于内容区域,设定行高是行内框高度不变,半行距分别添加/减少到行框的上下两边。行内框就是行内元素的边框。
2.行框(line box)
行框是指文本行的一个虚拟的矩形框,是是浏览器渲染模型中的一个概念,无法显示出来,行框高度等于本行内所有元素中行内框最大的值,当有多行内容时,每行都会有自己的行框。
同个IFC下的多个line box高度会不同。IFC中不可能有块级元素,当插入块级元素时(如p中插入div)会产生两个匿名快与div分隔开,即产生两个IFC,每个IFC对外表现为块级元素,与div垂直排列。
IFC 布局规则:
行内元素从容器的顶端开始,一个接一个地水平排布。
水平的padding,margin,border对行内元素有效,但垂直的padding,margin,border对行内元素无效,不影响其高度。
一个水平行中的行内框组成了行框
行框的高度始终容下所有的行内框,并只与行高有关,行内框小于行框时,行内框垂直位置由vertical属性决定。
行框的宽度由包含块和浮动元素决定:当不存在浮动元素时,行框的宽度等于包含块的内容区域的宽度;否则,因为行内元素会环绕浮动元素布局的特性,行框的宽度会比包含块的内容区域的宽度小。
当几个行内框在水平方向上无法放入一个行框时,行框将会被分割为几个行框,padding,margin,border在分割处没有视觉效果,如果行框无法分割(当单词过长或设定不换行),则会溢出。
创建IFC:
让行框的高度是包含块的高度的100%,让行内框内部元素使用vertical-align:middle 就OK了。
作用
水平居中:当一个块要在环境中水平居中时候,设置其为inline-block则会在外层产生IFC,通过text-align:center则可以使其水平居中。
垂直居中:创建一个IFC,用其中一个元素撑开父元素的高度,然后设置其vertical-align:middle,其他行内元素则可以在此父元素下垂直居中。

圣杯布局和双飞翼布局的实现

两者遵循要求:
两侧宽度固定,中间宽度自适应
中间部分在DOM结构上优先,以便先行渲染
允许三列中的任意一列成为最高列
只需要使用一个额外的

标签
圣杯布局:使用浮动和负值margin与relative定位

现在效果是这样的:
为了让left放在左边框中,right放在右边框中
为了让left放在第一行,可以设置margin-left: -100%;表示left内容在中间第一行靠左边,然后使用relative定位,相对于原来的定位向左移动200px即可到达左边对应位置,即position:relative,right:200px。然后设置right区域,只需要添加margin-right: -150px; 即可
为了不超出,需要设置三列的最小宽度,200+150,中间最小让#left移动放置200,即min-width:550
Center为什么要设置width:100%
因为center是浮动元素,浮动元素具有包裹性,在不显式设置宽度的情况下会自动“收缩”到内容的尺寸大小。如果去掉width: 100%,则当中间栏不包含或者包含较少内容时,整个布局会“崩掉”,而达不到这样的效果
双飞翼布局:
其他同上
显示为:
由于都设置了左浮动,可以在left下设置margin-left:-100%将左边放置到正确位置,而可以在right色湖之margin-left:-150px将右边放置到正确位置
设置最小宽度:由于双飞翼布局没有用到position:relative进行定位,所以最小页面宽度应该为200+150=350px。但是当页面宽度缩小到350px附近时,会挤占中间栏的宽度,使得其内容被右侧栏覆盖

Flex布局

flex container是开启弹性布局的元素
flex items是flex container里面的直接元素
开启flex布局方式:
display:flex(块级元素)或者display:inline-flex(行内元素)

main axis表示主轴,main start表示主轴开始位置 main end表示主轴结束位置,main size表示主轴大小
cross axis表示交叉轴,cross start表示交叉轴开始位置 cross end表示交叉轴结束位置,cross size表示交叉轴大小
默认的主轴为从左到右,交叉轴为从上到下
container属性:
决定主轴方向——flex-direction
row默认,主轴从左向右,row-reverse主轴从右向左,column主轴从上到下,column-reverse主轴从下到上
决定flex-item在主轴上的对齐方式——justify-content
justify-content:flex-start默认,与主轴开始地方对齐
justify-content:flex-end与main end对齐
justify-content:center:居中对齐
justify-content:space-between表示flex-item之间距离相等,与main start,main-end对齐
justify-content:space-evenly表示flex-item时间距离相等,flex-item与main-start和main-end之间距离等于flex-item之间的距离
justify-content:space-around表示flex-item时间距离相等,flex-item与main-start和main-end之间距离等于flex-item之间的距离的一半
决定flex-item在交叉轴上的对齐方式——align-items
align-items:normal,在弹性布局中效果与stretch一样
align-items:stretch,当item在交叉轴方向size为auto时,自动拉伸填充整个flex container
align-items:flex-start与交叉轴开始对齐
align-items:flex-end与交叉轴结束位置对齐
align-items:center居中对齐
align-items:baseline与基准线对齐
决定flex-container是单行还是多行——flex-wrap
flex-wrap:nowrap单行,默认
flex-wrap:wrap,多行
flex-wrap:wrap-reverse,多行,交叉轴与wrap相反
单行时,如果width不够,它默认会进行压缩在一行显示
多行时,如果width不够一个div宽度,他不用占用剩余的宽度,而是直接下一行
flex-flow是flex-direction和flex-wrap的缩写
决定多行item在交叉轴上的对齐方式——align-content
与justify-content相似
item属性
排列顺序——order
设置任意整数,值越小越排在前面,默认为0
覆盖container上设置的align-items——align-self
align-self,值与align-items一样
决定items如何扩展——flex-grow
设置任意非负数字,默认为0
当flex-container在主轴上有剩余位置才有效
如果所有item的flex-grow总和超过1,则每个扩展的size为剩余的sizeflex-grow占比,扩展即添加的size
如果和小于1,扩展宽度为flex-grow剩余宽度
决定item如何收缩——flex-shrink
设置任意非负数字,默认为1
items超过主轴长度才有效
当和超过1,则按照占比分配
如果小于1,则超出同扩展一样
设置主轴上大小——base-size
优先级从高到低
max-width、max-height
flex-basis
width
内容本身size
flex是flex-grow,flex-shrink,flex-basis的简写

px、em、rem的区别

px像素(Pixel)。相对长度单位。像素px是相对于显示器屏幕分辨率而言的。
em是相对长度单位。相对于当前对象内文本的字体尺寸。如当前对行内文本的字体尺寸未被人为设置,则相对于浏览器的默认字体尺寸。em会继承父级元素的字体大小。任何浏览器默认字体高度为16px,即1em表示16px
rem是CSS3新增的一个相对单位(root em,根em。区别在于使用rem为元素设定字体大小时,仍然是相对大小,但相对的只是HTML根元素。这个单位可谓集相对大小和绝对大小的优点于一身,通过它既可以做到只修改根元素就成比例地调整所有字体大小,又可以避免字体大小逐层复合的连锁反应。目前,除了IE8及更早版本外,所有浏览器均已支持rem。对于不支持它的浏览器,应对方法也很简单,就是多写一个绝对单位的声明。这些浏览器会忽略用rem设定的字体大小。
px 与 rem 的选择?
对于只需要适配少部分手机设备,且分辨率对页面影响不大的,使用px即可 。
对于需要适配各种移动设备,使用rem,例如只需要适配iPhone和iPad等分辨率差别比较挺大的设备。

Less预处理语言

为了让 CSS 富有逻辑性,短板不那么严重,涌现出了 一些神奇的预处理语言。 它们让 CSS 彻底变成一门 可以使用 变量 、循环 、继承 、自定义方法等多种特性的标记语言,逻辑性得以大大增强。
使用less:
页面中引入less.js(官网下载或CDN引入),或使用npm安装(npm install -g less,然后在css中使用$ lessc styles.less > styles.css)
变量:
定义方式:@名称:值(值变量),@选择器:值(选择器变量),@属性:值(属性变量)
例如:@width: 50%; @Wrap: wrap; @borderStyle: border-style; @images: “…/img”;
使用:width: @width; #@{Wrap}{color:#ffffff} @{borderStyle}: @Soild; background: url("@{images}/dog.png");
如果是变量名需要加{}
声明变量:
- 结构: @name: { 属性: 值 ;}; @background: {background:red;};
- 使用:@name();@background();
变量运算: - 加减法时 以第一个数据的单位为基准 - 乘除法时 注意单位一定要统一
变量作用域:就近原则
嵌套:&表示上一层选择器的名字

混合方法:
无参可以不用写括号
放入一定参数,可以使用默认或者自己传参
可以设置参数是变量 @_ 来表示,任何参数都可以匹配

媒体查询

Media Queries 除了IE6-8不支持
作用:viewport(视窗) 的宽度与高度,设备的宽度与高度,朝向 (智能手机横屏,竖屏) 。分辨率
使用方式:@media 媒体类型 and(媒体功能) {样式}
媒体类型:共11中,主要是all(所有设备),screen(用于电脑屏幕,平板电脑,智能手机等),print(用于打印机和打印预览),speech(应用于屏幕阅读器等发声设备)其他都已经废弃
可以使用not 媒体设备来排除特定设备,也可以使用only用来定某种特别的媒体类型。对于支持Media Queries的移动设备来说,如果存在only关键字,移动设备的Web浏览器会忽略only关键字并直接根据后面的表达式应用样式文件。对于不支持Media Queries的设备但能够读取Media Type类型的Web浏览器,遇到only关键字时会忽略这个样式文件。(only主要是处理不支持媒体查询但是能读取媒体类型的浏览器)
媒体功能:常用的为min-width,max-width,height(表示页面的高度),device-height(表示设备高度),max-device-height,resolution(分辨率),orientation(手机朝向portrait表示竖屏,landscape表示横屏)
Js判断横屏竖屏:window.orientation这个参数

vh与vw

vh:view height,vw:view width
vh和vw是css3引入的,称为视口单位允许我们更接近浏览器窗口定义大小
在桌面端,指的是浏览器的可视区域;在移动端,它涉及3个视口:Layout Viewport(布局视口),Visual Viewport(视觉视口),Ideal Viewport(理想视口)。
视口单位中的“视口”,桌面端指的是浏览器的可视区域;移动端指的就是Viewport中的Layout Viewport。
Vw表示视口宽度的1%,vmin表示vh和vw中较小的一个
与%的区别:%是元素的祖先元素,vw和vh是视口的尺寸

H5的语义化作用及语义化标签

语义化作用:
让页面内容更加结构化,结构更清晰,便于浏览器,搜索引擎解析。
语义化让文档更易读,搜索引擎的爬虫也依赖HTML标记来确定上下文和各个关键字的权重,利于SEO;
使屏幕阅读器能更好的为残疾认识服务,便于阅读和理解。
语义化标签:Header,Footer,Nav,Hgroup,Section,Article,Aside,Figure,Time,Datalist,Details,Address,Keygen,Progress

Web Worker和Web Socket

Web Socket:
websocket是一种协议,本质上和http,tcp一样。协议是用来说明数据是如何传输的。它的url前缀是ws:// 或者wss://,后者是加密的。客户端和服务端进行websocket交互的方式也有人理解为“HTTP握手+TCP数据传输”的方式。
HTTP握手+TCP数据传输:
浏览器(支持Websocket的浏览器)像HTTP一样,发起一个请求,然后等待服务端的响应;
服务器返回握手响应,告诉浏览器请将后续的数据按照websocket制定的数据格式传过来;
浏览器和服务器的socket连接不中断,此时这个连接和http不同的是它是双工的了;
浏览器和服务器有任何需要传递的数据的时候使用这个长连接进行数据传递
这里说它是HTTP握手,是因为浏览器和服务器在建立长连接的握手过程是按照HTTP1.1的协议发送的,有Request,Request Header, Response, Response Header。但是不同的是Header里面的字段是有特定含义的。
说它是TCP传输,主要体现在建立长连接后,浏览器是可以给服务器发送数据,服务器也可以给浏览器发送请求的。当然它的数据格式并不是自己定义的,是在要传输的数据外层有ws协议规定的外层包的。
数据传输过程
websocket的数据传输是frame形式传输的,比如会将一条消息分为几个frame,按照先后顺序传输出去。这样做会有几个好处:
大数据的传输可以分片传输,不用考虑到数据大小导致的长度标志位不足够的情况。
和http的chunk一样,可以边生成数据边传递消息,即提高传输效率。
Web Worker
当在 HTML 页面中执行脚本时,页面的状态是不可响应的,直到脚本已完成。
而web worker 是运行在后台的 JavaScript,独立于其他脚本,不会影响页面的性能。您可以继续做任何愿意做的事情:点击、选取内容等等,而此时 web worker 在后台运行。
除了DOM操作之外,理论上任何JS脚本任务都可放入worker中执行;语法上的限制,则是不能跨域访问JS。worker常用于需要消耗大量时间和CPU资源的复杂计算,以换来前台用户操作的友好型;换句话说,从用户体验上看,提高了服务性能。
worker的主线程和子线程间通过postMessage()来发送消息,通过向 web worker 添加一个 “onmessage” 事件监听器来获取接受到的消息。

CSS3及相关动画

CSS3动画相关的属性:transform,transition,animation.
变形Transform
transform: rotate | scale | skew | translate |matrix;
rotate:旋转,通过指定一个角度对原元素进行2D旋转,正值表示顺时针旋转,负值表示逆时针。默认原点是其中心位置,可以设置transform-origin.角度单位为deg
scale:缩放,通过指定X和Y方向上的缩放倍数对原元素进行2D缩放。两个参数
skew:扭曲,通过指定X和Y方向上的斜切角度,对原元素进行斜切变换。
translate:移动,通过指定X和Y方向的移动长度对元素进行移动,正值是向右下移动的。%表示自身宽度占比
matrix:矩阵变换
过渡Transition
transition主要包含四个属性值:执行过渡的属性名称:transition-property, 变换延续的时间:transition-duration,在变换的速率变化transition-timing-function,变换延迟时间transition-delay。列表用逗号隔开

例如:transition:width 0.1s,height 2s;
动画Animation
animation类似transition,不同的是animation可以定义每个关键帧的效果,可以实现更为复杂的动画。
常用属性:
@keyframes:关键帧动画。
animation-name:定义@keyframes的动画名称。
animation-duration:定义动画一个周期的秒或毫秒数。
animation-timing-function:定义动画的速度变化。
animation-delay:定义动画何时开始。
animation-iteration-count:定义动画被播放的次数,可定义为循环播放(infinite)。
animation-direction:定义是否循环交替反向播放动画。如果设置只播放一次就没有作用。(normal正常默认 |reverse反向播放 |alternate奇数次正向偶数次反向 |alternate-reverse奇数次反向偶数次正向 |initial设置该属性为他的默认值 |inherit从父元素继承该属性;)
定义关键帧动画例如:

如何实现响应式布局

实现响应式布局:为了网页兼容不同的额终端
使用Meta标签定义
使用 viewport meta 标签在手机浏览器上控制布局

通过快捷方式打开时全屏显示 隐藏状态栏 iPhone会将看起来像电话号码的数字添加电话连接,应当关闭 使用媒体查询 根据min-width等设置不同设备显示不同的方案 设置字体 rem是相对于根元素的,之前先重置根元素的大小,从而设置响应式字体 宽度不固定,使用百分比 图片的响应式 使用img的srcset属性:属性格式:图片地址 宽度描述w 像素密度描述x,多个资源之间用逗号分隔。 表示达到800w时显示middle.jpg,达到1440w时显示big.jpg,默认显示 ## SEO的概念及实现 SEO(Search Engine Optimization的简写):汉译为搜索引擎优化。指利用搜索引擎的规则提高网站在有关搜索引擎内的自然排名。目的是让其在行业内占据领先地位,获得品牌收益。很大程度上是网站经营者的一种商业行为,将自己或自己公司的排名前移。 SEO就是认识与了解搜索引擎怎样抓取网页、索引网页、怎样确定搜索关键词等技术后,以此优化网页内容,能够确保不影响用户习惯和内容的的前提下,提升网页在搜索引擎的排名,最终提升本产品在行业内的排名,最终提高网站宣传能力和产品销售能力的一种现代技术。 SEO常用的技术手段:搜索引擎优化的技术手段主要有黑帽(black hat)、白帽(white hat)两大类。通过作弊手法欺骗搜索引擎和访问者,最终将遭到搜索引擎惩罚的手段被称为黑帽,比如隐藏关键字、制造大量的meta字、alt标签等。而通过正规技术和方式,且被搜索引擎所接受的SEO技术,称为白帽。 SEO的相关基础知识: 死链、锚文本、目标关键词、长尾关键词、网站地图、沙盒效应 死链(broken links)。链接,失效的链接、错误链接,它原本是正常的,但是后来变成无效的链接,使得网页中打开这个死链接地址,服务器回应的是打不开的页面或友好的404错误页面。 锚文本(anchor text)。通过文本关键词加入链接代码,达到点击这个关键词可以链接到你设置的页面 目标关键词(keywords)。网站的主要关键词,也成为"主关键词"。 长尾关键词(Long Tail Keywords)。由两三个或更多短词组成的关键词。 网站地图(sitemap)。网站地图其实只是个页面,相当于网站的张路径地图,只是这个页面上面放置了整个站点所有页面的链接,做网站地图主要的目的是给搜索引擎看,搜索引擎蜘蛛非常喜欢网站地图的,主要是让搜索引擎读取这张地图,让搜索引擎更加快速的浏览你的整个网站。 ## HTML5的新特性 语义标签,增强型表单,视频和音频,Canvas绘图,SVG绘图 地理定位,拖放API,WebWorker,WebSocket,WebStorage Input新增了五个表单元素:datalist,progress,meter,keygen,output Input新增了表单属性:placeholder,required,pattern,min/max,step,height/width,autofocus,multiple Canvas和SVG的区别:

拖放API

WebStorage是HTML新增的本地存储解决方案之一,但并不是取代cookie而指定的标准,cookie作为HTTP协议的一部分用来处理客户端和服务器的通信是不可或缺的,session正式依赖与实现的客户端状态保持。WebSorage的意图在于解决本来不应该cookie做,却不得不用cookie的本地存储。
websorage拥有5M的存储容量,而cookie却只有4K,这是完全不能比的。
客户端存储数据有两个对象,其用法基本是一致。
localStorage:没有时间限制的数据存储
sessionStorage:在浏览器关闭的时候就会清除。

Less和Sass使用

字体格式

段落


粗体
大号字
着重字
斜体
小号字
加重语气
定义下标字
定义上标字
定义插入字

定义删除字

背景图像属性background

Background-image,为背景图片,可以为多个,用逗号隔开
Background-color,背景颜色
Background-origin,设置背景的定位方式,为border-box,padding-box,content-box
Background-clip,设置背景剪切方式,背景放好以后可以把位于其他部分剪切掉,值同origin
Background-repeat,设置背景重复方式,no-repeat,repeat-x,repeat-y
Background-size,设置背景图片大小,可以为px,可以为%,可以为cover比例缩放直到全部覆盖,可以为contain比例缩放直到适应背景宽高中一个
Background-position,设置图片的定位,
Background-attachment,设置背景图像是否固定或者随着页面的其余部分滚动。默认为scroll随页面滚动而滚动,fixed不会随页面滚动而滚动,local背景图片会随着元素内容的滚动而滚动。

文本阴影text-shadow

Text-shadow:none 或者length(2或者3个)&color
第一个表示阴影水平偏移值,第二个为垂直偏移值,第三个为对象的阴影模糊值不能为负
Text-shadow可以为多个阴影,用逗号隔开

文本溢出与换行

White-space设置是否允许换行
Text-overflow设置溢出clip表示不现实……而是简单剪切,ellipsis显示……省略标记插入最后一个字符,ellipsis-word显示……省略标记插入最后一个词

Line-break控制日文换行,
word-wrap控制换行,属性为break-word是强制换行,中文文本与英文语句没问题,但是长串英文无作用
word-break针对亚洲语言与非亚洲语言,break-all表示允许非亚洲语言文本任意字内断开,keep-all表示中文,韩文等是不允许字断开
white-space具有格式化文本作用,nowrap表示一行显示

JAVASCRIPT

Js根据已知数组创建一个新数组并初始化值
let array=new Array(Math.max.apply(Math,nums)).fill(0);

Map即对象,但有顺序问题
let obj={};
obj[4]=‘234’;
obj[2]=‘123’;
obj[1]=‘123’;
console.log(obj);

    let obj={};
    obj.a='234';
    obj.g='123';
    obj.c='123';
    console.log(obj);

JS数据类型

基本数据类型
string number boolean null undefined
引用数据类型
object

Undefined 与 Null 的区别
Undefined 与 null 的值相等,但类型不相等:
typeof undefined // undefined
typeof null // object
null === undefined // false
null == undefined // true

原始值和引用值类型及区别

原始值: 存储在栈中的简单数据段,即他们的值直接存储在变量访问的位置。
包括五种原始类型:undefined、null、boolean、number、string。

引用值:存储在堆中的对象,即存储在变量处的值是一个指针,只想存储对象的内存处。
包括:object、Function(function)、Array、Date、RegExp等

两者的区别:
原始变量及他们的值储存在栈中,当把一个原始变量传递给另一个原始变量时,是把一个栈房间的东西复制到另一个栈房间,且这两个原始变量互不影响。

引用值是把引用变量的名称储存在栈中,但是把其实际对象储存在堆中,且存在一个指针由变量名指向储存在堆中的实际对象,当把引用对象传递给另一个变量时,复制的其实是指向实际对象的指针,此时两者指向的是同一个数据,若通过方法改变其中一个变量的值,则访问另一个变量时,其值也会随之加以改变;但若不是通过方法而是通过重新赋值,此时,相当于重新开了一个房间,该值的原指针改变,则另外一个值不会随他的改变而改变。

Number和number的区别

var s = function () {

    };
    console.log(typeof s); //function
    console.log(s instanceof Function);  //true

    var b = new Function();
    console.log(typeof b);   //functon
    console.log(b instanceof Function);   //true

    // ----- number vs. Number -----
    var s = 7
    typeof s // "number"
    s instanceof Number // false

    var s = new Number(7)
    typeof s // "object"
    s instanceof Number // true

    var s = JSON.parse('{"s": 7}').s
    typeof s // "number"
    s instanceof Number // false

    // ----- array vs. object ------
    var a = [];
    a instanceof Array // true
    typeof a // "object"
    Array.isArray(a) // true

    var a = new Array()
    typeof a // "object"
    a instanceof Array // true
    Array.isArray(a) // true

https://www.cnblogs.com/thinking-better/p/5330120.html
1.Number与Number Object ——原始类型与包装类型(primitive VS wrapper object)
ECMAScript定义了7种数据类型:6种原始类型(ES6新增Symbol)以及Object。原始类型(primitive)不是对象,包装类型对象(wrapper object)属于Object的范畴,除了null和undefined原始类型都有对应的包装类型,我们不谈Symbol(分明是不够理解 ==):
● String for the string primitive.
● Number for the number primitive.
● Boolean for the boolean primitive.
● Symbol for the symbol primitive.
原始类型不是对象并且没有方法,为什么"test".length怎么可以使用,不是原始类型没有方法吗?这里有个机制:http://es5.github.io/#x10.4.3(step 3 的ToObject是核心)

判断数据类型typeof、instanceof、Object.prototype.toString.call()、constructor

typeof:主要用于原始类型的检测,可检测原始类型、方法/函数、对象,遵循(出于兼容考虑,直到ES6调用 typeof null 仍然返回object):
类型 结构
undefined “undefined”
null “object”
boolean “boolean”
number “number”
string “string”
symbol (ECMAScript 6 新增) “symbol”
宿主对象(JS环境提供的,比如浏览器) Implementation-dependent
函数对象 (implements [[Call]] in ECMA-262 terms) “function”
任何其他对象 “object”
instanceof:主要用于检测自定义对象,用来判断某个构造方法/构造函数(右侧)的prototype属性所指向的对象是否存在于另外一个要检测对象(左侧)的原型链上。简单来说就是 instanceof 是用来判断 A 是否为 B 的实例。
额外补点说明:
1.跨Frame/多窗口间不要用instanceof检测类型(可以用Object.prototype.toString);
2.instanceof的结果不是一成不变的,它可能会受到完全重写prototype的影响:
instanceof 的缺点
• 是否处于原型链上的判断方法不严谨
instanceof 方法判断的是是否处于原型链上,而不是是不是处于原型链最后一位,所以会出现下面这种情况:
var arr = [1, 2, 3];
console.log(arr instanceof Array) // true
console.log(arr instanceof Object); // true
function fn(){}
console.log(fn instanceof Function)// true
console.log(fn instanceof Object)// true
因为所有原型链的尽头都是 object,所以就造成了这种状况。当你自定义了一个类 A,并且继承了一个原生类 B,这个时候检测结果未必准确:
A instanceof A // true
A instanceof B // true
A instanceof Object //true
• 无法判断字面量方式创建的基本数据类型
对于基本数据类型来说,字面量方式创建出来的结果和实例方式创建的是有一定区别的
console.log(1 instanceof Number)//false
console.log(new Number(1) instanceof Number)//true
从严格意义上来讲,只有实例创建出来的结果才是标准的对象数据类型值,也是标准的 Number 这个类的一个实例;对于字面量方式创建出来的结果是基本的数据类型值,不是严谨的实例,但是由于 JS 的松散特点,导致了可以使用 Number.prototype 上提供的方法。
• 无法检测 null 和 undefined
对于特殊的数据类型 null 和 undefined,他们的所属类是 Null 和 Undefined,但是浏览器把这两个类保护起来了,不允许我们在外面访问使用。

constructor
constructor 作用和 instanceof 非常相似。但 constructor 检测 Object 与 instanceof 不一样,还可以处理基本数据类型的检测。
var aa=[1,2];
console.log(aa.constructor=Array);//true
console.log(aa.constructor
=RegExp);//false
console.log((1).constructor=Number);//true
var reg=/^$/;
console.log(reg.constructor
=RegExp);//true
console.log(reg.constructor===Object);//false
constructor 的缺点
• 无法检测 null 和 undefined
null 和 undefined 是无效的对象,因此是不会有 constructor 存在的,这两种类型的数据需要通过其他方式来判断。
• 不稳定
函数的 constructor 是不稳定的,这个主要体现在把类的原型进行重写,在重写的过程中很有可能出现把之前的 constructor 给覆盖了,这样检测出来的结果就是不准确的,由此可知 instanceof 同样也存在这个问题。
function Fn(){}
Fn.prototype = new Array()
var f = new Fn
console.log(f.constructor)//Array

Object.prototype.toString.call()
全能方法,最准确最常用,据 MDN 描述
每个对象都有一个 toString() 方法,当该对象被表示为一个文本值时,或者一个对象以预期的字符串方式引用时自动调用。默认情况下,toString() 方法被每个 Object 对象继承。如果此方法在自定义对象中未被覆盖,toString() 返回 “[object type]”,其中 type 是对象的类型。
在 Number、String,Boolean,Array,RegExp、Date、Function 等对象上 toString() 方法都是被重写过了的,会按照一定的规则返回字符串。但是在 object 对象上,这个方式是返回当前方法执行的主体(方法中的this)所属类的详细信息即[object Object],其中第一个 object 代表当前实例是对象数据类型的(这个是固定的 object),第二个 Object 代表的是 this 所属的类型。
为了每个对象都能通过 Object.prototype.toString() 来检测,需要以 Function.prototype.call() 或者 Function.prototype.apply() 的形式来调用,传递要检查的对象作为第一个参数,称为 thisArg。

类数组与数组的区别与转换

类数组:
1)拥有length属性,其它属性(索引)为非负整数(对象中的索引会被当做字符串来处理);
2)不具有数组所具有的方法;
类数组是一个普通对象,而真实的数组是Array类型。
常见的类数组有: 函数的参数 arguments, DOM 对象列表(比如通过 document.querySelectorAll 得到的列表), jQuery 对象 (比如 $(“div”)).
类数组可以转换为数组:
//第一种方法
Array.prototype.slice.call(arrayLike, start);
//第二种方法
[…arrayLike];
//第三种方法:
Array.from(arrayLike);
PS: 任何定义了遍历器(Iterator)接口的对象,都可以用扩展运算符转为真正的数组。
Array.from方法用于将两类对象转为真正的数组:类似数组的对象(array-like object)和可遍历(iterable)的对象。

数组的常见API

  1. .toString(); 将数组转为字符串,各个元素之间按照逗号分隔
    var test=[‘a’,‘b’,‘c’];
    console.log(test.toString()); // 1,2,3
    但是两种不同类型的的对象,也不是同一种
    var test=[‘a’,‘b’,‘c’];
    console.log(test.toString()); // 1,2,3
    var x=2;
    x.toString();
    console.log(test.toString()===x.toString());
    2.按照指定字符分割
    var test=[‘a’,‘b’,‘c’];
    console.log(test.join(’-’));//a-b-c
    .join(’-’) 括号中参数为改变的字符串
    3.拼接多个数组
    var arr1=[‘何旭刚’,‘温浩伟’,‘吴磊’];
    var arr2=[‘然哥’,‘来杰’];
    var arr3=[‘黄国缘’,‘徐坤’,‘金娅’];
    console.log(arr1.concat(arr2,arr3));
    //[ ‘何旭刚’, ‘温浩伟’, ‘吴磊’, ‘然哥’, ‘来杰’, ‘黄国缘’, ‘徐坤’, ‘金娅’ ]
    .concat(arr,arr );
    4.截取数组中的元素
    var arr=[‘林佳’,‘朱茗轩’,‘何旭刚’,‘温浩伟’,‘吴磊’,‘徐嘉鑫’,‘朱龙’,‘潘哥’];

console.log(arr.slice(2));
console.log(arr.slice(2,6));
console.log(arr.slice(-3,-1));
//[ ‘何旭刚’, ‘温浩伟’, ‘吴磊’, ‘徐嘉鑫’, ‘朱龙’, ‘潘哥’ ]
//[ ‘何旭刚’, ‘温浩伟’, ‘吴磊’, ‘徐嘉鑫’ ]
//[ ‘徐嘉鑫’, ‘朱龙’ ]
slice(start,end);
当end为空时,则默认为到数组结尾
当end为6时,数组的初始值时0开始的,所以到第六为的前一位;
当为负数时,从末尾开始计算。
5.翻转数组
var arr=[‘a’,‘b’,‘c’,‘d’];
console.log(arr.reverse());
reverse();
上述代码输出结果、、d c b a
6.排序
var arr=[23,9,78,6,45];
console.log(arr.sort(
function(a,b){
return a-b ; //从小打到排序
//return b-a //从大到小排序
}😉);
arr.sort(function(){
a-b
}));
7.删除数组元素
var arr=[‘何旭刚’,‘李思伟’,‘金娅’,‘徐坤’,‘徐佳鑫’,‘然哥’,‘汪洋’,‘李月’,‘刘德华’];
//console.log(arr.splice(1));
//console.log(arr.splice(1,2));
console.log(arr.splice(-3,0));
splice(start,count,val1,val2)
start为开始的下标,count为删除的数量
count为空 会一直删除到最后 start为赋值,表示为倒数,
val1,val2表示删除后替换的元素;返回删除的元素,原数组会发生变化。
//练习:创建数组包含a~h,每个字母是一个元素,删除cd,替换f为m,在下标为1的位置插入z
var arr=[‘a’,‘b’,‘c’,‘d’,‘e’,‘f’,‘g’,‘h’];
console.log( arr.splice(2,2) );
console.log( arr.splice(-3,1,‘m’) );
console.log( arr.splice(1,0,‘z’) );
console.log(arr);

8.往数组末尾添加元素 删除数组末尾的一个元素
var arr=[‘a’,‘b’,‘c’];
console.log(arr.push(‘d’,‘e’)); //返回的为数组的长度
console.log(arr.pop()); //返回的为删除的数值
在添加 或者删除的时候 原数组会发生变化
9.在数组开头添加 元素 删除数组开头的元素
var arr=[‘a’,‘b’,‘c’];
//console.log(arr.push(‘d’,‘e’)); //返回的为数组的长度
//console.log(arr.pop()); //返回的为删除的数值
console.log(arr.unshift(‘d’,‘e’));//返回的为数组的长度
console.log(arr.shift()); //返回的为删除的数值
在添加 或者删除的时候 原数组会发生变化。
10. forEach 遍历数组的所有元素

  1. every 用来判断所有的数组元素,都满足一个条件

  2. some 用来判断所有的数组元素,只要有一个满足条件即可

  3. sort 数组排序

  4. map 将元素重新组装,并返回

  5. filter 通过某一条件过滤数组

apply,call,bind的区别

apply方法
apply接受两个参数,第一个参数是this的指向,第二个参数是函数接受的参数,以数组的形式传入,且当第一个参数为null、undefined的时候,默认指向window(在浏览器中),使用apply方法改变this指向后原函数会立即执行,且此方法只是临时改变this指向一次。
var name=“martin”;
var obj={
name:“lucy”,
say:function(year,place){
console.log(this.name+" is “+year+” born from "+place);
}
};
var say=obj.say;
setTimeout(function(){
say.apply(obj,[“1996”,“China”])
} ,0); //lucy is 1996 born from China,this改变指向了obj
say(“1996”,“China”) //martin is 1996 born from China,this指向window,说明apply只是临时改变一次this指向
求数组中的最大值:
var arr=[1,10,5,8,3];
console.log(Math.max.apply(null, arr)); //10
其中Math.max函数的参数是以参数列表,如:Math.max(1,10,5,8,3)的形式传入的,因此我们没法直接把数组当做参数,但是apply方法可以将数组参数转换成列表参数传入,从而直接求数组的最大值。
call方法
call方法的第一个参数也是this的指向,后面传入的是一个参数列表(注意和apply传参的区别)。当一个参数为null或undefined的时候,表示指向window(在浏览器中),和apply一样,call也只是临时改变一次this指向,并立即执行。
var arr=[1,10,5,8,3];
console.log(Math.max.call(null,arr[0],arr[1],arr[2],arr[3],arr[4])); //10
bind方法
bind方法和call很相似,第一参数也是this的指向,后面传入的也是一个参数列表(但是这个参数列表可以分多次传入,call则必须一次性传入所有参数),但是它改变this指向后不会立即执行,而是返回一个永久改变this指向的函数。
var arr=[1,10,5,8,12];
var max=Math.max.bind(null,arr[0],arr[1],arr[2],arr[3])
console.log(max(arr[4])); //12,分两次传参
可以看出,bind方法可以分多次传参,最后函数运行时会把所有参数连接起来一起放入函数运行。
apply,call,bind三者区别
• 三者都可以改变函数的this对象指向。
• 三者第一个参数都是this要指向的对象,如果如果没有这个参数或参数为undefined或null,则默认指向全局window。
• 三者都可以传参,但是apply是数组,而call是参数列表,且apply和call是一次性传入参数,而bind可以分为多次传入。
• bind 是返回绑定this之后的函数,便于稍后调用;apply 、call 则是立即执行 。

实现bind方法(面试题)
简易版:
Function.prototype.bind=function () {
var _this=this;
var context=arguments[0];
var arg=[].slice.call(arguments,1);
return function(){
arg=[].concat.apply(arg,arguments);
_this.apply(context,arg);
}
};
完美版:
//实现bind方法
Function.prototype.bind = function(oThis) {
if (typeof this !== ‘function’) {
// closest thing possible to the ECMAScript 5
// internal IsCallable function
throw new TypeError(‘Function.prototype.bind - what is trying to be bound is not callable’);
}
var aArgs = Array.prototype.slice.call(arguments, 1),
fToBind = this,
fNOP = function() {},
fBound = function() {
// this instanceof fBound === true时,说明返回的fBound被当做new的构造函数调用
return fToBind.apply(this instanceof fBound
? this
: oThis,
// 获取调用时(fBound)的传参.bind 返回的函数入参往往是这么传递的
aArgs.concat(Array.prototype.slice.call(arguments)));
};
// 维护原型关系
if (this.prototype) {
// 当执行Function.prototype.bind()时, this为Function.prototype
// this.prototype(即Function.prototype.prototype)为undefined
fNOP.prototype = this.prototype;
}
// 下行的代码使fBound.prototype是fNOP的实例,因此
// 返回的fBound若作为new的构造函数,new生成的新对象作为this传入fBound,新对象的__proto__就是fNOP的实例
fBound.prototype = new fNOP();
return fBound;
};
var arr=[1,11,5,8,12];
var max=Math.max.bind(null,arr[0],arr[1],arr[2],arr[3]);
console.log(max(arr[4])); //12

new的原理

当我们用new运算符new一个构造函数产生一个实例时,比如说: var obj = new Func 时,其背后的步骤是这样的:
1:创建一个继承自 Func.prototype 的新对象;
2:执行构造函数 Func ,执行的时候,相应的传参会被传入,同时上下文(this)会被指定为第一步创建的新对象;
3:如果构造函数返回了一个“对象”,那么这个对象会取代步骤1中new出来的实例被返回。如果构造函数没有返回对象,那么new出来的结果为步骤1创建的对象。
注意:new Func 等同于new Func(),只能用在不传递任何参数的情况。
按照上述原理,写一段代码模拟new运算符的实现原理:
//new运算符原理实现
var new1 = function(fun){
var newObj = Object.create(fun.prototype);
var returnObj = fun.call(newObj);
if(typeof returnObj === ‘object’){
return returnObj
}else{
return newObj
}
}
其中 var newObj = Object.create(fun.prototype) 的意思是:创建一个新对象newObj,并让 newObj.proto 指向 fun,即 newObj.proto === fun 返回true。
测试一下
var strObj = new1(String);
alert(strObj instanceof String); //true
alert(strObj.proto.constructor === String); //true
可以看到,new1函数的运行效果和new运算符是一样的。我们继续给String的原型上添加一个方法,看看new1函数得到的strObj能否继承到这个方法:
String.prototype.defineByN = function(){
alert(“我是自定义方法”);
}
strObj.defineByN(); //弹出“我是自定义方法”
可以看到new1函数得到的strObj继承了到这个方法。

总结:
new 在执行时会做四件事情:
① 在内存中创建一个新的空对象。
② 让 this 指向这个新的对象。
③ 执行构造函数里面的代码,给这个新对象添加属性和方法。
④ 返回这个新对象(所以构造函数里面不需要 return )。

this指向

js中,this 的指向是看this是谁调用的,而不是在哪里定义的。只定义而未调用,此时this的指向是未知的,只有调用后才能知道this的指向。
1.默认绑定,默认绑定一般发生在回调函数和函数直接调用(立即执行函数)
function test() {
console.log(this); //window 或 严格模式下是undefined
}
setTimeout(function () {
console.log(this);
//window setTimeout比较奇怪,默认绑定严格模式下竟然不是undefined
});
arr.forEach(function(){
console.log(this);//window 或严格模式下是undefined
});
2.对象+点运算符调用,this指向调用它的对象。或数组枚举调用,this指向的是数组本身
//Arrayindex; 等同于数组对象直接打点调用函数
function foo(){
console.log(this.length);
}
var arr = [foo,2,3,4];
arr0; //4
3.构造函数 this 指向实例对象 原型对象里面的this 指向的也是 ldh这个实例对象
4.绑定事件函数 this 指向的是函数的调用者 比如btn这个按钮对象
5.显示绑定显示绑定call,apply,bind this指向绑定的对象
6.箭头函数里面的 this 是继承外面的环境。

闭包及其作用

闭包就是一个函数,这个函数能够访问其他函数的作用域中的变量。
闭包的作用:
1.可以间接调用函数内部的局部变量。
2.可以让这些变量的值始终保持在内存中。(因此要注意不能滥用闭包)
3.可以暂存数据,给变量开辟私密空间,避免外部污染

    闭包(closure)指有权访问另一个函数作用域中变量的函数。
    一个作用域可以访问另外一个函数的局部变量 
    我们fn 外面的作用域可以访问fn 内部的局部变量
    闭包的主要作用: 延伸了变量的作用范围

原型和原型链

在说这个原型和原型链之前,先把为什么会有原型讲清楚
1.构造函数
构造函数是一种特殊的函数,主要用来初始化对象,即为对象成员变量赋初始值,它总与 new 一起使用。我们可以把对象中一些公共的属性和方法抽取出来,然后封装到这个函数里面。
JavaScript 的构造函数中可以添加一些成员,可以在构造函数本身上添加,也可以在构造函数内部的 this 上添加。通过这两种方式添加的成员,就分别称为静态成员和实例成员。
 静态成员:在构造函数本上添加的成员称为静态成员,只能由构造函数本身来访问
 实例成员:在构造函数内部创建的对象成员称为实例成员,只能由实例化的对象来访问
构造函数方法很好用,但是存在浪费内存的问题。

我们希望所有的对象使用同一个函数,这样就比较节省内存,那么我们要怎样做呢?
构造函数原型 prototype

构造函数通过原型分配的函数是所有对象所共享的。
JavaScript 规定,每一个构造函数都有一个 prototype 属性,指向另一个对象。注意这个 prototype 就是一个对象,这个对象的所有属性和方法,都会被构造函数所拥有。
我们可以把那些不变的方法,直接定义在 prototype 对象上,这样所有对象的实例就可以共享这些方法。

  1. 原型是什么 ?
    一个对象,我们也称为 prototype 为原型对象。
  2. 原型的作用是什么 ?
    共享方法。

constructor 构造函数
对象原型( proto)和构造函数(prototype)原型对象里面都有一个属性 constructor 属性 ,constructor 我们称为构造函数,因为它指回构造函数本身。
constructor 主要用于记录该对象引用于哪个构造函数,它可以让原型对象重新指向原来的构造函数。
一般情况下,对象的方法都在构造函数的原型对象中设置。如果有多个对象的方法,我们可以给原型对象采取对象形式赋值,但是这样就会覆盖构造函数原型对象原来的内容,这样修改后的原型对象 constructor 就不再指向当前构造函数了。此时,我们可以在修改后的原型对象中,添加一个 constructor 指向原来的构造函数。

构造函数、实例、原型对象三者之间的关系

原型链

prototype与__proto__的关系与区别

对象都会有一个属性 proto 指向构造函数的 prototype 原型对象,之所以我们对象可以使用构造函数 prototype 原型对象的属性和方法,就是因为对象有 proto 原型的存在。
 __proto__对象原型和原型对象 prototype 是等价的
 __proto__对象原型的意义就在于为对象的查找机制提供一个方向,或者说一条路线,但是它是一个非标准属性,因此实际开发中,不可以使用这个属性,它只是内部指向原型对象 prototype

继承的实现方式及比较

ES6之前并没有给我们提供 extends 继承。我们可以通过构造函数+原型对象模拟实现继承,被称为组合继承。
借助call和父构造函数继承属性:
核心原理: 通过 call() 把父类型的 this 指向子类型的 this ,这样就可以实现子类型继承父类型的属性。
// 借用父构造函数继承属性
// 1. 父构造函数
function Father(uname, age) {
// this 指向父构造函数的对象实例
this.uname = uname;
this.age = age;
}
// 2 .子构造函数
function Son(uname, age, score) {
// this 指向子构造函数的对象实例
Father.call(this, uname, age);
this.score = score;
}
var son = new Son(‘刘德华’, 18, 100);
console.log(son);
借用原型对象继承方法:
一般情况下,对象的方法都在构造函数的原型对象中设置,通过构造函数无法继承父类方法。
核心原理:
① 将子类所共享的方法提取出来,让子类的 prototype 原型对象 = new 父类()
② 本质:子类原型对象等于是实例化父类,因为父类实例化之后另外开辟空间,就不会影响原来父类原型对象
③ 将子类的 constructor 从新指向子类的构造函数

// 借用父构造函数继承属性
// 1. 父构造函数
function Father(uname, age) {
// this 指向父构造函数的对象实例
this.uname = uname;
this.age = age;
}
Father.prototype.money = function() {
console.log(100000);

    };
    // 2 .子构造函数 
    function Son(uname, age, score) {
        // this 指向子构造函数的对象实例
        Father.call(this, uname, age);
        this.score = score;
    }
    // Son.prototype = Father.prototype;  这样直接赋值会有问题,如果修改了子原型对象,父原型对象也会跟着一起变化
    Son.prototype = new Father();
    // 如果利用对象的形式修改了原型对象,别忘了利用constructor 指回原来的构造函数
    Son.prototype.constructor = Son;
    // 这个是子构造函数专门的方法
    Son.prototype.exam = function() {
        console.log('孩子要考试');

    }
    var son = new Son('刘德华', 18, 100);
    console.log(son);
    console.log(Father.prototype);
    console.log(Son.prototype.constructor);

https://www.cnblogs.com/Yellow-ice/p/10473176.html
https://zhuanlan.zhihu.com/p/105312152

对于知乎的那篇文章中
function Parent(){
this.name = ‘web前端’;
this.type = [‘JS’,‘HTML’,‘CSS’];
}
Parent.prototype.Say=function(){
console.log(this.name);
}
function Son(){};
Son.prototype = new Parent();

son1 = new Son();
son1.Say();
son1 = new Son();
son2 = new Son();
son1.type.push(‘VUE’);
console.log(son1.type);//[‘JS’,‘HTML’,‘CSS’,‘VUE’]
console.log(son2.type);//[‘JS’,‘HTML’,‘CSS’,‘VUE’]

function Parent(name){
this.name = name;
this.type = [‘JS’,‘HTML’,‘CSS’];
}
Parent.prototype.Say=function(){
console.log(this.name);
}
function Son(name){
Parent.call(this,name);
}
Son.prototype = new Parent();
son1 = new Son(‘张三’);
son2 = new Son(‘李四’);
son1.type.push(‘VUE’);
son2.type.push(‘PHP’);
console.log(son1.type);//[‘JS’,‘HTML’,‘CSS’,‘VUE’]
console.log(son2.type);//[‘JS’,‘HTML’,‘CSS’,‘PHP’]
son1.Say();//张三
son2.Say();//李四
这两段代码输出结果不一样的原因分析:
第一段代码所有Son实例化对象都共享同一原型对象(Person的一个实例对象)而Son构造函数本身并没有type属性,所以Son的任意一个实例化对象找type属性时在自己身上找不到,就去__proto__()上找,找到后去修改了这个共有的属性。
第二段代码中,Son构造函数本身就有type属性,Son的实例化对象找type属性时在自己身上找得到就不去__proto__上找了

ES6面向对象
创建类:

类 constructor 构造函数

类添加方法

继承:

super 关键字用于访问和调用对象父类上的函数。可以调用父类的构造函数,也可以调用父类的普通函数
注意: 子类在构造函数中使用super, 必须放到 this 前面 (必须先调用父类的构造方法,在使用子类构造方法)
举例1:
class Father {
constructor(x, y) {
this.x = x;
this.y = y;
}
sum() {
console.log(this.x + this.y); //加this使用

        }
    }
    class Son extends Father {
        constructor(x, y) {
            super(x, y); //调用了父类中的构造函数
        }
    }
    var son = new Son(1, 2);
    var son1 = new Son(11, 22);
    son.sum();
    son1.sum();

举例2:
// super 关键字调用父类普通函数
class Father {
say() {
return ‘我是爸爸’;
}
}
class Son extends Father {
say() {
// console.log(‘我是儿子’);
console.log(super.say() + ‘的儿子’);
// super.say() 就是调用父类中的普通函数 say()
}
}
var son = new Son();
son.say();
// 继承中的属性或者方法查找原则: 就近原则
// 1. 继承中,如果实例化子类输出一个方法,先看子类有没有这个方法,如果有就先执行子类的
// 2. 继承中,如果子类里面没有,就去查找父类有没有这个方法,如果有,就执行父类的这个方法(就近原则)

注意点:

  1. 在 ES6 中类没有变量提升,所以必须先定义类,才能通过类实例化对象.
  2. 类里面的共有属性和方法一定要加this使用.
  3. 类里面的this指向问题.
  4. constructor 里面的this指向实例对象, 方法里面的this 指向这个方法的调用者

深拷贝与浅拷贝

  1. 浅拷贝只是拷贝一层, 更深层次对象级别的只拷贝引用.

  2. 深拷贝拷贝多层, 每一级别的数据都会拷贝.

  3. Object.assign(target, …sources) es6 新增方法可以浅拷贝
    浅拷贝举例:1.遍历对象 2.Object.assign(target,…sorces)
    // 浅拷贝只是拷贝一层, 更深层次对象级别的只拷贝引用.
    // 深拷贝拷贝多层, 每一级别的数据都会拷贝.
    var obj = {
    id: 1,
    name: ‘andy’,
    msg: {
    age: 18
    }
    };
    var o = {};
    // for (var k in obj) {
    // // k 是属性名 obj[k] 属性值
    // o[k] = obj[k];
    // }
    // console.log(o);
    // o.msg.age = 20;
    // console.log(obj);

    console.log('--------------');
    Object.assign(o, obj);
    console.log(o);
    o.msg.age = 20;
    console.log(obj);
    

深拷贝用递归

防抖和节流

https://www.jianshu.com/p/c8b86b09daf0
防抖,即短时间内大量触发同一事件,只会执行一次函数,实现原理为设置一个定时器,约定在xx毫秒后再触发事件处理,每次触发事件都会重新设置计时器,直到xx毫秒内无第二次操作,防抖常用于搜索框/滚动条的监听事件处理,如果不做防抖,每输入一个字/滚动屏幕,都会触发事件处理,造成性能浪费。

防抖是延迟执行,而节流是间隔执行,函数节流即每隔一段时间就执行一次,实现原理为设置一个定时器,约定xx毫秒后执行事件,如果时间到了,那么执行函数并重置定时器,和防抖的区别在于,防抖每次触发事件都重置定时器,而节流在定时器到时间后再清空定时器

时间戳版:

作用域和作用域链、执行期上下文

DOM常见的操作方式

什么是DOM?
DOM全称是Document Object Model(文档对象模型),是为HTML和XML提供的API。

注意: 引号 Element(s)
1.查找节点
document.getElementById(‘id属性值’); 返回拥有指定id的第一个对象的引用
document/element.getElementsByClassName(‘class属性值’); 返回拥有指定class的对象集合
document/element.getElementsByTagName(‘标签名’); 返回拥有指定标签名的对象集合
document.getElementsByName(‘name属性值’); 返回拥有指定名称的对象集合
document/element.querySelector(‘CSS选择器’); 仅返回第一个匹配的元素
document/element.querySelectorAll(‘CSS选择器’); 返回所有匹配的元素
document.documentElement; 获取页面中的HTML标签
document.body; 获取页面中的BODY标签
document.all[’’]; 获取页面中的所有元素节点的对象集合型
2.创建节点
document.createElement(‘元素名’); 创建新的元素节点
document.createAttribute(‘属性名’); 创建新的属性节点
document.createTextNode(‘文本内容’); 创建新的文本节点
document.createComment(‘注释节点’); 创建新的注释节点
document.createDocumentFragment( ); 创建文档片段节点
3.删除节点
parentNode.removeChild( existingChild );删除已有的子节点,返回值为删除节点
element.removeAttribute(‘属性名’);删除具有指定属性名称的属性,无返回值
element.removeAttributeNode( attrNode );删除指定属性,返回值为删除的属性
4.修改节点
parentNode.replaceChild( newChild, existingChild );用新节点替换父节点中已有的子节点
element.setAttributeNode( attributeName );若原元素已有该节点,此操作能达到修改该属性值的目的
element.setAttribute( attributeName, attributeValue );若原元素已有该节点,此操作能达到修改该属性值的目的
5.插入节点
parent.appendChild( element/txt/comment/fragment );向父节点的最后一个子节点后追加新节点
parent.insertBefore( newChild, existingChild );向父节点的某个特定子节点之前插入新节点
element.setAttributeNode( attributeName );给元素增加属性节点
element.setAttribute( attributeName, attributeValue );给元素增加指定属性,并设定属性值
6.设置样式
ele.style.styleName = styleValue;设置ele元素的CSS样式

还有很多DOM方法:
8.查找节点
parentObj.firstChild;  //如果节点为已知节点的第一个子节点就可以使用这个方法。此方法可以递归进行使用 parentObj.firstChild.firstChild…

parentObj.lastChild;  //获得一个节点的最后一个节点,与firstChild一样也可以进行递归使用 parentObj.lastChild.lastChild…
parentObj.childNodes; //获得节点的所有子节点,然后通过循环和索引找到目标节点
9.获取相邻的节点
curtNode.previousSibling; //获取已知节点的相邻的上一个节点
curtNode.nextSlbling;   // 获取已知节点的下一个节点
10.获取父节点
childNode.parentNode;  //得到已知节点的父节点

Array.sort()方法与实现机制

该排序方法每个浏览器中实现的都不太一样
chrome 目前采用快排(QuickSort)和插入排序(InsertaionSort)
火狐采用归并排序(MergeSort)。
IE使用快排。

使用方法:
sort() 方法用于对数组的元素进行排序,并返回数组。默认排序顺序是根据字符串UniCode码。因为排序是按照字符串UniCode码的顺序进行排序的,所以首先应该把数组元素都转化成字符串(如有必要),以便进行比较。
语法:arrayObject.sort(sortby);
参数sortby 可选,用来规定排序的顺序,但必须是函数。

升序排列:

降序排列

根据某个属性排序

Ajax的请求过程

(1)创建ajax对象
var xhr = new XMLHttpRequest();
(2)打开请求
//请求方法自定,第三个参数通常设为true,异步请求
xhr.open(‘GET’, url, true);
(3)发送请求
//可选,设置请求头,根据需要定,post请求的话要写
//xhr.setRequestHeader(“Content-type”,“application/x-www-form-urlencoded”);
xhr.send(要发送的数据);
(4)接收响应
//服务器响应状态(readyState)改变时都会被执行
xhr.onreadystatechange = function(){
//0 (未初始化)对象已经创建,但还没有调用open()方法
//1 (启动)已经调用open() 方法,但尚未调用send()方法发送请求
//2 (发送)send()方法已调用,请求已经发送完成,但尚未接收到响应
//3 (接收)已经接收到部分响应数据
//4 (完成)已经接收到了全部数据,而且已经可以在客户端使用了
//服务器响应状态(readyState)和响应的HTTP状态(status)同时满足才算成功
if (xhr.readyState4 && xhr.status200){
//通过xhr.responseText,获得服务器返回的内容
console.log(xhr.responseText)
}
}

JS的垃圾回收机制

https://www.cnblogs.com/mayun0504/p/10646620.html
https://zhuanlan.zhihu.com/p/60484579
现在各大浏览器通常用采用的垃圾回收有两种方法:标记清除、引用计数。
JS中最常见的垃圾回收方式是标记清除。

工作原理:是当变量进入环境时,将这个变量标记为“进入环境”。当变量离开环境时,则将其标记为“离开环境”。标记“离开环境”的就回收内存。

工作流程:

  1. 垃圾回收器,在运行的时候会给存储在内存中的所有变量都加上标记。
  2. 去掉环境中的变量以及被环境中的变量引用的变量的标记。
  3. 再被加上标记的会被视为准备删除的变量。
  4. 垃圾回收器完成内存清除工作,销毁那些带标记的值并回收他们所占用的内存空间。

引用计数 方式

工作原理:跟踪记录每个值被引用的次数。

工作流程:

  1. 声明了一个变量并将一个引用类型的值赋值给这个变量,这个引用类型值的引用次数就是1。
  2. 同一个值又被赋值给另一个变量,这个引用类型值的引用次数加1.
  3. 当包含这个引用类型值的变量又被赋值成另一个值了,那么这个引用类型值的引用次数减1.
  4. 当引用次数变成0时,说明没办法访问这个值了。
  5. 当垃圾收集器下一次运行时,它就会释放引用次数是0的值所占的内存。

JS中的String、Array和Math方法

String
1.charAt() 返回指定位置的字符。
var str=“Hello world!”
document.write(str.charAt(1)) //e
2.charCodeAt() 返回字符串中某个具体字符的 Unicode编码。
var str=“Hello world!”
document.write(str.charCodeAt(1)) //101
3.concat() 方法用于连接两个或多个字符串
该方法没有改变原有字符串,但是会返回连接两个或多个字符串新字符串
4.toLowerCase()
5.toUpperCase()
6. indexOf(searchValue, fromindex) 返回某个指定的字符串值在字符串中首次出现的位置。
7. lastIndexOf(search, fromindex) 返回一个指定的字符串值最后出现的位置,在一个字符串中的指定位置从后向前搜索。
8. trim()
9. match(searchvalue/Regexp) 字符串模式匹配只接受一个参数,由字符串或RegExp对象指定的一个正则表达式 ,返回存放结果的数组。
10. search(searchvalue/Regexp) 返回第一个与 regexp 相匹配的子串的起始位置。不执行全局匹配,它将忽略标志 g,总是从字符串的开始进行检索。
11. replace(searchvalue/Regexp,replacement) replacement可以是字符串,可以是函数。
12. split(separator,howmany) 用于把一个字符串分割成字符串数组。
13. parseInt()
Array
(见数组常用API)
concat() 用于连接两个或多个数组。
该方法不会改变现有的数组,而仅仅会返回被连接数组的一个副本。
push() 可接受任意数量参数,添加到数组末尾,返回修改数组的长度。
pop() 从末尾移除最后一项,减少数组长度,返回移除的项
unshift() 可接受任意数量参数,在数组前端添加任意个项,返回数组的长度
shift() 移除数组中的第一个项,数组长度减一,返回移除的项
reverse() 反转数组项的顺序
sort() 按升序排列数组项
slice() 一个或两个参数,返回起始位置和结束位置之间项不包括结束位置项
splice()
删除:两个参数,要删除第一项的位置和要删除的项数
插入:(起始位置,0(要删除的项),要插入的项)
替换:(起始位置,要删除的项数,要插入的项)
该方法始终返回一个数组,该数组中包含从原始数组中删除的项。
位置方法·:
indexOf()
lastIndexOf()
Math
ceil
floor
max
min
pow
round
random

String Array ES6扩展方法:

String扩展方法:
主要新增了模板字符
数组新增方法:Array.from将类数组或迭代对象转换为数组
类数组和数组的相同点:可以通过下标来访问,并且通过.length来获取类数组的元素的个数
类数组和数组的区别:类数组不能使用数组的各种api方法,数组没有问题
Copywithin:
Find()返回匹配的数组元素,没有匹配的返回undefined
findIndex()返回匹配的数组元素下标,没有匹配的就返回-1
fill(value,start,end)填充数据
keys(),values(),entries()返回迭代器,必须通过for of 来遍历返回
includes()检测数组中是否含有某一个值,有返回true,没有返回false
indexOf()检测数组中是否有某一个值,有返回下标,没有返回-1

addEventListener和onClick()的区别

1.onclick事件在同一时间只能指向唯一对象
2.onclick添加多次以后,后边的会覆盖前边的,addEventListener则可以给多个事件添加listener
3.addEventListener对任何DOM都是有效的,而onclick仅限于HTML
4.addEventListener可以控制listener的触发阶段,(捕获/冒泡)。对于多个相同的事件处理器,不会重复触发,不需要手动使用removeEventListener清除

new和Object.create的区别

DOM的location对象

浏览器从输入URL到页面渲染的整个流程(涉及到计算机网络数据传输过程、浏览器解析渲染过程)

见浏览器相关

跨域、同源策略及跨域实现方式和原理

见ajax

浏览器的回流(Reflow)和重绘(Repaints)

见浏览器相关

JavaScript中的arguments

EventLoop事件循环

宏任务与微任务

BOM属性对象方法

函数柯里化及其通用封装

JS的map()和reduce()方法

”和“=”的区别

JavaScript中提供相等运算符与=严格相等运算符,建议是只要变量的数据类型能够确定,一律使用===
==相等运算符
==在判断相等时会进行隐式的类型转换, 其比较遵循一些原则,即先转换类型再比较

  1. 如果有一个操作数是布尔值,则在比较相等性之前先将其转换为数值,即是调用Number()方法
  2. 如果一个操作数是字符串,另一个是数值,在比较相等性之前先将字符串转换为数值,同样调用Number()方法
  3. 如果一个操作数是对象,另一个操作数不是,则调用对象的valueOf()和toString()方法把对象转换成基础类型的值再比较,除Date对象外,会优先尝试使用valueOf()方法,用得到的基本类型按照前面的规则进行比较。
  4. 以及null == undefined,此外任何其他组合,都不相等。

1 == true //true // Number Boolean
2 == true //false
1 == “1” //true // Number String
[] == “” //true // Object String
[] == false // true // Object Boolean
[] == 0 //true // Object Number
[] == {} //false
[] == [] //false
{} == {} //false
null == undefined //true
在使用的时候可能会出现一些问题
0 == “0” //true
0 == [] //true
“0” == [] // false
如果是直接实现了valueOf()与toString()的方法,而不是调用原型链上的Object.prototype.valueOf()与Object.prototype.toString()方法,甚至能够产生异常。
var obj = {valueOf: function(){ return {} }, toString: function(){ return {}}}
console.log(obj == 0) // Uncaught TypeError: Cannot convert object to primitive value

===严格相等运算符
===先判断类型再比较,类型不同直接不相等
1 === true //false
1 === “1” //false
[] === “” //false
null === undefined //false

if

if()也可以看作是一个单独的运算符类别
if(true) console.log(“exec”); //exec
if(false) console.log(“exec”);
if(1) console.log(“exec”); //exec
if(0) console.log(“exec”);
if(-1) console.log(“exec”); //exec
if(“true”) console.log(“exec”); //exec
if(“1”) console.log(“exec”); //exec
if(“0”) console.log(“exec”); //exec
if("") console.log(“exec”);
if(null) console.log(“exec”);
if(undefined) console.log(“exec”);
if(“null”) console.log(“exec”); //exec
if(“undefined”) console.log(“exec”); //exec
if([]) console.log(“exec”); //exec
if({}) console.log(“exec”); //exec
if([0]) console.log(“exec”); //exec
if(NaN) console.log(“exec”);

setTimeout用作倒计时为何会产生误差?

ES6

ES5中只有全局作用域和函数作用域,没有块级作用域,ES6添加了块级作用域

let、const和var的概念与区别

let和var是声明变量的,const是声明常量的且一旦声明必须赋值不能改变
let和const不允许在相同作用域内重复声明
块级作用域——只在当前块内有效
块级作用域存在于const和let, 花括号{}

let和const不存在变量提升:即var先使用后定义会undefined,但是let先使用后定位直接报错

let和const存在暂时性死区(只要块级作用域内存在let命令,它所声明的变量就“绑定”(binding)这个区域,不再受外部的影响。在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”(temporal dead zone,简称 TDZ))

顶层对象中的let 和 const
从es6开始,全局变量(例如:import、class、let、const声明的)将逐步与顶层对象的属性隔离。
即全局定义的let和const不能通过window.obj找到,而var可以

变量提升与暂时性死区

var命令会发生“变量提升”现象,即变量可以在声明之前使用,值为undefined。但是使用ES6语法不会变量提升,未声明先使用立刻报错。
只要块级作用域内存在let命令,它所声明的变量就“绑定”(binding)这个区域,不再受外部的影响。凡是在声明之前就使用这些变量,就会报错。总之,在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”(temporal dead zone,简称 TDZ)。即未声明先使用的就是死区

变量的结构赋值

前后模式匹配:
 let [a,[b,c]]=[1,[2,3]]; // a b c 是变量
前多后少:
 let [a,b]=[1];   // a b 是变量,b表示undefined,只声明了未定义
前少后多:
let [,c]=[45,26,13] // c 是变量13
let […a]=[45,26,13]; // a 是变量,数组的形式 [45,26,13]
 … 拓展运算符  可以将数据类型变为数组
带有默认值:
先解构赋值,如果没有再考虑默认值
对象的解构赋值:
变量和属性必须相同才能进行解构,如果解构失败,就为undefined
let {name,a}={name:“zhang”,age:20};a为undefined
let {foo:b}={foo:“zhang”},b为zhang
对象解构默认值: 默认值跟数组解构的默认值是一样的,解构成功就直接赋值,解构不成功,就是没有值,或者值是 undefined 走默认值;
对象解构的赋值注意点:{}里面不能没有东西,

箭头函数及其this问题

箭头函数:var fn=(形参) => { 函数体 }
箭头函数多的this永远指向它的父作用域,不是调用时的this

箭头函数不能作为构造函数,不能使用new
箭头函数没有arguments,caller,callee,用…arg来代替

箭头函数通过call和apply调用,不会改变this指向,只会传入参数

箭头函数没有原型属性prototype
箭头函数不能作为Generator函数,不能使用yield关键字
箭头函数返回对象时,要加一个小括号({foo:123})
箭头函数在ES6 class中声明的方法为实例方法,不是原型方法

this指向:
非箭头函数this指向:普通函数调用都是指向window,对象函数时:哪个对象调用函数,函数里面的this指向哪个对象
箭头函数this指向:找到父元素的this

Symbol概念及其作用

Symbol是一种提供独一无二的值的数据类型,最大用处是用来定义对象的唯一属性名
Symbol函数前不能使用new命令,否则报错,这只因为Symbol是一个原始类型的值,不是对象。所以不能添加属性,类似于字符串的数据类型。
Symbol函数可以接受一个字符串作为参数,表示对Symbol实例的描述,主要是为了控制台显示容易区分,否则不同的Symbol在控制台输出都是Symbol(),有了参数加上了描述输出容易区分
如果Symbol的参数是一个对象,则会调用对象的toString方法转为字符串,生成一个Symbol值
Symbol函数的参数知识表示对当前Symbol值得描述,相同参数得Symbol函数返回值不相等
Symbol值不能与其他类型得值进行运算否则会报错
Symbol值可以显示转为字符串,String(Sym)
Symbol值可以转为布尔值,但是不能转为数值,Boolean(Sym),但是Number(sym)出错
Sym.description返回Symbol值得描述字符串
作为属性名:let mySymbol = Symbol();
Let a = { [ mySymbol ]: ’ hello ’ } 或者 let a={}; a[mySymbol]=’hello’
或者 Object.defineProperty( a , mySymbol , { value: ‘hello’} )
注意在Symbol值作为对象属性名时,不能使用点运算符,因为点运算符后总是字符串不会读取mySymbol作为标识名所指代得那个值,导致a得属性名实际上时一个字符串而不是Symbol值
Symbol值作为属性名时,该属性是公开属性不是私有属性
属性名的遍历:Object.getOwnPropertySymbols(obj)返回一个数组,对象内部所有Symbol值得属性名
Symbol属性名不会出现在for -in,for – of循环中
Reflect.ownKeys(obj)返回所有类型的属性名,包括常规字符串和Symbol
Symbol.for(str)方法可以搜索有没有以该参数作为名称的Symbol值,有则返回,没有就一个该字符串新建到全局

Set和Map数据结构

Set
类似于数组,但是成员的值都是唯一的,没有重复的值。Set本身就是一个构造函数,用来生成Set数据结构。
Let a = new Set(),或者const a=new Set([1,2,3,4,4,5])但是这样size只有5,因为4重复了
加入Set时数据类型不会发生改变,5和‘5’不同,在Set中两个NaN相同,但是两个{}空对象不相等
属性:
size返回Set实例的成员总数
方法:
add (value)添加某个值,返回Set结构本身
delete(value) 删除某个值,返回一个布尔值,表示删除是否成功
has(value)返回一个布尔值,表示是否为Set的成员
clear()清除所有成员,没有返回值

Array.form(s)将Set对象s转为数组,返回值为数组
遍历操作:
keys 为键名, values为键值, entries为键值对(数组)
forEach 例如: set.forEach((value,key)=>console.log(key+’:’+value))
扩展运算符…内部使用for…of循环,所以可以用于Set结构,[…s]表示将s对象转为数组
两个set并集:[…a,…b]返回的为并集数组
两个set交集:[…a].filter(x=>b.has(x))返回的为a和b 的交集
A相对b的差集:[…a].filter(x=>!b.has(x))返回a相对b的差集
扩展运算符与Array.from: [。。。set].map(val=>val2)等价于Array.from(set,val=>val2)
WeakSet
与Set类似没有重复的值
区别:成员只能是对象,不能是其他类型的值,其次,对象是弱引用,即垃圾回收机制不考虑WeakSet对该对象等待引用,即如果其他对象不再引用该对象,则垃圾回收机制会自动回收该对象所占用的内存,不考虑存在于WeakSet
语法:
接受数组或类数组的对象作为参数,该数组的所有成员都会自动称为WeakSet实例对象的成员
有的方法为:add,delete,has,没有size属性,没有办法遍历它的成员
不能遍历是因为运用了弱引用,成员可能随时消失,遍历机制无法保证成员的存在,
WeakSet的一个用处是存储DOM节点,不用担心这些节点从文档移除时会引发的内存泄漏

Map
Js的对象,本质是键值对的集合(Hash结构)
const map = new Map([ [‘name’,’zhangsan’], [‘title’,’author’] ])
属性:size属性,返回成员总数
方法:
set(key,value) 如果有key,则value更新,否则生成新的该键
get(key) 读取key对应的键值,如果找不到key返回undefined
has(key) 返回一个布尔值,表示某键是否在当前Map对象中
delete(key)删除某个键,返回布尔值表示是否删除成功
clear()清除所有成员,没有返回值
遍历方法:
map.keys()返回键名,map.values()返回键值,map.entries()返回所有成员
将map转为数组,[。。。map],数组中每个元素为数组,第一个为键,第二个为键值
将数组转为map,new Map([[1,2] , [3,4] , [5,4]])
将map转为对象for(let [k,v] of map) obj[k]=v
将对象转为map:new Map(obj)
将Map转为JSON:先准尉对象,然后JSON.stringify(对象)
WeakMap
与Map结构相似,用于生成键值对的集合
与Map区别:首先:直接收对象为键名,不接受其他类型的值作为键名,其次:WeakMap的键名所指向的对象,不计入垃圾回收机制
WeakMap的设计目的:想在某个对象上存放一些数据,但是这会形成对于这个对象的引用,如下:

形成了arr对e1和e2的引用,一旦不需要这两个对象,就必须手动删除这个引用,否则垃圾回收机制不会释放e1和e2占用的内存,如:arr【0】=null,一旦忘记写,就会造成内存泄漏。
WeakMap就是为了解决这个问题,它的键名所引用的对象都是弱引用,即垃圾回收机制不将该引用考虑在内,所以只要所引用的对象的其他引用被清除,垃圾回收机制就会释放该对象所占用的内存。即一旦不需要,WeakMap的键名对象和对应键值会自动消失,不用手动删除引用
WeakMap使用场合:它的键所对应对象可能在将来消失,WeakMap结构有助于防止内存泄漏
WeakMap的弱引用只是键名,键值任然正常引用,如下:
即使外部消除了obj的引用,WeakMap内部的引用依然存在
语法:没有遍历操作,没有size属性,不支持clear。只有四个方法:get,set,has,delete

Proxy

Reflect对象

Promise(手撕Promise A+规范、Promise.all、Promise相关API和方法)

Promise是异步编程的一种解决方案,比传统的回调函数和事件更合理强大。简单来说Promise是一个容器,里面保存着某个未来才会结束的事件(通常为异步操作)的结果。Promise是一个对象,可以获取异步操作的信息。
Promise对象的特点:
1对象状态不受外部影响。Promise对象代表一个异步操作,三种状态(进行中pending,已成功fulfilled,已失败rejected)。只有异步操作的结果可以决定当前的状态,任何操作无法改变。
2一旦状态改变就不会再变,任何时候都可以得到这个结果。Promise对状态的改变室友pending到fulfilled和pending到rejected两种。只要两种情况发生,状态凝固不会再变了。如果改变发生了,你再对Promise对象添加回调函数,也会立即得到这个结果。这和事件event不同,事件特点是错过了它再去监听是得不到结果的
Promise对象可以将异步操作以通古比操作的流程表达出来,避免层层嵌套回调函数
缺点:无法取消Promise,一旦建立就立即执行,无法中途取消;如果不设置回调函数,Promise内部抛出的错误不会反应到外部;当处于pending状态,无法得知目前进展到哪个阶段(刚开始还是即将完成)

两个参数resolve和reject都是函数由js引擎提供不用自己部署
Resolve函数作用:将状态由pending变为fulfilled,再异步操作成功时调用并将异步操作的结果作为参数传递出去
Reject函数作用:将状态由pending变为rejected,再异步操作失败时调用并将报出的错误作为参数传递出去
在Promise实例生成后可以用then方法分别指定成功状态和失败状态的回调函数

两个回调函数作为参数,第一个是状态变为成功时调用,第二个是变成失败时调用,第二个函数是可选参数。
Resolve和reject函数都是可以带参数的,如果resolve(其他promise),那这个成功调用就要等待其他promise的状态改变,如果已经改变则会立即调用
调用resolve和reject不会终结promise的参数函数的执行:如下:

先打印2是因为立即resolved的Promise是在本轮事件循环的末尾执行,总是晚于本轮循环的同步任务
如果Then()返回是一个新的Promise,所有可以使用链式写法,即then方法后再调用另一个then方法
Catch()也可以指定发生错误时的回调函数
Promise内部的错误不会影响到Promise外部的代码
Finally()方法用于指定不管最后对象状态如何都会执行的操作,方法不接受任何参数

Promise.all()
此方法用于将多个Promise实例包装成一个新的Promise实例,参数为一个数组,数组内部都是Promise实例
,参数也可以不是数组但是必须具有Iterator接口,且返回的每个成员都是Promise实例

P的状态判断:
只有p1,p2,p3的状态都是已成功,p状态才变成fulfilled,此时p1,p2,p3的返回值组成一个数组传递给p的回调函数
只要由一个rejected,p状态变成rejected已失败,此时第一个被reject的实例的返回值,会传递给p的回调函数

**如果作为参数的Promise实例,自己定义了catch方法,那么它一旦被rejected,并不会触发Promise.all()的catch方法,如上,会调用then,而不是catch,因为自己的catch方法返回值是一个新的Promise实例,也就是说p2指向的实际上是catch返回的新实例,执行完catch后就会变成resolved
Promise.race()
同样是将多个Promise实例包装成新的Promise实例

只要p1,p2,p3中有一个实例率先改变,p状态就随之改变,率先改变的Promise实例的返回值就传递给p的回调函数
Promise.allSettled()
参数为Promise数组,只有所有的参数实例都返回结果不管状态成功失败,包装实例才会结束
Promise.any()
只要有一个实例变成成功状态,包装实例就变成成功状态,所有都变成失败状态才会变成失败状态
Promise.resolve()——返回Promise对象,状态resolved
参数是Promise实例:不做任何修改
参数是thenable对象即then方法的对象:会将这个对象转为Promise对象,然后立刻执行thenable对象的then方法
参数不是具有then()方法的对象,或根本不是对象:返回一个新的Promise对象,状态为resolved
不带任何参数:直接返回一个resolved状态的Promise对象

SetTimeout在下一轮事件循环开始执行,Promise.resolve在本轮事件循环结束时执行,log时立即执行
Promise.reject()——返回Promise对象,状态为rejected

Iterator和for…of(Iterator遍历器的实现)

遍历器是一种接口,为各种数据结构提供统一的访问机制,

循环语法比较及使用场景(for、forEach、for…in、for…of)

Generator及其异步方面的应用

Generator函数是一个状态机,封装了多个内部状态,执行Generator函数会返回一个遍历器对象,可以依次遍历内部的每一个状态。形式上是一个普通函数,带式两个特征:function关键字与函数名有一个星号,内部使用yieid表达式定义不同的内部状态
调用方式同一般函数一样,但是返回值是指向内部状态的指针对象,也就是遍历器对象
yieId表达式:

async函数

几种异步方式的比较(回调、setTimeout、Promise、Generator、async)

class基本语法及继承

模块加载方案比较(CommonJS和ES6的Module)

ES6模块加载与CommonJS加载的原理

AJAX

跨域

出于浏览器的同源策略限制。同源策略(Sameoriginpolicy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。同源策略会阻止一个域的javascript脚本和另外一个域的内容进行交互。所谓同源(即指在同一个域)就是两个页面具有相同的协议(protocol),主机(host)和端口号(port)

1.请简述XMLHttpRequest、JSONP的适用场景,并针对两种请求形式简述如何检测请求错误

  1. XMLHttpRequest用于浏览器端与服务器端异步请求数据从面实现对页面的无刷新修改,支持GET/POST请求,一般用于非跨域的场景。如果需要使用XMLHttpRequest跨域请求数据,需要通过CORS头支持。 JSONP用于跨域请求数据的场景,只支持GET请求。
  2. XMLHttpRequest异常判断一般通过该对象的readystate和http状态码status来判断,JSONP的异常判断一般是onerror事件和超时timer来判断。
    XMLHttpRequest是实现了客户端与服务器的通信,支持post和get方式,一般用于非跨域的情况下,如果需要跨域,服务器端需要添加CORS头
    readyState是XMLHttpRequest对象的属性,若readyState为4,表示服务器返回了信息,然后用XMLHttpRequest对象的status获取http状态码
    JSONP是一种常用的跨域手段,但只支持js脚本和json格式的数据,利用了

Vue

vuex的应用场景

vuex 一般用于中大型 web 单页应用中对应用的状态进行管理,对于一些组件间关系较为简单的小型应用,使用 vuex 的必要性不是很大。vuex 更多地用于解决跨组件通信以及作为数据中心集中式存储数据。

浏览器相关

请简述浏览器渲染页面的过程

当浏览器获得一个html文件时,会“自上而下”加载,并在加载过程中进行解析渲染
解析:

  1. 浏览器会将HTML解析成一个DOM树,DOM 树的构建过程是一个深度遍历过程:当前节点的所有子节点都构建好后才会去构建当前节点的下一个兄弟节点。
  2. 将CSS解析成 CSS 规则树 。即CSSOM(CSS Object Model)
    (1. 遇到script文件和CSS文件都会另起线程去下载;内嵌的script标签和style标签,会直接执行,分别阻塞DOM树和CSS规则树
  3. 无论内嵌的script脚本、外链的script脚本下载完都会阻塞构建DOM树; CSS文件执行和内嵌的style标签阻塞CSSOM)
  4. 根据DOM树和CSSOM(CSS Object Model)来构造Rendering Tree。注意:Rendering Tree 渲染树并不等同于 DOM 树,因为一些像 Header 或 display:none 的东西就没必要放在渲染树中了。
  5. 有了Render Tree,浏览器已经能知道网页中有哪些节点、各个节点的CSS定义以及他们的从属关系。下一步操作称之为Layout,顾名思义就是计算出每个节点在屏幕中的位置。
  6. 再下一步就是绘制,即遍历render树,并使用UI后端层绘制每个节点。

重点:上述这个过程是逐步完成的,为了更好的用户体验,渲染引擎将会尽可能早的将内容呈现到屏幕上,并不会等到所有的html都解析完成之后再去构建和布局render树。它是解析完一部分内容就显示一部分内容,同时,可能还在通过网络下载其余内容。

重绘和重排

重绘
元素的外观改变出发的浏览器行为,浏览器会根据元素的新属性重新绘制,是元素外观重新展示。重绘不会重新布局。
重排
dom树会重新计算,节点的增删等就会改变dom树,发生重排。条哼元素的一些样式,比如修改窗口的大小,都会出发重排。
重绘不一定重排,重排一定会重绘。


引起重绘的常有属性
color border-style border-radius
visibility text-decoration box-shadow
background background-image background-position background-size background-repeat
outline-width outline-color outline-style outline


引起重排的属性和场景

  1. 增删可见的dom元素
  2. 元素的位置改变
  3. 元素的尺寸改变
  4. 页面渲染初始化
  5. 浏览器窗口大小改变
  6. 设置style属性
  7. 改变文字大小
  8. 激活伪类
  9. 操作class属性
  10. 内容改变
  11. 添加删除样式表

界面优化

计算机网络

1.流量控制和拥塞控制的区别

流量控制往往是指在发送端到接收端之间的点对点通信量的控制。流量控制所做的是抑制发送端发送数据的速率,以便使接收端来得及接收。
拥塞控制必须通信子网能够传送待传送的数据,是一个全局性的问题,涉及网络中所有的主机、路由器以及导致网络传输能力下降的所有因素。

2.计算机网络体系结构

2.网络层功能

 网络互连。源端与接收端处于不同网络时。
 路由选择。为分组通过通信子网选择适当路径,从源主机、目的主机以及路径上的所有路由器。
 拥塞控制。避免某通信线路和路由器负载过重,而其它空闲。
 为上层服务。物理地址、路由信息、拓扑结构对于传输层来说应是不可见的。

3.IP地址表示方式

4.IP地址与硬件地址

 从层次的角度看,
 硬件地址(或物理地址)是数据链路层和物理层使用的地址。
 IP 地址是网络层和以上各层使用的地址,是一种逻辑地址(称 IP 地址是逻辑地址是因为 IP 地址是用软件实现的)。

5.地址解析协议 ARP

 ARP请求分组:包含发送方硬件地址 / 发送方 IP 地址 / 目标方硬件地址(未知时填 0) / 目标方 IP 地址。
 本地广播 ARP 请求(路由器不转发ARP请求)。
 ARP 响应分组:包含发送方硬件地址 / 发送方 IP地址 / 目标方硬件地址 / 目标方 IP 地址。
 ARP 分组封装在物理网络的帧中传输。

6.分组转发算法

(1) 从数据报的首部提取目的主机的 IP 地址 D, 得出目的网络地址为 N。
(2) 若网络 N 与此路由器直接相连,则把数据报直接交付目的主机 D;否则是间接交付,执行(3)。
(3) 若路由表中有目的地址为 D 的特定主机路由,则把数据报传送给路由表中所指明的下一跳路由器;否则,执行(4)。
(4) 若路由表中有到达网络 N 的路由,则把数据报传送给路由表指明的下一跳路由器;否则,执行(5)。
(5) 若路由表中有一个默认路由,则把数据报传送给路由表中所指明的默认路由器;否则,执行(6)。
(6) 报告转发分组出错。

什么是UDP

什么是TCP

7.UDP和TCP的区别

8.TCP拥塞控制算法

拥塞的判断条件:
 重传定时器超时
 现在通信线路的传输质量一般都很好,因传输出差错而丢弃分组的概率是很小的(远小于 1 %)。只要出现了超时,就可以猜想网络可能出现了拥塞。
 收到三个相同(重复)的 ACK
 个别报文段会在网络中丢失,预示可能会出现拥塞(实际未发生拥塞),因此可以尽快采取控制措施,避免拥塞。
慢开始和拥塞避免

快重传和快恢复

9.TCP三次握手四次握手

1)A 的 TCP 向 B 发出连接请求报文段,其首部中的同步位 SYN = 1,并选择序号 seq = x,表明传送数据时的第一个数据字节的序号是 x。
2)B 的 TCP 收到连接请求报文段后,如同意,则发回确认。B 在确认报文段中应使 SYN = 1,使 ACK = 1,其确认号ack = x  1,自己选择的序号 seq = y。
3)A 收到此报文段后向 B 给出确认,其 ACK = 1,确认号 ack = y  1。A 的 TCP 通知上层应用进程,连接已经建立。B 的 TCP 收到主机 A 的确认后,也通知其上层应用进程:TCP 连接已经建立。

为什么A要再发一次确认?
 主要为了防止已失效的链接请求报文段突然又传送到B,因为产生错误。
 A发送给B的连接请求报文丢失而未收到B的确认,重传一次连接请求。收到确认后建立连接。
 异常:A第一次发出的连接请求并未丢失,而是在连接释放后延迟到了B。这就是一个已经失效的报文段。B收到此失效请求,会对A发出确认报文段。如果不采用报文握手,新的连接就建立了。A不理会B的确认,B一直等待。资源浪费了。

A 必须等待 2MSL 的时间
 第一,为了保证 A 发送的最后一个 ACK 报文段能够到达 B。
 第二,防止 “已失效的连接请求报文段”出现在本连接中。A 在发送完最后一个 ACK 报文段后,再经过时间 2MSL,就可以使本连接持续的时间内所产生的所有报文段,都从网络中消失。这样就可以使下一个新的连接中不会出现这种旧的连接请求报文段。

10.从点击URL到页面加载,每个阶段发生什么

1)浏览器分析链接指向页面的URL
2)浏览器向DNS请求解析域名的IP地址
3)域名系统解析出服务器的IP地址
4)浏览器与该服务器建立TCP链接(默认端口号为80)
5)浏览器发出HTTP请求
6)服务器通过HTTP响应把html文件发送给浏览器
7)TCP连接释放
8)浏览器解释html文件,并将Web页显示给用户

11.Http协议栈中各层数据流

客户机发起一次请求的时候:
客户机会将请求封装成http数据包–>封装成Tcp数据包–>封装成Ip数据包—>封装成数据帧—>硬件将帧数据转换成bit流(二进制数据)–>最后通过物理硬件(网卡芯片)发送到指定地点。
服务器硬件首先收到bit流… 然后转换成ip数据包。于是通过ip协议解析Ip数据包,然后又发现里面是tcp数据包,就通过tcp协议解析Tcp数据包,接着发现是http数据包通过http协议再解析http数据包得到数据。

12.Http和Https区别

https://www.runoob.com/w3cnote/http-vs-https.html 菜鸟教程
基本概念
HTTP(HyperText Transfer Protocol:超文本传输协议)是一种应用层协议。 简单来说就是一种发布和接收 HTML 页面的方法,被用于在 Web 浏览器和网站服务器之间传递信息。工作在 TCP 协议 80 端口,用户访问网站 http:// 打头的都是标准 HTTP 服务。HTTP 协议以明文方式发送内容,不提供任何方式的数据加密,如果攻击者截取了Web浏览器和网站服务器之间的传输报文,就可以直接读懂其中的信息,因此,HTTP协议不适合传输一些敏感信息,比如:信用卡号、密码等支付信息。

HTTPS(Hypertext Transfer Protocol Secure:超文本传输安全协议)是一种透过计算机网络进行安全通信的传输协议。HTTPS 经由 HTTP 进行通信,但利用 SSL/TLS 来加密数据包。HTTPS 开发的主要目的,是提供对网站服务器的身份认证,保护交换数据的隐私与完整性。HTTPS 默认工作在 TCP 协议443端口,它的工作流程一般如以下方式:
1、TCP 三次同步握手
2、客户端验证服务器数字证书
3、DH 算法协商对称加密算法的密钥、hash 算法的密钥
4、SSL 安全加密隧道协商完成
5、网页以加密的方式传输,用协商的对称加密算法和密钥加密,保证数据机密性;用协商的hash算法进行数据完整性保护,保证数据不被篡改。

13.HTTP工作过程(事务)

一次HTTP操作称为一个事务,其工作整个过程如下:
1 ) 地址解析,
如用客户端浏览器请求这个页面:http://localhost.com:8080/index.htm
从中分解出协议名、主机名、端口、对象路径等部分,对于我们的这个地址,解析得到的结果如下:
协议名:http
机名:localhost.com
端口:8080
对象路径:/index.htm
在这一步,需要域名系统DNS解析域名localhost.com,得主机的IP地址。
2)封装HTTP请求数据段
把以上部分结合本机自己的信息,封装成一个HTTP请求数据段
3)封装成TCP报文段,建立TCP连接(TCP的三次握手)
在HTTP工作开始之前,客户机(Web浏览器)首先要通过网络与服务器建立连接,该连接是通过TCP来完成的,该协议与IP协议共同构建Internet,即著名的TCP/IP协议族,因此Internet又被称作是TCP/IP网络。HTTP是比TCP更高层次的应用层协议,根据规则,只有低层协议建立之后才能进行更高层协议的连接,因此,首先要建立TCP连接,一般TCP连接的端口号是80。这里是8080端口
4)客户机发送请求命令
建立连接后,客户机发送一个请求给服务器,请求方式的格式为:统一资源标识符(URI:Uniform Resource Identifier)、协议版本号,后边是MIME信息包括请求修饰符、客户机信息和可能的内容。
5)服务器响应
服务器接到请求后,给予相应的响应信息,其格式为一个状态行,包括信息的协议版本号、一个成功或错误的代码,后边是MIME信息包括服务器信息、实体信息和可能的内容。
实体消息是服务器向浏览器发送头信息后,它会发送一个空白行来表示头信息的发送到此结束,接着,它就以Content-Type应答头信息所描述的格式发送用户所请求的实际数据
6)服务器关闭TCP连接
一般情况下,一旦Web服务器向浏览器发送了请求数据,它就要关闭TCP连接,然后如果浏览器或者服务器在其头信息加入了这行代码
Connection:keep-alive
TCP连接在发送后将仍然保持打开状态,于是,浏览器可以继续通过相同的连接发送请求。保持连接节省了为每个请求建立新连接所需的时间,还节约了网络带宽。

14.HTTP1.0和2.0的区别

版本 HTTP1.0 HTTP1.1
连接方面 使用 非持久连接,即在非持久连接下,一个tcp连接只传输一个web对象。每次请求和响应都需要建立一个单独的连接,每次连接只是传输一个对象,严重影响客户机和服务器的性能 默认使用持久连接(然而,HTTP/1.1协议的客户机和服务器可以配置成使用非持久连接)在持久连接下,不必为每个Web对象的传送建立一个新的连接,一个连接中可以传输多个对象。在一个TCP连接上可以传送多个HTTP请求和响应,减少了建立和关闭连接的消耗和延迟。HTTP 1.1的持续连接,也需要增加新的请求头来帮助实现,例如,Connection请求头的值为Keep-Alive时,客户端通知服务器返回本次请求结果后保持连接;Connection请求头的值为close时,客户端通知服务器返回本次请求结果后关闭连接。HTTP 1.1还提供了与身份认证、状态管理和Cache缓存等机制相关的请求头和响应头。并且不允许同时存在两个并行的响应。
缓存方面 主要使用header里的If-Modified-Since,Expires来做为缓存判断的标准 引入了更多的缓存控制策略例如Entity tag,If-Unmodified-Since, If-Match, If-None-Match等更多可供选择的缓存头来控制缓存策略带宽优化及网络连接的使用
状态码 无状态 新增了24个错误状态响应码,如409(Conflict)表示请求的资源与资源的当前状态发生冲突;410(Gone)表示服务器上的某个资源被永久性的删除
宽带优化 存在一些浪费带宽的现象,例如客户端只是需要某个对象一部分,而服务器却将整个对象送过来了,并且不支持断点续传功能 支持只发送header信息(不带任何body信息),如果服务器认为客户端有权限请求服务器,则返回100,否则返回401。客户端如果接收到100,才开始把请求body发送到服务器。这样当服务器返回401的时候,客户端就可以不用发送请求body了,节约了带宽。
Host头 HTTP1.0中认为每台服务器都绑定一个唯一的IP地址,因此,请求消息中的URL并没有传递主机名(hostname)。但随着虚拟主机技术的发展,在一台物理服务器上可以存在多个虚拟主机(Multi-homed Web Servers),并且它们共享一个IP地址。 HTTP1.1的请求消息和响应消息都应支持Host头域,且请求消息中如果没有Host头域会报告一个错误(400 Bad Request)

HTTP1.0和HTTP1.1现存的问题:
  1. HTTP1.x在传输数据时,每次都需要重新建立连接,无疑增加了大量的延迟时间,特别是在移动端更为突出
  2. HTTP1.x在传输数据时,所有传输的内容都是明文,客户端和服务器端都无法验证对方的身份,无法保证数据的安全性
  3. HTTP1.x在使用时,header里携带的内容过大,增加了传输的成本,并且每次请求header基本不怎么变化,尤其在移动端增加用户流量
  4. 虽然HTTP1.x支持了keep-alive,来弥补多次创建连接产生的延迟,但是keepalive使用多了同样会给服务端带来大量的性能压力,并且对于单个文件被不断请求的服务(例如图片存放网站),keep-alive可能会极大的影响性能,因为它在文件被请求之后还保持了不必要的连接很长时间

HTTP2.0特性

  1. 头信息和数据体都是二进制,称为头信息帧和数据帧
  2. 复用TCP连接,在一个连接里,客户端和浏览器都可以同时发送多个请求或回应,且不用按顺序一一对应,避免了“队头堵塞“,此双向的实时通信称为多工(Multiplexing)
  3. 引入头信息压缩机制(header compression),头信息使用gzip或compress压缩后再发送;客户端和服务器同时维护一张头信息表,所有字段都会存入这个表,生成一个索引号,不发送同样字段,只发送索引号,提高速度
  4. HTTP/2 允许服务器未经请求,主动向客户端发送资源,即服务器推送(server push)
    版本 HTTP1.1 HTTP2.0
    多路复用 在HTTP/1.1协议中,浏览器客户端在同一时间针对同一域名的请求有一定数据限制。超过限制数目的请求会被阻塞 HTTP2.0使用了多路复用的技术,做到同一个连接并发处理多个请求,而且并发请求的数量比HTTP1.1大了好几个数量级。而这个强大的功能则是基于“二进制分帧”的特性。
    首部压缩 不支持header数据的压缩 使用HPACK算法对header的数据进行压缩,这样数据体积小了,在网络上传输就会更快
    服务器推送 当我们对支持HTTP2.0的web server请求数据的时候,服务器会顺便把一些客户端需要的资源一起推送到客户端,免得客户端再次创建连接发送请求到服务器端获取。这种方式非常合适加载静态资源

15.HTTPS 的工作原理

1、客户端发起 HTTPS 请求
2、服务端的配置
采用 HTTPS 协议的服务器必须要有一套数字证书,可以自己制作,也可以向组织申请,区别就是自己颁发的证书需要客户端验证通过,才可以继续访问,而使用受信任的公司申请的证书则不会弹出提示页面。
这套证书其实就是一对公钥和私钥,如果对公钥和私钥不太理解,可以想象成一把钥匙和一个锁头,只是全世界只有你一个人有这把钥匙,你可以把锁头给别人,别人可以用这个锁把重要的东西锁起来,然后发给你,因为只有你一个人有这把钥匙,所以只有你才能看到被这把锁锁起来的东西。

3、传送证书
这个证书其实就是公钥,只是包含了很多信息,如证书的颁发机构,过期时间等等。

4、客户端解析证书
这部分工作是有客户端的TLS来完成的,首先会验证公钥是否有效,比如颁发机构,过期时间等等,如果发现异常,则会弹出一个警告框,提示证书存在问题。如果证书没有问题,那么就生成一个随机值,然后用证书对该随机值进行加密,就好像上面说的,把随机值用锁头锁起来,这样除非有钥匙,不然看不到被锁住的内容。

5、传送加密信息
这部分传送的是用证书加密后的随机值,目的就是让服务端得到这个随机值,以后客户端和服务端的通信就可以通过这个随机值来进行加密解密了。

6、服务端解密信息
服务端用私钥解密后,得到了客户端传过来的随机值(私钥),然后把内容通过该值进行对称加密,所谓对称加密就是,将信息和私钥通过某种算法混合在一起,这样除非知道私钥,不然无法获取内容,而正好客户端和服务端都知道这个私钥,所以只要加密算法够彪悍,私钥够复杂,数据就够安全。

7、传输加密后的信息
这部分信息是服务段用私钥加密后的信息,可以在客户端被还原。

8、客户端解密信息
客户端用之前生成的私钥解密服务段传过来的信息,于是获取了解密后的内容,整个过程第三方即使监听到了数据,也束手无策。

16.HTTP请求报文的组成部分

(1)请求行
请求行由请求方法字段、URL字段和HTTP协议版本字段3个字段组成,它们用空格分隔。
HTTP协议的请求方法有GET、POST、HEAD、PUT、DELETE、OPTIONS、 TRACE、CONNECT……
最常用的GET方法和POST方法以及HEAD方法。

GET:当客户端要从服务器中读取文档时,使用GET方法。GET方法 要求服务器将URL定位的资源放在响应报文的数据部分,回送给客户端。使用GET方法时,请求参数和对应的值附加在URL后面,利用一个问号(“?”)代 表URL的结尾与请求参数的开始,传递参数长度受限制(1024字节)。例如,/index.jsp?id=100&op=bind。

POST:当客户端 给服务器提交信息较多时可以使用POST方法。POST方法将请求参数封装在HTTP请求数据中,以名称/值的形式出现,可以传输大量数据,可用来传送文件。

HEAD:类GET方法,不响应页面Body部分,用于检查链接的可访问性及资源是否修改。

HTTP1.1 中的请求方式:
方法 作用
GET 请求获取由 Request-URI 所标识的资源
POST 请求服务器接收在请求中封装的实体,并将其作为由 Request-Line 中的 Request-URI 所标识的资源的一部分
HEAD 请求获取由 Request-URI 所标识的资源的响应消息报头
PUT 请求服务器存储一个资源,并用 Request-URI 作为其标识符
DELETE 请求服务器删除由 Request-URI 所标识的资源
TRACE 请求服务器回送到的请求信息,主要用于测试或诊断
CONNECT 保留将来使用
OPTIONS 请求查询服务器的性能,或者查询与资源相关的选项和需求

2)请求头部
请求头部由“关键字:值对”组成,关键字和值用英文冒号“:”分隔,典型的请求头有:
User-Agent:产生请求的浏览器类型。
Accept:客户端可识别的内容类型列表。
Host:请求的主机名,允许多个域名同处一个IP地址,即虚拟主机。

(3)空行
最后一个请求头之后是一个空行,发送回车符和换行符,通知服务器以下不 再有请求头。
对于一个完整的http请求来说空行是必须的,否则服务器会认为本次请求的数据尚未完全发送到服务器,处于等待状态。

(4) 请求数据
请求数据不在GET方法中使用,而是在POST方法中使用。POST方法适用于需要客户填写表单的场合。与请求数据相关的最常使用的请求 头是Content-Type和Content-Length。

17.Http状态码

HTTP状态码分类
分类 分类描述
1** 信息,服务器收到请求,需要请求者继续执行操作
2** 成功,操作被成功接收并处理
3** 重定向,需要进一步的操作以完成请求
4** 客户端错误,请求包含语法错误或无法完成请求
5** 服务器错误,服务器在处理请求的过程中发生了错误

200 - 请求成功
301 - 资源(网页等)被永久转移到其它URL
304 - 未修改。所请求的资源未修改,服务器返回此状态码时,不会返回任何资源。客户端通常会缓存访问过的资源,通过提供一个头信息指出客户端希望只返回在指定日期之后修改的资源
404 - 请求的资源(网页等)不存在
500 - 内部服务器错误

HTTP状态码列表
状态码 状态码英文名称 中文描述
100 Continue 继续。客户端应继续其请求

101 Switching Protocols 切换协议。服务器根据客户端的请求切换协议。只能切换到更高级的协议,例如,切换到HTTP的新版本协议

200 OK 请求成功。一般用于GET与POST请求
201 Created 已创建。成功请求并创建了新的资源
202 Accepted 已接受。已经接受请求,但未处理完成
203 Non-Authoritative Information 非授权信息。请求成功。但返回的meta信息不在原始的服务器,而是一个副本
204 No Content 无内容。服务器成功处理,但未返回内容。在未更新网页的情况下,可确保浏览器继续显示当前文档
205 Reset Content 重置内容。服务器处理成功,用户终端(例如:浏览器)应重置文档视图。可通过此返回码清除浏览器的表单域
206 Partial Content 部分内容。服务器成功处理了部分GET请求

300 Multiple Choices 多种选择。请求的资源可包括多个位置,相应可返回一个资源特征与地址的列表用于用户终端(例如:浏览器)选择
301 Moved Permanently 永久移动。请求的资源已被永久的移动到新URI,返回信息会包括新的URI,浏览器会自动定向到新URI。今后任何新的请求都应使用新的URI代替
302 Found 临时移动。与301类似。但资源只是临时被移动。客户端应继续使用原有URI
303 See Other 查看其它地址。与301类似。使用GET和POST请求查看
304 Not Modified 未修改。所请求的资源未修改,服务器返回此状态码时,不会返回任何资源。客户端通常会缓存访问过的资源,通过提供一个头信息指出客户端希望只返回在指定日期之后修改的资源
305 Use Proxy 使用代理。所请求的资源必须通过代理访问
306 Unused 已经被废弃的HTTP状态码
307 Temporary Redirect 临时重定向。与302类似。使用GET请求重定向

400 Bad Request 客户端请求的语法错误,服务器无法理解
401 Unauthorized 请求要求用户的身份认证
402 Payment Required 保留,将来使用
403 Forbidden 服务器理解请求客户端的请求,但是拒绝执行此请求
404 Not Found 服务器无法根据客户端的请求找到资源(网页)。通过此代码,网站设计人员可设置"您所请求的资源无法找到"的个性页面
405 Method Not Allowed 客户端请求中的方法被禁止
406 Not Acceptable 服务器无法根据客户端请求的内容特性完成请求
407 Proxy Authentication Required 请求要求代理的身份认证,与401类似,但请求者应当使用代理进行授权
408 Request Time-out 服务器等待客户端发送的请求时间过长,超时
409 Conflict 服务器完成客户端的 PUT 请求时可能返回此代码,服务器处理请求时发生了冲突
410 Gone 客户端请求的资源已经不存在。410不同于404,如果资源以前有现在被永久删除了可使用410代码,网站设计人员可通过301代码指定资源的新位置
411 Length Required 服务器无法处理客户端发送的不带Content-Length的请求信息
412 Precondition Failed 客户端请求信息的先决条件错误
413 Request Entity Too Large 由于请求的实体过大,服务器无法处理,因此拒绝请求。为防止客户端的连续请求,服务器可能会关闭连接。如果只是服务器暂时无法处理,则会包含一个Retry-After的响应信息
414 Request-URI Too Large 请求的URI过长(URI通常为网址),服务器无法处理
415 Unsupported Media Type 服务器无法处理请求附带的媒体格式
416 Requested range not satisfiable 客户端请求的范围无效
417 Expectation Failed 服务器无法满足Expect的请求头信息

500 Internal Server Error 服务器内部错误,无法完成请求
501 Not Implemented 服务器不支持请求的功能,无法完成请求
502 Bad Gateway 作为网关或者代理工作的服务器尝试执行请求时,从远程服务器接收到了一个无效的响应
503 Service Unavailable 由于超载或系统维护,服务器暂时的无法处理客户端的请求。延时的长度可包含在服务器的Retry-After头信息中
504 Gateway Time-out 充当网关或代理的服务器,未及时从远端服务器获取请求
505 HTTP Version not supported 服务器不支持请求的HTTP协议的版本,无法完成处理

非对称加密与对称加密

对称加密: 加密和解密的秘钥使用的是同一个.
非对称加密: 与对称加密算法不同,非对称加密算法需要两个密钥:公开密钥(publickey)和私有密钥(privatekey)。
对称加密算法:
   密钥较短,破译困难,除了数据加密标准(DES),另一个对称密钥加密系统是国际数据加密算法(IDEA),它比DES的加密性好,且对计算机性能要求也没有那么高.
优点:
  算法公开、计算量小、加密速度快、加密效率高
缺点:
  在数据传送前,发送方和接收方必须商定好秘钥,然后 使双方都能保存好秘钥。其次如果一方的秘钥被泄露,那么加密信息也就不安全了。另外,每对用户每次使用对称加密算法时,都需要使用其他人不知道的唯一秘钥,这会使得收、发双方所拥有的钥匙数量巨大,密钥管理成为双方的负担。
常见的对称加密算法有:
  DES、3DES、Blowfish、IDEA、RC4、RC5、RC6 和 AES
非对称加密算法:
  公开密钥与私有密钥是一对,如果用公开密钥对数据进行加密,只有用对应的私有密钥才能解密;如果用私有密钥对数据进行加密,那么只有用对应的公开密钥才能解密。因为加密和解密使用的是两个不同的密钥,所以这种算法叫作非对称加密算法。
非对称加密算法实现机密信息交换的基本过程是:
  甲方生成一对密钥并将其中的一把作为公用密钥向其它方公开;得到该公用密钥的乙方使用该密钥对机密信息进行加密后再发送给甲方;甲方再用自己保存的另一把专用密钥对加密后的信息进行解密。甲方只能用其专用密钥解密由其公用密钥加密后的任何信息。
优点:
  安全
缺点:
  速度较慢
常见的非对称加密算法有:
  RSA、ECC(移动设备用)、Diffie-Hellman、El Gamal、DSA(数字签名用)
Hash算法(摘要算法):
  Hash算法特别的地方在于它是一种单向算法,用户可以通过hash算法对目标信息生成一段特定长度的唯一hash值,却不能通过这个hash值重新获得目标信息。因此Hash算法常用在不可还原的密码存储、信息完整性校验等。
常见的摘要算法有:
   MD2、MD4、MD5、HAVAL、SHA

DNS

CDN

Cdn原理:广泛采用各种缓存服务器,将这些缓存服务器分布到用户访问相对集中的地区或网络中,在用户访问网站时,利用全局负载技术将用户的访问指向距离最近的工作正常的缓存服务器上,由缓存服务器直接响

操作系统

1.什么是进程,什么是线程,有什么区别

进程的定义:
1)进程是程序的一次执行过程
2)进程是一个程序及其数据在处理机上顺序执行时所发生的活动
3)进程是具有独立功能的程序在一个数据集合上运行的过程,它是系统进行资源分配和调度的一个独立单位
总结来说:进程是指一个具有独立功能的程序对某个数据集在处理机上的执行过程和分配资源的基本单位。
• 进程有两大类(系统中同时可有多个进程存在):
– 系统进程:起着资源管理和控制的作用,或者执行操作系统核心代码的进程。
– 用户进程:执行用户程序的进程。
• 系统进程与用户进程的区别:
1、系统进程被分配一个初始的资源集合,这些资源可以为它独占,也能以最高优先权的资格使用。用户进程通过系统服务请求的手段竞争使用系统资源;
2、系统进程可以做直接的I/O操作,而用户进程不能直接做I/O操作。
3、系统进程在核心态(管态)下活动,而用户进程则在用户态(目态)下活动。
进程和程序的区别:
• 进程是动态的,程序是静态的
程序本身可以作为软件资源而长期存在;
进程是程序的一次执行过程,有一定的生命期。
• 进程具有并发特征,而程序没有
进程是一个能够独立运行的单位,是作为资源申请和调度单位存在的,能与其他进程并发执行;
程序不能作为一个独立运行的单位而并发执行。

线程的定义:
引入线程的目的是为了减小程序在并发执行时所付出的时空开销,提高操作系统的并发性能。线程是程序执行的最小单位,是进程中的一个实体,线程自己不拥有系统资源,但它可以与同属一个进程的其他线程共享进程所拥有的全部资源。一个线程可以创建和撤销另一个线程,同一个进程中多个线程之间可以并发执行。
进程与线程的比较
1)线程是独立调度的基本单位,进程是拥有资源的基本单位
2)进程之间可以并发执行,多个线程之间也可以并发执行
3)创建或撤销进程时,系统都要为之分配或回收资源,因此操作系统所付出的开销远大于创建或撤销进程时的开销。类似的,在进行进程切换涉及当前执行进程CPU环境的保存以及新调度到进程CPU环境的设置,而线程切换时只需保存和设置少量寄存器内容,开销小。
4)进程的地址空间之间互相独立,同一进程的各线程间共享进程的资源,某进程内的线程对于其他进程不可见。
5)进程间通信需要进程同步和互斥手段的辅助,以保证数据的一致性,而线程间可以直接读/写进程数据段(全局变量)来进行通信。

2.什么是堆和栈

Stack:

  1. 和堆一样存储在计算机 RAM 中。
  2. 在栈上创建变量的时候会扩展,并且会自动回收。
  3. 相比堆而言在栈上分配要快的多。
  4. 用数据结构中的栈实现。
  5. 存储局部数据,返回地址,用做参数传递。
  6. 当用栈过多时可导致栈溢出(无穷次(大量的)的递归调用,或者大量的内存分配)。
  7. 在栈上的数据可以直接访问(不是非要使用指针访问)。
  8. 如果你在编译之前精确的知道你需要分配数据的大小并且不是太大的时候,可以使用栈。
  9. 当你程序启动时决定栈的容量上限。
    Heap:
  10. 和栈一样存储在计算机RAM。
  11. 在堆上的变量必须要手动释放,不存在作用域的问题。数据可用 delete, delete[] 或者 free 来释放。
  12. 相比在栈上分配内存要慢。
  13. 通过程序按需分配。
  14. 大量的分配和释放可造成内存碎片。
  15. 在 C++ 中,在堆上创建数的据使用指针访问,用 new 或者 malloc 分配内存。
  16. 如果申请的缓冲区过大的话,可能申请失败。
  17. 在运行期间你不知道会需要多大的数据或者你需要分配大量的内存的时候,建议你使用堆。
  18. 可能造成内存泄露。

前端安全

XSS

CSFA

DNS劫持

数据结构与算法

设计模式

Git

  • 1
    点赞
  • 12
    收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:技术工厂 设计师:CSDN官方博客 返回首页
评论 2

打赏作者

to-and-fro

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值