前言
本套笔试题真实(2019.10.9),做题时间要求:四十分钟。
可供自测(初级前端),按需取用。
正文
第一题
CSS 有几种方法实现垂直水平居中?请写出来。
第二题
var a='a123',b='b234',请在不调用其他变量的情况下,互换 a,b 的值。
第三题
请写出匹配邮箱账号的正则表达式,邮箱可包含下划线“_”,但不能以下划线开头。
第四题
定义两个类A、B,其中A类有属性 type 值为'a',使用 ES5 规范实现 B 类继承 A 类。
第五题
有 3 个基于 Promise 的异步函数,A、B、C;写出按顺序 A-B-C 调用的代码(前一个函数完成后,才能执行后一个函数)。
第六题
有一个元素长度超过 10000 且类型都会 Number 的数组 args,如何求其最大值的方法。
第七题
说说你对 HTTP 协议的理解,HTTP协议的底层实现。
第八题
分别写出下面两段代码的输出结果
for(var i=0;i<5;i++){ (function(){ setTimeout(function(){ console.log(i) },i*1000) })(i) } 复制代码
for(var i=0;i<5;i++){ (function(i){ setTimeout(function(){ console.log(i) },i*1000) })(i) }
第九题
根据下列代码,写出结果,并说明原因。
setTimeout(()=>{ console.log(1) },0) new Promise((resolve,reject)=>{ console.log(2) setTimeout(()=>{ console.log(3) resolve(4) },0) }).then((val)=>{ console.log(val) }) setTimeout(()=>{ console.log(5) },0) console.log(6)
第十题
除了压缩代码、合并文件外,列举出你所知道的优化网站首屏显示速度的方法?
第十一题
vue 数据双向绑定原理是什么,依赖收集是如何实现的?
第十二题
请用原生 js实现一个前端路由。
解答
仅供参考,期待交流
第一题解答
CSS 有几种方法实现垂直水平居中?请写出来。
答:
- 用inline-block和vertical-align来实现居中;( 参考- Centering in the Unknown)
- 用相对绝对定位和负边距实现上下左右居中;(常用)
- 用Flexbox来实现水平垂直居中,注意兼容;(常用)
- 利用绝对定位来实现居中;(参考)
- 使用css3中的transform;(参考)
- 使用table-cell,inline-block实现水平垂直居中;
小结:尽可能写全,关键是要分清在不同的场景用不同的方法!
第二题解答
var a='a123',b='b234',请在不调用其他变量的情况下,互换 a,b 的值。
答:
var a='a123'; var b='b234'; a={a:b,b:a} b=a.b a=a.a console.log(a) console.log(b)
第三题解答
请写出匹配邮箱账号的正则表达式,邮箱可包含下划线“_”,但不能以下划线开头。
答:
/^(?!_)[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/
第四题解答
定义两个类A、B,其中A类有属性 type 值为'a',使用 ES5 规范实现 B 类继承 A 类。
答:
- 原型链继承:即B.prototype-new A();
- 借用构造函数(call 或者 apply 的方式继承);
- 组合继承;
第五题解答
有 3 个基于 Promise 的异步函数,A、B、C;写出按顺序 A-B-C 调用的代码(前一个函数完成后,才能执行后一个函数)。
答:
function A(){ return new Promise(function(resolve,reject){ setTimeout(function(){ console.log("1"); resolve(); },3000); }); } function B(){ return new Promise(function(resolve,reject){ setTimeout(function(){ console.log("2"); resolve(); },1000); }); } function C(){ return new Promise(function(resolve,reject){ setTimeout(function(){ console.log("3"); },1000); }); } A().then(B).then(C) 或: A().then(()=>{ return B(); }).then(()=>{ return C(); })
第六题解答
有一个元素长度超过 10000 且类型都是 Number 的数组 args,如何求其最大值的方法。
答:选择快速排序(是对冒泡排序的一种优化)
时间复杂度:O(nlogn)
function quickSort(arr){ if(arr.length<=1){return arr;} //如果数组<=1,则直接返回 let pivotIndex = Math.floor(arr.length/2); let pivot = arr.splice(pivotIndex,1)[0]; //找基准,并把基准从原数组删除 let left=[], right=[]; //定义左右数组 for(let i=0; i<arr.length; i++){//比基准小的放在left,比基准大的放在right if(arr[i] <= pivot){ left.push(arr[i]); } else { right.push(arr[i]); } } return quickSort(left).concat([pivot],quickSort(right)); //递归 }
第七题解答
说说你对 HTTP 协议的理解,HTTP协议的底层实现。
答:HTTP是超文本传输协议,是一种可靠的应用层数据传输协议,传输前需要进行三次握手进行客户端和服务端的验证。
常用的方法是:GET、POST、PUT、DELETE;
常见的返回码有:200、302、403、404、500、503
底层实现: http协议的底层是在应用层里,是一个特殊处理的socket,建立在TCP/IP协议之上的一种广泛应用:服务器先初始化一个socket,与端口绑定,对端口进行监听,调用阻塞,等待客户端的连接。然后,初始化客户端的socket,与服务器的socket连接,需要经过三次握手。
第八题解答
分别写出下面两段代码的输出结果:
for(var i=0;i<5;i++){ (function(){ setTimeout(function(){ console.log(i) },i*1000) })(i) }
for(var i=0;i<5;i++){ (function(i){ setTimeout(function(){ console.log(i) },i*1000) })(i) }
答:分别是:
//5,5,5,5,5
//0,1,2,3,4
考察点:闭包:第一段代码没有传递 i 值,第二段代码有传递 i 值。
第九题解答
根据下列代码,写出结果,并说明原因。
setTimeout(()=>{ console.log(1) },0) new Promise((resolve,reject)=>{ console.log(2) setTimeout(()=>{ console.log(3) resolve(4) },0) }).then((val)=>{ console.log(val) }) setTimeout(()=>{ console.log(5) },0) console.log(6)
答:2,6,1,3,4,5
原因:
- 首先遇到setTimeout放到宏任务队列,
- 然后Promise的executor是一个同步函数,执行console.log(2),
- 然后又是一个setTimeout,再被推入到宏任务队列,
- 然后又遇到一个setTimeout,也被推到宏任务队列中
- 然后看到主线程的同步任务console.log(6),随即打印;
// 这个时候控制台打印了2,6;(可以在控制台中看到已返回“undefined”)
- 然后执行宏任务,console.log(1);
- 继续执行宏任务队列中的,console.log(3);此时,遇到resolve,promise.then是一个微任务,则推到主线程执行,console.log(4);
- 再执行宏任务队列的任务,console.log(5)
- 全都执行完啦!
力荐:
第十题解答
除了压缩代码、合并文件外,列举出你所知道的优化网站首屏显示速度的方法?
答:
- 使用 CDN 加速静态资源;
- webapck打包,减少资源载入,按需加载;
- 避免 JS 执行阻塞渲染;
- 图片使用懒加载,视频或音频禁止自动播放,用图标代替图片;
- 充分利用本地缓存;
第十一题解答
vue 数据双向绑定原理是什么,依赖收集是如何实现的?
答:Vue内部通过Object.defineProperty方法属性拦截的方式,把data对象里每个数据的读写转化成getter/setter,当数据变化时通知视图更新。
实现数据的双向绑定,首先要对数据进行劫持监听,所以我们需要设置一个监听器Observer,用来监听所有属性。如果属性发生变化了,就需要告诉订阅者Watcher看是否需要更新。因为订阅者Watcher是有很多个,所以我们需要有一个消息订阅器Dep来专门收集这些订阅者,然后在监听器Observer和订阅者Watcher之间进行统一管理。
第十二题解答
请用原生 js实现一个前端路由。
答:
原理:以 hash 形式(也可以使用 History API 来处理)为例,当 url 的 hash 发生变化时,触发 hashchange注册的回调,回调中去进行不同的操作,进行不同的内容的展示。
function Router() { this.routes = {}; this.currentUrl = ''; } Router.prototype.route = function(path, callback) { this.routes[path] = callback || function(){}; }; Router.prototype.refresh = function() { this.currentUrl = location.hash.slice(1) || '/'; this.routes[this.currentUrl](); }; Router.prototype.init = function() { window.addEventListener('load', this.refresh.bind(this), false); window.addEventListener('hashchange', this.refresh.bind(this), false); } window.Router = new Router(); window.Router.init();
上面路由系统 Router 对象实现,主要提供三个方法:
- init 监听浏览器 url hash 更新事件;
- route 存储路由更新时的回调到回调数组routes中,回调函数将负责对页面的更新;
- refresh 执行当前url对应的回调函数,更新页面;
结语
实打实写一哈更重要!祝需要笔试的盆友们顺利!