HTML及CSS
BFC
它是页面中的一块渲染区域,并且有一套渲染规则,可以看作是隔离了的独立容器,容器里面的元素不会在布局上影响到外面的元素。
body 根元素
浮动元素:float 除 none 以外的值
绝对定位元素:position (absolute、fixed)
display 为 inline-block、table-cells、flexo
verflow 除了 visible 以外的值 (hidden、auto、scroll)
- 解决父子元素margin重叠的问题;
- 包含浮动元素;
- 同层元素不和浮动元素重叠。
Doctype作用?严格模式与混杂模式如何区分?它们有何意义?
- Doctype声明于文档最前面,告诉浏览器以何种方式来渲染页面,这里有两种模式,严格模式和混杂模式。
- 严格模式的排版和JS 运作模式是 以该浏览器支持的最高标准运行。
- 混杂模式,向后兼容,模拟老式浏览器,防止浏览器无法兼容页面。
盒模型
// 标准盒模型
// height和width是内容的高度和宽度,不包括padding和border
box-sizing: content-box;
// IE6混杂模式下盒模型
// height和width包括padding和border,可以利用这一特点生成固定宽和高的区域。
box-sizing: border-box;
flex布局
对于父容器定义 display: flex; 父容器可以设置的属性:
- flex-wrap: nowrap; 默认不换行
- flex-direction: row; 默认在一行排列;column 在一列排列
- justify-content: flex-start; 设置弹性盒子在主轴方向上的对齐方式,默认子元素位于容器开头
- center 子元素位于容器的中心
- space-between 子元素 之间 留出空白
- space-around 子元素被空白包围,首尾元素的左边和右边也是空白
- align-items: stretch; 默认值 元素被拉伸以适应容器。
- center 元素位于容器的中心
- flex-start 元素位于容器的开头
- flex-end 元素位于容器的结尾 对于子元素
- order 定义子元素出现的顺序
- flex-grow 子元素放大的比例。默认是0,不放大
- flex-shrink 子元素缩小比例。默认是1,父元素空间不够的时候会缩小
- flex-basis 子元素的大小。默认是 auto, 即元素本身的大小。这里要注意的是子元素设置了权重 max-width > flex-basis > width
- flex; flex是 flex-grow、flex-shrink、 flex-basis的简写
- flex: 1; => flex: 1 1 0%;
- flex: none; => flex: 0 0 auto;
- flex: auto; => flex: 1 1 auto;
link标签和import标签的区别
- link属于html标签,而@import是css提供的
- 页面被加载时,link会同时被加载,而@import引用的css会等到页面加载结束后加载。
- link是html标签,因此没有兼容性,而@import只有IE5以上才能识别。
- link方式样式的权重高于@import的。
js基础
取消冒泡
//兼容写法
function stopPropagation(event){
if(event.stopPropataion){
// w3c 标准事件模型
event.stopPropagation();
}else{
// IE混杂模式事件模型
event.cancelBubble = true;
}
}
Object.defineProperty
Object.defineProperty(obj, 'music', {
value: '七里香', // 1. 定义值
configurable: true, // 2. 可以配置对象,删除属性
writable: true, // 3. 可以修改对象
enumerable: true, // 4. 可以枚举
// ☆ get,set设置时不能设置writable和value,它们代替了二者且是互斥的
get() { // 5. 获取obj.music的时候就会调用get方法
return song;
},
set(val) { // 6. 将修改的值重新赋给song
song = val;
}
});
this指向
- 默认绑定:全局环境中,this默认绑定到window。
- 隐式绑定:一般地,被直接对象所包含的函数调用时,也称为方法调用,this隐式绑定到该直接对象。
- 隐式丢失:隐式丢失是指被隐式绑定的函数丢失绑定对象,从而默认绑定到window。
- 显式绑定:通过call()、apply()、bind()方法把对象绑定到this上,叫做显式绑定。
- new绑定:如果函数或者方法调用之前带有关键字new,它就构成构造函数调用。对于this绑定来说,称为new绑定。
构造函数通常不使用return关键字,它们通常初始化新对象,当构造函数的函数体执行完毕时,它会显式返回。在这种情况下,构造函数调用表达式的计算结果就是这个新对象的值。如果构造函数使用return语句但没有指定返回值,或者返回一个原始值,那么这时将忽略返回值,同时使用这个新对象作为调用结果。如果构造函数显式地使用return语句返回一个对象,那么调用表达式的值就是这个对象。
改变this指向
- apply:调用一个对象的一个方法,用另一个对象替换当前对象。例如:B.apply(A, arguments);即A对象应用B对象的方法。
- call:调用一个对象的一个方法,用另一个对象替换当前对象。例如:B.call(A, args1,args2);即A对象调用B对象的方法。
- bind:除了返回是函数以外,它的参数和call一样。
箭头函数
- 箭头函数没有this,所以需要通过查找作用域链来确定this的值,这就意味着如果箭头函数被非箭头函数包含,this绑定的就是最近一层非箭头函数的this,
- 箭头函数没有自己的arguments对象,但是可以访问外围函数的arguments对象
- 不能通过new关键字调用,同样也没有new.target值和原型
基本数据类型
原始值:Undefined、Null、Boolean、Number、String、Symbol
引用值:Object
typeof的值 string boolan number undefined object function
typeof null === "object"
判断null (value === null)
区分数组还是对象
- arr.constructor
- arr instanceof Array
- Object.prototype.toString.call([])
- Array.isArray()
Symbol
- symbols 是一种无法被重建的基本类型
- symbols 有另一个很重要的用途,就是用作对象的 key
- 我们注意到使用 Object.keys() 并没有返回 symbols,这是为了向后兼容性的考虑
- symbols 可能对对象的私有属性没有直接好处,但是它有另外一个用途,它在不知道对象原有属性名的情况下,扩展对象属性很有用。
类数组变成数组
Array.from(document.querySelectorAll("div"))
Array.prototype.slicec.call(document.querySelectorAll("div"))
[...document.querySelectorAll("div")]
js原型
window.onload 和 DOMContentLoaded 区别
window.addEventListener('load', ()=>{
//页面全部资源加载完才会执行,包括图片、视频等
console.log("load");
})
window.addEventListener('DOMContentLoaded', ()=>{
//DOM 渲染完即可执行,此时图片、视频还可能没有加载完
console.log("DOMContentLoaded")
})
typeof和instanceof
- typeof在对值类型number、string、boolean 、null 、 undefined、 function的反应是精准的
- 对于对象{ } 、数组[ ] 、null 都会返回 object
- 用 instanceof 判断一个实例是否属于某种类型
- instanceof 运算符只能用于对象,不能用于原始类型的值
继承
- 原型链继承,将父类的实例作为子类的原型,他的特点是实例是子类的实例也是父类的实例,父类新增的原型方法/属性,子类都能够访问,并且原型链继承简单易于实现,缺点是来自原型对象的所有属性被所有实例共享,无法实现多继承,无法向父类构造函数传参。
// 借用构造函数(经典继承)
function Parent (name) {
this.name = name;
}
function Child (name) {
Parent.call(this, name);
}
Child.prototype = new Parent();
var child1 = new Child();
child1.names.push('yayu');
console.log(child1.names); // ["kevin", "daisy", "yayu"]
var child2 = new Child();
console.log(child2.names); // ["kevin", "daisy", "yayu"]
// 1.引用类型的属性被所有实例共享
// 2.在创建 Child 的实例时,不能向Parent传参
- 构造继承,使用父类的构造函数来增强子类实例,即复制父类的实例属性给子类,构造继承可以向父类传递参数,可以实现多继承,通过call多个父类对象。但是构造继承只能继承父类的实例属性和方法,不能继承原型属性和方法,无法实现函数服用,每个子类都有父类实例函数的副本,影响性能
// 借用构造函数(经典继承)
function Parent (name) {
this.name = name;
}
function Child (name) {
Parent.call(this, name);
}
var child1 = new Child('kevin');
console.log(child1.name); // kevin
var child2 = new Child('daisy');
console.log(child2.name); // daisy
// 1.避免了引用类型的属性被所有实例共享
// 2.可以在 Child 中向 Parent 传参
// 方法都在构造函数中定义,每次创建实例都会创建一遍方法。
- 实例继承,为父类实例添加新特性,作为子类实例返回,实例继承的特点是不限制调用方法,不管是new 子类()还是子类()返回的对象具有相同的效果,缺点是实例是父类的实例,不是子类的实例,不支持多继承
- 拷贝继承:特点:支持多继承,缺点:效率较低,内存占用高(因为要拷贝父类的属性)无法获取父类不可枚举的方法(不可枚举方法,不能使用for in 访问到)
- 组合继承:通过调用父类构造,继承父类的属性并保留传参的优点,然后通过将父类实例作为子类原型,实现函数复用
// 组合继承
function Parent (name) {
this.name = name;
this.colors = ['red', 'blue', 'green'];
}
Parent.prototype.getName = function () {
console.log(this.name)
}
function Child (name, age) {
Parent.call(this, name);
this.age = age;
}
Child.prototype = new Parent();
Child.prototype.constructor = Child;
var child1 = new Child('kevin', '18');
child1.colors.push('black');
console.log(child1.name); // kevin
console.log(child1.age); // 18
console.log(child1.colors); // ["red", "blue", "green", "black"]
var child2 = new Child('daisy', '20');
console.log(child2.name); // daisy
console.log(child2.age); // 20
console.log(child2.colors); // ["red", "blue", "green"]
- 寄生组合继承:通过寄生方式,砍掉父类的实例属性,这样,在调用两次父类的构造的时候,就不会初始化两次实例方法/属性,避免的组合继承的缺点
// 寄生组合式继承
function object(o) {
function F() {}
F.prototype = o;
return new F();
}
function prototype(child, parent) {
var prototype = object(parent.prototype);
prototype.constructor = child;
child.prototype = prototype;
}
// 当我们使用的时候:
prototype(Child, Parent);
监听对象属性的改变
ES5 中
Object.defineProperty(user,'name',{
set:function(key,value){
// 这也是 Vue 的原理
}
})
ES6 中
// 有新增属性不需要重新添加监听
var user = new Proxy({}, {
set:function(target,key,value,receiver){
}
})
Object.is
- 也不会进行强制类型转换。
- 与===有以下几点不同:
- +0===-0,Object.is(+0, -0)为 false
- NaN !== NaN,Object.is(NaN, NaN)为 true
EventLoop
- 从宏任务的头部取出一个任务执行;
- 执行过程中若遇到微任务则将其添加到微任务的队列中;
- 宏任务执行完毕后,微任务的队列中是否存在任务,若存在,则挨个儿出去执行,直到执行完毕;
- GUI 渲染;
- 回到步骤 1,直到宏任务执行完毕; 宏任务主要有:script(整体代码)、setTimeout、setInterval、I/O、UI 交互事件、postMessage、MessageChannel、setImmediate(Node.js 环境)。
微任务主要有:Promise.then、 MutationObserver、 process.nextTick(Node.js 环境)。
JS加载时间线
- 创建 Document 对象,开始解析 web 页面。解析 HTML 元素和他们的文本内容后添加 Element 对象和 Text 节点到文档中。这个阶段 document.readyState = 'loading'。
- 遇到 link 外部 css,创建线程,进行异步加载,并继续解析文档。
- 遇到 script 外部 js,并且没有设置 async、defer,浏览器同步加载,并阻塞,等待 js 加载完成并执行该脚本,然后继续解析文档。
- 遇到 script 外部 js,并且设置有 async、defer,浏览器创建线程异步加载,并继续解析文档。对于 async 属性的脚本,脚本加载完成后立即执行。(异步禁止使用 document.write(),因为当你整个文档解析到差不多,再调用 document.write(),会把之前所有的文档流都清空,用它里面的文档代替)
- 遇到 img 等(带有 src),先正常解析 dom 结构,然后浏览器异步加载 src,并继续解析档。看到标签直接生产 dom 树,不用等着 img 加载完 scr。
- 当文档解析完成(domTree 建立完毕,不是加载完毕),document.readyState='interactive'。
- 文档解析完成后,所有设置有 defer 的脚本会按照顺序执行。(注意与 async 的不同,但同样禁止使用 document.write());
- document 对象触发 DOMContentLoaded 事件,这也标志着程序执行从同步脚本执行阶段,转化为事件驱动阶段。
- 当所有 async 的脚本加载完成并执行后、img 等加载完成后(页面所有的都执行加载完之后),document.readyState = 'complete',window 对象触发 load 事件。
- 从此,以异步响应方式处理用户输入、网络事件等。
网络及浏览器
GET请求 POST请求 PUT请求
- GET产生一个TCP数据包;
- POST产生两个TCP数据包。
- 对于GET方式的请求,浏览器会把http header和data一并发送出去,服务器响应200(返回数据);
- 而对于POST,浏览器先发送header,服务器响应100 continue,浏览器再发送data,服务器响应200 ok(返回数据)
简单请求,非简单请求
- 使用下列方法之一:
- GET
- POST
- HEAD
- 不得人为设置该集合之外的其他首部字段。该集合为:
- Accept
- Accept-Language
- Content-Language
- Content-Type
- Content-Type 的值仅限于下列三者之一:
- text/plain
- multipart/form-data
- application/x-www-form-urlencoded 不会触发http预检请求的便是简单请求,想法能够触发http预检请求的便是复杂请求。
设置CORS的响应头
- Access-Control-Allow-Origin
- Access-Control-Allow-Headers
- Access-Control-Allow-Methods
- Access-Control-Max-Age 设置cors缓存时间
进程与线程
进程是资源分配的最小单位,线程是CPU调度的最小单位
进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动
线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位
TCP和UDP区别
- UDP
- 无连接
- 向报文,只是报文的搬运工
- 不可靠,没有拥塞控制
- 高效,头部开销只有4字节
- 支持一对一、一对多、多对多、多对一
- 适合直播、视频、语音、会议等实时性要求高的
- TCP
- 面向连接:传输前需要先连接
- 可靠的传输
- 流量控制:发送方不会发送速度过快,超过接收方的处理能力
- 拥塞控制:当网络负载过多时能限制发送方的发送速率
- 不提供时延保障
- 不提供最小带宽保障
- 头部开销20字节
TCP网络模型
- 应 表 会 传 网 数 物
- 应用层 http https ftp nfs 提供网络服务
- 表示层 数据格式化,加密。解密
- 会话层 dns 建立、维护,管理会话链接
- 传输层 tcp udp 建立、维护、管理端到端链接
- 网络层 ip icom arp ip寻址和路由选择
- 数据链路层 fddi 控制网络层与物理层的通信
- 物理层 比特流传输
http1.0 http1.1 http2.0
- HTTP1.0和HTTP 1.1的区别
- HTTP 1.0需要使用keep-alive参数来告知服务器端要建立一个长连接,而HTTP1.1默认支持长连接。
- HTTP 1.1支持只发送header信息
-
- 增加Host头域
- HTTP1.1和HTTP 2.0的区别
- 二进制分帧:能够突破1.x的性能限制
- 多路复用:http1.1中,同一时间,同一域名下的请求数量会有一定限制,超过限制的请求会被阻塞,这也是有些网站会多个静态资源的CDN域名的原因
- 头部压缩
- 服务端推送
- nginx 增加配置 listen 443 ssl http2
三次握手
- 第一次握手 : 客户端打算建立连接时,向服务器发出连接请求报文段,此时首部中的同步位 SYN = 1 ,同时选择一个初始需要 seq = x 。 TCP 规定,SYN = 1 的报文段 不能携带数据,但要消耗掉一个序号。这时,TCP 客户进程进入 SYN-SENT (同步已发送)状态。
- 第二次握手:服务器收到连接请求报文段后,如果同意建立连接,则向客户端发送确认。在确认报文段中应把 SYN 位 和 ACK 位 都置 1 ,确认号是 ack = x + 1,同时也为自己选择一个初始序号 seq = y。(这个报文段也不能携带数据,但同样要消耗掉一个序号。)这时 TCP 服务器进程进入 SYN-RCVD (同步收到) 状态。
- 第三次握手:客户端收到服务器的确认后,还要向服务器给出确认。确认报文段的 ACK 置为 1 ,确认号 ack = y + 1,而自己的序号 seq = x + 1 。这时, TCP 连接已经建立,客户端进入 ESTABLISHED (已建立连接) 状态。当 服务器 收到 客户端 的确认后,也进入 ESTABLISHED (已建立连接) 状态。
- 建立连接时,客户端发送SYN包到服务器,等待服务器响应。(SYN 同步序列编号,是建立连接时使用的握手信号)。
- 服务器收到SYN包,使用ACK包进行确认应答,同时自己也会发送一个SYN包,即发送SYN+ACK包。
- 客户端收到服务器的SYN包,向服务器发送确认包ACK。此包发送完毕,代表TCP连接完成,完成了三次握手。
为什么建立连接要三次握手,为什么不是2次,4次
三次是最小的安全次数,可以保证通信的双方都具有发送消息和接收响应的能力,发送方和接收方始终同步序号,可以实现可靠传输。
Https
- 客户端发起请求,服务端响应给用户端证书,证书中包含公钥;
- 客户端接收到证书后,生成随机数,通过公钥加密,将随机数发送给服务端,并凭随机数构造对称加密和服务端通信,并告知服务端此次通信后的通信都将使用随机数秘钥(Pre-master secret)进行加密;
- 服务端使用私钥解析随机数,并通过随机数构造对称加密算法,同样告知客户端之后的请求将使用随机数进行加密。
- 第一步,爱丽丝给出协议版本号、一个客户端生成的随机数(Client random),以及客户端支持的加密方法。
- 第二步,鲍勃确认双方使用的加密方法,并给出数字证书、以及一个服务器生成的随机数(Server random)。
- 第三步,爱丽丝确认数字证书有效,然后生成一个新的随机数(Premaster secret),并使用数字证书中的公钥,加密这个随机数,发给鲍勃。
- 第四步,鲍勃使用自己的私钥,获取爱丽丝发来的随机数(即Premaster secret)。
- 第五步,爱丽丝和鲍勃根据约定的加密方法,使用前面的三个随机数,生成"对话密钥"(session key),用来加密接下来的整个对话过程。
协商缓存和强缓存
强缓存
- expires: http1.0的产物;根据一个绝对时间来确定是否要利用缓存;
- cache-control: http1.1的产物,根据一个相对时间来确定是否利用缓存。
- Cache-Control:max-age=3600 协商缓存
- Last-Modified/If-modified-since:
- Etag/If-None-Match
CSRF
- 用户访问A网站并正常登陆。此时又开了另一个tab访问了B
- 网站B接收到用户请求后,返回一些攻击性代码,并发出一个请求要求访问第三方站点A。
- 根据网站B的请求,在用户不知情的情况下携带Cookie信息,向网站A发出请求
- Token验证
- Referer 验证(简单易行,但 referer 可能被改变)
- 隐藏令牌
- 将cookie设置为HttpOnly
- 增加验证,例如密码、短信验证码、指纹等。
XSS
往 Web 页面里插入恶意Script代码 不相信用户的任何输入 转义字符 url需要decode
httponly-这个属性可以防止XSS,它会禁止javascript脚本来访问cookie。 secure - 这个属性告诉浏览器仅在请求为https的时候发送cookie。