Web前端面试总结

2021-03-25  本文已影响0人  松_THOM

Const 定义常量

const定义对象里面的value是可以改变的,因为const是保证指针不变,修改属性的时候不会改变对象的指针

Session cookie token 的区别

session 是存在服务器上的,每个用户认证成功之后都会将session存在服务器内存中,用户量大的时候服务器的压力会增大

cookie不安全,存在客户端,可以被截取

token:登录成功之后,会对用户数据进行加密,生成加密token返回给客户端

Evevt Loop

1.同步任务和异步任务分别进入不同的执行“场所”,同步进入主线程,异步的进入EventTable然后注册函数

2. 当指定的事情完成之后,EventTable会将这个函数移入EventQueue 

3.主线程内的任务执行完毕为空,会去EventQueue读取对应的函数,注入主线程并执行,这个过程不断重复就是EventLoop

在js引擎中,有一个进程会不断检查主线程的执行情况

宏任务和微任务

1.存在微任务,就执行所有的微任务

2.微任务都执行完,执行下一个宏任务

图中没有画UI rendering的节点,因为这个是由浏览器自行判断决定的,但是只要执行UI rendering,它的节点是在执行完所有的microtask之后,下一个macrotask之前,紧跟着执行UI render。

JS 为什么要区分宏任务,微任务

为了插队。

一个Event Loop,Microtask 是在 Macrotask 之后调用,Microtask 会在下一个Event Loop 之前执行调用完,并且其中会将 Microtask 执行当中新注册的 Microtask 一并调用执行完,然后才开始下一次 Event loop,所以如果有新的 Macrotask 就需要一直等待,等到上一个 Event loop 当中 Microtask 被清空为止。由此可见, 我们可以在下一次 Event loop 之前进行插队

如果不区分 Microtask 和 Macrotask,那就无法在下一次 Event loop 之前进行插队,其中新注册的任务得等到下一个 Macrotask 完成之后才能进行,这中间可能你需要的状态就无法在下一个 Macrotask 中得到同步

状态的同步对于视图来说至关重要,这也就牵扯到了为什么 javascript 是单线程的原因所在

=>函数

1. 箭头函数的特性一:默认绑定外层this

上面提到:this的值是可以用call方法修改的,而且只有在调用的时候我们才能确定this的值。而当我们使用箭头函数的时候,箭头函数会默认帮我们绑定外层this的值,所以在箭头函数中this的值和外层的this是一样的。也就是默认指向在定义它时,它所处的对象,而不是执行时的对象,定义它的时候,可能环境是window

2. 箭头函数的特性二:不能用call方法修改里面的this

3.这表示多层对象嵌套里箭头函数里this是和最最外层保持一致的。

promise和async/await的区别

通过这两个图不难看出,若是在promise的.then中出现错误的话,外层的trycatch代码块是捕获不到错误的,所以就需要再加一层.catch,才能捕获到.then里面的报错,但是这样会显得代码有点冗余。而假如写成注释的async/await的格式,一个try/catch可以同时对同步以及异步进行错误处理,代码更加简洁。

1.使用async函数可以让代码简洁很多,不需要像Promise一样需要些then,不需要写匿名函数处理Promise的resolve值,也不需要定义多余的data变量,还避免了嵌套代码

2.错误处理方面更简单

3.async/await能够使得代码调试更简单。2个理由使得调试Promise变得非常痛苦:

①.不能在返回表达式的箭头函数中设置断点

②.如果你在.then代码块中设置断点,使用StepOver快捷键,调试器不会跳到下一个.then,因为它只会跳过异步代码。

使用await/async时,你不再需要那么多箭头函数,这样你就可以像调试同步代码一样跳过await语句。

事件委托

事件委托就是利用事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件

Event对象提供了一个属性叫target,可以返回事件的目标节点

列表,有4个li,里面的内容各不相同,点击li,event对象肯定是当前点击的对象,怎么指定到li上,下面我直接给解决方案

 var oUl = document.getElementById('test');

    oUl.addEventListener('click',function(ev){

        var target = ev.target;

        while(target !== oUl ){

            if(target.tagName.toLowerCase() == 'li'){

                console.log('li click~');

                break;

            }

            target = target.parentNode;

        }

    })

window的onload事件和domcontentloaded谁先谁后?

     一般情况下,DOMContentLoaded事件要在window.onload之前执行,当DOM树构建完成的时候就会执行DOMContentLoaded事件,而window.onload是在页面载入完成的时候,才执行,这其中包括图片等元素。大多数时候我们只是想在DOM树构建完成后,绑定事件到元素,我们并不需要图片元素,加上有时候加载外域图片的速度非常缓慢。

对Promise的理解

Promise是最早由社区提出和实现的一种解决异步编程的方案,比其他传统的解决方案(回调函数和事件)更合理和更强大。promise是为解决异步处理回调金字塔问题而产生的

原型链

所以当实例访问某个属性时,会先查找自己有没有,如果没有就通过__proto__访问自己构造函数的prototype有没有,前面说构造函数的原型是一个对象,如果原型对象也没有,就继续顺着构造函数prototype中的__proto__继续查找到构造函数Object()的原型,再看有没有,如果还没有,就返回undefined,因为再往上就是null了,这个过程就是我们熟知的原型链,说的再准确点,就是__proto__访问过程构成了原型链;

构造函数不需要显示的返回值。使用new来创建对象(调用构造函数)时,如果return的是非对象(数字、字符串、布尔类型等)会忽而略返回值;如果return的是对象,则返回该对象(注:若return null也会忽略返回值)。

typeOf 和instanceOf的区别

instanceof

