前端面试题总结

文章目录

5.19日

1. 箭头函数和普通函数的区别?

  1. 箭头函数是匿名函数,不能作为构造函数,不能使用new
  2. 箭头函数不能使用arguments,取而代之用rest参数…解决
  3. this的作用域不同,箭头函数会捕获其所在的上下文的this值,作为自己的this值
  4. 箭头函数的this永远指向其上下文的this,没有办改变其指向,
    普通函数的this指向调用它的对象
  5. 箭头函数没有原型属性(prototype)
  6. 箭头函数不能当做Generator函数,不能使用yield关键字

2. css居中的方法

1. 水平居中
  1. 行内元素
    text-align:center;
    看它的父元素是不是块级元素,如果是,则直接给父元素设置 text-align: center;
    如果不是,则先将其父元素设置为块级元素(display:block),
    再给父元素设置 text-align: center;
<style>
    #father {
        width: 500px;
        height: 300px;
        background-color: skyblue;
        text-align: center;
       }
</style>
 
<div id="father">
    <span id="son">我是行内元素</span>
</div>
  1. 块级元素
    宽度是固定的:margin: 0 auto;
<style>
    #father {
        width: 500px;
        height: 300px;
        background-color: skyblue;
    }
 
    #son {
        width: 100px;
        height: 100px;
        background-color: green;
        margin: 0 auto;
    }
</style>
 
<div id="father">
    <div id="son">我是块级元素</div>
</div>
  1. 使用定位
    父元素为相对定位,再设置子元素为绝对定位,
    设置子元素的left:50%,即让子元素的左上角水平居中;
    设置绝对子元素的 margin-left: -元素宽度的一半px; 或者设置transform: translateX(-50%);
<style>
    #father {
        width: 500px;
        height: 300px;
        background-color: skyblue;
        position: relative;
}
 
    #son {
        width: 100px;
        height: 100px;
        background-color: green;
        position: absolute;
        left: 50%;
        margin-left: -50px;
}
</style>
 
<div id="father">
    <div id="son">我是块级元素</div>
</div>
  1. 使用flex布局
    父元素添加属性 display: flex; justify-content: center;

<style>
    #father {
        width: 500px;
        height: 300px;
        background-color: skyblue;
        display: flex;
        justify-content: center;
    }
 
    #son {
        width: 100px;
        height: 100px;
        background-color: green;
    }
</style>
 
<div id="father">
    <div id="son">我是块级元素</div>
2. 垂直居中
  1. 单行行内元素
    单行行内元素的"行高等于盒子的高"即可

<style>
    #father {
        width: 500px;
        height: 300px;
        background-color: skyblue;
    }
 
    #son {
        background-color: green;
        line-height: 300px;
    }
</style>
 
<div id="father">
    <span id="son">我是单行的行内元素</span>
  1. 多行的行内元素
    给父元素设置display:table-cell;vertical-align: middle

<style>
    #father {
        width: 500px;
        height: 300px;
        background-color: skyblue;
        display: table-cell;
        vertical-align:middle;
    }
     #son {
        background-color: green;
    }
</style>
 
<div id="father">
    <span id="son">我是多行的行内元素我是多行的行内元素我是多行的行内元素我是多行的行内元素我是多行的行内元素我是多行的行内元素我是多行的行内元素我是多行的行内元素</span>
  1. 块级元素,定位
    设置父元素为相对定位,再设置子元素为绝对定位,
    设置子元素的top: 50%,即让子元素的左上角垂直居中;
    设置绝对子元素的 margin-top: -元素高度的一半px; 或者设置transform: translateY(-50%);

<style>
    #father {
        width: 500px;
        height: 300px;
        background-color: skyblue;
        position: relative;
}
 
    #son {
        height: 100px;
        background-color: green;
        position: absolute;
        top: 50%;
        margin-top: -50px;
}
</style>
 
<div id="father">
    <div id="son">我是块级元素</div>
</div>
  1. 使用flex布局
    父元素添加属性 display: flex; align-items: center;
<style>
    #father {
        width: 500px;
        height: 300px;
        background-color: skyblue;
        display: flex;
        align-items: center;
    }
 
    #son {
        width: 100px;
        height: 100px;
        background-color: green;
    }
</style>
 
<div id="father">
    <div id="son">我是块级元素</div>
</div>
3. 水平垂直居中
  1. 已知高度和宽度的元素
    A. 设置父元素为相对定位,给子元素设置绝对定位,
    top: 0; right: 0; bottom: 0; left: 0; margin: auto;
<style>
    #father {
        width: 500px;
        height: 300px;
        background-color: skyblue;
        position: relative;
}
 
    #son {
        width: 100px;
        height: 100px;
        background-color: green;
        position: absolute;
        top: 0;
        right: 0;
        bottom: 0;
        left: 0;
        margin: auto;
}
</style>
 
<div id="father">
    <div id="son">我是块级元素</div>
</div>
  1. 设置父元素为相对定位,给子元素设置绝对定位(已知宽度和高度)
    left: 50%; top: 50%; margin-left: --元素宽度的一半px; margin-top: --元素高度的一半px;

<style>
    #father {
        width: 500px;
        height: 300px;
        background-color: skyblue;
        position: relative;
}
 
    #son {
        width: 100px;
        height: 100px;
        background-color: green;
        position: absolute;
        left: 50%;
        top: 50%;
        margin-left: -50px;
        margin-top: -50px;
}
</style>
 
<div id="father">
    <div id="son">我是块级元素</div>
</div>
  1. 未知高度和宽度的元素
    父元素为相对定位,给子元素设置绝对定位,
    left: 50%; top: 50%; transform: translateX(-50%) translateY(-50%);

<style>
    #father {
        width: 500px;
        height: 300px;
        background-color: skyblue;
        position: relative;
}
 
    #son {
        background-color: green;
        position: absolute;
        left: 50%;
        top: 50%;
        transform: translateX(-50%) translateY(-50%);
}
</style>
 
<div id="father">
    <div id="son">我是块级元素</div>
</div>
  1. 使用flex布局
    父元素添加属性 display: flex; justify-content: center; align-items: center;
<style>
    #father {
        width: 500px;
        height: 300px;
        background-color: skyblue;
        display: flex;
        justify-content: center;
        align-items: center;
}
 
    #son {
        background-color: green;
}
</style>
 
<div id="father">
    <div id="son">我是块级元素</div>
</div>

3. css有哪些选择器?选择器的权值大小

内联样式 > ID 选择器 > 类选择器 = 属性选择器 = 伪类选择器 > 标签选择器 = 伪元素选择器

4. css定位

1. 静态定位(static)
 一般的标签元素不加任何定位属性都属于静态定位,在页面的最底层属于标准流。
2. 绝对定位(absolute)
  1. 绝对定位的元素从文档流中脱离,使用left、right、top、bottom等属性相对于其最接近的一个最有定位设置的父级元素进行绝对定位,如果元素的父级没有设置定位属性,则依据 body 元素左上角作为参考进行定位。绝对定位元素可层叠,层叠顺序可通过 z-index 属性控制,z-index值为无单位的整数,大的在上面,可以有负值。
  2. 绝对定位的定位方法:如果它的父元素设置了除static之外的定位,比如position:relative或position:absolute及position:fixed,那么它就会相对于它的父元素来定位,位置通过left , top ,right ,bottom属性来规定,如果它的父元素没有设置定位,那么就得看它父元素的父元素是否有设置定位,如果还是没有就继续向更高层的祖先元素类推,总之它的定位就是相对于设置了除static定位之外的定位的第一个祖先元素,如果所有的祖先元素都没有以上三种定位中的其中一种定位,那么它就会相对于文档body来定位(并非相对于浏览器窗口,相对于窗口定位的是fixed)。
<head>
	<style type="text/css">
		.box {
			background: red;
			width: 100px;
			height: 100px;
			float: left;
			margin: 5px;
		}
		.two {
			position: absolute;
			top: 50px;
			left: 50px;
		}
	</style>
</head>
<body>
	<div class="box" >One</div>
	<div class="box  two" >Two</div>
	<div class="box" >Three</div>
	<div class="box">Four</div>
</body>
  1. 将class="two"的div定位到距离的顶部和左侧分别50px的位置。会改变其他元素的布局,不会在此元素本来位置留下空白
    在这里插入图片描述
3. 相对定位(relative)
  1. 相对定位元素不可层叠,依据left、right、top、bottom等属性在正常文档流中偏移自身位置。同样可以用z-index分层设计。
<head>
	<style type="text/css">
		.box {
			background: red;
			width: 100px;
			height: 100px;
			float: left;
			margin: 5px;
		}
		.two {
			position: relative;
			top: 50px;
			left: 50px;
		}
	</style>
</head>
<body>
	<div class="box" >One</div>
	<div class="box  two" >Two</div>
	<div class="box" >Three</div>
	<div class="box">Four</div>
</body>
  1. 将class="two"的div定位到距离它本来位置的顶部和左侧分别50px的位置。不会改变其他元素的布局,会在此元素本来位置留下空白。
    在这里插入图片描述
4. 固定定位(fixed)
  1. 固定定位与绝对定位类似,但它是相对于浏览器窗口定位,并且不会随着滚动条进行滚动。

  2. 固定定位的最常见的一种用途是在页面中创建一个固定头部、固定脚部或者固定侧边栏,不需使用margin、border、padding。

