最近暑期实习招聘已经开始,我的目前参加了阿里的内推及腾讯和百度的实习生招聘,在此总结一下
一是备忘、总结提高,二是但愿给你们一些参考
其余面试及基础相关能够参考其余博文:javascript
每位面试官的面试时间基本都在 40-80 分钟,下面先简要介绍各个面试流程,问题详情见具体公司分类css
腾讯内推&校招 offer gothtml
首先腾讯分为三面,都为技术面:前端
复试两个面试官,包括电话远程 online codingvue
(我也不知道为何几天内三个面试官面我,只算两个面试过程 ヾ(´A`)ノ゚)终面一位面试官java
这位应该是大 boss ,他说并非前端开发的,面试的问题也不会很深刻,主要看我的对这个领域的想法以及对常见问题在前端领域的解决思路,不按套路出牌,emmm 感受回答的不理想网络安全的实现node
如何检测恶意脚本
如何屏蔽
...react
腾讯二面 & online codinggit
腾讯的远程 online coding 时间较长,大概一个多小时,不只要按要求编程,也要口述思路以及关键点,过程相似压力面,面试官说完题目要求会给你思考及coding 时间,他能够远程看到面试者的 coding 状态,主要考察应变能力,思惟活跃度,编码习惯,调试能力,以及测试方法,本人在此过程当中没有太注意测试过程,致使对于特殊状况考虑不全面,测试样例不完善,望小伙伴们注意 ヾ(´A`)ノ゚,不过,在口述代码时发现也能够本身提出来须要完善的地方。es6
coding 为一到两题,后续问题都是围绕它结合实际应用进行拓展,主要考察是否能灵活运用以及类似的思路转换,当时面试时间太长以及基础知识较差,进制转换,存储那些个基础被小学老师收回,一连串的炮轰简直爽歪歪,我的表示此过程本身的表现较差,也要重视基础基础啊老铁们 ( ̄_ ̄ )
经历了腾讯云的四个面试官,以及其余部门一个面试官的酱油面,腾讯的技术面试官广泛语速较快,思路转换很快,要跟上面试官的节奏,聊到本身比较熟悉的能够多说几句,他们也会顺着你回答的内容进行深刻,也会引导面试者的回答方向,若是不太熟尽可能坦白一些,不懂装懂很容易 gg
才接到通知另加两轮面试委员会现场技术面,简直爽歪歪 ヾ(´A`)ノ
腾讯校招现场
一面
面试官很 nice,基本看着简历问的,话题围绕项目(项目隔得时间过久,心里宁愿粗暴的技术面),基本为大体的了解,包括平时的学习习惯和关注的技术发展sass--定义function,使用rem
问是否有其余负面做用
想到了页面闪烁,因为初始化时须要计算页面尺寸,可能有缩放
如何避免:
<!-- 若是在页面加载完成后,页面是用js动态添加的,这个问题就不太明显, --> doc.addEventListener('DOMContentLoaded‘', function(e) { <!-- doc.body.style.fontSize = 12 * dpr + 'px'; 淘宝处理 --> }, false);
媒体查询
二面
面试官不是前端的,因此没有问很深刻的问题,主要模拟实际场景考察实现思路以及先后端的方案,后端没说出什么,基本上只是就前端层面进行了描述,包括实现思路、须要注意的问题、以及性能和安全方面的考虑阿里内推 二面 卒
我投的是蚂蚁金服的前端开发,投过简历硬生生排队等了12天,还被内推人提早告知蚂蚁的前端很严格 ( ̄_ ̄ )
阿里分为在线测试,初试 ......
首先是在线测试
投完简历后官网会有相关在线测试题挂掉了。。。
baidu offer got
百度投的是核心搜索部门,但一面后估计不合适,没有了消息,后简历转到百度金融
一面
面试官语速很快,通常不给太多思考时间--------感受本身说话都打着节拍 ( ̄_ ̄ )
二面
面试官很和善,是惟一一个认真看了我博客的面试官,很荣幸,也很紧张
基本偏向基础
但因为没安排好时间,面试时在户外,听不太清面试官的问题,在此提醒各位小伙伴提早选好面试场地,避免环境影响
三面
一样和善的面试官,开始考察基础知识,编译原理,网络协议等基础,后面考察我的素质,后续更注重我的经历,包括如何学习,找实习,实习中遇到的问题及如何解决,最骄傲的事情等等
关于结尾
百度 & 阿里面试结束后都有问:你以为在面试过程当中有什么没问到,但本身掌握比较好的技能么
面阿里时,头脑发晕,回答:没有,我感受您面的很专业,问的知识点都是比较核心的 ( ̄_ ̄ )腾讯二面教训
我:是否有导师带,实习的大体安排以及部门业务等
效果 差
面试官曰:
你那么关系有没有导师的问题,但学习中最重要的是靠本身,导师并非负责回答你全部问题的
百度经验
我:部门是否有按期交流分享的机会;工做中是按照职位仍是业务部门划分,如何交流;偏向页面仍是业务逻辑
我的在自学过程当中发现前端体系太大,不知对于前端学习,您有什么建议么
面试官:不少前端初学者都有相似的困惑,你最好本身从头开始作一个项目,无论是本身瞎想的仍是模仿的,在项目过程当中去发现须要学习什么技术,在遇到问题的时候才知道去哪一个方向发展和思考,只有在项目中才能持续的学习和提升,前端知识很碎,没有项目很难有一连串的经历
整体
整体来讲,面试中有按照面试题出的,也有直接聊的,通常也会结合实际工做中会遇到的场景以及技术中的一些坑,回答时结合本身的项目经验会更好,大厂的面试官更侧重于面试者对深层原理的理解,对于实习生来讲通常面基础,若是有深查原理的习惯,我的的可塑造性也会较高
三厂体验对比:
协议都会问到
相对来讲,百度更多基础知识点,更多考察对更基本的知识掌握,不限于前端,还包括组成原理和编译原理的一些知识,固然前端偏多(好比选取一个class 标签元素有几种方式等小细节的问题来考察,细到要把每一个表达说完整,把每一个单词拼出来)
阿里腾讯更侧重应用中的注意事项(如:IE 和其余浏览器中的事件处理机制)不太揪细节
三厂都有问到算法,腾讯相对更注重对算法和逻辑,对面试者基础知识要求较高,甚至涉及更底层的。
另两厂对算法,数据结构的要求都是了解阶段
如下为面试中的一些知识点以及我的的一些补充,敲黑板啦啦啦
事件阶段
通常的,事件分为三个阶段:捕获阶段、目标阶段和冒泡阶段。
捕获阶段(Capture Phase)
或这样描述:
任何事件产生时,如点击一个按钮,将从最顶端的容器开始(通常是html的根节点)。浏览器会向下遍历DOM树直到找到触发事件的元素,一旦浏览器找到该元素,事件流就进入事件目标阶段
目标阶段(Target Phase)
事件处理程序
DOM0 级事件处理程序
var btn5 = document.getElementById('btn5'); btn5.onclick=function(){ console.log(this.id);//btn5 };
基于 DOM0 的事件,对于同一个 dom 节点而言,只能注册一个,后边注册的 同种事件 会覆盖以前注册的。
利用这个原理咱们能够解除事件,btn5.onclick=null;
其中this就是绑定事件的那个元素;以这种方式添加的事件处理程序会在事件流的冒泡阶段被处理;
DOM2事件经过 addEventListener
和 removeEventListener
管理
// addEventListener(eventName,handlers,boolean);removeEventListener() // 两个方法都同样接收三个参数,第一个是要处理的事件名,第二个是事件处理程序, // 第三个值为false时表示在事件冒泡阶段调用事件处理程序,通常建议在冒泡阶段使用, // 特殊状况才在捕获阶段; // 注意:经过addEventListener()添加的事件处理程序只能用removeEventListener()来移除 // 而且移除时传入的参数必须与添加时传入的参数同样;好比 var btn2 = document.getElementById('btn2'); var handlers = function () { console.log(this.id); }; btn2.addEventListener('click',handlers,false); btn2.removeEventListener('click',handlers.false);
ie 事件处理程序
//IE事件处理程序(IE和Opera支持) /* IE用了attachEvent(),detachEvent(),接收两个参数,事件名称和事件处理程序, * 经过attachEvent()添加的事件处理程序都会被添加到冒泡阶段,因此平时为了兼容更多的浏览器最好将事件添加到事件冒泡阶段,IE8及之前只支持事件冒泡; */ var btn3 = document.getElementById('btn3'); var handlers2=function(){ console.log(this===window); // true,注意attachEvent()添加的事件处理程序运行在全局做用域; }; btn3.attachEvent('onclick',handlers2);
总结
DOM事件模型中的事件对象经常使用属性:
IE事件模型中的事件对象经常使用属性:
经过 readystate 属性值判断什么时候方法下载完毕可用
readystate共有如下几个值:注意上面5个值并不必定每一个事件都全包含,而且不必定是什么顺序。
Document.readyState 属性loading / 加载
document 仍在加载。interactive / 互动
文档已经完成加载,文档已被解析,可是诸如图像,样式表和框架之类的子资源仍在加载。complete / 完成
T文档和全部子资源已完成加载。状态表示 load 事件即将被触发。
当这个属性的值变化时,document 对象上的readystatechange 事件将被触发。
事件对象
IE
IE中事件对象是做为全局对象window.event
存在的Firefox
Firefox中则是作为句柄( handler )的第一个参数传入通用
var evt = window.event || arguments[0];
事件监听
Chrome、FireFox、Opera、Safari、IE9.0及其以上版本
js addEventListener(eventName,handler,boolean); removeEventListener() /* 两个方法都同样接收三个参数, * 事件名 * 事件处理程序 * boolean false时表示在事件冒泡阶段调用事件处理程序,通常建议在冒泡阶段使用 */
IE8.0及其如下版本
js element.attachEvent(type, handler); element.detachEvent(type, handler); /* element 要绑定事件的对象,html 节点 * type 事件类型 +'on' 如: "onclick, onmouseover" * listener 事件处理程序(只写函数名,不带括号) */
早期浏览器
obj['on' + type] = handler
阻止冒泡
event.stopPropagation
event.cancelBubble = true //IE
阻止默认事件
event.preventDefault()
event.returnValue = false //IE
// event(事件)工具集,来源:github.com/markyun markyun.Event = { // 页面加载完成后 readyEvent: function (fn) { if (fn == null) { fn = document; } var oldonload = window.onload; if (typeof window.onload != 'function') { window.onload = fn; } else { window.onload = function () { oldonload(); fn(); }; } }, // 视能力分别使用dom0||dom2||IE方式 来绑定事件 // 参数: 操做的元素,事件名称 ,事件处理程序 addEvent: function (element, type, handler) { if (element.addEventListener) { //事件类型、须要执行的函数、是否捕捉 element.addEventListener(type, handler, false); } else if (element.attachEvent) { element.attachEvent('on' + type, function () { handler.call(element); }); } else { element['on' + type] = handler; } }, // 移除事件 removeEvent: function (element, type, handler) { if (element.removeEnentListener) { element.removeEnentListener(type, handler, false); } else if (element.detachEvent) { element.detachEvent('on' + type, handler); } else { element['on' + type] = null; } }, // 阻止事件 (主要是事件冒泡,由于IE不支持事件捕获) stopPropagation: function (ev) { if (ev.stopPropagation) { ev.stopPropagation(); } else { ev.cancelBubble = true; } }, // 取消事件的默认行为 preventDefault: function (event) { if (event.preventDefault) { event.preventDefault(); } else { event.returnValue = false; } }, // 获取事件目标 getTarget: function (event) { return event.target || event.srcElement; }, // 获取event对象的引用,取到事件的全部信息,确保随时能使用event; getEvent: function (e) { var ev = e || window.event; if (!ev) { var c = this.getEvent.caller; while (c) { ev = c.arguments[0]; if (ev && Event == ev.constructor) { break; } c = c.caller; } } return ev; } };
什么叫跨域
方案
application/x-www-form-urlencoded
最多见的 POST 提交数据的方式了。浏览器的原生 form 表单,若是不设置 enctype 属性,那么最终就会以 application/x-www-form-urlencoded方式提交数据。
传递的key/val会通过URL转码,因此若是传递的参数存在中文或者特殊字符须要注意。
//例子 //b=曹,a=1 POST HTTP/1.1(CRLF) Host: www.example.com(CRLF) Content-Type: application/x-www-form-urlencoded(CRLF) Cache-Control: no-cache(CRLF) (CRLF) b=%E6%9B%B9&a=1(CRLF) //这里b参数的值"曹"由于URL转码变成其余的字符串了
multipart/form-data
常见的 POST 数据提交的方式。咱们使用表单上传文件时,必须让 form 的 enctyped 等于这个值
而且Http协议会使用boundary来分割上传的参数
text/xml
<!-- 例子 --> POST http://www.example.com HTTP/1.1(CRLF) Content-Type: text/xml(CRLF) (CRLF) <?xml version="1.0"?> <resource> <id>123</id> <params> <name> <value>homeway</value> </name> <age> <value>22</value> </age> </params> </resource>
application/json
用来告诉服务端消息主体是序列化后的 JSON 字符串
//例子 //传递json POST HTTP/1.1(CRLF) Host: www.example.com(CRLF) Content-Type: application/json(CRLF) Cache-Control: no-cache(CRLF) Content-Length: 24(CRLF) (CRLF) { "a":1, "b":"hello" }
(CRLF)指 \r\n
参考: HTTP常见Content-Type比较
两个序号和三个标志位:
标志位:共6个,即URG、ACK、PSH、RST、SYN、FIN等,具体含义以下:
须要注意的是:
为何须要确认
因为TCP链接时全双工的,所以,每一个方向都必需要单独进行关闭,这一原则是当一方完成数据发送任务后,发送一个FIN来终止这一方向的链接,收到一个FIN只是意味着这一方向上没有数据流动了,即不会再收到数据了,可是在这个TCP链接上仍然可以发送数据,直到这一方向也发送了FIN
首先进行关闭的一方将执行主动关闭,而另外一方则执行被动关闭,上图描述的便是如此。
为何TIME_WAIT状态须要通过2MSL(最大报文段生存时间)才能返回到CLOSE状态?
MSL是Maximum Segment Lifetime英文的缩写,中文能够译为“报文最大生存时间”,他是任何报文在网络上存在的最长时间,超过这个时间报文将被丢弃,RFC 793中规定MSL为2分钟,实际应用中经常使用的是30秒,1分钟和2分钟等。2MSL即两倍的MSL,TCP的TIME_WAIT状态也称为2MSL等待状态
为何链接的时候是三次握手,关闭的时候倒是四次握手?
参考: TCP三次握手详解及释放链接过程
对于HTTP协议来讲,加密的对象有如下两个:
解决方案:
查明对手的证书
虽然HTTP不能确认通讯方,但SSL是能够的。SSL不只提供了加密处理,还使用了"证书"的手段,可用于确认通讯方。证书是由值得信赖的第三方机构颁布,可用于肯定证实服务器和客户端是实际存在的。因此,只要能确认通讯方持有的证书,便可判断通讯方的真实意图。B、没法判断报文是否完整(报文可能已遭篡改)
HTTP协议没法判断报文是否被篡改,在请求或者响应发出后,在对方接收以前,即便请求或者响应遭到篡改是没法得知的。防止篡改:
经常使用的,肯定报文完整性方法:MD五、SHA-1 等 散列值校验方法,以及用来确认文件的数字签名方法。可是,使用这些方法,也没法百分百确保结果正确,由于MD5自己被修改的话,用户是没办法意识到得。
POST 用户安全登录
在关系到用户隐私的时候,要时刻遵循两个原则:要想让用户信息安全,就必须对其进行加密,让别人即使是拿到了安全信息,摆在眼前的也是一串乱码,没有半点用处
MD5是一种经常使用的加密方法,它是一种散列函数,利用MD5对用户信息进行加密,会增长用户信息安全性。
网上有关于MD5的第三方框架Category
利用这个第三方框架能够实现对密码进行MD5加密
+随机乱码字符防止被破解
对称加密
非对称加密
HTTPS简介
HTTPS实际上是有两部分组成:HTTP + SSL / TLS,也就是在HTTP上又加了一层处理加密信息的模块。服务端和客户端的信息传输都会经过TLS进行加密,因此传输的数据都是加密后的数据
SSL协议是经过非对称密钥机制保证双方身份认证,并完成创建链接,在实际数据通讯时经过对称密钥机制保障数据安全性
服务器 用RSA生成公钥和私钥
把公钥放在证书里发送给客户端,私钥本身保存
客户端首先向一个权威的服务器检查证书的合法性,若是证书合法,客户端产生一段随机数,这个随机数就做为通讯的密钥,咱们称之为对称密钥,用公钥加密这段随机数,而后发送到服务器
服务器用密钥解密获取对称密钥,而后,双方就已对称密钥进行加密解密通讯了
HTTPS 在传输数据以前须要客户端(浏览器)与服务端(网站)之间进行一次握手,在握手过程当中将确立双方加密传输数据的密码信息。TLS/SSL 协议不只仅是一套加密传输的协议,更是一件通过艺术家精心设计的艺术品,TLS/SSL 中使用了非对称加密,对称加密以及 HASH 算法。握手过程的具体描述以下:
浏览器得到网站证书以后浏览器要作如下工做:
a) 验证证书的合法性(颁发证书的机构是否合法,证书中包含的网站地址是否与正在访问的地址一致等),若是证书受信任,则浏览器栏里面会显示一个小锁头,不然会给出证书不受信的提示。
b) 若是证书受信任,或者是用户接受了不受信的证书,浏览器会生成一串随机数的密码,并用证书中提供的公钥加密。
c) 使用约定好的HASH算法计算握手消息,并使用生成的随机数对消息进行加密,最后将以前生成的全部信息发送给网站。网站接收浏览器发来的数据以后要作如下的操做:
a) 使用本身的私钥将信息解密取出密码,使用密码解密浏览器发来的握手消息,并验证HASH是否与浏览器发来的一致。
b) 使用密码加密一段握手消息,发送给浏览器。浏览器解密并计算握手消息的HASH,若是与服务端发来的HASH一致,此时握手过程结束,以后全部的通讯数据将由以前浏览器生成的随机密码并利用对称加密算法进行加密。
参考:图解HTTPS
重要的数据,要加密
好比用户名密码(若是简单的md5,是能够暴力破解),常见的是 md5(不可逆),aes(可逆),自由组合,还能够加一些特殊字符
举例:username = aes(username), pwd = MD5(pwd + username)
非重要数据,要签名
签名的目的是为了防止篡改,好比 http://www.xxx.com/getnews?id=1
,获取id为1的新闻,若是不签名那么经过id=2,就能够获取2的内容等等。怎样签名呢?
一般使用sign,好比原连接请求的时候加一个 sign 参数,sign=md5(id=1),服务器接受到请求,验证sign是否等于 md5(id=1) ,若是等于说明正常请求。
这会有个弊端,假如规则被发现,那么就会被伪造,因此适当复杂一些,仍是可以提升安全性的。
登陆态怎么作
http是无状态的,也就是服务器无法本身判断两个请求是否有联系,那么登陆以后,之后的接口怎么断定是否登陆呢
简单的作法,在数据库中存一个token字段(名字随意),当用户调用登录接口成功的时候,就将该字段设一个值,(好比aes(过时时间)),同时返回给前端,之后每次前端请求带上该值,服务器首先校验是否过时,其次校验是否正确,不经过就让其登录。(redis 作这个很方便哦,key有过时时间)
一种特殊的存储过程,存储过程通常经过定义的名字直接调用,而触发器是经过增、删、改进行触发执行的。会在事件发生时自动强制执行
触发器是一种特殊的存储过程,主要是经过事件来触发而被执行的。它能够强化约束,来维护数据的完整性和一致性,能够跟踪数据库内的操做从而不容许未经许可的更新和变化。能够联级运算。如,某表上的触发器上包含对另外一个表的数据操做,而该操做又会致使该表触发器被触发。
事务
就是被绑定在一块儿做为一个逻辑工做单元的SQL语句分组,若是任何一个语句操做失败那么整个操做就被失败,之后操做就会回滚到操做前状态,或者是上有个节点。
为了确保要么执行,要么不执行,就能够使用事务。要将一组语句做为事务考虑,就须要经过ACID测试,即原子性,一致性,隔离性和持久性。锁:
在全部的DBMS中,锁是实现事务的关键,锁能够保证事务的完整性和并发性。与现实生活中锁同样,它能够使某些数据的拥有者,在某段时间内不能使用某些数据或数据结构。固然锁还分级别的。共享锁(只读不写)、排他锁(可读可写)
设计原则
单体是一个用来划分命名空间并将一批相关的属性和方法组织在一块儿的对象,若是他能够被实例化,那么他只能被实例化一次
// 对象字面量 var Singleton = { attr1: 1, attr2: 2, method1: function(){ return this.attr1; }, method2: function(){ return this.attr2; } }; // 上面的全部成员变量都是经过Singleton来访问的,可是它并非单体模式; // 由于单体模式还有一个更重要的特色,就是能够仅被实例化一次,上面的只是不能被实例化的一个类,所以不是单体模式;对象字面量是用来建立单体模式的方法之一; /*要实现一个单体模式的话,咱们无非就是使用一个变量来标识该类是否被实例化 若是未被实例化的话,那么咱们能够实例化一次,不然的话,直接返回已经被实例化的对象 */ // 单体模式 var Singleton = function(name){ this.name = name; this.instance = null; }; Singleton.prototype.getName = function(){ return this.name; } // 获取实例对象 function getInstance(name) { if(!this.instance) { this.instance = new Singleton(name); } return this.instance; } // 测试单体模式的实例 var a = getInstance("aa"); var b = getInstance("bb"); console.log(a === b) // true console.log(a.getName()) // aa console.log(b.getName()) // aa
应用案例
弹窗
传统建立:好比我点击一个元素须要建立一个div,我点击第二个元素又会建立一次div,咱们频繁的点击某某元素,他们会频繁的建立div的元素,虽然当咱们点击关闭的时候能够移除弹出代码,可是呢咱们频繁的建立和删除并很差,特别对于性能会有很大的影响,对DOM频繁的操做会引发重绘等,从而影响性能;所以这是很是很差的习惯;咱们如今能够使用单体模式来实现弹窗效果,咱们只实例化一次就能够
编写通用的单体模式
咱们使用一个参数fn传递进去,若是有result这个实例的话,直接返回,不然的话,当前的getInstance函数调用fn这个函数,是this指针指向与这个fn这个函数;以后返回被保存在result里面;如今咱们能够传递一个函数进去,无论他是建立div也好,仍是建立iframe也好,总之若是是这种的话,均可以使用getInstance来获取他们的实例对象;
// 建立div var createWindow = function(){ var div = document.createElement("div"); div.innerHTML = "我是弹窗内容"; div.style.display = 'none'; document.body.appendChild(div); return div; }; // 建立iframe var createIframe = function(){ var iframe = document.createElement("iframe"); document.body.appendChild(iframe); return iframe; }; // 获取实例的封装代码 var getInstance = function(fn) { var result; return function(){ return result || (result = fn.call(this,arguments)); } }; // 测试建立div var createSingleDiv = getInstance(createWindow); document.getElementById("Id").onclick = function(){ var win = createSingleDiv(); win.style.display = "block"; }; // 测试建立iframe var createSingleIframe = getInstance(createIframe); document.getElementById("Id").onclick = function(){ var win = createSingleIframe(); win.src = "http://cnblogs.com"; };
客户类和工厂类分开。消费者任什么时候候须要某种产品,只需向工厂请求便可。消费者无须修改就能够接纳新产品。
工厂模式是为了解决多个相似对象声明的问题;也就是为了解决实列化对象产生重复的问题。
function CreatePerson(name,age,sex) { var obj = new Object(); obj.name = name; obj.age = age; obj.sex = sex; obj.sayName = function(){ return this.name; } return obj; } var p1 = new CreatePerson("longen",'28','男'); var p2 = new CreatePerson("tugenhua",'27','女');
模块模式的思路是为单体模式添加私有变量和私有方法可以减小全局变量的使用
prototype + constructor
装饰者(decorator)模式可以在不改变对象自身的基础上,在程序运行期间给对像动态的添加职责(方法或属性)。
与继承相比,装饰者是一种更轻便灵活的作法。
能够动态的给某个对象添加额外的职责,而不会影响从这个类中派生的其它对象。
// ES7装饰器 function isAnimal(target) { target.isAnimal = true return target } // 装饰器 @isAnimal class Cat { // ... } console.log(Cat.isAnimal) // true // 做用于类属性的装饰器: function readonly(target, name, descriptor) { discriptor.writable = false return discriptor } class Cat { @readonly say() { console.log("meow ~") } } var kitty = new Cat() kitty.say = function() { console.log("woof !") } kitty.say() // meow ~
发布---订阅模式又叫观察者模式,它定义了对象间的一种一对多的关系,让多个观察者对象同时监听某一个主题对象,当一个对象发生改变时,全部依赖于它的对象都将获得通知
发布订阅模式的流程以下:
【实现事件模型】
即写一个类或是一个模块,有两个函数,一个bind一个trigger,分别实现绑定事件和触发事件,核心需求就是能够对某一个事件名称绑定多个事件响应函数,而后触发这个事件名称时,依次按绑定顺序触发相应的响应函数。
大体实现思路就是建立一个类或是匿名函数,在bind和trigger函数外层做用域建立一个字典对象,用于存储注册的事件及响应函数列表,bind时,若是字典没有则建立一个,key是事件名称,value是数组,里面放着当前注册的响应函数,若是字段中有,那么就直接push到数组便可。trigger时调出来依次触发事件响应函数便可
var Event = (function(){ var list = {}, listen, trigger, remove; listen = function(key,fn){ if(!list[key]) { list[key] = []; } list[key].push(fn); }; trigger = function(){ var key = Array.prototype.shift.call(arguments), fns = list[key]; if(!fns || fns.length === 0) { return false; } for(var i = 0, fn; fn = fns[i++];) { fn.apply(this,arguments); } }; remove = function(key,fn){ var fns = list[key]; if(!fns) { return false; } if(!fn) { fns && (fns.length = 0); }else { for(var i = fns.length - 1; i >= 0; i--){ var _fn = fns[i]; if(_fn === fn) { fns.splice(i,1); } } } }; return { listen: listen, trigger: trigger, remove: remove } })(); // 测试代码以下: Event.listen("color",function(size) { console.log("尺码为:"+size); // 打印出尺码为42 }); Event.trigger("color",42);
代理是一个对象,它能够用来控制对本体对象的访问,它与本体对象实现了一样的接口,代理对象会把全部的调用方法传递给本体对象的
本地对象注重的去执行页面上的代码,代理则控制本地对象什么时候被实例化,什么时候被使用
优势:
// 先申明一个奶茶妹对象 var TeaAndMilkGirl = function(name) { this.name = name; }; // 这是京东ceo先生 var Ceo = function(girl) { this.girl = girl; // 送结婚礼物 给奶茶妹 this.sendMarriageRing = function(ring) { console.log("Hi " + this.girl.name + ", ceo送你一个礼物:" + ring); } }; // 京东ceo的经纪人是代理,来代替送 var ProxyObj = function(girl){ this.girl = girl; // 经纪人代理送礼物给奶茶妹 this.sendGift = function(gift) { // 代理模式负责本体对象实例化 (new Ceo(this.girl)).sendMarriageRing(gift); } }; // 初始化 var proxy = new ProxyObj(new TeaAndMilkGirl("奶茶妹")); proxy.sendGift("结婚戒"); // Hi 奶茶妹, ceo送你一个礼物:结婚戒
理解使用虚拟代理实现图片的预加载
在网页开发中,图片的预加载是一种比较经常使用的技术,若是直接给img标签节点设置src属性的话,若是图片比较大的话,或者网速相对比较慢的话,那么在图片未加载完以前,图片会有一段时间是空白的场景,这样对于用户体验来说并很差,那么这个时候咱们能够在图片未加载完以前咱们能够使用一个loading加载图片来做为一个占位符,来提示用户该图片正在加载,等图片加载完后咱们能够对该图片直接进行赋值便可;下面咱们先不用代理模式来实现图片的预加载的状况下代码以下:
// 不使用代理的预加载图片函数以下 var myImage = (function(){ var imgNode = document.createElement("img"); document.body.appendChild(imgNode); var img = new Image(); img.onload = function(){ imgNode.src = this.src; }; return { setSrc: function(src) { imgNode.src = "http://img.lanrentuku.com/img/allimg/1212/5-121204193Q9-50.gif"; img.src = src; } } })(); // 调用方式 myImage.setSrc("https://img.alicdn.com/tps/i4/TB1b_neLXXXXXcoXFXXc8PZ9XXX-130-200.png");
//利用代理模式来编写预加载图片 var myImage = (function(){ var imgNode = document.createElement("img"); document.body.appendChild(imgNode); return { setSrc: function(src) { imgNode.src = src; } } })(); // 代理模式 var ProxyImage = (function(){ var img = new Image(); img.onload = function(){ myImage.setSrc(this.src); }; return { setSrc: function(src) { myImage.setSrc("http://img.lanrentuku.com/img/allimg/1212/5-121204193Q9-50.gif"); img.src = src; } } })(); // 调用方式 ProxyImage.setSrc("https://img.alicdn.com/tps/i4/TB1b_neLXXXXXcoXFXXc8PZ9XXX-130-200.png");
这种懒加载方法不用代理模式也是能够实现的,只是用代理模式。咱们可让 myImage 只作一件事,只负责将实际图片加入到页面中,而loading图片交给ProxyImage去作。从而下降代码的耦合度。由于当我不想用loading的时候,能够直接调用myImage 方法。也便是说假如我门不须要代理对象的话,直接能够换成本体对象调用该方法便可
对比
优势
js 实现两个超大数相加
基础:
2^63 - 1
Math.pow(2, 53) - 1
js //js 最大和最小安全值 Number.MAX_SAFE_INTEGER //9007199254740991 Number.MIN_SAFE_INTEGER //-9007199254740991
var largeNumberAdd = function(num1, num2) { var arr1 = num1.split(''), arr2 = num2.split(''), tem = '', num3 = 0, result = [] var longDiff = arr1.length - arr2.length if (longDiff > 0) { for (let i = 0; i < longDiff; i++) { arr2.unshift('0') } }else if (longDiff < 0) { for (let i = 0; i < Math.abs(longDiff); i++) { arr1.unshift('0') } } for (let i = arr1.length - 1; i >= 0; i--) { tem = parseInt(arr1[i]) + parseInt(arr2[i]) + num3 // check if tem > 10 if (tem >= 10) { num3 = 1 result.push((tem + '')[1]) }else { num3 = 0 result.push(tem) } } return result.reverse().join('') } // console.log(largeNumberAdd('11111','11111')) console.log(largeNumberAdd('00000000000000000000011111','333331999')) console.log(11111+333331999) // console.log(largeNumberAdd('3333333333333333333333333333333311111111111111111111111111111111111111','333333333333333331111111111111111111111111111166666666666666'))
js 每秒钟的计算量
js 如何解析后台返回的超大数据
前提:
js 用浮点数表示全部64位数字,全部达到 2^53 的能够被精确表示,更大的数字都会被裁剪,——如何表示64位数字
虽然js 可以解析进制数字表示64位数字,但底层的数字表示不支持 64 位
在浏览器中执行如下代码
<html> <head> <script language="javascript"> function showPrecisionLimits() { document.getElementById("r50").innerHTML = 0x0004000000000001 - 0x0004000000000000; document.getElementById("r51").innerHTML = 0x0008000000000001 - 0x0008000000000000; document.getElementById("r52").innerHTML = 0x0010000000000001 - 0x0010000000000000; document.getElementById("r53").innerHTML = 0x0020000000000001 - 0x0020000000000000; document.getElementById("r54").innerHTML = 0x0040000000000001 - 0x0040000000000000; } </script> </head> <body onload="showPrecisionLimits()"> <p>(2^50+1) - (2^50) = <span id="r50"></span></p> <p>(2^51+1) - (2^51) = <span id="r51"></span></p> <p>(2^52+1) - (2^52) = <span id="r52"></span></p> <p>(2^53+1) - (2^53) = <span id="r53"></span></p> <p>(2^54+1) - (2^54) = <span id="r54"></span></p> </body> </html>
在Firefox,Chrome和IE浏览器中,能够看到,若是可以存储64位数字,则如下减法结果皆为1。而结果相反,能够看到2 ^ 53 + 1和2 ^ 53 间的差别丢失
js (2 ^ 50 + 1) - (2 ^ 50)= 1 (2 ^ 51 + 1) - (2 ^ 51)= 1 (2 ^ 52 + 1) - (2 ^ 52)= 1 (2 ^ 53 + 1) - (2 ^ 53)= 0 (2 ^ 54 + 1) - (2 ^ 54)= 0
位运算
所以,咱们能够选择用两个 32 位的数字表示 64 位整数,而后进行按位与
var a = [ 0x0000ffff, 0xffff0000 ]; var b = [ 0x00ffff00, 0x00ffff00 ]; var c = [ a[0] & b[0], a[1] & b[1] ]; document.body.innerHTML = c[0].toString(16) + ":" + c[1].toString(16); //结果 ff00:ff0000
前端网络安全的实现
如何检测恶意脚本
如何屏蔽
一面
二面
IP地址让网络上的两个节点之间能够创建点对点的链接
端口号则为端到端的链接提供了可能 (程序间通信的接口)
IP协议是由TCP、UDP、ARP、ICMP等一系列子协议组成的。其中
TCP和UDP协议
主要用来作传输数据使用的
在TCP和UDP协议中,都有端口号的概念存在
端口号的做用
主要是区分服务类别和在同一时间进行多个会话服务类别
举例来讲,有主机A须要对外提供FTP和WWW两种服务,若是没有端口号存在的话,这两种服务是没法区分的。
实际上,当网络上某主机B须要访问A的FTP服务时,就要指定目的端口号为21;根据一个给定的元素生成一个css 选择器,函数名为genCssSelector ,
点击某元素弹出该元素及其父元素,相似 querySelector
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>Document</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <script language="javaScript"> // your code here var genCssSelector = function (e) { e = e || window.event var tar = e.target || e.srcElement var objArr = [] while (tar) { if (tar.id) { objArr.push('#' + tar.id) console.log('id') return objArr.reverse().join(' ') // 考虑 id 的惟一性,若是有 id,则中止查找 }else if (tar.className) { objArr.push('.' + tar.className.split(' ')[0]) // 考虑若是有多个 class }else { objArr.push(tar.nodeName.toLowerCase()) } tar = tar.parentNode } objArr.pop() return objArr.reverse().join(' ') } document.addEventListener('click', function (e) { //点击li时,返回:html body #page .content.main .refer ul li console.log(genCssSelector(e)); }) </script> </head> <body> <div id="page"> <div class="main" id="main"> <div class="reference refer"> <ul> <li></li> <li></li> 23333 </ul> </div> </div> </div> </body> </html>
JS获取DOM元素的方法(8种)
getElementById
getElementsByName
getElementsByTagName
getElementsByClassName
document.documentElement
document.body
querySelector
querySelectorAll
获取一组元素
获取子元素
dom.childNodes
返回一个nodeList(元素的全部子元素)
nodeValue属性
得到和改变文本节点的值获取父、兄
parentNode
nextSibling
previousSbiling
建立元素
createDocumentFragment
createElement
createTextNode
建立一个文本节点
增删改元素
appendChild
removeChild
replaceChild
insertBefore
直接调用eval
var json = '{"a":"1", "b":2}'; var obj = eval("(" + json + ")"); // obj 就是 json 反序列化以后获得的对象
原理
JSON 脱胎于 JS,同时也是 JS 的子集,因此可以直接交给 eval 运行
加上圆括号的目的是迫使eval函数在处理JavaScript代码的时候强制将括号内的表达式(expression)转化为对象,而不是做为语句(statement)来执行
例如对象字面量{},如若不加外层的括号,那么eval会将大括号识别为JavaScript代码块的开始和结束标记,那么{}将会被认为是执行了一句空语句
缺点
XSS 漏洞
如:参数 json 并不是真正的 JSON 数据,而是可执行的 JS 代码对参数 json 作校验,只有真正符合 JSON 格式,才能调用 eval
```js
// 1. 用 4 个正则表达式分为两个阶段解决(包容ie 和safari 的regexp 引擎)
// 2. 将 json 反斜杠替换为 '@' (non-json字符)
// 3. 用 ']' 替换全部简单标记
// 4. 删除全部跟随冒号,逗号或文本开始的方括号
// 5. 若是只剩下 '] , { }' 则是安全的
var rx_one = /^[],:{}\s]$/;
var rx_two = /\(?:["\/bfnrt]|u[0-9a-fA-F]{4})/g;
var rx_three = /"[^"\\\n\r]"|true|false|null|-?\d+(?:.\d)?(?:[eE][+-]?\d+)?/g;
var rx_four = /(?:^|:|,)(?:\s[)+/g;
if (
rx_one.test(
json
.replace(rx_two, "@")
.replace(rx_three, "]")
.replace(rx_four, "")
)
) {
var obj = eval("(" +json + ")");
}
```
第一种 eval 的方法,至关于一古脑儿把 JSON 字符串塞进去。
其实咱们还能够手动逐个字符地扫描,而后进行判断,这就是第二种方法:递归
// 所谓递归,就是重复调用value 函数 value = function () { // Parse a JSON value. It could be an object, an array, a string, a number, // or a word. white(); // 根据当前字符是什么,咱们便能推导出后面应该接的是什么类型 switch (ch) { case "{": return object(); case "[": return array(); case "\"": return string(); case "-": return number(); default: return (ch >= "0" && ch <= "9") ? number() : word(); } }; // 调用核心的 next 函数,逐个读取字符 var next = function (c) { // If a c parameter is provided, verify that it matches the current character. if (c && c !== ch) { error("Expected '" + c + "' instead of '" + ch + "'"); } // Get the next character. When there are no more characters, // return the empty string. ch = text.charAt(at); at += 1; return ch; };
false true null
进行匹配,不匹配返回错误以 {"a":"1", "b":2}
为例
程序大体逻辑是:启动 → 首次调用 value() → 发现是 { → 原来是对象,走 object() → 经过 string() 获得 key 值为 "a" → 读取到冒号,哦,后面多是对象、数组、布尔值等等,具体是什么,还得再次调用 value() 才知道 → ……
xml 解析
close tag
使用一个 nodeStack 栈,在 opentag 时推入节点,close tag 时检查当前节点是否和栈尾节点是否匹配,匹配则推出末尾节点comment
setState 不保证同步
setState()
不会马上改变 this.state
,而是建立一个即将处理的 state 转变。在调用该方法以后访问 this.state
可能会返回现有的值。使用回调函数
setState 方法接收一个 function 做为回调函数。这个回掉函数会在 setState 完成之后直接调用,这样就能够获取最新的 state
js this.setState({ selection: value }, this.fireOnSelect)
setTimeout
在 setState 使用 setTimeout 来让 setState 先完成之后再执行里面内容
js this.setState({ selection: value }); setTimeout(this.fireOnSelect, 0);
shouldComponentUpdate
解决
setState()
将老是触发一次重绘,除非在 shouldComponentUpdate()
中实现了条件渲染逻辑和渲染无关的状态尽可能不要放在 state 中来管理
一般 state 中只来管理和渲染有关的状态 ,从而保证 setState 改变的状态都是和渲染有关的状态。这样子就能够避免没必要要的重复渲染。其余和渲染无关的状态,能够直接以属性的形式保存在组件中,在须要的时候调用和改变,不会形成渲染。
不能颇有效的管理全部的组件状态
一面
jsonp cors
css
js & jq
vue
操做系统
计算机网络
数据结构
二面
如何作一个 css 选择器
见本文 阿里-在线编程给定一组dom 节点,和一个css样式表,找出不含有样式的dom
面试官很耐心的解释了,仍是没听明白题目居中问题
没有详细问,我分了两个方面分别回答get & post
回答了大多数应聘者的 “标准答案”, 但经面试官指点,顿悟,大概这就叫高手吧
三面
数字的存储
无符号与有符号二进制存储
理解有符号数和无符号数负数闲聊了一下,关于保研等等,总共 四十分钟
原理:增大父框的实际宽度后,使用CSS3属性box-sizing进行布局的辅助。
用法:先将父框设置为 margin-left: -*px
,再设置子框 float: left、width: 25%、padding-left、box-sizing: border-box
.parent{ margin-left: -20px; } .column{ float: left; width: 25%; padding-left: 20px; box-sizing: border-box; /*包含padding区域 w+g*/ }
原理:经过增长一个父框的修正框,增大其宽度,并将父框转换为 table,将子框转换为 tabel-cell 进行布局。
用法:先将父框的修正框设置为 margin-left: -*px
,再设置父框 display: table、width:100%、table-layout: fixed
,设置子框 display: table-cell、padding-left
.parent-fix{ margin-left: -20px; } .parent{ display: table; width:100%; table-layout: fixed; } .column{ display: table-cell; padding-left: 20px; }
原理:经过设置CSS3布局利器flex中的flex属性以达到等分布局。
用法:将父框设置为display: flex,再设置子框flex: 1,最后设置子框与子框的间距margin-left。
// 直接获取---须要高版本浏览器支持 document.querySelectorAll("div.aa") // 相似属性选择器的写法 document.querySelectorAll("div[class='aa']") // 补充一下还能够not选择器 document.querySelectorAll(".aa:not(ul)") document.getElementsByClassName('cls') // jq $('.className')
js 单线程:
用途决定,操做 DOM
任务队列
排队缘由:计算量大的同步执行,IO设备(输入输出设备)很慢(好比Ajax操做从网络读取数据)异步。
异步任务指的是,不进入主线程、而进入"任务队列"(task queue)的任务,只有"任务队列"通知主线程,某个异步任务能够执行了,该任务才会进入主线程执行
"任务队列"中的事件,除了IO设备的事件之外,还包括一些用户产生的事件(好比鼠标点击、页面滚动等等)。只要指定过回调函数,这些事件发生时就会进入"任务队列",等待主线程读取。
全部同步任务都在主线程上执行,造成一个执行栈(execution context stack)。
主线程以外,还存在一个"任务队列"(task queue)。只要异步任务有了运行结果,就在"任务队列"之中放置一个事件。
一旦"执行栈"中的全部同步任务执行完毕,系统就会读取"任务队列",看看里面有哪些事件。那些对应的异步任务,因而结束等待状态,进入执行栈,开始执行。
主线程不断重复上面的第三步。
只要主线程空了,就去检查异步的任务队列,若是异步事件触发,则将其加到主线程的执行栈
深刻了解定时器
零延迟 setTimeout(func, 0)
调用setTimeout()以后,该方法会返回一直数值ID,表示超时调用。这个超时调用ID是计划执行代码的惟一标识符,能够经过它来取消超时调用
超时调用的代码都是在全局做用域中执行的,所以函数中this的值在非严格模式下指向window对象,严格模式下是undefined。
Event Loop
异步与event loop没有太直接的关系,准确的来说event loop 只是实现异步的一种机制
主任务 ——> micro task ——> 渲染视图 ——> macro task
主线程从"任务队列"中读取事件,这个过程是循环不断的,因此整个的这种运行机制又称为Event Loop(事件循环)
Javascript 中的事件循环是以任务为单位的,将不少个待执行的任务串联在一块儿就造成了队列 Task Queue,不少的队列前后按顺序执行任务就造成了 Event Loop
一个事件循环(EventLoop)中会有一个正在执行的任务(Task),而这个任务就是从 macrotask 队列中来的。
当这个 macrotask 执行结束后,全部可用的 microtask 将会在同一个事件循环中执行
当这些 microtask 执行结束后还能继续添加 microtask 一直到真个 microtask 队列执行结束。
一个事件循环(event loop)会有一个或多个任务队列(task queue)
task queue 就是 macrotask queue当一个 task 被放入队列 queue(macro或micro) 那这个 task 就能够被当即执行了
Micro Task
当咱们想以同步的方式来处理异步任务时候就用 microtask(好比咱们须要直接在某段代码后就去执行某个任务,就像Promise同样)
Macro Task
任务队列中,在每一次事件循环中,从 macrotask 队列开始执行,macrotask只会提取一个执行,而microtask会一直提取,直到microsoft队列为空为止。
也就是说若是某个microtask任务被推入到执行中,那么当主线程任务执行完成后,会循环调用该队列任务中的下一个任务来执行,直到该任务队列到最后一个任务为止。而事件循环每次只会入栈一个macrotask,主线程执行完成该任务后又会检查microtasks 队列并完成里面的全部任务后再执行macrotask的任务。
执行过程以下:
为啥要用 microtask?
// 验证 (function () { const $test = document.getElementById('test') let counter = 0 function func1() { $test.innerText = ++counter alert('func1') } function func2() { $test.innerText = ++counter alert('func2') } function func3() { $test.innerText = ++counter alert('func3') } function func4() { $test.innerText = ++counter alert('func4') } (function () { // main task func1() // macro task setTimeout(() => { func2() // micro task Promise.resolve().then(func4) }, 0); // macro task setTimeout(func1, 0); // micro task Promise.resolve().then(func3) // main task func4() })() // alert func1 // alert func4 // alert func3 // UI update ---> counter = 3 // alert func2 // alert func4 // UI update ---> counter = 5 // alert func1 // UI update ---> counter = 6 })()
fetch
返回一个Promise对象, 根据 Promise Api 的特性, fetch能够方便地使用then方法将各个处理逻辑串起来
mode
// fetch能够设置不一样的模式使得请求有效 fetch(url, {mode: 'cors'});
Jsonp
SSE(server-sent-events)
单向通道(服务器 -> 浏览器)
ES 6之前:
ES 6:
ES 7:
回调函数
通常是须要在一个耗时操做以后执行某个操做时能够使用回调函数
问题:
在回调函数以外没法捕获到回调函数中的异常
var fs = require('fs'); try{ fs.readFile('not_exist_file', 'utf8', function(err, data){ console.log(data); }); } catch(e){ console.log("error caught: " + e); }
尝试读取一个不存在的文件,这固然会引起异常,可是最外层的try/catch语句却没法捕获这个异常。这是异步代码的执行机制致使的
为何异步代码回调函数中的异常没法被最外层的try/catch语句捕获?
异步调用通常分为两个阶段,提交请求和处理结果,这两个阶段之间有事件循环的调用,它们属于两个不一样的事件循环(tick),彼此没有关联。
异步调用通常以传入callback的方式来指定异步操做完成后要执行的动做。而异步调用本体和callback属于不一样的事件循环。
try/catch语句只能捕获当次事件循环的异常,对callback无能为力。
事件监听(订阅-发布)
典型的逻辑分离方式,对代码解耦颇有用处
把不变的部分封装在组件内部,供外部调用,须要自定义的部分暴露在外部处理。
从某种意义上说,事件的设计就是组件的接口设计。
//发布和订阅事件 var events = require('events'); var emitter = new events.EventEmitter(); emitter.on('event1', function(message){ console.log(message); }); emitter.emit('event1', "message for you");
Promise 对象
用同步操做的流程写法来表达异步操做,避免了层层嵌套的异步回调
Promise.prototype.then()
//原生Primose顺序嵌套回调示例 var fs = require('fs') var read = function (filename){ var promise = new Promise(function(resolve, reject){ fs.readFile(filename, 'utf8', function(err, data){ if (err){ reject(err); } resolve(data); }) }); return promise; } read('./text1.txt') .then(function(data){ console.log(data); return read('./text2.txt'); // 返回了一个新的Promise实例 }) .then(function(data){ console.log(data); });Promise构造函数的参数是一个函数,在这个函数中咱们写异步操做的代码
调用read函数时,实际上返回的是一个Promise对象,经过在这个Promise对象上调用then方法并传入resolve方法和reject方法来指定异步操做成功和失败后的操做。
Promise.prototype.catch()
用于指定发生错误时的回调函数
read('./text1.txt') .then(function(data){ console.log(data); return read('not_exist_file'); }) .then(function(data){ console.log(data); }) .catch(function(err){ console.log("error caught: " + err); }) .then(function(data){ console.log("completed"); })
使用Promise对象的catch方法能够捕获异步调用链中callback的异常
Promise对象的catch方法返回的也是一个Promise对象,所以,在catch方法后还能够继续写异步调用方法
Promise.all()
var p = Promise.all([p1,p2,p3]);
只要p一、p二、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。
```js
var promises = [1, 2].map(function(fileno){
return read('./text' + fileno + '.txt');
});
Promise.race()
var p = Promise.race([p1,p2,p3]);
Promise.resolve()
var p = Promise.resolve('Hello'); p.then(function (s){ console.log(s) });
Promise.reject()
Promise.reject
方法的参数reason,会被传递给实例的回调函数。var p = Promise.reject('出错了'); p.then(null, function (s){ console.log(s) });
整个Generator函数就是一个封装的异步任务,或者说是异步任务的容器。异步操做须要暂停的地方,都用yield语句注明。
function* gen(x){ var y = yield x + 2; return y; } var g = gen(1); var r1 = g.next(); // { value: 3, done: false } console.log(r1); var r2 = g.next() // { value: undefined, done: true } console.log(r2);
**Generator函数的函数名前面有一个"*"**
ES 7中的async和await
区别:
当我满心充满着自信和喜悦时,仿佛看到了面试官眉头一皱,So?
aspect | GET | POST |
---|---|---|
浏览器回退 | 无影响 | 回退会再次提交请求 |
地址标记 | 产生的 URL 地址能够被 Bookmark | 提交地址不被标记 |
cache | 该请求会被浏览器主动 cache | 该请求不会被缓存 |
编码 | 只能进行url编码 | 支持多种编码方式 |
参数保留 | 请求参数会被完整保留在浏览器历史记录里 | POST中的参数不会被保留 |
长度限制 | 有(浏览器限制,IE-2083个字符) | 无(限制做用的是服务器的处理程序的处理能力) |
参数类型 | 只接受ASCII字符 | 没有限制 |
参数传递 | 经过URL传递 | 放在Request body中 |
字符 | 表示 | 补充 |
---|---|---|
二进制 | 0/1 | 八个二进制位能够组合出256种状态,这被称为一个字节(byte) |
八进制 | 0~7 | |
十进制 | 0~9 | |
十六禁止 | 0~9 A~F |
编码 | 特征 | 补充 |
---|---|---|
二十一进制码(BCD码) | 保留了十进制数的权,而数字则用二进制数码0和1的组合来表示 | 在须要高精度的计算中BCD编码比较经常使用(了解) |
ASCII码 | 美国信息交换标准委员会制定的7位字符编码,用7位二进制码表示一个字符,第8 位用于肯定附加的128 个特殊符号字符、外来语字母和图形符号 | |
GB2312 | 为了保存非英文,使用127号以后的空位保存新的字母(一个8位的字节能够组合256种状态,ASCII只编到127号),一直编到最后一位255,并且不一样国家表示的符号也不同,也能够说GB2312是对ASCII的中文扩展 | 不够用,后来只要求只要第一个字节是大于127就固定表示这是一个汉字的开始,称之为GBK编码 |
GB18030 / DBCS | 编码中又增长了几千个新的少数民族的字,GBK扩展成了GB18030统称它们叫作DBCS | |
Unicode | ISO(国际标准化组织)废弃了全部地区性编码方案,作了一套包括了地球上全部文化、符号以及字母的编码;ISO规定:必须用两个字节,16位来统一表示全部的字符,不管是半角的英文字母,仍是全角的汉字,它们都是统一的一个字符!也就是两个字节 | |
UTF-8 | UTF-8 互联网上使用最广的一种 Unicode 的实现方式,每次以8个位为单位传输数据;UTF-16就是每次 16 个位 | UTF-8 最大的一个特色,就是它是一种变长的编码方式,Unicode一个中文字符占 2 个字节,而UTF-8一个中文字符占3个字节,UTF-8是Unicode的实现方式之一 |
进制转换
------十进制转其余------- var a = 24; a.toString(2);//11000 a.toString(8);//30 a.toString(16);//18 ------其余转十进制------- var b=11000,c=30,d=18; console.log(parseInt(b, 2)); // 二进制转十进制 console.log(parseInt(c, 8)); // 八进制转十进制 console.log(parseInt(d, 16));// 十六进制转十进制
前端编码问题
在使用nodeJS编写前端工具时,对文本文件的操做比较多,这就涉及到了文件的编码问题,经常使用的文本编码有UTF8和GBK两种,而且UTF8文件还可能带有BOM(字节顺序标记),在读取不一样编码的文本文件时,须要将文件内容转换为JS使用的UTF8编码字符串后才能正常处理
移除 BOM
BOM用于标记一个文本文件使用Unicode编码,其自己是一个Unicode字符("\uFEFF"),位于文本文件头部以告诉其余编辑器以utf8来显示字符
可是在网页上并不须要添加BOM头识别,由于网页上能够使用 head头 指定charset=utf8告诉浏览器用utf8来解释.可是你用window自动的编辑器,编辑,而后有显示在网页上这样就会显示出0xEF 0xBB 0xBF这3个字符。这样网页上就须要去除0xEF 0xBB 0xBFjs 去除
// 能够经过文件头的几个字节来判断文件是否包含BOM以及使用哪一种Unicode,若是读取文件的时候不去掉BOM // 假如咱们将几个JS文件合并成一个,若是文件中含有BOM字符,就会致使语法错误 // 因此咱们用 nodeJS读取文件是通常先去掉BOM var bin = fs.readFileSync(pathname);//经过node 中fs模块同步读文件内容 //判断文件头的字节 if (bin[0] === 0xEF && bin[1] === 0xBB && bin[2] === 0xBF) { bin = bin.slice(3); }
GBK 转 UTF8
NodeJS支持在读取文本文件时,或者在Buffer转换为字符串时指定文本编码,但GBK编码不在NodeJS自身支持范围内,通常咱们借助iconv-lite这个三方包来转换编码,首先使用npm下载这个第三方包,读取GBK文件函数以下:
var iconv = require('iconv-lite'); function readGBKText(pathname) { var myFs = fs.readFileSync(pathname); return iconv.decode(myFs, 'gbk'); }
经常使用的线性结构有:线性表,栈,队列,循环队列,数组
线性表中包括顺序表、链表等,其中:
其余
**若有不足,欢迎交流,祝各位看官 offer 拿到手软 O(∩_∩)O**
个人博客即将搬运同步至腾讯云+社区,邀请你们一同入驻:https://cloud.tencent.com/developer/support-plan