前端

选择题 1:

对于一条100M的宽带,理论下载速度上限是多少?
A. 12.5MB/s
B. 100MB/s
C. 10MB/s
D. 10Mb/s

答:A 速率我记得是1Mbps=128KB/s ,简单做个乘法就是100mbps= 12800(KB/s) / 1024 = 12.5MB/s

选择题 2:

关于 for of 和 for in 的描述,正确的是?
A. for in 可以循环普通对象
B. for of 可以循环普通对象
C. 都不可以循环数组
D. 都可以循环数组

答:AD ,知识盲点,来记一下。

for...of 是ES6中为了SetMap的引入的所诞生的循环模式,为了解决传统forfor...in遍历结构问题而生的。

/*
*	这是一个遍历对象的代码片段
* for...of会给出报错 而 for...in可以正常返回。
*/
const obj = {a:1,b:2,c:3}
for( var o in obj){
	console.log(o); //a,b,c
	console.log(obj[o]); //1,2,3
}
for(var o of obj){
	console.log(o); //Uncaught TypeError: obj is not iterable
}

可以看到for...in的返回是对象中的属性名,而for...of会直接给出报错:XXX不可迭代,很明显for...of不能用循环普通对象,只能对实现了iterable(迭代器)接口的对象遍历,这是第一个区别。

/*
*	这是一个遍历数组的代码片段
* for...of可以正常返回number 而 for...in 也能返回,但却是输出了字符串类型
*/
const arr = [0,1,2,3,4]
for( var o in arr){
	console.log(o); //'0','1','2','3','4'
	console.log(arr[o]) //0,1,2,3,4
}
for(var o of arr){
	console.log(o); //0,1,2,3
}

可以看到for...in的默认返回是字符串值,需要代入arr[]才能正常输出,而for...of默认给出value值,所以通常情况下,for...in 适合用于遍历对象,而for..of则适合用于实现迭代器接口的对象,如数组/字符串/map/set。这是第二个区别。

选择题3:

关于事件冒泡描述正确的是?
A. 从目标元素向 document 冒泡
B. 从 document 向目标元素冒泡
C. 从 document 向目标元素冒泡,再从目标元素向 document 冒泡
D. 以上都不是

答:A 这是一道事件流的问题,也算是知识盲点,记一下笔记:

DOM事件流是一个传导机制,可分为三个触发阶段,事件捕获 -> 目标元素 -> 事件冒泡

捕获流由网景提出,是从页面结构最外面传递直到目标元素。

冒泡流是由微软IE提出,则是从目标元素向最外面传递。

element.addEventListener(event, function, useCapture)
Parameters:
      event	Required.
                  The name of the event.
                  Do not use the "on" prefix.
                  Use "click" not "onclick".
      function	Required.
                  The function to run when the event occurs.
      useCapture	Optional (default = false).
                  false - The handler is executed in the bubbling phase.
                  true - The handler is executed in the capturing phase.

后来在W3C推动下合并了俩者设计,这里直接用addEventListener()来演示。

<head>
    <style>
        body {width: 100%;height: 100%;background-color: darksalmon;}
        #lv1 {width: 800px;height: 400px;background-color: crimson;}
        #lv2 {width: 600px;height: 300px;background-color: gold;}
        #lv3 {width: 400px;height: 200px;background-color: darkorange;}
    </style>
</head>
<body>
    <script>
        /*
         *  这是一段测试事件流的代码片段
         *  当注册捕获时,点击lv3,消息顺序:#document->#body->#lv1->#lv2->#lv3
         *  当注册冒泡时,点击lv3,消息顺序:#lv3->#lv2->#lv1->#body->#document
         */
  window.onload = () => {
         var lv1 = document.getElementById('lv1');
         var lv2 = document.getElementById('lv2');
         var lv3 = document.getElementById('lv3');
         //事件捕获
         document.addEventListener('click', (e) => {console.log(e.currentTarget);}, true);
         document.body.addEventListener('click', (e) => {console.log(e.currentTarget);}, true);
         lv1.addEventListener('click', (e) => {console.log(e.currentTarget);}, true);
         lv2.addEventListener('click', (e) => {console.log(e.currentTarget);}, true);
         lv3.addEventListener('click', (e) => {console.log(e.currentTarget);}, true);
         //事件冒泡
         lv1.addEventListener('click', (e) => {console.log(e.currentTarget);}, false);
         lv2.addEventListener('click', (e) => {console.log(e.currentTarget);}, false);
         lv3.addEventListener('click', (e) => {console.log(e.currentTarget);}, false);
         document.body.addEventListener('click', (e) => {console.log(e.currentTarget);}, false);
         document.addEventListener('click', (e) => {console.log(e.currentTarget);}, false);
    };
    </script>
    <div id="lv1">
        <div id="lv2">
            <div id="lv3">点我立即升仙!</div>
        </div>
    </div>