5.粘性定位(sticky)
  1. position: sticky; 基于用户的滚动位置来定位。
6. 绝对定位和相对定位的区别
  1. 绝对定位好像把不同元素安排到了一栋楼的不同楼层(除首层,文本流放在首层),它们之间互不影响;相对定位元素在首层,与文本流一起存放,它们之间互相影响。

  2. 被设置了绝对定位的元素,在文档流中是不占据空间的,如果某元素设置了绝对定位,那么它在文档流中的位置会被删除,它浮了起来,其实设置了相对定位也会让元素浮起来,但它们的不同点在于,相对定位不会删除它本身在文档流中占据的空间,其他元素不可以占据该空间,而绝对定位则会删除掉该元素在文档流中的位置,使其完全从文档流中抽了出来,其他元素可以占据其空间,可以通过z-index来设置它们的堆叠顺序 。

5.21日

1. http状态码

  1. HTTP 状态码由三个十进制数字组成,第一个十进制数字定义了状态码的类型,后两个数字没有分类的作用。HTTP 状态码共分为以下 5 种类型:
    在这里插入图片描述
1. 2XX 请求成功
  1. 200 OK
    200表示请求在服务器端被正常处理了。在响应报文内,随状态码一起返回的信息会因方法的不同而发生改变。
2. 3XX 重定向
  1. 301 Moved Permanently
    永久重定向,301状态码表示请求的资源已经分配了新的URI,以后请求该资源应该访问新的URI。也就是说,如果已经把资源对应的 URI保存为书签了,这时应该按 Location 首部字段提示的 URI 重新保存。
  2. 302 Found
    临时重定向,302表示请求的资源已经被分配了新的URI,希望客户端本次能使用新的URI访问。和301不同的是,这种资源的URI变更是临时的额,而不是永久的,因此不用去更新书签。
  3. 303 See Other
    该状态码和 302 有着异曲同工之妙,表示由于请求对应的资源存在着另一个 URI,应使用 GET方法定向获取请求的资源。
    如果浏览器原本是用POST方法去请求服务器,收到303状态码之后,会改用GET并访问资源新的URI。
  4. 304 Not Modified
    304 状态码表示客户端发送附带条件的请求时,服务器端允许请求访问资源,但未满足条件的情况。例如,客户端请求的资源在客户端本地已有缓存,会在请求头部中加入“If-Modified-Since", "If-None-Match"等字段,服务端根据这些字段信息判断这些资源信息是否经过修改,如果没有则返回 304 状态码,客户端可以直接使用缓存中的资源。
    304 状态码返回时,不包含任何响应的主体部分。304 虽然被划分在 3XX 类别中,但是和重定向没有关系。
    PS:附带条件的请求是指采用GET方法的请求报文中包含If-Match,If-Modified-Since,If-None-Match,If-Range,If-Unmodified-Since中任一首部。
  5. 307 Temporary Redirect
    临时重定向,和 302 Found 状态码有相同的含义。区别在于 307 不会强制浏览器将 POST 方法改为 GET 方法,而是遵循浏览器自身的标准。
3. 4XX 客户端错误
  1. 400 Bad Request
    400 状态码表示请求报文中存在语法错误。当错误发生时,需修改请求的内容后再次发送请求。另外,浏览器会像 200 OK 一样对待该状态码。
  2. 401 Unauthorized
    401 状态码表示发送的请求需要有通过 HTTP 认证(BASIC 认证、DIGEST 认证)的认证信息。第一次收到 401 状态码表示需要进行用户认证,第二次再收到 401 状态码说明用户认证失败。
  3. 403 Forbidden
    403 状态码表明对请求资源的访问被服务器拒绝了,当未获得文件系统的访问授权,访问权限出现某些问题(从未授权的发送源 IP 地址试图访问)等列举的情况都可能发生 403 。
  4. 404 Not Found
    404 是我们最常见的状态码之一,它表示服务器上无法找到请求资源。此外,也可能是服务器端在拒绝请求且不想说明原因的时候使用。
4. 5XX 服务器错误
  1. 500 Internal Server Error
    500 状态码表明服务器端在执行请求时发生了错误。也有可能是 Web应用存在的 bug 或某些临时的故障。
  2. 502
    服务器暂时不可用,有时是为了防止发生系统过载
  3. 503 Service Unavailable
    503 状态码表明服务器暂时处于超负载或正在进行停机维护,现在无法处理请求。

2. 什么是BFC?

  1. BFC(Block Formatting Context) 块级格式化环境
    BFC是一个CSS中的一个隐含的属性,可以为一个元素开启BFC
    开启BFC该元素会变成一个独立的布局区域

  2. 元素开启BFC后的特点:
    1.开启BFC的元素不会被浮动元素所覆盖
    2.开启BFC的元素子元素和父元素外边距不会重叠
    3.开启BFC的元素可以包含浮动的子元素

  3. 可以通过一些特殊方式来开启元素的BFC:
    1)设置元素的浮动(不推荐)
    2)将元素设置为行内块元素(不推荐)
    3)将元素的overflow设置为一个非visible的值
    常用的方式 为元素设置 overflow:hidden 开启其BFC 以使其可以包含浮动元素

  4. 解决高度塌陷问题
    在浮动布局中,父元素的高度默认是被子元素撑开的,
    当子元素浮动后,其会完全脱离文档流,子元素从文档流中脱离
    将会无法撑起父元素的高度,导致父元素的高度丢失
    父元素高度丢失以后,其下的元素会自动上移,导致页面的布局混乱

5.22日

1. js判断基本数据类型的方法

1. typeof

在这里插入图片描述

  1. 对于基本类型,除 null 以外,均可以返回正确的结果。(string,number,boolean,symbol,undefined,可判断,null返回object)
  2. 对于引用类型,除 function 以外,一律返回 object 类型。(不能判断数组)
  3. 对于 null ,返回 object 类型。
  4. 对于 function 返回 function 类型
2. instanceof
  1. instanceof 是用来判断 A 是否为 B 的实例,表达式为:A instanceof B,如果 A 是 B 的实例,则返回 true,否则返回 false。 在这里需要特别注意的是:instanceof 检测的是原型
    实现原理
    在这里插入图片描述
    注意:如果声明方式不是构造函数声明方式,instanceof失效
    Array.isArray() 方法 。该方法用以确认某个对象本身是否为 Array 类型。
3. constructor
  1. 当一个函数 F被定义时,JS引擎会为F添加 prototype 原型,然后再在 prototype上添加一个 constructor 属性,并让其指向 F 的引用。如下所示:
    在这里插入图片描述
  2. 当执行 var f = new F() 时,F 被当成了构造函数,f 是F的实例对象,此时 F 原型上的 constructor 传递到了 f 上,因此 f.constructor == F
    在这里插入图片描述
  3. 注意: null 和 undefined 是无效的对象,因此是不会有 constructor 存在的,这两种类型的数据需要通过其他方式来判断。
    函数的 constructor 是不稳定的,这个主要体现在自定义对象上,当开发者重写 prototype 后,原有的 constructor 引用会丢失,constructor 会默认为 Object
4. toString()
  1. toString() 是 Object 的原型方法,调用该方法,默认返回当前对象的 [[Class]] 。这是一个内部属性,其格式为 [object Xxx] ,其中 Xxx 就是对象的类型。

对于 Object 对象,直接调用 toString() 就能返回 [object Object] 。而对于其他对象,则需要通过 call / apply 来调用才能返回正确的类型信息。
在这里插入图片描述

6.3日

1.什么是事件委托与冒泡?

1.事件的冒泡
  1. 所谓的冒泡指的就是事件的向上传导,当后代元素上的事件被触发时,其祖先元素的相同事件也会被触发。
2.如何阻止事件的冒泡
  1. 在开发中大部分情况冒泡都是有用的,如果不希望发生事件冒泡,可以通过事件对象来取消冒泡
<div id="box1">
			我是box1
			<span id="s1">我是span</span>
</div>
<script type="text/javascript">
			
			window.onload = function(){
			
				//为s1绑定一个单击响应函数
				var s1 = document.getElementById("s1");
				s1.onclick = function(event){
					event = event || window.event;
					alert("我是span的单击响应函数");
					
					//取消冒泡
					//可以将事件对象的cancelBubble设置为true,即可取消冒泡
					event.cancelBubble = true;
				};
				
				//为box1绑定一个单击响应函数
				var box1 = document.getElementById("box1");
				box1.onclick = function(event){
					event = event || window.event;
					alert("我是div的单击响应函数");
					
					event.cancelBubble = true;
				};
				
				//为body绑定一个单击响应函数
				document.body.onclick = function(){
					alert("我是body的单击响应函数");
				};
				
				
			};
					
</script>         
  1. 可以将事件对象的cancelBubble设置为true,即可取消冒泡
3.事件的委派
  1. 指将事件统一绑定给元素的共同的祖先元素,这样当后代元素上的事件触发时,会一直冒泡到祖先元素,从而通过祖先元素的响应函数来处理事件。事件委派是利用了冒泡,通过委派可以减少事件绑定的次数,提高程序的性能

6.11日

1. 什么是同源策略?

  1. 两个页面地址中的协议、域名和端口号一致,则表示同源。
    在这里插入图片描述

  2. 同源策略的限制:

    1. 存储在浏览器中的数据,如localStroage、Cookie和IndexedDB不能通过脚本跨域访问

    2. 不能通过脚本操作不同域下的DOM

    3. 不能通过ajax请求不同域的数据

