译者:文章作者是一个面试官,主要内容是前端的面试题,对于前端的理解还是挺深的。
原文链接请点击,以下是原文翻译:
我介绍下我在面试Twitter和Stripe的前端工程师时遇到的问题。在面试时,我自己还是能够有很大的自由的,遇到的许多组问题,有着很好的立意,可能会对别人有所帮助。
首先,想要考察一个人是很难的,尤其想在45分钟里考验一个人是否适合要求,更是难事。而面试者都想被聘用,很多顶尖的面试者都会尝试站在面试官的角度思考问题,但实际上这样并不一定有什么好处。我也多次因此中招。。。但是呢,分享出来总是个好的开始。
最好的求职者呢,当然是有着GitHub一样简历的人,我们能够点击查看他参与的开源项目。我通常会看他们的代码,并且询问代码中一些设计初衷。如果求职者有着很好的代码记录,那么接下去的工作就是看他能不能适应团队文化了。如果求职者的代码写的不好,我会开始问一些编程问题。
我遇到的求职者通常都是很有技巧并且是专业的程序猿,所以一般不好问题逻辑问题,当然别的面试官可能会问,每个人的习惯不同,但是问逻辑问题通常不是一个好的前端面试官的做法。我的问题通常设计巧妙,每个问题都简单但又能考察JS的某个方面。
面试过程不用白板,但是面试者可以在自己的笔记本上写代码,或者用我的,编辑器没有限制,我通常用Chrome测试写的代码。
1 对象的原型(Prototypes)
开始一般很简单,要求应聘者创建名叫 spacify 的函数,传入一个string参数,要求将string字符串的每个字符直接都加入一个空格:
spacify('hello world') // => 'h e l l o w o r l d'
虽然看起来问题很简单,但是是个不错的起始问题,尤其有些手机开发人员称他们懂JS的时候,这些人有些并不会写function。
标准答案如下,使用for循环做也是可以的:
function spacify(str) {
return str.split('').join(' ');
}
然后的要求是,spacify函数能够紧接着写在String对象的后面:
'hello world'.spacify();// => 'h e l l o w o r l d'
这个问题能够考察应聘者对于原型的理解。当然,这种考题可能会涉及争议,很多人觉得直接在对象的原型里增加属性是很危险的。标准答案:
String.prototype.spacify = function(){
return this.split('').join(' ');
};
然后,我会让应聘者解释下function的表达式和function的声明之间的区别。
译者答:实际上,表达式,即expression方式,不如声明方式好理解,function add(){} 这样形式的函数能够命名提升,并且很好地类比于C的变量作用域,即局部声明的函数会覆盖全局的声明。但是,如果使用表达式方式,需要把函数写在最前面。如果先调用函数,后写函数表达式,JS会尝试调用全局的函数,全局未找到,局部由于写在了后面,也无法找到,会出现undefined。
2 参数
第二部分,我会问一些精心设计的问题,考察应聘者对于arguments对象的理解。首先设定有一个函数叫log:
log('hello world')
然后让应聘者完成这个函数,并且能够将字符串参数传递给console.log()。正确的答案无非就几行,但是更好的答案是:
function log(msg){
console.log(msg);
}
紧接着,我会修改log的接口,使它能够接收多个参数,并且,同时希望console.log也能够接收多个参数:
log('hello','world');
通常的我会得到使用apply的答案,有时候应聘者会在apply和call之间犹豫,我会直接指出使用apply是对的,重点在于给console传哪些参数:
function log(){
console.log.apply(console, arguments);
};
下一步,我会让应聘者在记录传入的字符串的同时,在字符串前面加上 (app) 几个字符,即log函数调用结果是:
'(app) hello world'
这个问题还是有些难度的,有实力的应聘者会知道arguments本身是提前定义的数组,想操作它需要先转换成标准的数组。通常都是用array.prototype.slice:
function log(){
var args = Array.prototype.slice.call(arguments);
args.unshift('(app)');
console.log.apply(console, args);
};
译者注:apply方法会遍历数组,并且将数组的每个元素都作为参数传给同一个函数,最后console.log执行了多次。
3 上下文
这部分问题会考察应聘者对于上下文和this的熟悉程度。首先定义一个count,count里读取了当前上下文。
var User = {
count: 1,
getCount: function() {
return this.count;
}
};
然后我给出几行调用,要求给出调用的输出:
console.log(User.getCount());
var func = User.getCount;
console.log(func());
答案是1和undefined。很多人会被绊在这里。func是在window的上下文中调用的,所以没有count的属性。然后我要求应聘者改写,使得func能够绑定User,并且输出1。
正确答案是使用Function.prototype.bind:
var func=User.getCount.bind(User);
console.log(func());
通常我会接着解释说这样写在旧的浏览器并不好用,要求应聘者完善它。尽管看着他们纠结并不好受,但是他们能够通过这个问题展示出对apply和call的理解,以便决定我们是否聘用他们。
Function.prototype.bind =
Function.prototype.bind || function(context){
var self = this;
return function(){
return self.apply(context, arguments);
};
}
如果应聘者用代码尝试查看浏览器版本,然后再用bind,可以额外加分。如果他们到这里都做出来了,我会要求他们再在count的实现上加上参数。
4 覆盖物
最后一部分要求应聘者构建实用的覆盖物(弹窗)。我发现这个很有作用,因为能够全名考察前端相关技术:HTML、CSS和JS。如果应聘者在前面表现出色,我会让他们尽快接触到这部分题目。
额外的功能实现是加分项,取决于应聘者是否选择。但是有几项是必须考察的:
使用position:fixed比使用position:absolute摇号,并且能够保证叠加层能够在用户向下滚动时覆盖整个窗口。如果应聘者在这里用错了,我会要求他们解释两者的区别:
.overlay {
position: fixed;
left: 0;
right: 0;
bottom: 0;
top: 0;
background: rgba(0,0,0,.8);
}
如何使内容居中也是一个考察点。有的应聘者会用CSS和absolute位置,这种方法在内容是固定长宽时是好用的,其它情况下应该使用JS定位。
.overlay article {
position: absolute;
left: 50%;
top: 50%;
margin: -200px 0 0 -200px;
width: 400px;
height: 400px;
}
最后我会要求覆盖图层能够在被点击后关闭,目的是考察多种事件的使用。多数情况下会在覆盖物上增加监听点击事件的监听器,就没了:
$('.overlay').click(closeOverlay);
但是,这里的问题是,点击覆盖物的子成员也会关闭整个覆盖物,这个不是我们想要的。解决方法是检查点击的目标:
$('.overlay').click(function(e){
if (e.target == e.currentTarget)
closeOverlay();
});
5 其它的想法
这里的问题可能连前端的一粟都没有考察到,有更多的点可以提出问题,比如性能,HTML5接口,AMD和CommonJS模型,构造函数,类型和盒子模型。我通常根据应聘者的爱好将问题混合起来。
我非常推荐这个前端开发者面经,同时也非常推荐在JavaScript Gargen上的文档。
译后感言:之前一直觉得,前台不好写,并且前台没有像后台Java语言等那么简单粗暴易上手,现在来看呢,前台还是足够强大的,只是自己知道的东西还是太少,进而写前台时候缺乏技巧性和准确性,很多东西写不出来;原来觉得前台可能不足以作为长期工种,现在觉得说好的前台工程师,也是可以做很长时间,前台也有很多可以深入的事情。