玄武笔试综合问答题

137 阅读4分钟

1. 一次完整的 HTTP 事务是怎样的过程? 1. 读取缓存:搜索自身的 DNS 缓存。(如果 DNS 缓存中找到IP 地址就跳过接下来解析域名的操作,直接访问该 IP 地址) 2. DNS解析:将域名解析成IP地址 3. TCP连接:三次握手,简述过程如下: 1. 客户端:服务端你在么?(客户端向服务端发起一个 syn (同步)信号,这个信号携带着客户端的一些编号信息) 2. 服务端:客户端我在,你要连接我么?(服务端向客户端回复一个 ack (响应)信号,同时也发一个 syn (同步)信号给客户端) 3. 客户端:对的服务端,我要连接。(客户端收到服务端回复的信息后,再向服务端发一个 ack 信号) 连接打通,可以开始请求.... 4. 发送HTTP请求 5. 服务器处理请求并返回HTTP报文 6. 浏览器解析渲染页面 7. 断开连接:TCP四次挥手,简述如下: 1. 客户端向服务端发起 FIN 信号,说要断开连接; 2. 服务端向客户端回复一个 ack 信号,说我收到了你的请求,但是我这边还有一些数据处理收尾工作,等我处理完了再告诉你; 3. 服务端向客户端发起一个 FIN 信号,说我这边可以了,现在我们断开连接吧; 4. 客户端向服务端发起一个 ack 信号,告诉服务端确认,到此连接就断开了。 注意: 关于第 6 步浏览器解析渲染页面,可以聊聊如果返回的是html页面 1. 根据 HTML 解析出 DOM 树 2. 根据 CSS 解析生成 CSS 规则树 3. 结合 DOM 树和 CSS 规则树,生成渲染树 4. 根据渲染树计算每一个节点的信息 5. 根据计算好的信息绘制页面 拓展问题: 1. 三次握手,为啥要三次,两次不行么? - 第二步收到第一步的信息:说明了客户端有数据发送能力,服务端有数据接收能力; - 第三步收到第二步的信息:说明了客户端有数据接收能力,服务端有数据发送能力; 2. 三次握手,哪个阶段可以携带数据 / 能不能携带数据? 前两次不能携带数据,第三次可以携带数据。 3. 前两次为什么不能携带数据,如果真的带了有什么危害? 前两次仅仅是进行连接握手的操作,此时连接还没有完全打通,携带数据 1. 可能因为连接没有实现而浪费; 2. 会造成syn攻击,syn攻击就是在连接阶段携带数据让服务器处理,那么大量的请求进来,在没有进行真正的业务处理之前就耗费大量的资源直至计算机资源耗尽。 4. 什么叫半连接,什么叫全连接? - 半连接:进行了前两步的操作叫半连接,在握手进行第二步完成后,会把当前这个连接放入连接池,等待连接完全建立,如果连接最终没有建立,那么再销毁这个半连接 - 全连接:完整进行了三次握手的连接称为全连接。 #### 2. 是否了解 Vuex 或者 Redux?说一说它们使用的场景以及解决了哪些痛点? #### 3. 实现快速排序算法 javascript var quickSort = function(arr) { if (arr.length <= 1) return arr let left = [], right = [] let baseDot = Math.floor(arr.length / 2) let base = arr.splice(baseDot, 1)[0] for (let i = 0; i < arr.length; i++) { if (arr[i] < base) { left.push(arr[i]) } else { right.push(arr[i]) } } return quickSort(left).concat([base], quickSort(right)) } console.log(quickSort([1,21,5,32,54,82,15,2])); 实现一个 quickSort 的封装,并且定义数组 left 和 right,找到数组 arr 的基准点 baseDot 和对应的基数 base,然后遍历数组的每一项和 base 进行对比,最后递归调用,给出一个跳出条件 javascript if (arr.length <= 1) return arr #### 4. 如何优化网站?有哪些具体方法和措施? #### 5. 谈谈 JSONP 的使用场景? - ##### jsonp 的原理 jsonp,即 json + padding,动态创建 script 标签,利用 script 标签的 src 属性可以获取任何域下的 js 脚本,通过这个特性(也可以说漏洞),服务器端不再返回 json 格式,而是返回一段调用某个函数的 js 代码,在 src 中进行了调用,这样实现了跨域。 - ##### 应用场景 在网上经常看到别人的 blog 中在用 jsonp 模仿 360 和百度进行跨域拿数据,这两者就是典型的跨域请求案例。又比如在近期开发中前端部分用的是 vue.js 进行开发,所以跟后台进行交互的时候就可以通过跨域进行通信,正好用的 jsonp (折腾 一番之后,最终没有用这种方式,后面会说到),另外,qq空间大部分用的都是jsonp。 - ##### 优缺点 - 优点:完美解决了在测试或者开发中获取不同域下的数据,用户传递一个 callback 参数给服务端,然后服务端返回数据时会将这个 callback 参数作为函数名来包裹住 JSON 数据,这样客户端就可以随意定制自己的函数来自动处理返回数据了。简单来说数据没有发生很大变化。 - 缺点: 1. 安全性:JSONP 会从其它域加载 JavaScript 脚本并直接执行,如果 JavaScript 脚本中包含恶意攻击代码,那我们的网站将会受到威胁。所以当我们访问非自己维护的服务器的 JSONP 接口时,需要留心。 2. 出错处理:script 标签的 onerror 函数在 HTML5 才定义,并且即使我们定义了 onerror 处理函数,我们也不容易捕捉到错误发生的原因。 #### 6. 谈谈 reflow 和 repaint - reflow(回流):DOM 树结构发生变化,要重新构建,之后要重新渲染;(一定会伴随重绘) - repaint(重绘):DOM 树没发生变化,渲染树变化,重新渲染页面; 注意: - display 为 none 的元素在页面不需要渲染,渲染树构建不会包括这些节点;(脱离文档流) - visibility 为 hidden 的元素会在渲染树中。visibility 为 hidden 就类似于透明度为 0,其实还在文档流中,还是有渲染的过程。 拓展问题: 1. 哪些行为会引起回流,怎么去减少呢? - DOM的增删行为 比如你要删除某个节点,给某个父元素增加子元素,这类操作都会引起回流。如果要加多个子元素,最好使用 documentfragment。 - 几何属性的变化 比如元素宽高变了,border变了,字体大小变了,这种直接会引起页面布局变化的操作也会引起回流。如果你要改变多个属性,最好将这些属性定义在一个class中,直接修改class名,这样只用引起一次回流。 - 元素位置的变化 修改一个元素的左右 margin,padding 之类的操作,所以在做元素位移的动画,不要更改 margin 之类的属性,使用定位脱离文档流后改变位置会更好。 - 获取元素的偏移量属性 例如获取一个元素的 scrollTop、scrollLeft、scrollWidth、offsetTop、offsetLeft、offsetWidth、offsetHeight 之类的属性,浏览器为了保证值的正确也会回流取得最新的值,所以如果你要多次操作,最取完做个缓存。 - 页面初次渲染 无法避免。 - 浏览器窗口尺寸改变 resize事件发生也会引起回流。 - .... #### 7. 常见的 HTTP 状态码有哪些?分别代表含义 - 200:请求成功; - 301:重定向,所请求的页面已经转移到新的 URL。 - 304:重定向,服务器告诉客户,原来缓冲的文档还可以继续使用。 - 400:客户端错误,语法错误,服务器未能理解请求。 - 404:客户端错误,服务器无法找到被请求的页面。 - 500:服务器错误,请求未完成,服务器遇到不可预知的情况。 - 501:服务器错误,请求未完成,服务器不支持所请求的功能,或者服务器无法完成请求。 #### 8. 什么是跨域? 在 HTML 中,<a>, <form>, <img>, <script>, <iframe>, <link> 等标签以及 Ajax 都可以指向一个资源地址,而所谓的跨域请求就是指:当前发起请求的域与该请求指向的资源所在的域不一样。这里的域指的是这样的一个概念:我们认为若协议 + 域名 + 端口号均相同,那么就是同域。 #### 9. 解释下 js 中 this 是如何工作的? 简单说,this就是指当前函数的运行环境。由于JavaScript支持运行环境的动态切换,所以this的指向是动态的。 所谓“运行环境”其实就是对象。可以理解成,this指函数运行时所在的那个对象。 ###### this在不同情况下,指向各不相同 - 全局环境 / 函数调用 在全局环境使用 this,它指的就是顶层对象 window。(不管是不是在函数内部,只要是在全局环境下运行,this 就是指全局对象 window) javascript console.log(this === window) // true function f() { console.log(this === window); // true } f(); - 构造函数 构造函数中的this,指的是实例对象。 javascript var O = function(p) { this.p = p; }; O.prototype.m = function() { return this.p; }; var a = new O("a"); console.log (a.p); // a console.log (a.m()); // a 上面代码定义了一个构造函数 O。由于 this 指向实例对象,所以在构造函数内部定义 this.p,就相当于定义实例对象有一个 p 属性;然后 m 方法可以返回这个 p 属性。 - 方法调用 当 a 对象的方法被赋予 b 对象,该方法就变成了普通函数,其中的 this 就从指向 a 对象变成了指向 b 对象。这就是 this 取决于运行时所在的对象的含义,所以要特别小心。如果将某个对象的方法赋值给另一个对象,会改变 this 的指向。 javascript var o1 = new Object(); o1.m = 1; o1.f = function () { console.log(this.m); } o1.f() // 1 var o2 = new Object(); o2.m = 2; o2.f = o1.f o2.f() // 2 - Node.js 在 Node.js 中,this 的指向又分成两种情况: 1. 全局环境中,this 指向全局对象 global; 2. 模块环境中,this 指向 module.exports。 #### 10. 描述一下 cookies,sessionStorage,localStorage 的区别? - 相同点:都是保存在浏览器端的、同源的 - 不同点: - sessionStorage:仅在当前浏览器窗口关闭之前有效; localStorage:始终有效,窗口或浏览器关闭也一直保存,本地存储,因此用作持久数据; - cookie 数据始终在同源的 http 请求中携带(即使不需要),即 cookie 在浏览器和服务器间来回传递。 cookie 数据还有路径(path)的概念,可以限制 cookie 只属于某个路径下 sessionStorage 和 localStorage 不会自动把数据发送给服务器,仅在本地保存。 - 存储大小限制也不同,cookie 数据不能超过 4K,sessionStorage 和 localStorage 可以达到 5M - 作用域不同 sessionStorage:不在不同的浏览器窗口中共享,即使是同一个页面; localstorage:在所有同源窗口中都是共享的;也就是说只要浏览器不关闭,数据仍然存在; cookie: 也是在所有同源窗口中都是共享的.也就是说只要浏览器不关闭,数据仍然存在。 #### 11. 什么是闭包?什么场景需要用到? 我的理解:能访问父函数的参数并且能立即执行或者被直接return出来的函数为闭包。 **注意:**函数被执行时使用的作用域链(scope chain)是被定义时的作用域链,而不是执行时的作用域链。 javascript var scope = "global scope"; function checkScope() { var scope = "local scope"; function f() { return scope; } return f(); } checkScope(); // "local scope" 再看看下面的调用写法: javascript var scope = "global scope"; function checkScope() { var scope = "local scope"; function f() { return scope; } return f; } checkScope()(); // "这次返回什么?" checkScope 被调用时,将内部嵌套的函数 f 返回,因此 checkScope()() 这句执行时,其实运行的是 f(),f 函数返回scope 变量,在这种情况下,应该是从函数 checkScope 中寻找变量 scope,因为函数被执行时使用的作用域链(scope chain)是被定义时的作用域链。 ###### 应用场景 1. 通过循环给页面上多个 DOM 节点绑定事件 场景描述:假如页面上有 5 个 button,要给 button 绑定 onclick 事件,点击的时候,弹出对应 button 的索引编号。(循环给多个 button 绑定事件) html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <button>Button0</button> <button>Button1</button> <button>Button2</button> <button>Button3</button> <button>Button4</button> <script> var btns = document.getElementsByTagName('button'); for(var i = 0; i < btns.length; i++) { (function(i) { btns[i].onclick = function() { alert(i); } }(i)) } </script> </body> </html> 在闭包的作用下,定义事件函数的时候,每次循环的 i 值都被封闭起来,这样在函数执行时,会查找定义时的作用域链,这个作用域链里的 i 值是在每次循环中都被保留的,因此点击不同的 button 会 alert 出来不同的 i。 2. 封装变量 闭包可以将一些不希望暴露在全局的变量封装成“私有变量”。 假如有一个计算乘积的函数,mult 函数接收一些 number 类型的参数,并返回乘积结果。为了提高函数性能,我们增加缓存机制,将之前计算过的结果缓存起来,下次遇到同样的参数,就可以直接返回结果,而不需要参与运算。这里,存放缓存结果的变量不需要暴露给外界,并且需要在函数运行结束后,仍然保存。 所以可以采用闭包。 js var mult = (function() { var cache = {}; var calculate = function() { var a = 1; for(var i = 0, len = arguments.length; i < len; i++) { a = a * arguments[i]; } return a; } return function() { var args = Array.prototype.join.call(arguments, ','); if(args in cache) { return cache[args]; } return cache[args] = calculate.apply(null, arguments); } }()) 3. 延续局部变量的寿命 img对象经常用于数据上报,如下 js var report = function(src) { var img = new Image(); img.src = src; } report('http://xxx.com/getUserInfo'); 这段代码在运行时,发现在一些低版本浏览器上存在 bug,会丢失部分数据上报,原因是 img 是 report 函数中的局部变量,当 report 函数调用结束后,img 对象随即被销毁,而此时可能还没来得及发出 http 请求,所以此次请求就会丢失。 因此,我们使用闭包把 img 对象封闭起来,就可以解决数据丢失的问题: js var report = (function() { var imgs = []; return function(src) { var img = new Image(); imgs.push(img); img.src = src; } }()) **拓展:**立即执行函数有两种写法: javascript (function(i) { }(i)) javascript (function(i) { })(i) #### 12. null 和 undefined 的区别? undefined: 在 JavaScript 中, undefined 是一个没有设置值的变量。 typeof 一个没有值的变量会返回 undefined。 null: 在 JavaScript 中 null 表示 "什么都没有"。 null 是一个只有一个值的特殊类型,表示一个空对象引用。 区别: - undefined 表示一个变量没有被声明,或者被声明了但没有被赋值(未初始化),一个没有传入实参的形参变量的值为 undefined,如果一个函数什么都不返回,则该函数默认返回 undefined。null 则表示“什么都没有”,即“空值”。 - Javascript 将未赋值的变量默认值设为 undefined;Javascript 从来不会将变量设为 null。它是用来让程序员表明某个用var声明的变量时没有值的; - undefined 不是一个有效的 JSON,而 null 是; - null 和 undefined 的值相等,但类型不等:undefined 的类型 (typeof) 是 undefined;null 的类型 (typeof) 是 objectjavascript null == undefined // true null === undefined // false typeof undefined // undefined typeof null // object - null 和 undefined 之间的主要区别在于它们被转换为原始类型的方式。 在'null'上执行算术转换时,则值为 0,可以使用以下代码片段验证此转换。 javascript var v1 = 5 + null; console.log(v1) 执行时,此代码的将输出 5 但是,“undefined”不执行任何此类转换。如果您尝试将“undefined”添加到数字中,您将获得NaN或Not-a-Number。以下代码片段说明了“undefine”的这一方面。 javascript var v2 = 5 + undefined; console.log(v2) 执行时,代码将输出: NaN #### 13. 介绍下标准 css 盒子模型?与低版本的 IE 盒子模型有什么不同? 1. W3C 定义的盒子模型包括 margin、border、padding、content ,元素的 width / height = content 的宽度 / 高度; 2. IE 盒子模型与 W3C 的盒子模型唯一区别就是元素的宽度,元素的 width / height = content + padding + border; #### 14. Label 标签的作用?其中 for、accesskey 属性做什么的? 作用:用于绑定一个表单元素,当点击 label 标签的时候,被绑定的表单元素就会获得输入焦点。 for 属性: - 功能:表示 Label 标签要绑定的 HTML 元素,你点击这个标签的时候,所绑定的元素将获取焦点。 - 用法: html <label for = "InputBox">姓名</label> <input id = "InputBox" type="text"> accesskey 属性: - 功能:表示访问 Label 标签所绑定的元素的热键,当您按下热键,所绑定的元素将获取焦点。 - 用法: html <label for = "InputBox" accesskey = "N">姓名</label> <input id = "InputBox" type="text"> - 局限性:accesskey 属性所设置的快捷键不能与浏览器的快捷键冲突,否则将优先激活浏览器的快捷键。