2. 如何解决跨域(非同源策略请求)问题?

1. 通过jsonp跨域
  1. JSONP 就是利用 script 标签的跨域能力来发送请求的。
  2. 实现原理
    在这里插入图片描述

6.12号

1. vue的生命周期

在这里插入图片描述

6.18日

1.css过渡和动画

1. transition(过渡)
  1. 过渡(transition)
    通过过渡可以指定一个属性发生变化时的切换方式
    通过过渡可以创建一些非常好的效果,提升用户的体验
  2. transition-property: 指定要执行过渡的属性
    多个属性间使用,隔开
    如果所有属性都需要过渡,则使用all关键字
    大部分属性都支持过渡效果,注意过渡时必须是从一个有效数值向另外一个有效数值进行过渡
  transition-property: height , width; 
  transition-property: all; 
  1. transition-duration: 指定过渡效果的持续时间
    时间单位:s 和 ms 1s = 1000ms
 transition-duration: 100ms, 2s; 
 transition-duration: 2s; 
  1. transition-timing-function: 过渡的时序函数
    指定过渡的执行的方式
    可选值:
    1)ease : 默认值,慢速开始,先加速,再减速
    2)linear :匀速运动
    3)ease-in : 加速运动
    4)ease-out : 减速运动
    5)ease-in-out: 先加速 后减速
    6)cubic-bezier() :来指定时序函数
    https://cubic-bezier.com
    7)steps() 分步执行过渡效果
    可以设置一个第二个值:
    end , 在时间结束时执行过渡(默认值)
    start , 在时间开始时执行过渡
   transition-timing-function: cubic-bezier(.24,.95,.82,-0.88); 
   transition-timing-function: steps(2, start); 
  1. transition-delay: 过渡效果的延迟,等待一段时间后再执行过渡
   transition-delay: 2s;
  1. transition 可以同时设置过渡相关的所有属性,只有一个要求,如果要写延迟,则两个时间中第一个是持续时间,第二个是延迟
   transition:all 2s;
2. animation(动画)
  1. 动画和过渡类似,都是可以实现一些动态的效果,
    不同的是过渡需要在某个属性发生变化时才会触发
    动画可以自动触发动态效果
    设置动画效果,必须先要设置一个关键帧,关键帧设置了动画执行每一个步骤
   @keyframes test {
            /* from表示动画的开始位置 也可以使用 0% */
            from{
                margin-left: 0;
                background-color: orange;
            } 

            /* to动画的结束位置 也可以使用100%*/
            to{
                background-color: red;
                margin-left: 700px;
            }
        }
  1. animation-name: 要对当前元素生效的关键帧的名字
    animation-name: test; 
  1. animation-duration: 动画的执行时间
   animation-duration: 4s;
  1. animation-delay : 动画的延时
   animation-delay: 2s; 
   animation-timing-function: ease-in-out;
  1. animation-iteration-count 动画执行的次数
    可选值:
    次数
    infinite 无限执行
    animation-iteration-count: 1;
  1. animation-direction
    指定动画运行的方向
    可选值:
    normal 默认值 从 from 向 to运行 每次都是这样
    reverse 从 to 向 from 运行 每次都是这样
    alternate 从 from 向 to运行 重复执行动画时反向执行
    alternate-reverse 从 to 向 from运行 重复执行动画时反向执行
   animation-direction: alternate-reverse;
  1. animation-play-state: 设置动画的执行状态
    可选值:
    running 默认值 动画执行
    paused 动画暂停
   animation-play-state: paused;
  1. animation-fill-mode: 动画的填充模式
    可选值:
    none 默认值 动画执行完毕元素回到原来位置
    forwards 动画执行完毕元素会停止在动画结束的位置
    backwards 动画延时等待时,元素就会处于开始位置
    both 结合了forwards 和 backwards
   animation-fill-mode: both;
3. canvas

HTML5 的 canvas 元素使用 JavaScript 在网页上绘制图像。
画布是一个矩形区域,您可以控制其每一像素。
canvas 拥有多种绘制路径、矩形、圆形、字符以及添加图像的方法。

7月13日

1. 输出100以下随机数

  1. 如果要创建一个从x到y的随机数,就可以这样写

    Math.round(Math.random()*(y-x))+x;

    //0-100的随机数
    Math.round(Math.random()*100)

7月14日

1. 前端安全存在那些漏洞?

1. CSRF(Cross-site request forgery)跨站请求伪造
  1. 指攻击者冒充用户发起请求(在用户不知情的情况下),完成一些违背用户意愿的事情。攻击者诱导用户进入第三方网站,在第三方网站中,向被攻击网站发送跨站请求。利用用户在被攻击网站已经获取的注册凭证,绕过后台的用户验证,达到冒充用户对被攻击的网站执行某项操作的目的。
  2. 攻击流程
    1)用户登录a.com,并保留了登录凭证(Cookie)。
    2)攻击者引诱用户访问了b.com。
    3)b.com 向 a.com 发送了一个请求:a.com/act=xx。浏览器会默认携带a.com的Cookie。
    4)a.com接收到请求后,对请求进行验证,并确认是用户的凭证,误以为是用户自己发送的请求。
    5)a.com以用户的名义执行了act=xx。
    6)攻击完成,攻击者在受害者不知情的情况下,冒充受害者,让a.com执行了自己定义的操作。
  3. 防御CSRF攻击
    目前防御 CSRF 攻击主要有三种策略:验证 HTTP Referer 字段;在请求地址中添加 token 并验证;在 HTTP 头中自定义属性并验证。

1)验证 HTTP Referer 字段

根据 HTTP 协议,在 HTTP 头中有一个字段叫 Referer,它记录了该 HTTP 请求的来源地址。在通常情况下,访问一个安全受限页面的请求来自于同一个网站,比如需要访问 http://bank.example/withdraw?account=bob&amount=1000000&for=Mallory,用户必须先登陆 bank.example,然后通过点击页面上的按钮来触发转账事件。这时,该转帐请求的 Referer 值就会是转账按钮所在的页面的 URL,通常是以 bank.example 域名开头的地址。而如果黑客要对银行网站实施 CSRF 攻击,他只能在他自己的网站构造请求,当用户通过黑客的网站发送请求到银行时,该请求的 Referer 是指向黑客自己的网站。因此,要防御 CSRF 攻击,银行网站只需要对于每一个转账请求验证其 Referer 值,如果是以 bank.example 开头的域名,则说明该请求是来自银行网站自己的请求,是合法的。如果 Referer 是其他网站的话,则有可能是黑客的 CSRF 攻击,拒绝该请求。

这种方法的显而易见的好处就是简单易行,网站的普通开发人员不需要操心 CSRF 的漏洞,只需要在最后给所有安全敏感的请求统一增加一个拦截器来检查 Referer 的值就可以。特别是对于当前现有的系统,不需要改变当前系统的任何已有代码和逻辑,没有风险,非常便捷。

然而,这种方法并非万无一失。Referer 的值是由浏览器提供的,虽然 HTTP 协议上有明确的要求,但是每个浏览器对于 Referer 的具体实现可能有差别,并不能保证浏览器自身没有安全漏洞。使用验证 Referer 值的方法,就是把安全性都依赖于第三方(即浏览器)来保障,从理论上来讲,这样并不安全。事实上,对于某些浏览器,比如 IE6 或 FF2,目前已经有一些方法可以篡改 Referer 值。如果 bank.example 网站支持 IE6 浏览器,黑客完全可以把用户浏览器的 Referer 值设为以 bank.example 域名开头的地址,这样就可以通过验证,从而进行 CSRF 攻击。

即便是使用最新的浏览器,黑客无法篡改 Referer 值,这种方法仍然有问题。因为 Referer 值会记录下用户的访问来源,有些用户认为这样会侵犯到他们自己的隐私权,特别是有些组织担心 Referer 值会把组织内网中的某些信息泄露到外网中。因此,用户自己可以设置浏览器使其在发送请求时不再提供 Referer。当他们正常访问银行网站时,网站会因为请求没有 Referer 值而认为是 CSRF 攻击,拒绝合法用户的访问。

2)在请求地址中添加 token 并验证

CSRF 攻击之所以能够成功,是因为黑客可以完全伪造用户的请求,该请求中所有的用户验证信息都是存在于 cookie 中,因此黑客可以在不知道这些验证信息的情况下直接利用用户自己的 cookie 来通过安全验证。要抵御 CSRF,关键在于在请求中放入黑客所不能伪造的信息,并且该信息不存在于 cookie 之中。可以在 HTTP 请求中以参数的形式加入一个随机产生的 token,并在服务器端建立一个拦截器来验证这个 token,如果请求中没有 token 或者 token 内容不正确,则认为可能是 CSRF 攻击而拒绝该请求。

这种方法要比检查 Referer 要安全一些,token 可以在用户登陆后产生并放于 session 之中,然后在每次请求时把 token 从 session 中拿出,与请求中的 token 进行比对,但这种方法的难点在于如何把 token 以参数的形式加入请求。对于 GET 请求,token 将附在请求地址之后,这样 URL 就变成 http://url?csrftoken=tokenvalue。 而对于 POST 请求来说,要在 form 的最后加上 ,这样就把 token 以参数的形式加入请求了。但是,在一个网站中,可以接受请求的地方非常多,要对于每一个请求都加上 token 是很麻烦的,并且很容易漏掉,通常使用的方法就是在每次页面加载时,使用 javascript 遍历整个 dom 树,对于 dom 中所有的 a 和 form 标签后加入 token。这样可以解决大部分的请求,但是对于在页面加载之后动态生成的 html 代码,这种方法就没有作用,还需要程序员在编码时手动添加 token。