</body>

​ 效果:

参考资料

浅谈事件冒泡和事件捕获 - 知乎 (zhihu.com)

选择题4:

以下哪些 script 标签属性会使脚本有可能在 DOMContentLoaded 事件之后加载?
A. <script async>
B. <script defer>
C. <script type="module">
D. <script type="module" async>

答: A D

DomContentLoadedLoad有些相似,但是前者状态发生在后者之前。说明文档的子资源还未完成加载。

description readyState
/ 文档还在加载 loading
DOMContentLoaded 文档加载完,还需要等待样式表、图像、子框架 interactive
Loaded 所有资源完成加载 complete

一般来说,脚本代码会在ContentLoaded前和文档加载前同步完成,但实际环境中脚本代码一般要依靠cdn外链来引入,那么当cdn连接出现问题,或者下载很慢,页面加载就会被阻塞,导致了页面空白或区域加载失败。在早期的web设计里,甚至有一个著名的倡导原则叫:把脚本代码放在body底部。为了改变这种不合理的情况,后来就为script标签增加了deferasync这两个属性来启用异步加载脚本。

script description
/ 和页面同步加载,按照标签顺序先后执行
defer 异步加载,但脚本会根据 script 标签顺序先后执行,保证在DOMContentLoaded前完成
async 异步加载,脚本每个都会在下载完成后立即执行(谁先加载完谁先来),无关 script 标签出现的顺序,有可能在DomContentLoaded前也有可能在这之后

随着JS规范的发展,ES6引入了模块化,通过export导入和import引入来加载需要的代码部分,当在DOM需要引入模块时,可以在scipt标签上添加 type="module"的属性。如:

<script type="module" src="module.js" async></script> 
<script type="module">
import {sum} from './example.js'; 
let res = sum(1,2);
</script>
scirpt description
type=module 异步加载,效果等同于defer
type=module async 异步加载,效果等同于async

参考资料

(DOMContentLoaded_安歌的博客的博客-CSDN博客_domcontentloaded

(5条消息) 详解 script 标签中 defer 和 async_zhangpaopao0609的博客-CSDN博客

后端

选择题 1:

Go 中关于整型切片的初始化,以下正确的是?
A. s := []int{1, 2, 3, 4, 5}
B. s := make([]int)
C. s := make([]int, 0)
D. s := make([]int, 5, 10)

答:A C D

看来后端的内容是靠偏Go的,这题考验的是Go的语法。

参考资料:

(5条消息) Go语言切片详解_JIeJaitt的博客-CSDN博客_go 切片

选择题 2:

以下哪些操作可能触发本地 CPU cache 失效?
A. 本地读取
B. 本地写入
C. 远端读取
D. 远端写入

答D

这里的选项其实来自于计算机组成中本地CPUcache读写的MESI缓存一致性协议的概念。

现代CPU基本都是多核心的情况下,CPU指令与内存间要进行读写交互,每一个核心都有(二级或三级)高速缓存架构,而CPU与内存间的交互必须通过高速缓存,高速缓存是CPU和内存之间的临时中转站(局部性原理)。

这就引申出来俩个问题,这就是缓存一致性的问题:

如何保证在当前核心cache被读写修改后,内存里的数据和缓存的数据一样?

如何保证当前核心的缓存被修改后和其他核心的缓存中包含的数据能保持一样?

为了解决这个问题,渐渐产生了MESI协议。它将每个缓存块添加了四个状态(2bit),分别是M 修改,E独享,S共享,I无效。通过这四个状态实现了一套缓存读写的事务管理,限定了缓存块的具体有效性,如:

当多核心的共享数据被CPU核心要求修改时,会先广播请求获得所有权,并将其他CPU核心的缓冲块设置为失效。而MESI的触发事件分为四种即本地(指的是所有权核心的cache)读取、本地写入、远端(指的是其他核心cache)读取、远端写入。而当远端写入触发时,就会将其他共享数据的核心cache设为失效。

这块是CS61C… 上学期遇见一些事摆烂没去看了,好吧这学期一定要看一看。

参考资料:

Cache Policies

7个示例科普CPU Cache | 酷 壳 - CoolShell

12 张图看懂 CPU 缓存一致性与 MESI 协议,真的一致吗? - 简书 (jianshu.com)