快毕业了搞一些面试题刷一刷,自己不会的会总结在这里,每个问题我会附上让我理解对应知识点的文章,便于以后查看,如果还能帮助到铁子们那就更好了。
CSS
- position属性
static: 正常流,默认值
relative: 相对定位,相对于正常流,也就是相对于本来就应存在的位置
absolute: 绝对定位,相对于第一个不是static的父元素
fixed: 绝对定位,相对于浏览器窗口 - 当padding,margin的值是百分比时,是按照父类的宽度为参照的
- 块级元素、行内元素
块级元素默认占据一整行,display: block
行内元素不可设置height和width,大小由内容撑开,margin和padding只有left和right有效,不可包含块级元素,display: inline
display: inline-block,可设置宽高,margin和padding都有效的行级元素 - 引用dalao文章,水平垂直居中的方法
js
- apply、call方法和argument的用法,看这篇就够了
- 自己实现new操作符
new操作符的四个动作- 新建一个对象obj
- 设置原型链
- 将构造函数this指向obj并执行构造函数体
- 判断第三步的结果是否为引用值,如果是引用值则返回这个值,反之则返回obj
模仿这四个动作自己实现new操作符如下,引用的下面的文章 , 聊聊 new 操作符
function create(Con, ...args) {
let obj = {}
Object.setPrototypeOf(obj, Con.prototype)
let result = Con.apply(obj, args)
return result instanceof Object ? result : obj
}
- Eventloop
下面的执行顺序是什么?有问题看这篇描述
答案:1、7、6、8、2、4、3、5、9、11、10、12
//主线程直接执行
console.log('1');
//丢到宏事件队列中
setTimeout(function() {
console.log('2');
process.nextTick(function() {
console.log('3');
})
new Promise(function(resolve) {
console.log('4');
resolve();
}).then(function() {
console.log('5')
})
})
//微事件1
process.nextTick(function() {
console.log('6');
})
//主线程直接执行
new Promise(function(resolve) {
console.log('7');
resolve();
}).then(function() {
//微事件2
console.log('8')
})
//丢到宏事件队列中
setTimeout(function() {
console.log('9');
process.nextTick(function() {
console.log('10');
})
new Promise(function(resolve) {
console.log('11');
resolve();
}).then(function() {
console.log('12')
})
})
-
原型,原型链和继承
在js中每个对象都有一个__proto__属性,指向它的原型对象。每个函数都有一个prototype属性(只有函数才有prototype属性),这是一个指针,指向一个对象,就是通过调用构造函数而创建的那个对象实例的原型对象。其中原型对象会自动获得一个constructor属性,这个属性指向prototype属性所在的指针。(hh看着有点绕)
看看这篇文章可以理解原型和原型链 我对js原型和原型链的理解
这篇里有很多继承的实现方式JS原型链和继承别再被问倒了 -
如何准确判断this指向问题
1.如果使用new操作符,指向新创建的对象
2.如果函数使用call、apply、或bind绑定了对象,this指向这个对象,如果传入的是null或undefined,则指向全局对象(不严格模式,严格模式指向undefined)
3.如果函数在上下文对象调用(XXX.fn())则指向上下文对象
4.箭头函数中this继承上层代码块的this
5.如都没有使用上述则指向全局对象(不严格模式,严格模式指向undefined)嗨,你真的懂this吗?
//这个题能得出和控制台一样的答案this就盘的明明又白白了,引用自上面的文章,答案和分析在里面 -。-
var number = 5;
var obj = {
number: 3,
fn: (function () {
var number;
this.number *= 2;
number = number * 2;
number = 3;
return function () {
var num = this.number;
this.number *= 2;
console.log(num);
number *= 3;
console.log(number);
}
})()
}
var myFun = obj.fn;
myFun.call(null);
obj.fn();
console.log(window.number);
-
箭头函数特点
1.this继承上层结构体
2.不可以使用arguments对象,该对象在箭头函数体内不存在。如果要用,可以用 rest 参数代替
3.箭头函数没有自己的this,所以不能用call()、apply()、bind()这些方法去改变this的指向
4.不可被用作构造函数,也就是不能被new操作符调用
5.不可以使用yield命令,因此箭头函数不能用作 Generator 函数。 -
防抖节流
场景:用于解决平时开发中遇到输入框监听或是浏览器滚动监听函数中有复杂操作时造成卡顿的问题。
防抖:每当函数执行时设置一个定时器,过了等待时间才执行,如果这段时间又触发了函数则刷新时间重新等待。(持续触发函数时,执行最后一次)js防抖和节流
节流:规定一段时间内只执行一次目标函数。
//debounce(防抖)
function debounce(fn,wait) {
let timer = null
return function (){
if(!!timer) clearTimeout(timer);
timer = setTimeOut(()=>{fn},wait)
}
}
//throttle(节流)
//时间戳
function throttle(fn,wait) {
let prev = Date.now()
return function (){
let now = Date.now()
if(now - prew > wait){
fn
prev = Date.now()
}
}
}
//定时器
function throttle(fn,wait) {
let timer = null
return function (){
if(!timer){
setTimeOut(()=>{
fn
timer = null
},wait)
}
}
}
- 作用域问题
建立一个函数,3秒后输出数组的所有元素。这个问题其实是结合了闭包和作用域两部分知识点
//1.使用let
let arr = [1,2,3,4,5]
function test(arr) {
for(let i=0;i<arr.length;i++){
setTimeout(()=>{
console.log(arr[i])
},3000)
}
}
test(arr)
/**for循环中i若使用var定义则会输出5个5,因为setTimeout会将任务创建到宏任务队列尾部,
也就是说要先执行完for循环才会执行console,由于var是跨作用域创建变量,所以相当于在5个for循环作用域中使用的
是同一个变量i,所以for执行完后i会变成4。而let则是只存在于当前块级作用域中,不会被其他for循环使用,也就没有
这个问题了。
*/
//2.使用var和自执行函数,新建函数作用域将变量保存住
let arr = [1,2,3,4,5]
function test(arr) {
for(var i=0;i<arr.length;i++;){
(function (lockI){
setTimeout(()=>{
console.log(lockI)
},3000)
}(arr[i]))
}
}
test(arr)
- 深拷贝
浅拷贝只是简单的将对象在栈中存储的引用地址拷贝,而指向的堆中的数据还是原对象数据,所以浅拷贝出的对象值被修改,原对象的值也会被修改。下面有两种实现深拷贝的方式。(没有考虑null和undefined)
//1.
JSON.parse(JSON.stringify(obj))
//2.
function test(aaa) {
let result
if(typeof aaa ==='object') {
//判断是不是基本类型
result = Array.isArray(aaa)?[]:{}
for(let i in aaa){
result[i] = typeof aaa[i] ==='object' ? test(aaa[i]) : aaa[i]
}
}else {
//基本类型直接赋值
result = aaa
}
return result
}
- 事件委托
简单的来说,事件委托就是利用js事件冒泡的特性,将内层元素的事件委托给外层处理,网上有个例子描述得特别到位:一个公司有很多个员工,每天都会有快递,如果快递到的时候每个要收快递的员工都去公司门口收,那门口就被堵住了,就算没被堵住,这样的操作效率也不高,所以有人就想,为什么不把快递委托给前台收呢?? 这样就可以不用每个人在上班时间都跑出来收了,节约了人力和时间成本,前台收到了快递再根据快递上的信息找到每个员工就行了,就算有新员工来,前台也照样可以根据信息找到他,这样也免去了新员工因为不熟悉环境而收不到快递的情况,简直一举多得 事件委托
浏览器
- 从输入URL到页面展示,发生了什么
1.DNS解析 DNS解析过程
2.返回域名对应的ip地址
3.进行tcp三次握手
4.发送http请求
5.服务端处理请求并返回http报文
6.浏览器渲染- HTML parser --> DOM Tree 标记化算法,进行元素状态的标记
- dom 树构建CSS parser --> Style Tree 解析 css 代码,生成样式树
- attachment --> Render Tree 结合 dom树 与 style树,生成渲染树
- layout: 布局
- GPU painting: 像素绘制页面
- 跨标签页通讯方式
1.通过postMessage,通过window.open或iframe打开的窗口,可通过postMessage发送消息,通过监听message可收到消息
2.通过localStorage和window.onStorage设置和获取共享消息(重复设置相同localStorage无法监听到,受到浏览器隐身模式限制)
3.通过设置cookie共享消息,setInterval轮询查询获取cookie值
4.借助服务端 - 事件循环
浏览器有宏任务队列macrotask(task)和微任务队列microtask(jobs)
先执行宏任务,执行完一个宏任务会清空微任务队列,再执行下一个宏任务
宏任务创建:setTimeOut、setInterval、script标签、setImmediate、UI render、I/O
微任务创建:promise、ajax、process.nextTick、Async/Await、MutationObserver - 本地存储
主要有cookie(NAME=VALUE、Path、Domain、Secure、Expires)、localStorage和sessionStorage。
推荐文章深入理解Cookie、本地存储小结
cookie描述
区别:- cookie大小限制4k,local和session则是5M,IE是10M。
- cookie可设置过期时间,localStorage如果不手动删除永远不会过期,sessionStorage在窗口关闭时删除。
- V8垃圾回收机制
chrome浏览器的垃圾回收机制
垃圾回收:将不再使用的内存空间释放。
JavaScript 引擎会通过向下移动 ESP(记录当前执行状态的指针) 来销毁该函数保存在栈中的执行上下文。
V8引擎将堆内存空间分为新生代(存放存活时间短的对象)和老生代(老生代空间存放存活时间长的对象)两部分。
新生代空间回收过程:Scavenge 算法,将新生代空间对半分为两个空间,对象空间和空闲空间。对象空间中存活对象 复制到空闲空间,清空对象空间,然后将对象空间和空闲空间反转。执行了两次此过程还存活的对象会提升到老生代空间中。
老生代空间回收过程:标记 - 清除(Mark-Sweep)算法,递归标记存活的对象,未被标记的会被释放。再进行压缩算法: 将内存中清除后导致的碎片化对象往内存堆的一端移动,解决 内存的碎片化。 - 内存泄漏
内存泄漏指已经不需要使用的对象无法被垃圾回收机制释放的情况。闭包,超出dom引用,未被及时关闭的定时器、事件监听、全局变量都会引起内存泄漏。 - get和post的区别
- get请求在url中,post请求在请求体中
- get请求会被浏览器缓存,post不会
- get请求不安全,暴露在url中
- get请求浏览器后退不会重发,post会
- get请求受url长度限制
- get请求发送一个tcp数据包,post发送两个tcp数据包对于GET方式的请求,浏览器会把http header和data一并发送出去,服务器响应200(返回数据);而对于POST,浏览器先发送header,服务器响应100 continue,浏览器再发送data,服务器响应200 ok(返回数据)
http
- tcp/ip三次握手四次挥手的问题 面试官,不要再问我三次握手和四次挥手的问题了
- 为什么三次,两次握手不可以吗
- 什么是半连接队列
- 什么是SYN攻击,怎么预防
- 挥手为什么四次
- 为什么等到2MSL客户端才会close
- tcp流量控制和拥塞处理
- 流量控制:滑动窗口协议,控制发送方发送速度,接收方在发送ACK确认时发送自己的接受窗口大小,从而控制发送方的发送速度。
- 拥塞处理:1(慢启动和拥塞避免算法)2(快速重传和快速恢复算法)tcp流量控制和拥塞控制