该方法还有一个缺点是难以保证 token 本身的安全。特别是在一些论坛之类支持用户自己发表内容的网站,黑客可以在上面发布自己个人网站的地址。由于系统也会在这个地址后面加上 token,黑客可以在自己的网站上得到这个 token,并马上就可以发动 CSRF 攻击。为了避免这一点,系统可以在添加 token 的时候增加一个判断,如果这个链接是链到自己本站的,就在后面添加 token,如果是通向外网则不加。不过,即使这个 csrftoken 不以参数的形式附加在请求之中,黑客的网站也同样可以通过 Referer 来得到这个 token 值以发动 CSRF 攻击。这也是一些用户喜欢手动关闭浏览器 Referer 功能的原因。

3)在 HTTP 头中自定义属性并验证

这种方法也是使用 token 并进行验证,和上一种方法不同的是,这里并不是把 token 以参数的形式置于 HTTP 请求之中,而是把它放到 HTTP 头中自定义的属性里。通过 XMLHttpRequest 这个类,可以一次性给所有该类请求加上 csrftoken 这个 HTTP 头属性,并把 token 值放入其中。这样解决了上种方法在请求中加入 token 的不便,同时,通过 XMLHttpRequest 请求的地址不会被记录到浏览器的地址栏,也不用担心 token 会透过 Referer 泄露到其他网站中去。

然而这种方法的局限性非常大。XMLHttpRequest 请求通常用于 Ajax 方法中对于页面局部的异步刷新,并非所有的请求都适合用这个类来发起,而且通过该类请求得到的页面不能被浏览器所记录下,从而进行前进,后退,刷新,收藏等操作,给用户带来不便。另外,对于没有进行 CSRF 防护的遗留系统来说,要采用这种方法来进行防护,要把所有请求都改为 XMLHttpRequest 请求,这样几乎是要重写整个网站,这代价无疑是不能接受的。

2. XSS(Cross-Site Scripting)跨站脚本攻击
  1. 是一种代码注入攻击。攻击者通过在目标网站上注入恶意脚本,使之在用户的浏览器上运行。利用这些恶意脚本,攻击者可获取用户的敏感信息如 Cookie、SessionID 等,进而危害数据安全。XSS 的本质是:恶意代码未经过滤,与网站正常的代码混在一起;浏览器无法分辨哪些脚本是可信的,导致恶意脚本被执行。

7月30日

1. display,visibility,opacity三个属性有什么区别?

  1. display:none
    该方法会改变页面布局。
    1)元素彻底消失,脱离文档流。
    2)子元素跟随父元素被隐藏,并且无法单独显示。
    3)绑定的事件也无法触发。

  2. opacity: 0
    该方法不会改变页面布局。
    1)将元素的透明度设置为0
    2)子元素opacity: 1 是无效的,元素依旧无法显示。
    3)绑定的的事件仍然可以触发。

  3. visibility:hidden;
    该方法不会改变页面的布局
    1)使元素不可见
    2)子元素设置visibility: visible; 后,子元素会显示,但是父元素不会显示。
    3)绑定的事件不可触发。

8月2日

1.Vue响应式原理

  1. vue响应式指的是:组件的data发生变化,立刻触发试图的更新
  2. 原理:
    1) Vue 采用数据劫持结合发布者-订阅者模式的方式来实现数据的响应式,通过Object.defineProperty来劫持数据的setter,getter,在数据变动时发布消息给订阅者,订阅者收到消息后进行相应的处理。
    2)通过原生js提供的监听数据的API,当数据发生变化的时候,在回调函数中修改dom
    3)核心API:Object.defineProperty
    注:
    1)数据劫持指的是在访问或者修改对象的某个属性时,通过一段代码拦截这个行为,进行额外的操作或者修改返回结果。
    2)Object.defineProperty
    参考: https://www.jianshu.com/p/8fe1382ba135

8月3日

1. HTTP常见的请求头

1)Accept:浏览器可接受的MIME类型。
Accept 头字段用于指出客户端程序(通常是浏览器)能够处理的 MIME (Multipurpose Internet Mail Extensions,多用途互联网邮件扩展)类型。例如,如果浏览器和服务器同时支持 png 类型的图片,则浏览器可以发送包含 image/png 的 Accept 的头字段,服务器检查到 Accept 头中包含 image/png 这种 MIME 类型,可能在网页中的 img 元素中使用 png 类型的文件。MIME 类型有很多种,例如,下面的这些MIME类型都可以作为 Accept 头字段的值。
在这里插入图片描述2)Accept-Charset:浏览器可接受的字符集。
在这里插入图片描述
3)Accept-Encoding:浏览器能够进行解码的数据编码方式,比如gzip。Servlet能够向支持gzip的浏览器返回经gzip编码的HTML页面。许多情形下这可以减少5到10倍的下载时间。在这里插入图片描述4)Accept-Language:浏览器所希望的语言种类,当服务器能够提供一种以上的语言版本时要用到。
5)Authorization:授权信息,通常出现在对服务器发送的WWW-Authenticate头的应答中。
6)Connection:表示是否需要持久连接。如果Servlet看到这里的值为“Keep-Alive”,或者看到请求使用的是HTTP 1.1(HTTP 1.1默认进行持久连接),它就可以利用持久连接的优点,当页面包含多个元素时(例如Applet,图片),显著地减少下载所需要的时间。要实现这一点,Servlet需要在应答中发送一个Content-Length头,最简单的实现方法是:先把内容写入ByteArrayOutputStream,然后在正式写出内容之前计算它的大小。
7)Content-Length:表示请求消息正文的长度。
8)cookie
在这里插入图片描述

9)referer
在这里插入图片描述
10)Host:Host 请求头指明了请求将要发送到的服务器主机名和端口号。Host让虚拟主机托管成为了可能,也就是一个IP上提供多个Web服务。
11)User-Agent:浏览器类型,如果Servlet返回的内容与浏览器类型有关则该值非常有用。
12)Cache-Control
在这里插入图片描述

2. 如何去除字符串中的最后一个字符?

substr,substring,slice

3. 事件的冒泡和事件的捕获

所谓的冒泡指的就是事件的向上传导,当后代元素上的事件被触发时,其祖先元素的相同事件也会被触发。事件的捕获正好相反
取消事件的冒泡
DOM中提供stopPropagation()方法,但IE不支持,使用event对象在事件函数中调用就行。

IE中提供的是,cancelBubble属性,默认为false,当它设置为true时,就是阻止事件冒泡,也是用event对象在事件函数中调用

jQuery中提供了stopPropagation()方法来停止事件冒泡,当需要时,只需用用event对象来调用就行,即event.stopPropagation()
在这里插入图片描述

4. cookie属性

1)name:cookie的名称。
2)value:cookie的值。
3)domain:可以访问此cookie的域名。
非顶级域名,如二级域名或者三级域名,设置的cookie的domain只能为顶级域名或者二级域名或者三级域名本身,不能设置其他二级域名的cookie,否则cookie无法生成。

顶级域名只能设置domain为顶级域名,不能设置为二级域名或者三级域名,否则cookie无法生成。

二级域名能读取设置了domain为顶级域名或者自身的cookie,不能读取其他二级域名domain的cookie。所以要想cookie在多个二级域名中共享,需要设置domain为顶级域名,这样就可以在所有二级域名里面或者到这个cookie的值了。
顶级域名只能获取到domain设置为顶级域名的cookie,其他domain设置为二级域名的无法获取。
4)path:为可以访问此cookie的页面路径。 比如domain是abc.com,path是/test,那么只有/test路径下的页面可以读取此cookie。
5)expires/Max-Age:为此cookie超时时间。若设置其值为一个时间,那么当到达此时间后,此cookie失效。不设置的话默认值是Session,意思是cookie会和session一起失效。当浏览器关闭(不是浏览器标签页,而是整个浏览器) 后,此cookie失效。
6)Size:此cookie大小。
7)http:cookie的httponly属性。若此属性为true,则只有在http请求头中会带有此cookie的信息,而不能通过document.cookie来访问此cookie。
8)secure:设置是否只能通过https来传递此条cookie

5. promise.all有一个reject了,后面的还会执行吗,如何让后面的也执行?

不会,使用Promise.allSettled
Promise.allSettled跟Promise.all类似, 其参数接受一个Promise的数组, 返回一个新的Promise, 唯一的不同在于, 其不会进行短路, 也就是说当Promise全部处理完成后我们可以拿到每个Promise的状态, 而不管其是否处理成功.

6.怎么理解前端的工程化?

1.模块化

模块化就是将一个大文件拆分成相互依赖的小文件,再进行统一的拼装和加载。
1)CommonJS
概念
Node 应用由模块组成,采用 CommonJS 模块规范。每个文件就是一个模块,有自己的作用域。在一个文件里面定义的变量、函数、类,都是私有的,对其他文件不可见。在服务器端,模块的加载是运行时同步加载的;在浏览器端,模块需要提前编译打包处理。
特点
1)所有代码都运行在模块作用域,不会污染全局作用域。
2)模块可以多次加载,但是只会在第一次加载时运行一次,然后运行结果就被缓存了,以后再加载,就直接读取缓存结果。要想让模块再次运行,必须清除缓存。
3)模块加载的顺序,按照其在代码中出现的顺序。
基本语法
暴露模块:module.exports = value或exports.xxx = value
引入模块:require(xxx),如果是第三方模块,xxx为模块名;如果是自定义模块,xxx为模块文件路径
此处我们有个疑问:CommonJS暴露的模块到底是什么? CommonJS规范规定,每个模块内部,module变量代表当前模块。这个变量是一个对象,它的exports属性(即module.exports)是对外的接口。加载某个模块,其实是加载该模块的module.exports属性。
在这里插入图片描述
上面代码通过module.exports输出变量x和函数addX。
在这里插入图片描述
require命令用于加载模块文件。require命令的基本功能是,读入并执行一个JavaScript文件,然后返回该模块的exports对象。如果没有发现指定模块,会报错。
模块的加载机制
CommonJS模块的加载机制是,输入的是被输出的值的拷贝。也就是说,一旦输出一个值,模块内部的变化就影响不到这个值。
2)AMD
CommonJS规范加载模块是同步的,也就是说,只有加载完成,才能执行后面的操作。AMD规范则是非同步加载模块,允许指定回调函数。由于Node.js主要用于服务器编程,模块文件一般都已经存在于本地硬盘,所以加载起来比较快,不用考虑非同步加载的方式,所以CommonJS规范比较适用。但是,如果是浏览器环境,要从服务器端加载模块,这时就必须采用非同步模式,因此浏览器端一般采用AMD规范。此外AMD规范比CommonJS规范在浏览器端实现要来着早。
3)CMD
CMD规范专门用于浏览器端,模块的加载是异步的,模块使用时才会加载执行。CMD规范整合了CommonJS和AMD规范的特点。在 Sea.js 中,所有 JavaScript 模块都遵循 CMD模块定义规范。
4)ES6模块化
ES6 模块的设计思想是尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量。CommonJS 和 AMD 模块,都只能在运行时确定这些东西。比如,CommonJS 模块就是对象,输入时必须查找对象属性。
参考文档:https://juejin.cn/post/6844903744518389768

2.组件化
3.规范化

规范化其实是工程化中很重要的一个部分,项目初期规范制定的好坏会直接影响到后期的开发质量。

目录结构的制定
编码规范
前后端接口规范
文档规范
组件管理
Git分支管理
Commit描述规范
定期CodeReview
视觉图标规范

4.自动化

任何简单机械的重复劳动都应该让机器去完成。
图标合并
持续集成
自动化构建
自动化部署
自动化测试

8月15日

1. 什么是原型和原型链?

1. 原型

(1) 函数的prototype属性

  • 每个函数都有一个prototype属性, 它默认指向一个Object空对象(即称为: 原型对象)
  • 原型对象中有一个属性constructor, 它指向函数对象
    (2) 给原型对象添加属性(一般都是方法)
  • 作用: 函数的所有实例对象自动拥有原型中的属性(方法)
    (3) 隐式原型和显式原型
    1) 每个函数function都有一个prototype,即显式原型
    2)每个实例对象都有一个__proto__,可称为隐式原型
    3) 对象的隐式原型的值为其对应构造函数的显式原型的值
    4.)内存结构
    5)总结:
  • 函数的prototype属性: 在定义函数时自动添加的, 默认值是一个空Object对象
  • 对象的__proto__属性: 创建对象时自动添加的, 默认值为构造函数的prototype属性值
  • 程序员能直接操作显式原型, 但不能直接操作隐式原型(ES6之前)
    在这里插入图片描述
2.原型链

1. 定义
1) 访问一个对象的属性时,
* 先在自身属性中查找,找到返回
* 如果没有, 再沿着__proto__这条链向上查找, 找到返回
* 如果最终没找到, 返回undefined
2)别名: 隐式原型链
3)作用: 查找对象的属性(方法)
2. 原型链属性问题

  1. 读取对象的属性值时: 会自动到原型链中查找
  2. 设置对象的属性值时: 不会查找原型链, 如果当前对象中没有此属性, 直接添加此属性并设置其值
  3. 方法一般定义在原型中, 属性一般通过构造函数定义在对象本身上
    在这里插入图片描述
2 事件循环机制

执行js代码的时候,遇见同步任务,直接推入调用栈中执行,遇到异步任务,将该任务挂起,等到异步任务有返回之后推入到任务队列中,当调用栈中的所有同步任务全部执行完成,将任务队列中的任务按顺序一个一个的推入并执行

3 防抖节流
  1. 防抖
    当持续触发事件时,一定时间段内没有再触发事件,事件处理函数才会执行一次,如果设定时间到来之前,又触发了事件,就重新开始延时。也就是说当一个用户一直触发这个函数,且每次触发函数的间隔小于既定时间,那么防抖的情况下只会执行一次。(例如搜索引擎搜索的时候)
  2. 节流
    当持续触发事件时,保证在一定时间内只调用一次事件处理函数,意思就是说,假设一个用户一直触发这个函数,且每次触发小于既定值,函数节流会每隔这个时间调用一次

8月16日

1. 继承

1. 原型链继承

原理:实现的本质是通过将子类的原型指向了父类的实例,

优点:

  • 父类新增原型方法/原型属性,子类都能访问到
  • 简单容易实现

缺点:

  • 不能实现多重继承
  • 来自原型对象的所有属性被所有实例共享
  • 创建子类实例时,无法向父类构造函数传参
//父类型
function Person(name, age) {
    this.name = name,
    this.age = age,
    this.play = [1, 2, 3]
    this.setName = function () { }
}
Person.prototype.setAge = function () { }
//子类型
function Student(price) {
    this.price = price
    this.setScore = function () { }
}
Student.prototype = new Person('wang',23) // 子类型的原型为父类型的一个实例对象
var s1 = new Student(15000)
var s2 = new Student(14000)
console.log(s1,s2)
2.借用构造函数实现继承

原理:在子类型构造函数中通过用call()调用父类型构造函数

特点

  • 解决了原型链继承中子类实例共享父类引用属性的问题
  • 创建子类实例时,可以向父类传递参数
  • 可以实现多重继承(call多个父类对象)

缺点

  • 实例并不是父类的实例,只是子类的实例
  • 只能继承父类的实例属性和方法,不能继承父类原型属性和方法
  • 无法实现函数复用,每个子类都有父类实例函数的副本,影响性能

2. get和post的区别

GET在浏览器回退时并不会进行操作的,而POST会再次提交请求。
GET请求会被浏览器主动cache,而POST不会,除非手动设置。
GET请求只能进行url编码,而POST支持多种编码方式。
GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留。
GET请求在URL中传送的参数是有长度限制的,而POST没有。
对参数的数据类型,GET只接受ASCII字符,而POST没有限制。
GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息。
GET参数通过URL传递,POST放在Request body中。

3.Tcp/Ip 模型

1. 网络接口层
网络接口把数据链路层和物理层放在一起,对应TCP/IP概念模型的网络接口。对应的网络协议主要是:Ethernet、FDDI和能传输IP数据包的任何协议。
2. 网际层
网络层对应TCP/IP概念模型的网际层,网络层协议管理离散的计算机间的数据传输,如IP协议为用户和远程计算机提供了信息包的传输方法,确保信息包能正确地到达 目的机器。这一过程中,IP和其他网络层的协议共同用于数据传输,如果没有使用一些监视系统进程的工具,用户是看不到在系统里的IP的。网络嗅探器 Sniffers是能看到这些过程的一个装置(它可以是软件,也可以是硬件),它能读取通过网络发送的每一个包,即能读取发生在网络层协议的任何活动,因 此网络嗅探器Sniffers会对安全造成威胁。重要的网络层协议包括ARP(地址解析协议)、ICMP(Internet控制消息协议)和IP协议(网 际协议)等。
3.传输层
传输层对应TCP/IP概念模型的传输层。传输层提供应用程序间的通信。其功能包括:格式化信息流;提供可靠传输。为实现后者,传输层协议规定接收端必须发回确认信 息,如果分组丢失,必须重新发送。传输层包括TCP(Transmission Control Protocol,传输控制协议)和UDP(User Datagram Protocol,用户数据报协议),它们是传输层中最主要的协议。TCP建立在IP之上,定义了网络上程序到程序的数据传输格式和规则,提供了IP数据 包的传输确认、丢失数据包的重新请求、将收到的数据包按照它们的发送次序重新装配的机制。TCP 协议是面向连接的协议,类似于打电话,在开始传输数据之前,必须先建立明确的连接。UDP也建立在IP之上,但它是一种无连接协议,两台计算机之间的传输 类似于传递邮件:消息从一台计算机发送到另一台计算机,两者之间没有明确的连接。UDP不保证数据的传输,也不提供重新排列次序或重新请求的功能,所以说 它是不可靠的。虽然UDP的不可靠性限制了它的应用场合,但它比TCP具有更好的传输效率。
4.应用层
应用层、表示层和会话层对应TCP/IP概念模型中的应用层。应用层位于协议栈的顶端,它的主要任务是应用。一般是可见的,如利用FTP(文件传输协议)传输一个文件,请求一个和目 标计算机的连接,在传输文件的过程中,用户和远程计算机交换的一部分是能看到的。常见的应用层协议有:HTTP,FTP,Telnet,SMTP和 Gopher等。
TCP/IP模型各个层次的功能和协议
在这里插入图片描述
说明:TCP/IP与OSI最大的不同在于OSI是一个理论上的网络通信模型,而TCP/IP则是实际运行的网络协议。

