为了寻找暑假实习,我在网上寻找了很多的面经,整理了一份前端知识点清单。如今找到实习,也把我的整理回馈社区。
操作系统
死锁,如何解决死锁
-
当系统中的某些不可剥夺的资源被多个进程同时需求,进程占据一定资源,并请求对方资源,会导致所有进程都无法推进,这就是死锁。
-
死锁的四要素是:互斥、不可剥夺、请求与保持、循环等待。
-
解决死锁的方法就是破坏死锁的四要素(预防避免死锁),或者检测到思索并解开它(解决死锁)
进程、线程两者区别
-
进程:程序在一个数据集上的一次运行过程、是系统进行资源调配和调度的一个独立单位。
-
隶属与进程的一个实体,比进程更小一级的运行单位。是CPU的调度单位。
-
区别:
-
线程是最基本的调度单位(CPU级)
-
进程是资源分配的基本单位,与之相比,线程不具备单独资源
-
也正因为没有独立资源,线程的调度开销小。
-
计算机网络
TCP链接过程
-
三次握手建立链接:
-
SYN=1,seq=x;
-> -
SYN=1,ACK=1,seq=y,ack=x+1;
<- -
ACK,seq=x+1,ack=y+1;
->
-
-
四次挥手中断链接
-
FIN=1,seq=x;
-> -
ACK=1,ack=x+1,seq=y;
<- -
FIN=1,ack=x+1,seq=z;
<- -
ACK=1,ack=z+1,seq=x+1;
->
-
TCP重传机制(为何可靠)
TCP的重传机制
TCP是GBK和SR优点的综合,在滑动窗口中发送多个数据包,当窗口左侧的数据包得到确认,窗口右移。在这个过程中。
TCP维护一个计时器,当计时器走完且确认还没到,重新发送所有没有得到确认的数据包。
但若是连续接到三个相同的确认信息(拥塞),则立即重发(快速重发机制)
重发时,只发送未被确认的信息。
TCP拥塞控制(发生了延时和丢包)
TCP拥塞控制
拥塞原因
当发送速率接近路由器缓存,排队时延
当发送速率大于路由器缓存,丢包重发时延
当发生丢包,上游路由器的传输容量被浪费
TCP拥塞控制
TCP 必须使用端到端拥塞控制而不是网络辅助的拥塞控制,因为 lP层不向端系统提供显 式的网络拥塞反馈。拥塞控制的过程是源主机不断试探网络传输能力的过程。
维护一个变量-——拥塞窗口来表征网络的拥塞情况,表示为CongWin。
发送窗口 = min{CongWin, RcvWin}
拥塞窗口同样也是以字节为单位。
TCP发送方通过”丢包事件“感知路径上的拥塞。”丢包事件“为:要么出现超时,要么收到来自接收方的3个相同的ACK。处理这两种丢包事件的方法也不相同,前者超时丢包,可以认定存在网络拥塞现象,所以直接慢启动来试探;后者也有可能是乱序传输的问题,所以将CongWin减半来应对。
TCP Reno拥塞控制算法——当感知到发生拥塞,调整速率的算法。
算法对CongWin的调整是以MSS字节为单位进行的。
慢启动
并不是指速率回复慢(这是指数级的),而是起点低(1MSS)。
发送方每接到一个确认就将CongWin+MSS,因为同时发送多个报文段,所以呈指数增长。
拥塞避免
为防止指数式增长会造成阻塞情况,当congWin达到一定阈值后,就从指数增长变为线性增长。
发送方每经过一个RTT时间就将CongWin+1,此时是线性增长。
阈值的计算:上次阻塞时的拥塞窗口大小的1/2.
快重传
收到 3 个重复 ACK 后,立即重发丢失数据报,而不用等待计时器。
快恢复
与快重传相对应,发生快重传后,TCP 将拥塞窗口(CongWin)减小一半(乘性减),然后线性地增长(拥塞避免算法,加性增)。
TCP与UDP的区别:
-
TCP基于有链接,而UDP基于无连接
-
有链接意味着信息的传送有始有终也就是可靠,而无连接不能进行状态追踪,也就意味着尽最大努力传送,不负责结果。
-
TCP的要求更多,存在大量的控制字段和用于控制的数据包,所以无论是数据总传输效率还是单次传送的数据占用率都更低。UDP更高效。
网络协议模型:
-
OSI七层模型:
-
应用层
-
表示层
-
会话层
-
传输层
-
网络层
-
链路层
-
物理层
-
-
传统五层结构
-
应用层
-
传输层
-
网络层
-
链路层
-
物理层
-
-
各层所包含的协议:
-
应用层:HTTP、DNS、SMTP、FTP
-
传输层:UDP、TCP
-
网络层:IP
-
ARP协议:
地址解析协议ARP,位于网络层。已知一个机器的IP地址,解析获得其硬件地址。
每个主机都有一个ARP缓存,若该IP在缓存中则直接访问,若不在,则广播该信息,收到回复后录入缓存。
DNS协议:
将互联网上的主机地址转换为IP地址,位于应用层。使用UDP协议。
什么是全双工、半双工、单工:
-
单工:只能由一方向另一方传递信息,信息流动是单向的
-
半双工:信息可以双向传递,但同一时刻只能有一个方向
-
全双工:信息可以双向传递,可以在同时双向传递。
网络安全
什么是XSS,如何防御:
XSS,Cross-Site-Scripting,一种代码注入攻击。
通过在网站上注入恶意脚本,从而使浏览器产生意料外的行为。(如发送cookie、sessionID等)。可能发生XSS攻击的地方:
-
来自用户的UGC内容(用户生成内容,评论、微博、表单等)
-
来自第三方的链接
-
URL参数
-
POST参数
-
Cookie(来自其他子域注入)
存储型XSS
步骤:
-
攻击者将恶意代码提交到数据库中
-
用户请求时,网站将恶意代码从数据库中提取,与HTML混合响应给浏览器
-
用户执行,恶意代码也被执行
-
恶意代码将用户数据发送给攻击者网站。
反射型XSS
步骤:
-
攻击者构造特殊URL,包含恶意代码
-
用户打开URL,服务器将恶意代码与HTML合并相应给服务器
-
用户执行
-
中招
反射型XSS与存储型XSS的区别就在于,存储型XSS的恶意代码存储在数据库中,而反射型的则是诱导用户点击一个包含恶意代码的URL。问题都存在服务器端,不对提交的数据防范。
DOM型XSS
-
攻击者构造特殊的URL,包含恶意代码
-
用户打开URL
-
用户收到响应后解析执行,取出URL中的恶意代码执行
-
中招。
DOM型攻击的问题出在前端上,利用了JavaScript的漏洞。
防范
-
存储型和反射型
-
输入过滤:不仅要前端过滤也要后端过滤,防止绕过前端直接向后端发送请求
-
HTML转义:在电话、邮箱等格式确定的输入中进行转义可以有效防止HTML类的注入攻击
-
纯前端渲染:存储型和反射型的攻击都源于服务器误将恶意代码夹入代码中返回,那么将要执行的渲染代码放在前端执行就可以了。数据与代码分离。只需要关注DOM型攻击就可以了
-
-
DOM型
-
在可执行"字符串"作为代码的时候要格外小心,尽量把innerHTML、document.write变成.textContent、setAttribute
-
react中尽量使用dangerousSetInnerHTML功能。
-
内联事件监听器也可以将字符串执行,
location、onclick、onerror、onload等 -
JavaScript的
setTimeout、setInterval、eval
-
什么是CSRF,如何防御:
一种诱导当前已登录用户在第三方网站向被攻击网站发送非本意的请求的攻击。
用户在正规网站上已经登陆,这时他打开了一个第三方网站,第三方网站要求用户向正规网站发送恶意请求(带着登录标识cookie、sessionID)
-
攻击者通过第三方网站发出攻击,被攻击网站无法防止攻击放生
-
攻击者利用登录标识冒充用户提交操作,并不直接窃取数据,也无法获取到数据,只是冒用。
防御
-
验证码:可以有效防止CSRF操作,但是降低用户体验
-
Referer check:成本最低,但是部分低级浏览器可以伪造referer
-
token:目前最普遍的方法,原理:既然CSRF是通过发送请求时自带的cookie来冒用的,那么使用不存放于cookie中的身份信息来验证用户就可以了。服务器端随机生成一个token,浏览器发送请求时在参数中或者头部附带上这个token。
-
cookie 的一个字段:samesite可以过滤非同一站点发出的请求
数据结构&算法
见
[数据结构&算法] ./数据结构and算法.md
编码题
实现LazyMan:
var LazyMan = function(name) { return new _LazyMan(name); } class _LazyMan { constructor(name) { this.name = name; this.tasks = []; this.init(); Promise.resolve().then(() => { this.next(); }) } next() { var task = this.tasks.shift(); if (task) { task(); } } init() { let task; let _name = this.name; let that = this; task = function() { console.log('This is ' + _name); that.next(); } this.tasks.push(task); return this; } eat(food) { let task; let _food = food; let that = this; task = function() { console.log('eat ' + food); that.next(); } this.tasks.push(task); return this; } sleep(time) { let task; let _time = time; let that = this; task = function() { setTimeout(() => { console.log('sleep for ', _time); that.next() }, _time) } this.tasks.push(task); return this; } sleepFirst(time) { let task; let _time = time; let that = this; task = function() { setTimeout(() => { console.log('first sleep for ' + _time); that.next(); }, _time); } this.tasks.unshift(task); return this; } } LazyMan('tom').eat('afood').sleep(1000).eat('bfood').sleepFirst(2000)
实现XMLHttpRequest的promise封装(实现封装Ajax):
实现Queue
/* * 实现一个Queue类,要求包含两个函数 * task函数:新增一个任务。包含两个参数,等待时间和回调函数 * start函数:执行任务队列。将所有任务按队列顺序执行,执行完一个任务才能执行下一个任务 */ var Queue = function(){ this.tasks = []; } Queue.prototype.task = function(time, func){ let _task; (()=>{ var _time = time; var _func = func; var that = this; _task = function(){ setTimeout(_func, _time); that.next(); } })(); this.tasks.push(_task); return this; } Queue.prototype.next = function(){ let task = this.tasks.shift(); task&&task(); } Queue.prototype.start = function(){ this.next(); } let q = new Queue(); q.task(1000, ()=>{console.log(1)}).task(2000, ()=>{console.log(2)}).start();
洗牌算法
var numList = [1,2,3,4,5,6,7,8,9]; var func =function(numList){ let maxNum = numList.length; let result = []; var getRand = function(max){ return Math.floor(Math.random()*max); } while(maxNum>0){ console.log(numList); let randNum = getRand(maxNum); let num = numList[randNum]; result.push(num); _numList = [...numList.slice(0,randNum),...numList.slice(randNum+1)]; numList = _numList; maxNum--; } return result; } console.log(func(numList));
实现小驼峰
var func = function(name){ let reg = /(-.)/g; return name.replace(reg, (e)=>{ return e[1].toUpperCase(); }) } console.log(func('ab-cd-e'));
间隔输出
var func = function(arr){ (()=>{ var _arr = arr; let interId = setInterval(()=>{ let num = _arr.shift(); if(num){ console.log(num); }else{ clearInterval(interId); } }, 1000); })(); } func([1,2,3,4,5,6])
对象深拷贝
有关深拷贝,需要知道的一些知识
target = JSON.parse(JSON.stringfiy(sourse))是实现深拷贝的最简单方法,但是有局限性,对于两个目的相同的引用会重复复制,不能有循环引用等
Object.assign是实现浅拷贝的最简单手段,即遍历所有可遍历属性并复制或覆盖。
Object.create()使用已有对象作为现对象的prototype。
var Obj = function() { this._null = null; this._undefined = undefined; this._number = 1; this._string = 'hello'; this._boolean = true; this._symbol = Symbol(); this._function = function() { console.log('hello'); } this._object = new Object(); this._object2 = this._object; } var deepClone = function(sourse) { if (sourse == null || sourse == undefined) { return sourse; } else if (!(sourse instanceof Object)) { let target = sourse; return target; } else if (sourse instanceof Array) { let target = []; Object.assign(target, sourse); return target; } else if (sourse instanceof Symbol) { return new Object(sourse); } else if (sourse instanceof Function) { return sourse } else { let target = {}; for (i in sourse) { target[i] = deepClone(sourse[i]) } return target; } } let obj = new Obj(); console.log(deepClone(obj));
柯里化
let add = function(x, y){ return x+y; } let currying = (fn, ...args1)=>{ return (...args2)=>{ return fn.call(null, ...args1, ...args2); } } console.log(currying(add, 1)(234));
发布订阅模式
class Event { constructor() { this.listeners = {}; } on(type, callback) { if (!this.listeners[type]) { this.listeners[type] = []; } this.listeners[type].push(callback); } off(type, callback) { if (!Array.isArray(this.listeners[type])) { return; } let index = this.listeners[type].findIndex(func => func == callback); if (index >= 0) { this.listeners[type].splice(index, 1); } return; } once(type, callback) { if (!this.listeners[type]) { this.listeners[type] = []; } this.listeners[type].push(callback); callback._once = true; } trigger(event) { const { type } = event; this.listeners[type].forEach(callback => { callback(event.value); if (callback._once) { this.off(type, callback); } }); } } var handle = function() { console.log('here the call'); } var handleOnce = function() { console.log('call it once'); } var event = new Event(); event.on('click', handle); event.once('click', handleOnce); event.trigger({ type: 'click' }); event.off('click', handle); event.trigger({ type: 'click' });
HTTP
HTTP缓存策略
HTTP缓存保存了文件副本,会替代对资源的请求,提高性能。但是不应该缓存过期资源。
与缓存相关的信息标记存储在HTTP报文的header字段。
-
强制缓存:若该缓存未过期,则直接使用该缓存
-
对比缓存:(当该缓存过期时)先发送请求给服务器,查看该缓存是否需要更新。服务器返回304,则证明该缓存可用,直接读取缓存即可;否则服务器返回200,并附带请求的资源。
那么,如何判断资源是否过期呢
-
Expires:HTTP1.0的东西;内容是到期时间。(通常不使用了)
-
Catch-control:
-
private:客户端缓存,中间代理不可缓存
-
public:所有都可缓存
-
max-age:内容将在xxx秒后过期
-
no-catch:即max-age=0,资源立刻过期
-
no-store:该资源不缓存
-
-
缓存标识
-
Etag
-
If-None-match
这一对优先级更高,但Etag标识符需要服务器计算,服务器负担大
-
Last-Modified
-
If-Modified-Since
-
缓存分为强制缓存和对比缓存,而采取哪种策略主要是通过判断缓存的有效时间来判断的,HTTP1时,主要采用Expires来记录缓存的有效时间,但因为使用的是服务器时间,所以如果客户端时间与服务器时间有误差的话,就会出现错误。HTTP1.1时新增了catch-control头部,主要有:public、private、max-age、no-catch、no-store等字段,maxage是根据缓存在客户端的存储时间来计算的。如果缓存未过期,则使用强制缓存,若缓存已过期,则使用对比缓存。对比缓存有两对头部可以代表:last-modified/if-modified-since||Etag/if-none-match。前者记录最后的修改时间,后者根据缓存内容生成一个标识;如果未发生改变,则返回304,可以使用缓存;否则返回200同时传输新的文件。
Expires vs Catch-Control
Expires是HTTP1的产物,使用服务器的格林威治时间,客户端可能会不同步
Catch-Control是HTTP1.1的产物,使用客户端的保存时间,优先级高于Expires。
last-modified/if-modified-since vs Etag/if-none-match
前者是根据服务器的修改时间作为判断依据,可能出现服务器无有效更新却记录为改变的情况。记录的时间单位为秒,所以精度不如Etag,因为Etag在每次修改后都会更新。
后者根据服务器的内容生成的一个标识,只有内容发生变化后才会变化,但是生成Etag耗费服务器资源。Etag优先级大于last-modified。
HTTP状态码:
-
1xx:信息传递
-
2xx:成功
- 200请求正常处理
-
3xx:重定向
-
301永久转移
-
302临时转移
-
304缓存未修改
-
-
4xx:客户端错误
-
400语法错误
-
401要求身份认证
-
403拒绝执行
-
404找不到资源或网页
-
408请求超时
-
-
5xx:服务器错误
-
500服务器内部错误
-
503服务器负载超载
-
HTTP、HTTP1.0、HTTPS、HTTP2.0
-
HTTP
无状态协议,建立在TCP之上。
它的延时主要来自:
-
浏览器阻塞:浏览器向一个域名发送的请求最多4个,后续请求会被阻塞
-
DNS查询:通过DNS缓存可以有效缓解延时
DNS的递归查询和迭代查询
DNS查询过程中,主机向本地域名服务器的查询是递归查询,主机只请求一次,在那之后,本地域名服务器会作为查询主机向其他本地域名服务器查询
而本地域名服务器向根域名服务器的查询是迭代查询,查询主机保持不变。
总结下来,本地域名服务器是工具人,担任了最多的查询任务。
-
建立链接的开销:HTTP1.0是无连接的,所以每一个请求都至少需要3次握手后才能携带数据包,
-
TCP拥塞策略:应对拥塞的策略中的慢启动(发送数量(MSS)从1开始)和拥塞避免(拥塞窗口减半)会影响HTTP传输大文件时的速率。
-
-
HTTP1.1
在HTTP1.0的基础上进行了改进:
-
新增了有关缓存的字段:Etag、Last-Since、Catch-Control等
-
宽带优化:支持只请求资源的一部分,从而实现了断点续传功能
-
新增24个错误状态吗
-
Host头管理
-
长连接和流水线:这时HTTP1.1的主要改进
-
长连接:建立的一个TCP链接可以发送多个HTTP请求。
-
流水线:理论上可以不必等待之前请求结束就发起下一个请求(异步请求)但是实现起来有难度:要求响应也要按照顺序收到。所以当上一个请求响应没返回时,后续请求也都会被阻塞,称为线头阻塞。浏览器也必须开辟缓存来保存先到的后续请求,若是浏览器在中间与服务器断联可能还需要重新处理多个请求。还必须客户端、代理、服务端都支持流水线功能。
只能通过建立多个TCP链接来解决问题,但是浏览器对同一域名的链接不能超过6-8个。其实还可以将资源存放于不同的父子域名中,这样可以扩大请求链接数量,但也都是讨巧的方法。
-
-
-
HTTPS
基于SSL/TSL链接,有效的防止运营商劫持。以下是HTTPS链接建立过程:
- 首先客户端发送请求建立SSL链接
-
服务器将CA证书发送给客户端,其中包括非对称加密的公钥。
- 客户端判断证书的有效性,若有效,则生成一个对称加密的key,用非对称加密算法加密后发送给服务器。
-
链接建立。
-
基于SSL/TSL,可以有效的防止运营商劫持
-
使用端口为443, HTTP为80
-
HTTP2.0
-
新的二进制格式:通过二进制传输,简单且兼容
-
多路复用:多个url的请求可以在一个线路中传输,在接收方根据id分配到不同的服务器上。
-
header压缩:
-
服务器推送:服务器主动发送可能用到的数据包,提高加载速度。
-
同源策略
用于限制一个origin的文档或它加载的脚本如何能与另一个源的资源进行交互
同源:协议/域名/端口 都相等的情况下为同源
非同源的限制:
无法获取非同源网页的Cookie、LocalStorage和indexDB
无法获取非同源网页的DOM
无法向非同源url发送AJAX请求
跨源的解决方案:
-
更改源:可以通过
document.domain:"xxx"来将源设为其父域,从而与其兄弟域之间交互 -
CORS:跨域资源共享。
-
简单请求:
-
条件:
请求方法:GET/HEAD/POST
头信息不超过:
-
Accept
-
Accept-language
-
Content-language
-
Last-Event-ID
-
Content-Type
-
-
原理:对于简单请求,浏览器直接发出CORS请求,就是在头信息中添加一个Origin字段。而服务器根据这个字段来决定是否同意这次请求。
-
如果Origin指定的源不在许可范围内,服务器会返回一个正常的HTTP相应,浏览器发现回应的头信息中没有包含
Access-Control-Allow-Origin字段,会抛出一个错误。注意不能通过HTTP状态码来判断对错,因为可能会返回200. -
如果Origin所指定的源在许可范围内,则响应中因该有
Access-Control-Allow-Origin相关字段。
-
-
-
非简单请求
-
预检请求:
预检请求是对服务器有特殊要求的请求,比如PUT、DELETE或
Content-type=application/json的请求。预检请求是在正式发送请求之前,发送一个OPTION请求询问服务器是否支持其使用的方法和使用的请求头部。
-
预检请求的回应:
与正式的请求类似,服务器支持相应方法和头部的请求的回应中包含
Access-Control-Allow-Origin字段。若没有,则代表否定。 -
在预检请求之后:
就像简单请求那样,开始正常的CORS请求。
-
-
-
JSONP
script标签不受跨域影响,不论传输的是什么资源。所以利用script标签,前端传递一个函数给服务器,而服务器将数据作为参数传给函数从而传递给前端。
<script>、<img>、<link>、<Iframe> -
PostMessage
应用场景:
-
页面与其打开的新窗口之间的信息传递
-
多窗口之间的信息传递
-
页面与iframe之间的信息传递
利用
Window.postMessage()方法otherWindow.postMessage(message, targetOrigin, [transfer])-
otherWindow:其他窗口的一个引用
-
message:需要传送的数据
-
targetOrigin:通过窗口的Origin属性来限制哪些窗口可以接收到信息(协议/端口/域名/*)
-
-
webSocket
HTTP有一个缺陷,只能由客户端向服务器发送请求,而服务器不能主动向客户端请求。
当服务器有连续的状态变化时,客户端实时接收就成了问题。通常使用轮询方法,定期发送请求查看是否更改,比如聊天室的信息实时接收。但是轮询的效率低,就有了websocket
websocket是双向对话,属于服务器推送的一种。
-
建立在TCP之上,服务端实现容易
-
与HTTP协议有良好的兼容性,默认端口为80和443,且握手采用HTTP协议,能通过各种HTTP代理服务器
-
数据格式比较轻量
-
可以发送文本或者二进制数据
-
没有同源限制,客户端可以与服务器任意通信
-
服务器推送服务
-
轮询
客户端定期发送信息请求
-
长轮询
服务器接收到客户端的请求不立即响应,而是暂时挂起,当有信息时或到达一定时间后再响应。
-
长连接
HTTP1.1的特性
-
websocket
HTML5新协议允许服务器主动向客户端推送。
RPC和HTTP的区别
RPC直接建立在TCP之上(也可以使用HTTP协议),省却了很多的冗余HTTP报文。
RPC主要用于公司内部服务调用,效率高,性能消耗低,服务治理方便。
cookie和session的区别
-
Cookie:
Cookie本质上是服务器存储在客户端上的一小段文本,客户端在请求时将该文本夹在请求中发出去。
客户端向服务器请求保存当前信息,服务器的相应中包含了
set-cookie字段,通知客户端设定cookie;当下次客户端发送请求时,会自动附带cookie字段,服务器根据cookie就能得知要回复的会话信息。 -
Session:
Session的信息存储在服务器中,通过SessionID来通信
Session是通过Cookie来实现的,Cookie的内容就是SessionID,相比之下,把数据存储在服务器端更加安全。但是禁用cookie后session依然可以通过修改url的方式将sessionId放在url中传送。
session本质上是一个抽象概念,是为了维持会话状态的实现的一个交互状态,而cookie是真实存在的,除了在客户端存储信息能让服务器认出客户端外,还可以用于方便用户,如记录账号密码这样的。
cookie和localStorage区别
-
localStorage没有过期事件,可以自己封装一个逻辑来实现
-
localstorage的存储容量是5M,cookie是4k
-
localstorage是永久生效的,sessionStorage仅在窗口关闭前生效
-
localstorage是同源限制,sessionstorage还限制只能同一浏览器窗口读取。
从输入URL到网页渲染的全过程
-
输入URL
-
DNS解析
浏览器缓存 - 操作系统缓存 - 本地host文件缓存 - 路由器缓存 - 本地域名服务器缓存 - 顶级
-
建立TCP链接
三次握手 SYN;ACK、SYN;ACK;
-
发送HTTP请求
-
服务器处理
-
服务器相应
-
浏览器渲染
-
链接结束(四次挥手)
四次挥手 FIN;ACK;FIN;ACK;
Content-type
常见的媒体格式类型如下:
-
text/html : HTML格式
-
text/plain :纯文本格式
-
text/xml : XML格式
-
image/gif :gif图片格式
-
image/jpeg :jpg图片格式
-
image/png:png图片格式
以application开头的媒体格式类型:
-
application/xhtml+xml :XHTML格式
-
application/xml: XML数据格式
-
application/atom+xml :Atom XML聚合格式
-
application/json: JSON数据格式
-
application/pdf:pdf格式
-
application/msword : Word文档格式
-
application/octet-stream : 二进制流数据(如常见的文件下载)
-
application/x-www-form-urlencoded :
中默认的encType,form表单数据被编码为key/value格式发送到服务器(表单默认的提交数据的格式)
GET和POST区别:
-
GET通过URL请求数据,POST通过body传输数据
-
因为POST的数据在body中,所以更加安全
-
GET只支持ASCII,而POST无限制
-
GET请求是无害的(对服务器数据而言)是幂等的(多次请求均一个后果),POST确实有害而不幂等的。
POST和PUT的区别:
- PUT方法是幂等的,POST不是
PATCH和PUT的区别:
- PATCH是可局部修改的。
HTML
script:defer、async
-
二者均无:浏览器会立即加载并执行指定的脚本,立即指的是当文档解析到该脚本所在位置时,立刻执行渲染,执行完后才继续执行下面的代码。
-
async:加载和执行后续文档的过程将和该脚本内容在执行时阻塞渲染
-
defer:该脚本的内容与整个文档并行加载,但是最后执行。
meta头部的作用
meta标签提供关于HTML文档的元数据,他不会体现在页面中,但是对于机器可读,通常用于浏览器(如何显示内容和重新加载页面)和搜索引擎(关键词)。
viewport
viewport是用户网页的可视区域。移动端浏览器通常是虚拟的viewport,比手机屏幕宽,这样就可以兼容没有对移动端优化的网页布局。
<meta name="viewport" content="width=device-width, initial-scale=1.0">
-
width:指定可视窗口的大小,可以直接指定,当设为device-width时,指的是单位缩放为100%的CSS像素
-
height:同上
-
initial-scale:初始缩放比例
-
maximum-scale:
-
minimum-scale:
-
user-scalable:用户能否自定义窗口大小。
@import和link区别
@import是CSS提供的语法规则,而link是HTML标签
-
顺序:link标签引入css的同时加载;@import在页面加载完毕后加载(注意只是加载不同,而不是渲染)
-
兼容性:@import是CSS2.1才有的语法;link不存在兼容性问题
-
可以通过js操作dom插入link标签;@import却不行
Hybrid技术
设备像素占比
CSS
优先级
!import>行内样式>id>类选择器(类、伪类、属性)>标签>继承>通配符
哪些属性继承
-
字体系列font
-
文本系列
-
text-indent:文本缩进
-
text-align:文本水平对齐
-
text-shadow:文本阴影
-
line-height:行高
-
work-spacing:增加或减少单词间空白
-
letter-spacing:增加或减少文本间空白
-
text-transform:控制文本大小写
-
direction:文本书写方向
-
color:文本颜色
-
-
元素可见visibility
-
表格布局:
-
列表属性
-
...
哪些属性不可继承
-
display
-
文本属性:
-
vertical-align:文本垂直对齐
-
text-decoration:文本修饰线
-
-
盒子模型属性:宽高、内外边距、边框
-
背景属性
-
position
-
生成内容属性content
-
轮廓:outline
CSS中的长度单位
-
绝对长度单位:
-
px:逻辑像素
-
in:inches,
1in = 96px; -
cm:
1cm = 37.8px; -
mm:
1mm = 3.78px;
-
-
相对长度单位
-
em:当前元素的字体大小
-
rem:根元素的字体大小
-
ex:当前字体下
x的高度,不同的font-family会有不同 -
ch:当前字体下
0的高度,不同的font-family会有不同
-
-
相对视区的长度单位
-
vw/vh:视区的宽高
-
vmin/vmax:视区宽高中更大或更小的那一个
-
css中表示颜色的方式
-
八进制和十六进制:#RRGGBB
-
RGB颜色:
rgb(255, 0, 0) -
RGBA:
rgba(255,0,0,0)第四个维度是透明度 -
HSL:色调(0-360)、饱和度(%)、明度(%)
inline-block的间隔问题
inline-block之间存在间隔是因为文档标签之间的空格导致的,要消除标签,可以采取
-
父节点设
font-size=0,这样空格便不再显现 -
float、position等另其中内容脱离文档流
BEM规范
-
使用双划线标识不同类型版本
-
使用双下划线标识后代关系
.block__child{} .block__child--enable{} .block__child--disable{}
可以避免污染全局css属性。
JavaScript
防抖和节流
防抖
在函数被触发n秒后再回调执行,如果函数在这期间被调用,则重新计数。
用途:
-
搜索联想
-
窗口大小resize
利用setTimeOut和clearTimeout来实现
节流
函数每n秒只被触发一次
用途
-
滚动事件监听
-
拖动事件监听
-
鼠标多次点击
通过获取Date来判断
-
node.js如何加载文件,有什么区别
-
require:common.js的规范
-
运行时加载
-
拷贝到本页面
-
全部加载
-
-
import:es6提出的js新语法
-
按需加载
-
编译时加载
-
只引用定义
-
-
其他
源码、反码、补码
-
源码就是十进制直接转换为二进制的形式,最高位为符号位
-
反码:正数的反码就是本身,负数的反码就是源码除了符号位之外所有位取反
-
补码:正数的补码就是本身,负数的补码就是反码+1;
-
有关零的问题:
-
源码有两个零
-
反码有两个零
-
补码只有一个零所以负数范围更大一些。
-
JavaScript精度问题
JavaScript采用64位双精度浮点数。最高一位是符号位,接着11位是指数,剩下的52位是有效数字。因为所有的Number类型都用此表示,所以浮点数的运算中会有很多的问题。
解决这些问题的方法:
-
传到后台计算
-
指定精度
-
将小数部分当作正数计算,计算完后加上小数点。
typeof、instanceof
typeof可以用于判断变量的类型,number、string、boolean、object(包括Array、null)、function、Symbol、undefined七种类型。
typeof通过变量的第三位机器码来判断变量的类型,null与Object的低三位均为000所以typeof判断null为object
instanceof可以判断一个对象是否为某种类型(包括祖先类型)。
实现方法主要是遍历左表达式的原型链,查看其类型是否与右表达式相同。
需要注意的是,虽然typeof null === 'object'但是null instanceof null === false
HTML5新特性
-
新增一些语义化标签,footer、nav、artical
-
多媒体,
video\audio等元素 -
图像效果:
canvas\svg等元素 -
对离线存储的更好支持:
localstorage/cookies等 -
websocket
-
webworker
CSS3新特性
-
transform、translate、animation
-
border-radius、border-image、box-shadow
-
background-clip、background-origin、background-size
-
多列布局
-
box-sizing
ES6的新特性
-
const、let
-
模板字符串(反引号``)
-
箭头函数
-
不需要function
-
不需要return
-
继承当前上下文的this
-
-
函数的参数默认值
-
对象和数组的解构语法
-
for of和for in
-
class类语法
js动画和css3动画的差异性
js动画在单线程的js引擎中计算,容易造成丢帧,而CSS更流畅一些
js功能更加强大,控制更加细节,
css3在性能较低的浏览器中可以自动降级,而js则需要添加代码
css3的兼容性不太好,js则不存在
node.js
node.js是一个语言,也是一个平台,也是一个开发环境。
node.js是google基于JavaScript开发的,因此node.js主要使用JavaScript的代码来编写,但是又有所不同,他的功能是基于服务端的,相当于一个在服务端开发运行的JavaScript语言。没有浏览器的相关API,却有本地操作系统的API
webpack
是一个模块化打包工具,可以用来管理项目中的模块依赖,并编译输出模块中所需的静态文件。它可以很好的管理、打包开发中所需的HTML、js、CSS和静态文件(图片、字体)等。对于不同类型的依赖,webpack有对应的模块加载器,而且会分析模块间的依赖关系,最后生成优化的静态资源。
webpack基本功能和工作原理
-
代码转换:Typescript编译成JavaScript、SCSS编译成CSS
-
文件优化:压缩js、css、html文件,合并压缩图片等
-
代码分割:提取多个页面的公共代码,提取首屏的不需要执行的代码异步执行
-
模块合并:把多个模块合并成一个
-
自动刷新:监听本地源代码变化,自动构建,刷新浏览器
-
代码校验:在提交到仓库前检测代码规范,以及单元测试
-
自动发布:更新完代码后,自动构建出线上发布代码,并传输给发布系统。
webpack打包原理
将所有依赖打包成一个bundle.js,将代码分割成单元,按需加载。
webpack名词解析
-
entry:入口,告诉webpack从哪个模块开始构建项目
-
output:出口,告诉webpack将打包好的项目输出到哪里以及如何命名。
-
loader:告诉webpack如何转换某一类型的文件,并引出到打包文件的。
-
bundle:打包出来的文件
-
chunk:代码分割后的代码块
-
module:开发中的某一模块
-
模块热更新:webpack的一个功能,源代码修改后不需要手动刷新浏览器就自动更新。
Babel
Babel是JavaScript的语法转换器。大致分为三个部分
-
解析:将代码转换为AST(抽象语法树)
-
转换:访问AST节点,并进行变换操作
-
生成:根据AST生成新的代码。
使用框架的好处
-
组件化
-
代码分层
-
完整的生态
-
UI更新的托管
TypeScript
TypeScript最大的特定就是强类型和支持ES6语法,它是JavaScript一个超集。
JavaScript作为一个弱类型语言,虽然可以写出很简洁的代码,但是不利于开发大型项目,所以有了TypeScript的补充。