2017年9月15号百度前端一面
笔试其实做得蛮不好的,收到面试通知有点出乎意料。自觉以自己现在的知识深度和广度还不足以通过大厂的层层面试,于是抱着学习的心态去了。个人感觉是一次蛮好的查漏补缺,总共一个小时的时间,基本每个知识点都问到了,从HTML到CSS,从JS到WEB安全和性能优化。常考的知识点在这次面试中都有体现,也没有什么偏题怪题。面试官也很和善,问到的知识点我大概30%没答上吧,基本都会耐心地解释一下。
好了废话不多话,整理一下这次面试问到的问题(有些死活也想不起来了),老规矩的分为JS和CSS+HTML以及其他三大类,顺便把答案也附上,也小伙伴们一个参考。
CSS+HTML
-
内联元素与块级元素的区别
块级元素独占一行;
内联元素不换行,内联元素不能设置宽高,可以设置padding,不能设置margin-top、margin-bottom。
补充:若设置
display:inline-block
,表现为同行显示,但可以设置width、height、padding、margintext-indent
属性只对块级元素起作用。 -
常见的内联元素与块级元素(这里只写了我自己日常常用的,若想知道全部的内联和块级有些什么的可以自行搜索)
内联元素:
<span><a><img>
(<img>
内联块状元素,可以设置宽高)块级元素:
<div><p><h1-6><ol><ul><pre>
补充: 替换元素是浏览器根据标签的元素与属性来判断具体的内容。如
<input>
-
说一下标准盒模型和IE盒模型
当你看到这一行的时候,请按F12,换到element这一栏,就会看到一个四四方方的盒子,中间有一块数字X数字的蓝色区域,这叫content,剩下的区域在上面都写上名字了(仅针对Chrome),这就是标准盒模型。
至于什么是IE盒模型,在标准盒模型中,width指的就是content的宽,而IE中,width指的是content+padding+border,即是说IE把content定义为了content+padding+border(其实我觉得这种定义方式还挺利于理解的)。
-
box-sizing:border-box是什么效果
在上一题盒模型的基础上,border-box就类似于IE的盒模型,如果你设置了一个width,同时设置了
box-sizing:border-box
,这时候浏览器就会帮你把border和padding计算到width中去。 -
写一个左边固定宽度,右边自适应的两栏布局
<div id="left"></div> <div id="right"></div>
#left{ float:left; width:200px; } #right { width:100%; margin-right:-200px; }
-
上题的基础上如何清除浮动
第一种方法答
clear:both
,问clear:both
放在哪,于是画了一个在左右两个div之下的div说在这里设置clear:both
。然后又引申出来,如果用一个div元素将左右的两个元素包裹起来,可以在容器div中设置
:after
伪类。CSS如下(其实我一直对伪类有点困惑,照着码从来没想过是啥,今天面试官给我一指瞬间就get 了):.container::after { content: " "; clear:both; }
第二种方法
(这题我问面试官,他边说我边记,记完我问还有吗,他愣了一下,然后反问是我面你还是你面我(⊙﹏⊙))
第二种清除浮动的办法就是下一题的BFC,包裹两个div的父容器生成一个块级格式上下文,与外面隔绝开来独立的一块,也不管什么浮动不浮动了。具体BFC什么样写在下一题。
-
BFC(清除浮动)
Block Formatting Context
BFC大概就是上面说的,一个独立的块级上下文,怎么才能形成BFC找了一下标准说法:
- float的值不为none
- overflow的值不为visible
- display的值为inline-block、table-cell、table-caption
- position的值为absolute或fixed
这里的四个条件都是针对父元素即上面设置的
.container
的,满足其中一个就可以生成一个BFC,自然也能做到清除浮动了。(这里面试官主要跟我说的是设置overflow:hidden)
-
垂直margin的合并
垂直margin合并就是上下相邻的两个块级元素,如果刚好,上面设置
margin-bottom
,下面设置margin-top
,这俩外边距相遇了,那两个就合并了,本来可能上面margin-bottom
设置20px
,margin-top
设置10px
,合并之后两个元素上下的距离就变为20px
,即两个属性中较大的值。这里补充的一点就是垂直margin合并的条件时在同一个BFC中才会发生的,如果两个BFC就算它俩的margin相遇了,也不会融合的。
-
水平居中,垂直水平居中(position)
水平居中:
margin:0 auto
这里上下的外边距随便设置,不一定是0,左右要自适应即auto
。行内元素如何居中:水平
text-align:center
,垂直设置line-height
与height
一样高。垂直水平居中就合并一下。垂直水平居中: ①利用flex布局,很简单的三行代码,在父容器里设置。
.container { display:flex; justify-content:center; align-items:center; }
②利用position:这里就不是设置父容器了,而是元素本身
div{ position:absolute; margin:auto; bottom:0; top:0; left:0; right:0; }
在我说完flex之后,面试官就问利用position怎么做,然后我就说了上下左右都为0,把margin自适应给忘了。
补充:还有利用css3里的
transform
,主要是针对不定宽高(即宽高为百分比的情况),定宽高的话可以用负的margin值来做到,都是差不多的思想。transform实现垂直水平居中:
div{ position: absolute; top: 50%; left: 50%; width:50%;//注意这里的宽高都为百分比 height:30%; transform: translate(-50%, -50%); }
-
用过哪些选择器,选择器的优先级(同样的这里选择器列举的也是我自己用过比较熟悉的)
(这里的分类参考MDN中对选择器的分类)
简单选择器:元素选择器、类选择器、ID选择器、(*)通配选择器;通配选择器匹配所有的元素,慎用,对性能有影响。
属性选择器:
[attr][attr="val"][attr~="val"]
依次是元素中包含该属性、元素中包含该属性且属性值为val
、元素中包含该属性且属性值中包含val
。其他还有|^$
等,含义类似正则。伪类和伪元素: 伪类 前 一个冒号,常用的
:link :visited :hover :active(love hate)
,针对链接;以及nth-child nth-of-type
。伪元素前两个冒号,常用的
::after ::before
(前面清除浮动就是用到了::after
伪元素)组合选择器和多用选择器:①A,B:满足A或B(A和B也行)②A B:B是A的后代节点③A>B:B是A的直接子节点④A+B:AB有相同的父结点,并且B紧跟在A的后面⑤A~B:AB有相同的父节点,B在A之后,但不一定是紧挨着A(即④是⑤ 的子集)
-
元素和元素的伪类的优先级
属性选择器,伪类选择器和class类选择器优先级一样,伪元素选择器和元素选择器一样
-
HTML5新增了哪些
具体可以看MDN中的介绍:点我
语义化方面:
<header><footer><nav><section><article><section><hgroup><aside>
视频和音频:
<audio><video>
图像方面:
<canvas>、WebGL(通过canvas.getContext('webgl')获得对象)、<SVG>
数据存储:
sessionStorage、localStorage
-
讲一下localStorage和sessionStorage
sessionStorage存储一个会话中的数据,会话结束后数据就会被销毁。
localStorage的数据是永久存储在客户端的,除非主动删除,否则不会过期。
一般设置大小为5M以下。
API:(localStorage和sessionStorage的API都是一样的,这里以sessionStorage为示例)
sessionStorage.key(0) //0位索引,返回第0位数据的键值 sessionStorage.getItem("key") //键值为key的属性值 sessionStorage.setItem("key","value") //存储名为key,值为value sessionStorage.removeItem("key") //删除键值为key的属性 sessionStorage.clear(); //删除所有sessionStorage中的属性
JS
-
事件代理的原理
事件冒泡
-
怎么判断一个数组
var arr = [1,2,3]; Object.prototype.toString.call(arr);//[object Array] //还可以用instanceof arr instanceof Array; // true
-
原型、原型链
原型:原型是一个对象,其他对象可以通过它实现属性继承。JS中每个函数都有一个prototype属性,它指向了函数的原型对象。
原型链:这里先给ECMA中的定义
Every object created by a constructor has an implicit reference (called the object's prototype) to the value of its constructor's "prototype" property. Furthermore, a prototype may have a non‑null implicit reference to its prototype, and so on; this is called the prototype chain.
翻译过来大概是这么个意思:
每个由构造函数创建的对象都有一个隐式原型,指向构造函数的
prototype
属性。 此外,这个原型也可能会有一个非空的隐式原型指向它的原型,它的原型再指向一个原型等等等;这就叫做原型链。死记硬背肯定要不得。一般我就画个例子,类似什么person,student之类的,然后再解释,student的原型是person,person也有一个原型指向上一级的原型,这样一直向上找到
Object.prototype
,这是原型链最后一层了,再往上找Object.prototype.__proto__
的话,就是null
了。这里再补充一下
prototype和__proto__
的区别。显示原型(
prototype
):显示原型实现基于原型的继承和属性的共享。隐式原型(
[[prototype]]
):隐式原型是的作用就是构成原型链,通过隐式原型可以一层层往上查找对象的原型。__proto__
是个不标准的属性,是浏览器为了实现对[[prototype]]
的访问所提供的一个方法。常理来说[[prototype]]
即隐式原型是不可访问的。ES5里提供了Object.getPrototypeOf()
这个方法来获得[[prototype]]
。 -
写了一个表达式让我说元素的原型是什么
首先是写了一个
var dog = new Animal()
,我说是Animal.prototype
;然后是var arr = [1,2,3]
,我说是Array.prototype
;最后是问Object
的原型,Object
是个构造函数嘛,那就是Function.prototype
。 -
闭包
(这里的定义来自于红宝书)闭包是指有权访问另一个函数作用域中的变量的函数。
死记硬背肯定累,我一般都记这段代码
function outer(){ var x = "我是来自outer的x"; return function inner(){ console.log(x); } } var a = outer(); a(); //我是来自outer的x
反正对我而言代码比定义印象深刻多了,然后再自己用语言把这段代码描述一下,基本就能解释闭包了。
-
作用域、作用域链
作用域怎么解释,这个看了很多地方,都觉得不满意。还是引用高程里面这段话吧。
执行环境(execution context)定义了变量或函数有权访问的其他数据,决定了它们各自的行为。
为什么拿出来却是执行环境,是因为看了一篇文章,感觉里面的说法还蛮有趣的。作用域大致也是这么个意思,但作用域是静态的,执行环境是动态的,也就是说执行环境是你执行的时候才确认的,而作用域是定义的时候确认的。
作用域链:保证对执行环境有权访问的所有变量和函数的有序访问。
这里我个人理解加上看高程里面的说法,感觉就是类似栈的结构,全局执行环境在栈底,进入一个函数,一个执行环境就被压入栈中。在当前这个函数,即栈顶的执行环境,若是没找到需要变量,则往下找。
当执行完这个函数后,这个函数的执行环境就出栈,进入之前的执行环境中,一直到最后栈里只剩下了全局执行环境。
-
变量对象
每个执行环境都有一个与之关联的变量对象(variable object),环境中定义的所有变量和函数都保存在这个对象中。
活动对象(activation object):当函数被调用时,活动对象就被激活了。除了包含arguments这个特殊参数外,还包含了与变量对象一样的,当前执行环境中的所有变量和函数等等等。(我个人理解,活动对象就是arguments+被激活的变量对象)。
-
实现
sub/pub(on,off,triger,triger(*,{"name":"Alex"}))
*表示所有(大概知道是怎么个思路但是让我写就蒙蔽了,跟面试官说了之后他跟我讲说因为以后公司里面写框架的话基本都会用到观察者模式,所以了解如何实现还是很有必要的)
大概题目就是一个Emitter的类,其中有
on,off,trigger
三个函数。on
传入注册的事件名和相应的回调函数;off
传入事件名删除对于这个事件的监听;trigger
触发事件,参数为触发的事件及传入回调函数中的参数。//创建一个对象用于保存注册的事件 var eventObj = {}; Emitter.prototype.on = function(event,fn){ if(!eventObj[event]){ //若不存在这个事件,则在对象中创建一个属性,值为一个空的数组 eventObj[event] = []; } //将传入回调函数添加到事件的回调函数数组中 eventObj[event].push(fn); } Emitter.prototypr.off = function(event){ if(!eventObj[event]){ //不存在该事件,直接返回false return false; } //若存在则删除 delete eventObj[event]; } Emitter.prototype.trigger = function(event,args){ //若传入星号,则遍历事件对象中的所有属性,执行对应数组中的回调函数 if(event === "*"){ for(events in eventObj){ for(let i = 0;i<events.length;i++){ events[i](args); } } //若传入是event名,则遍历执行属性对应数组中的所有回调函数 } else if(eventObj[event]){ for(let i = 0;i<eventObj[event].length;i++){ eventObj[event][i](args); } } }
这一段代码没测试,只大概写了下简单思路,有什么错误欢迎指出。至于什么是观察者模式这里就不赘述了。
-
给一段英文,让每个单词的首字母大写
(这是最后一个问题吧,面试官说那最后做一个小的算法吧,我一听算法全身毛都竖起来了,结果没想到拿出来是这么道题。。。。)
看了一眼就打算说怎么做,结果面试官说想想再说……吓的我还以为有什么陷阱。仔细看了两眼,就很普通的一段英文嘛。
然后就说用正则去匹配英文中的空格逗号句号括号等等分隔符,然后
split
成数组,遍历数组,对每个元素的首字母都toUpperCase
。面试官点点头,然后我又问还有什么更有效率的办法吗(
怎么好像真的我在面他),他说也可以不用split
,直接正则匹配每个单词然后替换首字母。
其他
-
性能优化
这个问题太宽泛了,而且面试中基本都会问到。这次面试回答这个问题的时候我就感觉自己说得不够有条理,基本是在脑袋里抓到什么说什么,这样纯靠记忆力去说,也容易说不完整。(当然性能优化想说全面说详细那恐怕一个小时都不够面的了)
在这个面经里就不详细说了,要找文章的话网上一大堆。打算等校招季闲下来一点后再慢慢按自己思路整理一篇文章出来。
-
Web安全了解哪些
这里我就说了两个,XSS(Cross Site Scripting)和CRSF(Cross Site Request Forgery)。
是什么:XSS是跨站脚本攻击,在所有可输入的地方,没有对输入数据进行处理的话,都会存在XSS漏洞;CRSF是跨站请求伪造,攻击者盗用用户身份,发送恶意请求。
如何防范:
XSS:对输入进行转义,例如
<>
转换为HTML字符实体< >
CRSF:增加验证流程(验证码,指纹验证等)。
-
用过什么构建工具,介绍一下
Webpack:把你的项目当做一个整体,通过一个给定的主文件(如:index.js),Webpack将从这个文件开始找到你的项目的所有依赖文件,使用loaders处理它们,最后打包为一个(或多个)浏览器可识别的JavaScript文件。
这里我认为webpack的关键字就是压缩和打包。接下来的就看自己实际应用中用到了什么就再具体说一说。