instance中文翻译为实例,因此instanceof的含义就不言而喻,判断该对象是谁的实例,同时我们也就知道instanceof是对象运算符。这里的实例就牵扯到了对象的继承,它的判断就是根据原型链进行搜寻,在对象obj1的原型链上如果存在另一个对象obj2的原型属性,那么表达式(obj1 instanceof obj2)返回值为true;否则返回false。

new和instanceof的内部机制

For in 和for of 的区别

foreach 正常不可以终端遍历过程。可以抛除一个异常终止循环。用some 和 every 可以轻松实现。

for...in 语句用于遍历数组或者对象的属性(对数组或者对象的属性进行循环操作)

for in得到对对象的key或数组,字符串的下标

for of和forEach一样,是直接得到值

for of不能对象用

Thunk 函数的含义

flex-grow和flex-shrink属性有什么用?

首先是   flex-basis  ,basis英文意思是<主要成分>,所以他和width放在一起时,肯定把width干掉,basis遇到width时就会说我才是最主要的成分,你是次要成分,所以见到我的时候你要靠边站。

其次是   flex-grow,grow英文意思是<扩大,扩展,增加>,这就代表当父元素的宽度大于子元素宽度之和时,并且父元素有剩余,这时,flex-grow就会说我要成长,我要长大,怎么样才能成长呢,当然是沿着主轴分享父元素的空间了

比如剩余空间为 x =150px,三个元素的 flex-grow 分别为 a,b,c。设 sum 为 a + b + c。那么三个元素将得到剩余空间分别是 x * a / sum, x * b / sum, x * c / sum 相当于权重

当所有元素的 flex-grow 之和小于 1 的时候(注意是 1,也就是说每个元素的 flex-grow 都是一个小数如 0.2 这样的),上面式子中的 sum 将会使用 1 来参与计算,而不论它们的和是多少。也就是说,当所有的元素的 flex-grow 之和小于 1 的时候,剩余空间不会全部分配给各个元素。

实际上用来分配的空间是 sum(flex-grow) / 1 * 剩余空间,这些用来分配的空间依然是按 flex-grow 的比例来分配。

还是上面一个例子,但是三个元素的 flex-grow 分别是 0.1,0.2,0.3,那么计算公式将变成下面这样:

150 * 0.1 / 1 = 15px

150 * 0.2 / 1 = 30px

150 * 0.3 / 1 = 45px

150px - 15px - 30px - 45px = 60px,即还有 60px 没有分配给任何子元素。

三个元素的最终宽度分别为:

A的宽度为A.width+15px

B的宽度为A.width+15px

C的宽度为A.width+15px

另外,flex-grow 还会受到 max-width 的影响。如果最终 grow 后的结果大于 max-width 指定的值,max-width 的值将会优先使用。同样会导致父元素有部分剩余空间没有分配。

 flex-shrink

该属性用来设置,当父元素的宽度小于所有子元素的宽度的和时(即子元素会超出父元素),子元素如何缩小自己的宽度的。 flex-shrink的默认值为1,当父元素的宽度小于所有子元素的宽度的和时,子元素的宽度会减小。值越大,减小的越厉害。如果值为0,表示不减小。

举个例子:

父元素 500px。三个子元素分别设置为 150px,200px,300px。

三个子元素的 flex-shrink 的值分别为 1,2,3。

首先,计算子元素溢出多少:150 + 200 + 300 - 500 = -150px。

那这 -150px 将由三个元素的分别收缩一定的量来弥补。

具体的计算方式为:每个元素收缩的权重为其 flex-shrink 乘以其宽度。

所以总权重为 1 * 150 + 2 * 200 + 3 * 300 = 1450

三个元素分别收缩:

150 * 1(flex-shrink) * 150(width) / 1450 = -15.5

150 * 2(flex-shrink) * 200(width) / 1450 = -41.4

150 * 3(flex-shrink) * 300(width) / 1450 = -93.1

三个元素的最终宽度分别为:

150 - 15.5 = 134.5

200 - 41.4 = 158.6

300 - 93.1 = 206.9

同样,当所有元素的 flex-shrink 之和小于 1 时,计算方式也会有所不同:

此时,并不会收缩所有的空间,而只会收缩 flex-shrink 之和相对于 1 的比例的空间。

还是上面的例子,但是 flex-shrink 分别改为 0.1,0.2,0.3。

于是总权重为 145(正好缩小 10 倍,略去计算公式)。

三个元素收缩总和并不是 150px,而是只会收缩 150px 的 (0.1 + 0.2 + 0.3) / 1 即 60% 的空间:90px。

每个元素收缩的空间为:

90 * 0.1(flex-shrink) * 150(width) / 145 = 9.31

90 * 0.2(flex-shrink) * 200(width) / 145 = 24.83

90 * 0.3(flex-shrink) * 300(width) / 145 = 55.86

三个元素的最终宽度分别为:

150 - 9.31 = 140.69

200 - 24.83 = 175.17

300 - 55.86 = 244.14

当然,类似 flex-grow,flex-shrink 也会受到 min-width 的影响。

Http请求中的keep-alive

在http早期,每个http请求都要求打开一个tpc socket连接,并且使用一次之后就断开这个tcp连接。

使用keep-alive可以改善这种状态,即在一次TCP连接中可以持续发送多份数据而不会断开连接。通过使用keep-alive机制,可以减少tcp连接建立次数,也意味着可以减少TIME_WAIT状态连接,以此提高性能和提高httpd服务器的吞吐率(更少的tcp连接意味着更少的系统内核调用,socket的accept()和close()调用)。

但是,keep-alive并不是免费的午餐,长时间的tcp连接容易导致系统资源无效占用。配置不当的keep-alive,有时比重复利用连接带来的损失还更大。所以,正确地设置keep-alive timeout时间非常重要。

上一篇下一篇

猜你喜欢

热点阅读