最近暑期实习招聘已经开始,个人目前参加了阿里的内推及腾讯和百度的实习生招聘,在此总结一下 一是备忘、总结提升,二是希望给大家一些参考 其他面试及基础相关可以参考其他博文:
每位面试官的面试时间基本都在 40-80 分钟,下面先简要介绍各个面试流程,问题详情见具体公司分类
腾讯内推&校招 offer got
首先腾讯分为三面,都为技术面:
腾讯二面 & online coding
经历了腾讯云的四个面试官,以及其他部门一个面试官的酱油面,腾讯的技术面试官普遍语速较快,思路转换很快,要跟上面试官的节奏,聊到自己比较熟悉的可以多说几句,他们也会顺着你回答的内容进行深入,也会引导面试者的回答方向,如果不太熟尽量坦白一些,不懂装懂很容易 gg
才接到通知另加两轮面试委员会现场技术面,简直爽歪歪 ヾ(´A`)ノ
腾讯校招现场
html <!-- 如果在页面加载完成后,页面是用js动态添加的,这个问题就不太明显, --> doc.addEventListener('DOMContentLoaded‘', function(e) { <!-- doc.body.style.fontSize = 12 * dpr + 'px'; 淘宝处理 --> }, false);
阿里内推 二面 卒
我投的是蚂蚁金服的前端开发,投过简历硬生生排队等了12天,还被内推人提前告知蚂蚁的前端很严格 ( ̄_ ̄ ) 阿里分为在线测试,初试 ......
baidu offer got
百度投的是核心搜索部门,但一面后估计不合适,没有了消息,后简历转到百度金融
关于结尾
总体
总体来说,面试中有按照面试题出的,也有直接聊的,一般也会结合实际工作中会遇到的场景以及技术中的一些坑,回答时结合自己的项目经验会更好,大厂的面试官更侧重于面试者对深层原理的理解,对于实习生来说一般面基础,如果有深查原理的习惯,个人的可塑造性也会较高
三厂体验对比:
以下为面试中的一些知识点以及个人的一些补充,敲黑板啦啦啦
事件阶段
一般的,事件分为三个阶段:捕获阶段、目标阶段和冒泡阶段。
事件处理程序
js var btn5 = document.getElementById('btn5'); btn5.onclick=function(){ console.log(this.id);//btn5 };
btn5.onclick=null;
其中this就是绑定事件的那个元素;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);var btn3 = document.getElementById('btn3'); var handlers2=function(){ console.log(this===window); // true,注意attachEvent()添加的事件处理程序运行在全局作用域; }; btn3.attachEvent('onclick',handlers2); ```
总结
DOM事件模型中的事件对象常用属性:
IE事件模型中的事件对象常用属性:
注意上面5个值并不一定每个事件都全包含,并且不一定是什么顺序。 Document.readyState 属性 一个文档的 readyState 可以是以下之一:
当这个属性的值变化时,document 对象上的readystatechange 事件将被触发。
事件对象
window.event
存在的var evt = window.event || arguments[0];
事件监听
js addEventListener(eventName,handler,boolean); removeEventListener() /* 两个方法都一样接收三个参数, * 事件名 * 事件处理程序 * boolean false时表示在事件冒泡阶段调用事件处理程序,一般建议在冒泡阶段使用 */
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;
}
};
什么叫跨域
方案
(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协议来说,加密的对象有以下两个:
为了有效防止这些弊端,可以采用HTTPS。
要想让用户信息安全,就必须对其进行加密,让别人即便是拿到了安全信息,摆在眼前的也是一串乱码,没有半点用处 MD5是一种常用的加密方法,它是一种散列函数,利用MD5对用户信息进行加密,会增加用户信息安全性。 网上有关于MD5的第三方框架Category 利用这个第三方框架可以实现对密码进行MD5加密 +随机乱码字符防止被破解
对称加密
非对称加密
HTTPS简介
HTTPS其实是有两部分组成:HTTP + SSL / TLS,也就是在HTTP上又加了一层处理加密信息的模块。服务端和客户端的信息传输都会通过TLS进行加密,所以传输的数据都是加密后的数据
SSL协议是通过非对称密钥机制保证双方身份认证,并完成建立连接,在实际数据通信时通过对称密钥机制保障数据安全性
HTTPS 在传输数据之前需要客户端(浏览器)与服务端(网站)之间进行一次握手,在握手过程中将确立双方加密传输数据的密码信息。TLS/SSL 协议不仅仅是一套加密传输的协议,更是一件经过艺术家精心设计的艺术品,TLS/SSL 中使用了非对称加密,对称加密以及 HASH 算法。握手过程的具体描述如下:
参考:图解HTTPS
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) ,如果等于说明正常请求。
这会有个弊端,假如规则被发现,那么就会被伪造,所以适当复杂一些,还是能够提高安全性的。一种特殊的存储过程,存储过程一般通过定义的名字直接调用,而触发器是通过增、删、改进行触发执行的。会在事件发生时自动强制执行
触发器是一种特殊的存储过程,主要是通过事件来触发而被执行的。它可以强化约束,来维护数据的完整性和一致性,可以跟踪数据库内的操作从而不允许未经许可的更新和变化。可以联级运算。如,某表上的触发器上包含对另一个表的数据操作,而该操作又会导致该表触发器被触发。
设计原则
单体是一个用来划分命名空间并将一批相关的属性和方法组织在一起的对象,如果他可以被实例化,那么他只能被实例化一次
// 对象字面量
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
应用案例
编写通用的单体模式
我们使用一个参数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 (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 位整数,然后进行按位与
```js
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等一系列子协议组成的。其中
根据一个给定的元素生成一个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
只获取到一个元素,没有找到返回nullgetElementsByName
getElementsByTagName
getElementsByClassName
document.documentElement
获取htmldocument.body
获取bodyquerySelector
获取一个元素querySelectorAll
获取一组元素获取子元素
dom.childNodes
返回一个nodeList(元素的所有子元素) 获取父、兄
parentNode
nextSibling
previousSbiling
创建元素
createDocumentFragment
创建一个dom片段createElement
创建一个具体的元素createTextNode
创建一个文本节点增删改元素
appendChild
removeChild
replaceChild
insertBefore
直接调用eval
var json = '{"a":"1", "b":2}';
var obj = eval("(" + json + ")"); // obj 就是 json 反序列化之后得到的对象
原理
JSON 脱胎于 JS,同时也是 JS 的子集,所以能够直接交给 eval 运行
缺点
第一种 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 解析
setState()
不会立刻改变 this.state
,而是创建一个即将处理的 state 转变。在调用该方法之后访问 this.state
可能会返回现有的值。解决方案
js this.setState({ selection: value }, this.fireOnSelect)
setTimeout
在 setState 使用 setTimeout 来让 setState 先完成以后再执行里面内容
js this.setState({ selection: value }); setTimeout(this.fireOnSelect, 0);
shouldComponentUpdate
解决
setState()
将总是触发一次重绘,除非在 shouldComponentUpdate()
中实现了条件渲染逻辑一面
jsonp cors
css
js & jq
vue
操作系统
计算机网络
数据结构
二面
详细见 CSS 居中
三面
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*/ }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; }// 直接获取---需要高版本浏览器支持
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设备的事件以外,还包括一些用户产生的事件(比如鼠标点击、页面滚动等等)。只要指定过回调函数,这些事件发生时就会进入"任务队列",等待主线程读取。
只要主线程空了,就去检查异步的任务队列,如果异步事件触发,则将其加到主线程的执行栈
深入了解定时器
setTimeout(func, 0)
零延迟并不是意味着回调函数立刻执行。它取决于主线程当前是否空闲与“任务队列”里其前面正在等待的任务。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 队列执行结束。
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
})()
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()
```js
//原生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构造函数的参数是一个函数,在这个函数中我们写异步操作的代码
在异步操作的回调中,根据err变量来选择是执行resolve方法还是reject方法 调用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]);
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函数的函数名前面有一个"*"**
区别:
当我满心充满着自信和喜悦时,仿佛看到了面试官眉头一皱,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编码字符串后才能正常处理
常用的线性结构有:线性表,栈,队列,循环队列,数组 线性表中包括顺序表、链表等,其中:
其他
**如有不足,欢迎交流,祝各位看官 offer 拿到手软 O(∩_∩)O**
我的博客即将搬运同步至腾讯云+社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan