“惨痛”的一次面试之旅
来源:互联网 发布:算法导论第三版pdf下载 编辑:程序博客网 时间:2024/05/15 08:39
星期一晚上刚下高铁就发现深圳乌云密布,还没等我掐指一算,雨水就哗啦啦地拍打着大地;
雨一直下,气氛不太融洽.......手机查了一下下一个目标地的距离,发现还需要一个半小时的路程才能到达面试的地方,背上书包没多想,马不停蹄地开始转战于各个地铁口,换乘,换乘,再换乘。终于到达了目的地附近,肚子仿佛知道了这个“喜讯”,大叫一声,才发现坐了4个小时高铁的我还没吃饭;这个时候不知道哪根神经短路了,对自己说,不能吃太饱,不然等下会想睡觉,然后自己就稀里糊涂地去买了一瓶菊花茶,提提神。
废话不多说,由于自己对于一些基本知识只是浮于表面,再加上自己还是缺少一种创新精神和思想;所以在面试中节节败退;
直接上面试题:
1.css中的position分为哪几种,都有什么特点?
absolute
生成绝对定位的元素,相对于 static 定位以外的第一个父元素进行定位。
元素的位置通过 "left", "top", "right" 以及 "bottom" 属性进行规定。
fixed生成绝对定位的元素,相对于浏览器窗口进行定位。
元素的位置通过 "left", "top", "right" 以及 "bottom" 属性进行规定。
relative生成相对定位的元素,相对于其正常位置进行定位。
因此,"left:20" 会向元素的 LEFT 位置添加 20 像素。
static默认值。没有定位,元素出现在正常的流中(忽略 top, bottom, left, right 或者 z-index 声明)。inherit规定应该从父元素继承 position 属性的值。这个是W3C上面的介绍;
如果你不给这个元素定义positon的话,其就默认为static;
然后根据这个条件我们再看一下"absolute说的相对于 static 定位以外的第一个父元素进行定位"这句话,因为这里我答错了,我回答的是absolute是被relative所限制,因为在平时在别人代码的过程中,我发现一般都是relative和absolute来进行互相组合的,比如bootstrap中的modal弹出框;所以我天真的认为只有relative可以限制absolute,其他的都不能;
然后就是fixed和absolute都是脱离了文档流的,其他的没有脱离文档流,既然脱离了文档流那么它的位置改变是不会引起重排;但是如果absolute和float同时存在,则float失去效果
(但是需要我们注意的是给元素的float属性赋值后,也能脱离文档流,进行左右浮动,紧贴着父元素(默认为body文本区域)的左右边框,直到碰到其他的浮动元素;
而此浮动元素在文档流空出的位置,由后续的(非浮动)元素填充上去:块级元素直接填充上去,若跟浮动元素的范围发生重叠,浮动元素覆盖块级元素。内联元素:有空隙就插入。)
2017/7/25 更新;
对于上面说的浮动元素我们遇到最多的问题就是如何清除浮动;(例如塌陷)
目前最常用的方法就是利用伪选择器配合clear来清除浮动;
http://www.cnblogs.com/dolphinX/p/3508869.html
关于BFC的入门可以看一下这个:(通俗一点来讲,可以把 BFC 理解为一个封闭的大箱子,箱子内部的元素无论如何翻江倒海,都不会影响到外部。)
https://zhuanlan.zhihu.com/p/25321647
http://www.cnblogs.com/CafeMing/p/6252286.html
2.如何实现一个带有还有黑色上边框的三角形?
实现一个三角形很简单,利用border,如何让这个三角形带有黑色上边框呢? 就是类似于我们平时聊天那种气泡式对话框那个角。
我们就再创建一个黑色的三角形在我们的三角形的上方1px处,然后让其被覆盖住就行;
下面是我自己写的一个很粗略的样式,后续改进;
<style>#Triangle{width:0px;height:0px;border:10px solid transparent;border-bottom-color:black;position:absolute;top:10px;}#Triangle:after{content:"";width:0px;height:0px;border:10px solid transparent;border-bottom-color:#e4e4e4;position:absolute;top:-9px;left:-10px;} </style> <div id="Triangle"> </div>
3.如何原生实现检测一个变量是不是数组?
这个就是需要我们去实现一个isArray这个方法:
方法1:
var arr = [ ];
arr instanceof Array // true
instanceof 是用来判断这个对象是不是由某个指定的构造器函数所创建出来的;
方法2:
var arr = [ ];
arr.constructor == Array // true
constructor 是用来寻找这个对象的构造器函数
方法3:
var arr=[ ];
Object.prototype.toString.call(arr) === '[object Array]';
我们需要用对象原型上的toString这个方法来获取对象的类型,因为其他数组类型都有自己的toString这个方法。
4.实现一个throttle节流函数
var throttle = function(callback,delay){var last = 0 return function(){var curr = new Date().getTime();if (curr - last > delay){callback.apply(this, arguments)last = curr }}}document.onmousemove=throttle(function(){console.log("lzj");},100)这就是一个节流函数,保证我的mousemove事件只在100ms中触发一次;
new Date().getTime(); 返回的是指定的日期和时间距 1970 年 1 月 1 日午夜(GMT 时间)之间的毫秒数。
callback为我们需要节流的函数,我们限制这个函数在delay这段时间内只运行一次;
由于last最开始的时候就给了0,所以这里函数刚执行的时候肯定会运行我们需要调用的callback,然后把这次时间记录在last中(last是利用闭包的特性保存下来),再进入这个函数的时候又会得到一个新的时间,我们再跟上次的时间比较一下,如果大于这个时间,我们则执行,否则不执行;
下面是uderscore.js中的源码:
_.throttle = function(func, wait, options) { var context, args, result; var timeout = null; var previous = 0; if (!options) options = {}; var later = function() { previous = options.leading === false ? 0 : _.now(); timeout = null; result = func.apply(context, args); if (!timeout) context = args = null; }; return function() { var now = _.now(); if (!previous && options.leading === false) previous = now; var remaining = wait - (now - previous); context = this; args = arguments; if (remaining <= 0 || remaining > wait) { if (timeout) { clearTimeout(timeout); timeout = null; } previous = now; result = func.apply(context, args); if (!timeout) context = args = null; } else if (!timeout && options.trailing !== false) { timeout = setTimeout(later, remaining); } return result; }; };
然后我们也需要了解一下函数消抖:
var debounce = function(callback, delay){var lastreturn function(){var ctx = this, args = argumentsclearTimeout(last)last = setTimeout(function(){callback.apply(ctx, args)}, delay) } }document.onmousemove=debounce(function(){console.log("lzj");},100)
这个函数保证我们的mousemove移动100ms以后没有其再次移动鼠标后触发;
其实这种函数思想我们可以用在keydown keyup这种用户输入信息的校验上,等其输入完毕后再进行校验;
程序的思想在于我们利用setTimeout来延时执行,如果这段时间内没有再次触发这个函数则执行,否则就清除掉上一次的定时器,再开启一个定时器去执行;
下面是underscore.js中的源码:
_.debounce = function(func, wait, immediate) { var timeout, args, context, timestamp, result; var later = function() { var last = _.now() - timestamp; if (last < wait && last >= 0) { timeout = setTimeout(later, wait - last); } else { timeout = null; if (!immediate) { result = func.apply(context, args); if (!timeout) context = args = null; } } }; return function() { context = this; args = arguments; timestamp = _.now(); var callNow = immediate && !timeout; if (!timeout) timeout = setTimeout(later, wait); if (callNow) { result = func.apply(context, args); context = args = null; } return result; }; };
5.一道综合的面试题
function Foo() { getName = function () { console.log (1); }; return this; } Foo.getName = function () { console.log (2); }; Foo.prototype.getName = function () { console.log(3); }; var getName = function () { console.log (4); }; function getName() { console.log (5); } // 请写出一下的输出结果 Foo.getName(); getName(); Foo().getName(); getName(); new Foo.getName(); new Foo().getName(); new new Foo().getName();
在网上一查果然是道很经典的面试题,╮(╯▽╰)╭竟然没做过。
OK,我就重新做一次吧~
Foo.getName( );
这个答案是2,因为函数也是一个对象,所以也能为其添加属性;
getName( );
这个答案是4,因为函数声明在变量声明的前面,var getName=function( ){ console.log( 4) }也会覆盖掉 函数定义的getName( );
Foo( ).getName( );
这个答案是1,这里就需要注意一下了,Foo这个函数返回的是this,我们说过this是谁,需要看什么时候调用,谁调用它,我们可以看出,这个this是window,而且Foo中又重新对于getName( )进行了赋值,且为全局变量,所以为1。
getName() ;
这个答案也是1,因为刚才执行了Foo( ),所以对全局变量getName进行了新的赋值;
new Foo.getName( );
这个答案是2,因为Foo.getName( )优先级高于 new ,所以先执行Foo.getName( ); 得出了是2,再new一个2,所以还是2;
new Foo( ).getName( );
这个地方答案是3,因为new Foo( )的优先级高于 . (我们的点操作符) 这时候的Foo()中的this,因为有new的存在,所以这个this不是window,而是Foo,所以我们这里的new Foo( )其实是new了一个Foo对象的实例,因此,我们需要调用getName( )的时候需要去它原型上找,因此为3;
new new Foo( ).getName( );
这个答案是3,这里先执行的是new Foo( )得到一个Foo的实例,然后调用getName( ),最后对于这个结果再进行new,其实就是对于3再new 一下,结果还是3;
( 对于最后两个答案可以参见一下这个博客,出题人就是他~~http://www.cnblogs.com/xxcanghai/p/5189353.html#!comments)
6 理解 JavaScript 的 async/await (我还要继续看一下)
/*下面是其他面试的补充*/
7.在 javascript 中获取格式为 yyyy-mm-dd 的日期字符串
var date = new Date(); var mon = date.getMonth() + 1;var day = date.getDate();var nowDay = date.getFullYear() + "-" + (mon<10?"0"+mon:mon) + "-" +(day<10?"0"+day:day);注:如果想获得自己定义的一个时间,则改成var date=new Date("2016-5-12") ;
获取小时:getHours( 0---23); 获取分钟:getMinutes(0--59); 获取秒钟:getSeconds(0--59);
8.求一个字符串中出现次数最多的字符次数,及这个字符;
/*求字符串中出现次数最多的字符*/function fn(string){var obj={};var temp=[];var len=string.length;var max=0;for(var i=0;i<len;i++){if(obj[string[i]]){obj[string[i]]++;}else{obj[string[i]]=1;}}for( key in obj){if(obj[key]>max){max=obj[key];}}for(var key in obj){if(max==obj[key]){temp.push(key);}}return temp; }var myWord="aabbddeee";console.log(fn(myWord));
其实这里用到了数组去重的一个思想,只不过在去重的逻辑里面稍加修改,关键逻辑是:如果我这个字符不存在,则给这个字符对应的值赋为1,如果已经存在了,则累加,这样就很容易算出我们每一个字符对应的一个出现字数;然后再去遍历求出最大次数; 当然我们还需要考虑到最大次数存在多个字符的情况下,不过这里用对象就一起解决了;
9.HTML页面加载和解析的流程
(网上找的)
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1.用户输入网址(假设是个html页面,并且是第一次访问),浏览器向服务器发出请求,服务器返回html文件;
2. 浏览器开始载入html代码,发现<head>标签内有一个<link>标签引用外部CSS文件;
3. 浏览器又发出CSS文件的请求,服务器返回这个CSS文件;
4. 浏览器继续载入html中<body>部分的代码,并且CSS文件已经拿到手了,可以开始渲染页面了;
5. 浏览器在代码中发现一个<img>标签引用了一张图片,向服务器发出请求。此时浏览器不会等到图片下载完,而是继续渲染后面的代码;
6. 服务器返回图片文件,由于图片占用了一定面积,影响了后面段落的排布,因此浏览器需要回过头来重新渲染这部分代码;
7. 浏览器发现了一个包含一行javascript代码的<script>标签,赶快运行它;
8. Javascript脚本执行了这条语句,它命令浏览器隐藏掉代码中的某个<div> (style.display=”none”)。突然少了这么一个元素,浏览器不得不重新渲染这部分代码;
9. 终于等到了</html>的到来,浏览器泪流满面……
10. 等等,还没完,用户点了一下界面中的“换肤”按钮,Javascript让浏览器换了一下<link>标签的CSS路径;
11. 浏览器召集了在座的各位<div><span><ul><li>们,“大伙儿收拾收拾行李,咱得重新来过……”,浏览器向服务器请求了新的CSS文件,重新渲染页面。
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
注意
从上面看出来js是加载后立即执行,所以它会阻塞后面的渲染;
解决办法:a.尽量把js外部链接的脚本放在页面的最后加载,也就是</body>的前面,将多个js进行合并成一个;
b.利用<script>标签的defer属性去标示本元素所含的脚本不会修改DOM,因此代码会安全的延迟执行;H5中新加了一个async属性,也是用于异步加载脚本,它和defer的相同点是采用并行下载,不会阻塞页面渲染;区别在于async是加载完后自动执行,defer是需要等待页面完成后再执行;
c.动态创建脚本,我们可以通过doucument.createElement("script")来进行动态创建<script>标签;
刚刚自己实践了js脚本异步加载,发现有几点我们在使用过程中需要注意的是:
用defer或者是async脚本是外部链接,否则不生效;
比如: 我想去获取DOM节点
<script type="text/javascript" defer> var div=document.getElementById("Triangle") console.log(div);</script>这样是不行的,需要把代码放到一个外部js中,这样引用才可以
<script type="text/javascript" src="event.js" defer> </script>
还有就是async是文件下载完就执行,defer是页面渲染完才执行,所以async是不稳定的,顺序上没有完全依赖;我们最好使用这两个属性的时候,文件代码没有对节点的访问;
而且css的加载顺序是从右到左匹配,例如 .nav li 是先找到所有的li标签,然后去寻找拥有nav这个class的标签;所以我们尽量去减少CSS选择的DOM深度;(JQ的匹配顺序是从左到右)
10.求一个数组中长度最长的升序的开始索引和长度
function searchIncreaSequence(arr){if(!arr){return;}if(arr.length<3){return;}var tempMaxLen=1, //临时保存最大升序长度 tempMaxIndex=0, //临时保存最大升序的开始索引 arrLen=arr.length;var obj=new Object();//返回对象,保存最后的最大升序长度和开始索引obj.maxLen=1;obj.maxIndex=0;for(var i=0;i<arrLen-1;i++){if(arr[i]<arr[i+1])//对数组是否是升序进行判断{tempMaxLen++;if(tempMaxLen>obj.maxLen) //比较出最大的升序长度{obj.maxLen=tempMaxLen;obj.maxIndex=tempMaxIndex;//保存开始索引}}else{ //如果数组不是升序,则重置最大长度和开始索引tempMaxLen=1;tempMaxIndex=i+1;}}return obj;}var sls=[1,2,3,1,2,3,4,1,2,3];var result=searchIncreaSequence(sls);console.log("最大长度:"+result.maxLen+" "+"开始索引:"+result.maxIndex);
11.关于setTimeout的面试题
for(var i=0;i<5;i++){setTimeout(function(){console.log(i);},i*1000);}
for(var i=0;i<5;i++){(function(i){ setTimeout(function(){ console.log(i); },i*1000)})(i)}
刚开始输出一个0,然后每隔一秒输出1,2,3,4;
for(var i=0;i<5;i++){(function( ){ setTimeout(function(){ console.log(i); },i*1000)})(i)}
刚开始输出一个5,然后每隔一秒钟输出一个5,一共5个5;
for(var i=0;i<5;i++){setTimeout((function(){console.log(i);})(i),i*1000);}
立即输出0,1,2,3,4
setTimeout(function () { console.log(1)}, 0);new Promise(function executor(resolve) { console.log(2); for(var i=0;i<1000;i++) { i==0000&&resolve(); } console.log(3);}).then(function () { console.log(4);}); console.log(5);
Promise的任务会在当前事件循环末尾中执行,而setTimeout中的任务是在下一次事件循环执行
12.实现一个计数器函数,每调用一次,其返回值加1;
function count(){ var num=1; count=function(){ num++; return num; } return num;}console.log(count());console.log(count());console.log(count());
OK~还要就是一些自己做的项目上是否有想过性能优化方面的问题等等,总之这一次面试经历让自己很“惨痛”,和面试官的交流就能看出来是什么样才是一个“合格”的程序员,而且有些基础知识自己也看到过,但是浮于表面,只是见过,没有真正理解,有些问题自己也想过,但是没有继续深入下去研究等等......然后最后还想说的就是数学不好的也不能当好一个程序员~~╭(╯^╰)╮
回到家已经是晚上10点钟,长达5个小时的路程加面试让自己很疲惫又很兴奋,肚子似乎也能体会到我的感受,又吆喝了我一声,于是乎自己买了一碗泡面和一包辣条开始思考自己没答上来的问题...............
- “惨痛”的一次面试之旅
- 缅怀一次惨痛的网易有道面试经历
- 一次惨痛的经历
- 几次惨痛的面试经历
- 记录一次惨痛的升级glibc 教训
- 记一次惨痛的引用错jquery的事件
- 用DELL的一次DEBUG惨痛经历(两天啊)
- zabbix优化记一次惨痛的zabbix数据库优化
- 记一次惨痛的java服务器full gc.......经过
- 记:去哪儿网前端面试失败的惨痛经历~~
- 一次XXX的面试
- 一次难忘的面试
- 一次百思不得其解的面试
- 一次的面试体会
- 一次面试的感想
- 一次面试的实录
- 一次面试的总结
- 一次面试的经过
- 普通程序员如何入门AI
- surfACview和videoview播放视频文章链接(待完善)
- Java 9 HTTP/2的支持功能前瞻
- 进程与线程的区别与联系
- android里CountDownTimer类的用法
- “惨痛”的一次面试之旅
- Linux程序崩溃core使用(续)
- Linux Man 手册
- Kotlin-内联函数
- 博客阅读记录
- BZOJ 1941 [Sdoi2010] Hide and Seek
- VLD内存泄露库的使用
- IDEA中安装MyBatis Plugins(Mybatis-Generator)插件及破解方法
- Eclipse解决Tomcat版本过低不能发布问题