4. OSI七层模型

物理层
数据传输单元:比特
传输介质:例如电缆、光纤、网卡、集线器等等

数据链路层
数据传输单元:帧
采用差错控制法和流量控制法,使有差错的物理线路变成无差错的数据链路
网络层
差错控制:是指在数据通信过程中能发现或纠正差错,将差错限制在尽可能小的允许范围内。
流量控制:对链路上的帧的发送速率的控制,以使接收方有足够的缓冲空间来接收每一帧

网络层(IP)
数据传输单元:分组 / 包
为数据包选择路由

传输层(TCP,UDP)
数据传输单元:报文段
提供可靠的端到端连接及数据传输服务

会话层
维护两个会话主机间连接的建立,管理和终止,及数据的交换

表示层
负责数据格式变换,数据加密解密,数据压缩恢复
把数据转换为合适、可理解的语法和语义

应用层(HTTP,DNS,FTP)
应用程序间的通信

8月17日

1. flex:1(1 1 auto)

第一个参数表示: flex-grow 定义项目的放大比例,默认为0,即如果存在剩余空间,也不放大
第二个参数表示: flex-shrink 定义了项目的缩小比例,默认为1,即如果空间不足,该项目将缩小
第三个参数表示: flex-basis给上面两个属性分配多余空间之前, 计算项目是否有多余空间, 默认值为 auto, 即项目本身的大小

2. Etag优先级为什么高于LastModified?

  1. 一些文件也许会周期性的更改,但是他的内容并不改变(仅仅改变的修改时间),这个时候,我们并不希望客户端认为这个文件被修改了,而重新 get
  2. 某些文件修改非常频繁,比如在秒以下的时间内进行修改(比方说 1s 内修改了 N 次),If-Modified-Since能检查到的粒度时 s 级的,这种修改无法判断(或者说 UNIX 记录 MTIME只能精确到秒)
  3. 某些服务器不能精确得到的文件的最后修改时间

3. TCP是如何保证可靠传输的?

TCP主要提供了检验和、序列号/确认应答、超时重传、最大消息长度、滑动窗口控制等方法实现了可靠性传输。

1. 检验和

通过检验和的方式,接收端可以检测出来数据是否有差错和异常,假如有差错就会直接丢弃TCP段,重新发送。TCP在计算检验和时,会在TCP首部加上一个12字节的伪首部。检验和总共计算3部分:TCP首部、TCP数据、TCP伪首部

2.序列号/确认应答

这个机制类似于问答的形式。比如在课堂上老师会问你“明白了吗?”,假如你没有隔一段时间没有回应或者你说不明白,那么老师就会重新讲一遍。其实计算机的确认应答机制也是一样的,发送端发送信息给接收端,接收端会回应一个包,这个包就是应答包。
在这里插入图片描述
上述过程中,只要发送端有一个包传输,接收端没有回应确认包(ACK包),都会重发。或者接收端的应答包,发送端没有收到也会重发数据。这就可以保证数据的完整性。

3.超时重传

超时重传是指发送出去的数据包到接收到确认包之间的时间,如果超过了这个时间会被认为是丢包了,需要重传。那么我们该如何确认这个时间值呢?

我们知道,一来一回的时间总是差不多的,都会有一个类似于平均值的概念。比如发送一个包到接收端收到这个包一共是0.5s,然后接收端回发一个确认包给发送端也要0.5s,这样的两个时间就是RTT(往返时间)。然后可能由于网络原因的问题,时间会有偏差,称为抖动(方差)。

从上面的介绍来看,超时重传的时间大概是比往返时间+抖动值还要稍大的时间。
在这里插入图片描述
但是在重发的过程中,假如一个包经过多次的重发也没有收到对端的确认包,那么就会认为接收端异常,强制关闭连接。并且通知应用通信异常强行终止。

4. 最大消息长度

在建立TCP连接的时候,双方约定一个最大的长度(MSS)作为发送的单位,重传的时候也是以这个单位来进行重传。理想的情况下是该长度的数据刚好不被网络层分块。
在这里插入图片描述

5. 滑动窗口控制

我们上面提到的超时重传的机制存在效率低下的问题,发送一个包到发送下一个包要经过一段时间才可以。所以我们就想着能不能不用等待确认包就发送下一个数据包呢?这就提出了一个滑动窗口的概念。
在这里插入图片描述
窗口的大小就是在无需等待确认包的情况下,发送端还能发送的最大数据量。这个机制的实现就是使用了大量的缓冲区,通过对多个段进行确认应答的功能。通过下一次的确认包可以判断接收端是否已经接收到了数据,如果已经接收了就从缓冲区里面删除数据。
在窗口之外的数据就是还未发送的和对端已经收到的数据。那么发送端是怎么样判断接收端有没有接收到数据呢?或者怎么知道需要重发的数据有哪些呢?通过下面这个图就知道了。
在这里插入图片描述
如上图,接收端在没有收到自己所期望的序列号数据之前,会对之前的数据进行重复确认。发送端在收到某个应答包之后,又连续3次收到同样的应答包,则数据已经丢失了,需要重发。

6.拥塞控制

窗口控制解决了 两台主机之间因传送速率而可能引起的丢包问题,在一方面保证了TCP数据传送的可靠性。然而如果网络非常拥堵,此时再发送数据就会加重网络负担,那么发送的数据段很可能超过了最大生存时间也没有到达接收方,就会产生丢包问题。为此TCP引入慢启动机制,先发出少量数据,就像探路一样,先摸清当前的网络拥堵状态后,再决定按照多大的速度传送数据。

此处引入一个拥塞窗口:

发送开始时定义拥塞窗口大小为1;每次收到一个ACK应答,拥塞窗口加1;而在每次发送数据时,发送窗口取拥塞窗口与接送段接收窗口最小者。

慢启动:在启动初期以指数增长方式增长;设置一个慢启动的阈值,当以指数增长达到阈值时就停止指数增长,按照线性增长方式增加至拥塞窗口;线性增长达到网络拥塞时立即把拥塞窗口置回1,进行新一轮的“慢启动”,同时新一轮的阈值变为原来的一半。
在这里插入图片描述

4.如何判断一个对象是数组呢?

  1. instanceof
  2. Object.prototype.toString.call()
  3. Array.isArray()
  4. arr.constructor===Array

5.如何遍历一个数组?

1. for
    for(let i = 0;i<arr.length;i++){
        console.log(arr[i])
    }

1、for循环不到数组的私有属性
2、可以使用return|break|continue终止|结束循环
3、for属于编程式写法

2. forEach
    arr.forEach((item)=>{
        console.log(item);
    })

1、forEach循环不到数组的私有属性
2、return|break|continue不起作用
3、forEach属于声明式写法,不关心具体实现

如何终止循环?
使用try…catch来终止循环

let arr = [1, 2, 3]
try {
	arr.forEach(item => {
		if (item === 2) {
			throw('循环终止')
		}
		console.log(item)
	})
} catch(e) {
	console.log('e: ', e)
}

3. for of
   for(let val of arr){
        console.log(val);
    }

1、不可以遍历数组的私有属性的值
2、val的值就是arr项的值
3、可以使用return|break|continue终止|结束循环

4.map
    let arr = [1,2]
      arr.map((item,index)=>{
           console.log(item,index)
      })

返回新数组
不可以终止循环

6. 如何遍历对象?

1. for in

for in 循环是最基础的遍历对象的方式,它还会得到对象原型链上的属性

// 创建一个对象并指定其原型,bar 为原型上的属性
const obj = Object.create({
 bar: 'bar'
})
 
// foo 为对象自身的属性
obj.foo = 'foo'
 
for (let key in obj) {
 console.log(obj[key]) // foo, bar
}

可以看到对象原型上的属性也被循环出来了

在这种情况下可以使用对象的 hasOwnProperty() 方法过滤掉原型链上的属性

