一、背景
一面结束30min后HR打电话通知二面,但我想准备一下,于是约定两天后参加二面,以下为部分面试题。
二、简答题
- 怎样让一个元素上下左右居中?
假设父元素class为outside,子元素class为inside,如下:
1 .outside 2 position: relative 3 .inside 4 position: absolute 5 top: 50% 6 left: 50% 7 width: w = 150px 8 height: h = 80px 9 margin-left: -(w / 2) 10 margin-top: -(h / 2)
追问:如果子元素不设置宽高呢?
1 .outside 2 display: flex 3 .inside 4 justify-content:center 5 align-items:center;
- HTTP状态码304、400、401、500和503分别表示什么?
- 304:客户端发送了一个带条件的GET 请求且该请求已被允许,而文档的内容(自上次访问以来或者根据请求的条件)并没有改变,则服务器应当返回这个304状态码。
追问:怎么判断文档内容没有改变?
参考链接:https://blog.csdn.net/qq_37960324/article/details/83374855
客户端在请求一个文件的时候,发现自己缓存的文件有 Last Modified ,那么在请求中会包含 If Modified Since ,这个时间就是缓存文件的 Last Modified 。因此,如果请求中包含 If Modified Since,就说明已经有缓存在客户端。
服务端只要判断这个时间和当前请求的文件的修改时间就可以确定是返回 304 还是 200 。对于静态文件,例如:CSS、图片,服务器会自动完成 Last Modified 和 If Modified Since 的比较,完成缓存或者更新。但是对于动态页
面,就是动态产生的页面,往往没有包含 Last Modified 信息,这样浏览器、网关等都不会做缓存,也就是在每次请求的时候都完成一个 200 的请求。因此,对于动态页面做缓存加速,首先要在 Response 的 HTTP Header 中增
加 Last Modified 定义,其次根据 Request 中的 If Modified Since 和被请求内容的更新时间来返回 200 或者 304 。虽然在返回 304 的时候已经做了一次数据库查询,但是可以避免接下来更多的数据库查询,并且没有返回页面内
容而只是一个 HTTP Header,从而大大的降低带宽的消耗,对于用户的感觉也是提高。当这些缓存有效的时候,通过 Fiddler 或HttpWatch 查看一个请求会得到这样的结果:
第一次访问 200
按F5刷新(第二次访问) 304
按Ctrl+F5强制刷新 200
- 400:服务器无法理解请求的格式,客户端不应当尝试再次使用相同的内容发起请求。
- 401:请求未授权,对于需要登录的网页,服务器可能返回此响应。
- 500:最常见的服务器端错误。
- 503:服务器端暂时无法处理请求,可能是过载或维护。
3. 下面两段代码分别输出什么?
1 for(var i=0;i<3;i++){ 2 console.log(i); 3 setTimeout(function(){ 4 console.log(i); 5 },0) 6 }
输出:0 1 2 3 3 3
解释:setTimeout()是以异步的方式执行的。在执行for循环的时候,并不是执行一次for循环就立刻执行一次setTimeout(),而会让setTimeout()进入另一条线程进行等待,当主线程(这里就是for循环)执行完后,setTimeout()再依次
执行。当使用var声明变量时,i会在全局作用域中找到它的值,此时i为3。
1 for(let i=0;i<3;i++){ 2 console.log(i); 3 setTimeout(function(){ 4 console.log(i); 5 },0) 6 }
输出:0 1 2 0 1 2
解释:let和var不同,当使用let声明变量时,是有块级作用域的,let声明的i都会存在于for块级作用域中,每一次for循环都会生成一个块级作用域。
追问:如何修改第一段代码,使其定输出结果和第二段代码相同?
调用立即执行函数()()并传入参数
1 for(var i=0;i<3;i++){ 2 console.log('b'+i); 3 (function fun(i){ 4 setTimeout(function(){ 5 console.log(i); 6 },0) 7 })(i); 8 }
输出:0 1 2 0 1 2
4.谈谈本地储存的过程
参考链接:https://www.cnblogs.com/captainMforlife/p/11288424.html
本地存储主要有:cookie、localStorage和sessionStorage。利用本地存储,把一部分数据保存在客户端,减少对服务器的请求,降低服务器压力,提升网页加载速度。
- Cookie:主要由服务器生成,且前端也可以设置,保存在客户端本地的一个文件,通过response响应头的set-Cookie字段进行设置,且Cookie的内容自动在请求的时候被传递给服务器。在客户端和服务器之间来回传递,耗性能。Cookie可以记录用户ID、密码、浏览过的网页、停留的时间等信息。当你再次来到该网站时,网站通过读取Cookies,得知你的相关信息,就可以做出相应的动作,如不用输入ID、密码就直接登录等等。一个网站只能读取它自己放置的信息,不能读取其他网站的Cookie文件。因此,Cookie文件还保存了host属性,即网站的域名或ip。 这些属性以名值对的方式进行保存,内容大多进行了加密处理。Cookie文件的命名格式是:用户名@网站地址[数字].txt
优点:
(1)给用户更人性化的使用体验,如记住“密码功能”、老用户登录欢迎语;
(2)弥补了HTTP无连接特性;
(3)站点统计访问人数的一个依据
缺点:
(1)它无法解决多人共用一台电脑的问题,带来了不安全因素;
(2)Cookie文件容易被误删除;
(3)一人使用多台电脑;
(4)Cookies欺骗。修改host文件,可以非法访问目标站点的Cookie;
(5)容量有限制,不能超过4kb;
(6)在请求头上带着数据安全性差。
- localStorage:主要是前端开发人员在前端设置,一旦数据保存在本地后,就可以避免再向服务器请求数据,因此减少不必要的数据请求,减少数据在浏览器和服务器间不必要地来回传递。可以长期存储数据,没有时间限制,一天,一年,两年甚至更长,数据都可以使用。localStorage中一般浏览器支持的是5M大小,这个在不同的浏览器中会有所不同。优点:
(1)alStorage拓展了cookie的4k限制;
(2)alStorage可以将第一次请求的5M大小数据直接存储到本地,相比于cookie可以节约带宽;
(3)alStorage的使用也是遵循同源策略的,所以不同的网站直接是不能共用相同的localStorage。
缺点:(1)需要手动删除,否则长期存在;
(2)大小不一,版本的支持也不一样;
(3)alStorage只支持string类型的存储,JSON对象需要转换;
(4)alStorage本质上是对字符串的读取,如果存储内容多的话会消耗内存空间,会导致页面变卡。
- sessionStorage:主要是前端开发人员在前端设置,sessionStorage(会话存储),只有在浏览器被关闭之前使用,创建另一个页面时同时可以使用,关闭浏览器之后数据就会消失。存储上限制:不同的浏览器存储的上限也不一样,但大多数浏览器把上限限制在5MB以下。
- Cookie:主要由服务器生成,且前端也可以设置,保存在客户端本地的一个文件,通过response响应头的set-Cookie字段进行设置,且Cookie的内容自动在请求的时候被传递给服务器。在客户端和服务器之间来回传递,耗性能。
5.如何实现一个百度搜索框的功能?怎么做输入提示?
参考链接:https://blog.csdn.net/zyf19971112/article/details/82872955
- jsonp.js封装
1 function jsonp(url, options) { 2 // 创建script标签 3 var $script = document.createElement('script'); 4 // 解决缓存问题 5 var f = url.indexOf('?') > - 1 ? '&' : '?'; 6 url += f + '_=' + Date.now(); 7 // 把参数拼接到url上面 8 for(var i in options) { 9 url += '&' + i + '=' + options[i]; 10 } 11 $script.src = url; 12 document.body.appendChild($script); 13 }
- baidu.js:实现具体功能函数
1 var baiduInput = (function(){ 2 var timer = null; 3 return { 4 init: function(ele) { 5 this.$ele = document.querySelector(ele); 6 this.$inputSearch = this.$ele.querySelector('input'); 7 this.$listTipsBox = this.$ele.querySelector('.search-list'); 8 this.event(); 9 }, 10 event:function(){ 11 var _this = this; 12 this.$inputSearch.onfocus = function() { 13 // 判断文本内是否有文字,如果有就显示下拉框 14 _this.checkInput(); 15 _this.getData(); 16 } 17 this.$inputSearch.oninput = function() { 18 //判断文本内容为空, 隐藏下拉框,如果有文字显示下拉框 19 _this.checkInput(); 20 clearInterval(timer); 21 // 目的: 减少http请求, 降低对服务器的压力 22 timer = setTimeout(function() { 23 _this.getData(); 24 }, 500) 25 // 根据输入的内容,获取下拉框数据, 并渲染到下拉框中 26 }, 27 document.onclick = function(e) { 28 if(e.target !== _this.$inputSearch) { 29 // 如果点击的不是搜索框, 让搜索框中的下拉框隐藏 30 _this.listShow(); 31 } 32 } 33 // this.$inputSearch.onblur = function() { 34 // } 35 // 利用事件委托给每一个li添加点击事件 36 this.$listTipsBox.onclick = function(e) { 37 e = e || window.event; 38 var target = e.target || e.srcElement; 39 if(target.nodeName === 'LI') { 40 // 把li上面的文本赋值给文本框 41 _this.$inputSearch.value = target.innerHTML; 42 _this.listShow(); 43 // 隐藏下拉框 44 } 45 } 46 }, 47 listShow: function(val) { 48 val = val || 'none'; 49 this.$listTipsBox.style.display = val; 50 }, 51 checkInput: function(val) { 52 // 获取文本框的值 53 val = val || this.$inputSearch.value; 54 if(val === '') { 55 this.listShow(); 56 } else { 57 this.listShow('block'); 58 } 59 }, 60 getData: function(val) { 61 if (val === '') return; 62 val = val || this.$inputSearch.value; 63 var params = { 64 wd: val, 65 cb: "baiduInput.insertData" 66 } 67 jsonp('https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su', params); 68 }, 69 insertData: function(data) { 70 data = data.s; 71 data = data.map(function(x) { 72 return "<li>" + x + "</li>"; 73 }) 74 this.$listTipsBox.innerHTML = data.join(''); 75 // console.log(data); 76 } 77 } 78 }())
- jsonp.js封装
三、笔试题
函数add同时满足add(a,b)和add(a)(b),且输出结果为a+b,如:add(2,3)和add(2)(3)均得到5。以下是我的代码:
1 function add(a,b){ 2 if(typeof b=="undefined"){ //或者arguments.length==0 3 return function(b){ 4 return a+b; 5 } 6 }else{ 7 return a+b; 8 } 9 }
10 console.log(add(2,3)); //5
11 console.log(add(2)(3)); //5
追问:如果有传入多个参数,怎样实现上述函数。如:add(1)(2)(3)(4)
1 function add(a){ 2 function fun(b){ 3 a+=b; 4 return fun; 5 } 6 fun.toString=function(){ 7 return a; 8 } 9 return fun; 10 }
11 console.log(add(1)(2)(3)(4)); //10
console.log输出函数时调用其toString方法,给函数fun指定了它自己的toString方法,并且指定了返回值为a。
四、总结
看得出来字节跳动很重视基础,尤其是原生JS,没考过框架的问题。由于接口和搜索框的问题没回答上,再加上比较紧张有些会的也忘了,导致二面没过。但我通过这两次面试增加了经验,查缺补漏巩固了知识,还是很有收获。