for (let key in obj) {
 if (obj.hasOwnProperty(key)) {
  console.log(obj[key]) // foo
 }
2. Object.keys

Object.keys() 是 ES5 新增的一个对象方法,该方法返回对象自身属性名组成的数组,它会自动过滤掉原型链上的属性,然后可以通过数组的 forEach() 方法来遍历

Object.keys(obj).forEach((key) => {
 console.log(obj[key]) // foo
})

另外还有 Object.values() 方法和 Object.entries() 方法,这两方法的作用范围和 Object.keys() 方法类似,因此不再说明

for in 循环和 Object.keys() 方法都不会返回对象的不可枚举属性

如果需要遍历不可枚举的属性,就要用到前面提到的 Object.getOwnPropertyNames() 方法了

3. Object.getOwnPropertyNames

Object.getOwnPropertyNames() 也是 ES5 新增的一个对象方法,该方法返回对象自身属性名组成的数组,包括不可枚举的属性,也可以通过数组的 forEach 方法来遍历

// 创建一个对象并指定其原型,bar 为原型上的属性
// baz 为对象自身的属性并且不可枚举
const obj = Object.create({
 bar: 'bar'
}, {
 baz: {
  value: 'baz',
  enumerable: false
 }
})
 
obj.foo = 'foo'
 
// 不包括不可枚举的 baz 属性
Object.keys(obj).forEach((key) => {
 console.log(obj[key]) // foo
})
 
// 包括不可枚举的 baz 属性
Object.getOwnPropertyNames(obj).forEach((key) => {
 console.log(obj[key]) // baz, foo
})
4. Object.getOwnPropertySymbols

ES2015 新增了 Symbol 数据类型,该类型可以作为对象的键,针对该类型 ES2015 同样新增Object.getOwnPropertySymbols() 方法

Object.getOwnPropertySymbols(obj).forEach((key) => {
 console.log(obj[key])
})

什么都没有,因为该对象还没有 Symbol 属性

// 给对象添加一个不可枚举的 Symbol 属性
Object.defineProperties(obj, {
 [Symbol('baz')]: {
  value: 'Symbol baz',
  enumerable: false
 }
})
 
// 给对象添加一个可枚举的 Symbol 属性
obj[Symbol('foo')] = 'Symbol foo'
 
Object.getOwnPropertySymbols(obj).forEach((key) => {
 console.log(obj[key]) // Symbol baz, Symbol foo
})
5. Reflect.ownKeys

Reflect.ownKeys() 方法是 ES2015 新增的静态方法,该方法返回对象自身所有属性名组成的数组,包括不可枚举的属性和 Symbol 属性

Reflect.ownKeys(obj).forEach((key) => {
 console.log(obj[key]) // baz, foo, Symbol baz, Symbol foo
})

在这里插入图片描述
这其中只有 for in 循环会得到对象原型链上的属性,其它方法都只适用于对象自身的属性

7. 数组中forEach和map的区别

1、返回值
forEach()方法返回undefined ,而map()返回一个包含已转换元素的新数组。


const numbers = [1, 2, 3, 4, 5];
 
// 使用 forEach()
const squareUsingForEach = [];
numbers.forEach(x => squareUsingForEach.push(x*x));
 
// 使用 map()
const squareUsingMap = numbers.map(x => x*x);
 
console.log(squareUsingForEach); // [1, 4, 9, 16, 25]
console.log(squareUsingMap);     // [1, 4, 9, 16, 25]

由于forEach()返回undefined,所以我们需要传递一个空数组来创建一个新的转换后的数组。map()方法不存在这样的问题,它直接返回新的转换后的数组。在这种情况下,建议使用map()方法。

2.链接其他方法
map()方法输出可以与其他方法(如reduce()、sort()、filter())链接在一起,以便在一条语句中执行多个操作。
另一方面,forEach()是一个终端方法,这意味着它不能与其他方法链接,因为它返回undefined。
3. 性能
map()方法比forEach()转换元素要好。
4. 中断
这两种方法都不能用 break 中断,否则会引发异常:
5. 总结
建议使用map()转换数组的元素,因为它语法短,可链接且性能更好。
如果不想返回的数组或不转换数组的元素,则使用forEach() 方法。
最后,如果要基于某种条件停止或中断数组的便利,则应使用简单的for循环或for-of / for-in循环。

8. for in 和 for of的区别

  1. for…in 循环:只能获得对象的键名,不能获得键值

    for…of 循环:允许遍历获得键值

var arr = ['red', 'green', 'blue']
 
for(let item in arr) {
  console.log('for in item', item)
}
/*
  for in item 0
  for in item 1
  for in item 2
*/
 
for(let item of arr) {
  console.log('for of item', item)
}
/*
  for of item red
  for of item green
  for of item blue
*/
  1. for in 遍历对象,会遍历原型链上的属性
    for of 遍历数组
    都可以被中断
    都不可遍历枚举类型(symbol)

9. 检测一个空对象

  1. for in 循环判断
var obj = {};
var b = function() {
    for(var key in obj) {
        return false;
    }
    return true;
}
alert(b());//true
  1. jquery的isEmptyObject方法
    此方法是jquery将(for in)进行封装,使用时需要依赖jquery
var data = {};
var b = $.isEmptyObject(data);
alert(b);//true
  1. Object.getOwnPropertyNames()方法
    此方法是使用Object对象的getOwnPropertyNames方法,获取到对象中的属性名,存到一个数组中,返回数组对象,我们可以通过判断数组的length来判断此对象是否为空
    注意:此方法不兼容ie8,其余浏览器没有测试
var data = {};
var arr = Object.getOwnPropertyNames(data);
alert(arr.length == 0);//true
  1. .使用ES6的Object.keys()方法
    是ES6的新方法, 返回值也是对象中属性名组成的数组
var data = {};
var arr = Object.keys(data);
alert(arr.length == 0);//true

8月19日

1. 三栏布局

1. flex

重点在与 main 中设置 display 为 flex,left 、right 定宽设置为 200px,middle 设置 flex: 1 即可

 <header>Header</header>
	<main>
		<div class="left">Left</div>
		<div class="middle">Middle</div>
		<div class="right">Right</div>
	</main>
    <footer>Footer</footer>
header, footer {
    width: 100%;
	height: 100px;
	background: rgb(251, 84, 48);
}
main {
	display: flex;
	background-color: rgb(109, 110, 106);
}
.left {
	width: 200px;
	height: 400px;
	background-color: rgb(253, 214, 99);
}
.middle {
	flex: 1;
	height: 400px;
	background-color: rgb(78, 187, 252);
}
.right {
	width: 200px;
	height: 400px;
	background-color: rgb(30, 215, 209);
}

[优缺点]
使用 flex 写圣杯布局特别简单,而且缩放到最小也不会变形。

但是 flex 会有有浏览器兼容性问题,可以在网站 https://caniuse.com/?search=flex 查看支持,可以看到,其实大部分浏览器都支持了 flex,重点还是在 IE 上。

2. float 布局一

left、right 使用 float 向左右浮动,脱离文档流。middle 通过 margin-left 和 margin-right 使得内容不被 left 、right 遮挡。

    <header>Header</header>
	<main>
		<div class="left">Left</div>
		<div class="right">Right</div>
		<div class="middle">Middle</div>
	</main>
    <footer>Footer</footer>
html, body {
    margin: 0;
	padding: 0;
	color: #FFF;
	text-align: center;
}
header, footer {
	width: 100%;
	height: 100px;
	background: rgb(251, 84, 48);
}
.left {
	float: left;
	width: 200px;
	height: 400px;
	background-color: rgb(253, 214, 99);
}
.middle {
	margin: 0 200px;
	height: 400px;
	background-color: rgb(78, 187, 252);
}
.right {
	float: right;
	width: 200px;
	height: 400px;
	background-color: rgb(30, 215, 209);
}

[优缺点]
middle 在 html 结构中放在最后,这样有什么影响呢?

  1. 不利于SEO优化,搜索引擎抓取html 的顺序是从上到下,有的搜索引擎对抓取的长度有限制,所以最好把重要的内容放前面;

  2. 读屏软件按照标签顺序进行读屏

  3. 样式按顺序加载,样式加载慢的情况下当然是先加载主要内容的样式更好

3. float 布局二

为了解决上面的问题,以同样的思路进行思考,可以将 middle 放到最上面,这时候 left right 脱离文档流排在 middle 下方,此时我们再利用 position: relative; top: -高度; 将 left right 上移。

    <header>Header</header>
	<main>
		<div class="middle">Middle</div>
		<div class="left">Left</div>
		<div class="right">Right</div>
	</main>
    <footer>Footer</footer>
html, body {
    margin: 0;
	padding: 0;
	color: #FFF;
	text-align: center;
}
header, footer {
	width: 100%;
	height: 100px;
	background: rgb(251, 84, 48);
}
.left, .right {
	position: relative;
	top: -400px;
}
.left {
	float: left;
	width: 200px;
	height: 400px;
	background-color: rgb(253, 214, 99);
}
.middle {
	margin: 0 200px;
	height: 400px;
	background-color: rgb(78, 187, 252);
}
.right {
	float: right;
	width: 200px;
	height: 400px;
	background-color: rgb(30, 215, 209);
}
4. 绝对定位
    <header>Header</header>
	<main>
		<div class="middle">Middle</div>
		<div class="left">Left</div>
		<div class="right">Right</div>
	</main>
    <footer>Footer</footer>
        html, body {
			margin: 0;
			padding: 0;
			color: #FFF;
			text-align: center;
		}
		header, footer {
			width: 100%;
			height: 100px;
			background: rgb(251, 84, 48);
		}
		main {
			position: relative;
		}
		.left, .right {
			position: absolute;
			top: 0;
		}
		.left {
			left: 0;
			width: 200px;
			height: 400px;
			background-color: rgb(253, 214, 99);
		}
		.middle {
			margin: 0 200px;
			height: 400px;
			background-color: rgb(78, 187, 252);
		}
		.right {
			right: 0;
			width: 200px;
			height: 400px;
			background-color: rgb(30, 215, 209);
		}
5. 利用 calc 计算属性

left、middle、right均浮动,中间宽度设置为 100% - 两边宽度和,非常清晰易懂,父容器main清除浮动。

    <header>Header</header>
	<main>
		<div class="left">Left</div>
		<div class="middle">Middle</div>
		<div class="right">Right</div>
	</main>
	<footer>Footer</footer>
        html, body {
			margin: 0;
			padding: 0;
			color: #FFF;
			text-align: center;
		}
		header, footer {
			width: 100%;
			height: 100px;
			background: rgb(251, 84, 48);
		}
		main {
			overflow: hidden;
		}
		.left, .right, .middle {
			float: left;
		}
		.left {
			width: 200px;
			height: 400px;
			background-color: rgb(253, 214, 99);
		}
		.middle {
			width: calc(100% - 400px);
			height: 400px;
			background-color: rgb(78, 187, 252);
		}
		.right {
			width: 200px;
			height: 400px;
			background-color: rgb(30, 215, 209);
		}

注意:calc 计算属性计算符号两边需要有空格,同 flex 布局一样,也存在兼容性问题,可以在上面提到的网站查看

6. Table 布局
    <header>Header</header>
	<main>
		<div class="left">Left</div>
		<div class="middle">Middle</div>
		<div class="right">Right</div>
	</main>
	<footer>Footer</footer>
        html, body {
			margin: 0;
			padding: 0;
			color: #FFF;
			text-align: center;
		}
		header, footer {
			width: 100%;
			height: 100px;
			background: rgb(251, 84, 48);
		}
		main {
			display: table;
			width: 100%;
		}
		.left, .right, .middle {
			display: table-cell;
		}
		.left {
			width: 200px;
			height: 400px;
			background-color: rgb(253, 214, 99);
		}
		.middle {
			height: 400px;
			background-color: rgb(78, 187, 252);
		}
		.right {
			width: 200px;
			height: 400px;
			background-color: rgb(30, 215, 209);
		}

2.前端性能优化

1.加载更快
  • 让传输的数据包更小(压缩文件/图片)
  • 减少网络请求的次数
  • 减少渲染的次数
  • 提前渲染
1.1.1 图片压缩和文件压缩
  • 减小文件的大小
1.1.2 雪碧图/精灵图
  • 雪碧图/精灵图:多张图标合并在一张大图中

  • 使用方法

    ​ 1. 引入图片

    ​ 2. 通过背景定位具体图标

  • 优化的方式

    • 减少加载网页图片时服务器的请求次数

      可以合并多数背景图片和小图标,方便在任何位置使用,这样不同位置的请求只需要调用一个图片,从而减少对服务器的请求次数, 降低服务器压力,同时提高了页面的加载速度,节约服务器的流量。

1.1.3 ssr服务器端渲染
  1. CSR是Client Side Render简称;页面上的内容是我们加载的js文件渲染出来的,

​ js文件运行在浏览器上面,服务端只返回一个html模板。

  1. SSR是Server Side Render简称;页面上的内容是通过服务端渲染生成的,浏览器直接显示服务端返回的html就可以了。(服务端渲染:渲染过程在服务器端完成,最终的渲染结果HTML页面通过HTTP协议发送给客户端。对于客户端而言,只是看到了最终的 HTML 页面,看不到数据,也看不到模板。客户端渲染:服务器端把模板和数据发送给客户端,渲染过程在客户端完成。)

优化方式

​ 减少网络传输:响应快,用户体验好,首屏渲染快

​ 对搜索引擎友好,搜索引擎爬虫可以看到完整的程序源码,有利于SEO.

1.1.4 缓存
  • http缓存:不需要通过服务器传输数据,直接从http缓存中获取

    • 协商缓存
    • 强制缓存
  • 本地缓存:

    • localstorage:把一般不需要变动的大型数据存储在localstorage中,打开页面判断localstorage中是否有该数据,有就直接从浏览器中获取
  • 优化方式:

    • 减少网络传输的次数
2. 渲染更快
1.2.1 css和js文件的位置

1. css写head:

​ css放在body标签尾部时, DOMTree构建完成之后便开始构建RenderTree, 并计算布局渲染网页,

​ 等加载解析完css之后, 开始构建CSSOMTree, 并和DOMTree重新构建RenderTree,

​ 重新计算布局渲染网页

​ css放在head标签中时, 先加载css, 之后解析css构建CSSOMTree, 于此同时构建DOMTree,

​ CSSOMTree和DOMTree都构建完毕之后开始构建RenderTree, 计算布局渲染网页
在这里插入图片描述

2. js写底部
1. JavaScript时会阻止其他内容的下载,要等到JS文件下载解析完之后才会显示网页内容。若JS文件很大放在前面就会导致加载时间较长,网页会一直白屏
2. 因为JS一般会涉及到一些DOM操作,所以要等全部的dom元素都加载完再加载JS。

js文件放在头部如图:
在这里插入图片描述
js文件放在body底部如图:
在这里插入图片描述

1.2.2 懒加载
  • 方法:默认进入页面只展示首屏能够展示的内容,当滚动条拉动到页面底部继续拉动再进行数据加载和渲染
    优化方法:
    • 减少不必要的数据传输和渲染
    • 使页面渲染更快
    • 在这里插入图片描述
1.2.3 对dom查询进行缓存
  • 每次查询dom元素都需要遍历,将查询结果缓存起来

    // 不缓存DOM查询结果
    for (let i = 0; i < document.getElementsByTagName('p').length; i++) {
    // 每次循环,都会计算length,频繁进行DOM查询
    }
    
    // 缓存DOM查询结果
    const pList = document.getElementsByTagName('p')
    const length = pList.length
    for (let i = 0; i < length; i++) {
    // 缓存length,只进行一次DOM查询
    }
    
  • 优化方式:减少相同运算的运算次数

1.2.4 将dom操作合并
  • 多次dom操作合并成一次

  • 优化方式:减少dom渲染的次数

    // 未合并
    const listNode = document.getElementById('list')
    // 执行插入
    for (let i = 0; i < 10; i++) {
      const li = document.createElement('li')
      li.innerHTML = 'list item ' + i
      // 创建一个插入一个
      listNode.appendChild(frag)
    }
    
    // 合并
    const listNode = document.getElementById('list')
    // 创建一个文档片段,此时还没有插入到DOM树中
    const frag = document.createDocumentFragment()
    // 执行插入
    for (let i = 0; i < 10; i++) {
    const li = document.createElement('li')
    li.innerHTML = 'list item ' + i
    frag.appendChild(li)
    }
    // 都完成之后,再插入到DOM树中
    listNode.appendChild(frag)
    

    3. tcp和udp的区别

    在这里插入图片描述
    TCP向上层提供面向连接的可靠服务 ,UDP向上层提供无连接不可靠服务。
    虽然 UDP 并没有 TCP 传输来的准确,但是也能在很多实时性要求高的地方有所作为
    对数据准确性要求高,速度可以相对较慢的,可以选用TCP

4.非对称加密和对称加密

1、加密和解密过程不同

对称加密过程和解密过程使用的同一个密钥,加密过程相当于用原文+密钥可以传输出密文,同时解密过程用密文-密钥可以推导出原文。但非对称加密采用了两个密钥,一般使用公钥进行加密,使用私钥进行解密。

2、加密解密速度不同

对称加密解密的速度比较快,适合数据比较长时的使用。非对称加密和解密花费的时间长、速度相对较慢,只适合对少量数据的使用。

3、传输的安全性不同

对称加密的过程中无法确保密钥被安全传递,密文在传输过程中是可能被第三方截获的,如果密码本也被第三方截获,则传输的密码信息将被第三方破获,安全性相对较低。

非对称加密算法中私钥是基于不同的算法生成不同的随机数,私钥通过一定的加密算法推导出公钥,但私钥到公钥的推导过程是单向的,也就是说公钥无法反推导出私钥。所以安全性较高。

非对称加密和对称加密的区别:

1、加密算法不同

在非对称加密中使用的主要算法有:RSA、Elgamal、背包算法、Rabin、D-H、ECC(椭圆曲线加密算法)等。

在对称加密中使用的主要算法有:DES(Data Encryption Standard)、3DES(Triple DES)、AES(Advanced Encryption Standard)、Blowfish等。

2、加密安全性不同

对称加密的通信双方使用相同的秘钥,如果一方的秘钥遭泄露,那么整个通信就会被破解。

而非对称加密使用一对秘钥,一个用来加密,一个用来解密,而且公钥是公开的,秘钥是自己保存的,不需要像对称加密那样在通信之前要先同步秘钥。非对称加密与,其安全性更好。

3、加密耗时不同

非对称加密使用一对秘钥,一个用来加密,一个用来解密,这样加密和解密花费时间就会更长长。

对称加密中加密方和解密方使用同一个密钥,加密解密的速度比较快,耗时短,适合数据比较长时的使用。

5. HTTPS

1.HTTPS 的实现原理

HTTPS 在内容传输的加密上使用的是对称加密, 非对称加密只作用在证书验证阶段。
HTTPS的整体过程分为证书验证和数据传输阶段 具体的交互过程如下:

① 证书验证阶段:

1)浏览器发起 HTTPS 请求;

2)服务端返回 HTTPS 证书;

3)客户端验证证书是否合法 如果不合法则提示告警。

② 数据传输阶段:

1)当证书验证合法后 在本地生成随机数;

2)通过公钥加密随机数 并把加密后的随机数传输到服务端;

3)服务端通过私钥对随机数进行解密;

4)服务端通过客户端传入的随机数构造对称加密算法 对返回结果内容进行加密后传输。

6. Vue的双向绑定

在这里插入图片描述

6. 闭包打印输出

for (var i = 0; i <5; i++) {
    setTimeout(()=> {
      console.log(i)
    }, i * 1000)
  }
  
for(var i = 0 ;i<5;i++){
   (function(i){
        setTimeout(()=>{
                console.log(i)
        },i*1000)
   }(i))
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值