这次的面试机会来的也很偶然,大概4月初的时候在 v2ex 论坛上看到了酷家乐的招聘信息,就照着邮箱发了自己的简历,当时也没有太在意。到了4月24号左右,收到了酷家乐的在线笔试邀约,在说这次面试前可以先聊聊这次在线笔试。
到现在为止,在线笔试也做了阿里、蘑菇街的,做个横向对比,酷家乐这次的笔试题目分配是20道选择题、3道编程题。很有趣的是在20道选择题中,大概前15道都是围绕数据结构、组成原理、操作系统、网络原理出的题,当初做的时候也是绞尽脑汁回想以前的知识点,我一度怀疑是不是投错了职位,因为像阿里、蘑菇街的笔试题目还都是围绕着前端这一边的,直到最后大概5题才是 js 的题目。3道编程题,一道是实现函数功能,一道是自己写一个 json.stringify() 函数,第3道是 canvas 的题目,大概题目好像是在页面中实现一个可以拖拽的方块。
选择题做的模模糊糊,编程题也只做出一个,当时已经不怎么抱希望。只是从笔试的网站和重视基础的题目,隐隐感受到这家公司的逼格。最后在上周四,接到了笔试通过的电话,并预约了周一的现场面试。
话不多说,直接接入正题。在一面的时候,面试官先拿出了一张考卷让我做,上面6道js(闭包
、原型链
、this
、类型判断
、变量提升
、函数提升
都有)、1道css(盒模型
),说实话题目不是很难,只要准备过题目,都是可以答出来的。
这里列出几道我记得的题目,再附上面试官结合题目问的问题。
1、
console.log(foo());
var foo = function() {
return 1;
}
console.log(foo());
function foo() {
return 2;
}
console.log(foo());
答案:2 1 1
解析:很基础的变量提升、函数提升,详细可以移步 JavaScript中的变量提升和函数提升。
2、
for(var i = 0; i < 6; i++) {
setTimeout(function() {
console.log(i); //位置1
}, 1000 * i);
}
console.log(i); //位置2
问:1、 实现的效果;
2、 将 var i = 0;
改成 let i = 0;
效果如何;
3、除了上面的方法,还有什么方法可以达到上面的效果,并能规避上面的错误;
4、将 setTimeout 的时间 1000 * i 改成 0,效果如何;
答:1、 先打印一个6,再每隔一秒打印一个6;
2、 这里光注意 let 在 循环内的表现,疏忽了位置2的报错,正确答案是:首先报出一个 ReferenceError: i is not defined
,然后每隔一秒输出 0,1,2,3,4,5;
3、手写代码:
for(var i = 0; i < 6; i++) {
(function(i) {
setTimeout(function() {
console.log(i);
}, 1000 * i);
})(i)
}
console.log(i);
4、先打印位置2的1个6,然后打印出6个6
3、
function foo() {
console.log(typeof kkk);
console.log(typeof bar);
var kkk;
function bar() {};
}
console.log(typeof foo());
问:1、效果如何;
2、函数没有返回值,返回什么;
3、typeof 在判断类型时有什么弊端;
4、function 同样算是一种 object,为什么不像 Array 一样返回 object 而是返回 function?
答:1、undefined、function、undefined;
2、undefined;
3、在判断 Array、Date等对象都返回 object,不能确切判定出,typeof null = object
;
4、这里面试的时候不清楚,回来之后查了好多的资料,然后我在一篇博文(ECMA-262-3 in detail. Chapter 7.2. OOP: ECMAScript implementation.)上看到这样的一段话:
Thus [[Call]] besides the [[Class]] property (which equals to “Function”) is the main in respect of objects distinguishing. Therefore the objects having internal [[Call]] property are called as functions.
上面这段话大致翻译成这样:
因此[[Call]]是除了[[Class]]属性(相当于“Function”)object 识别的主要部分。 因此具有内部[[Call]]属性的对象被称为函数。
typeof 运算符结果(重点看最后4个)
4、
var bar = {
foo: function() {return this.baz},
baz: 1
};
(function() {
console.log(typeof arguments[0]());
})(bar.foo)
答案:undefined
(这里另有坑)
一开始我认为 arguments[0] ()
可以转换为 bar.foo()
,所以我的答案是 number。后来面试官提示这里匿名函数参数传递的是函数的地址,我连忙改口说因为这里的函数调用是 function 调用,故 this 指向 window,所以是 undefined。
后来回来之后,复盘的时候发现这里似乎被面试官挖了一个坑往里面跳,答案仍旧是 undefined,不过原理却完全不同。
这里的 this 指向的不是 window,而是 arguments 这个类数组对象,arguments[0] ()
可以替换成是 arguments.0()
(伪代码,实际不能这么写),可以把 arguments 看成这样:
arguments = {
0: bar.foo, //也就是 functon() {return (this.baz)}
1: 第二个参数, //没有
...,
length: 1 //只有一个参数
}
那么此处这个函数是作为 arguments这个对象的 method 方式运行的,故this指向 arguments,返回 undefined。(对 this 的解释可以移步:this 的4条绑定规则及优先级)。
卷纸上的题目只能记得上面的4个(没办法,老年人记性)。
问完卷纸上的题目,面试官开始拿着我的简历开始问问题,也是围绕着上面写的一些点,这里举几个例子:
然后问了点我简历里写的项目问题,问完简历上面的问题后,面试官又提了一些其他的东西:
display:flex;
和 transform: translate(-50%, -50%);
两种办法(详情可参见 CSS 实现水平居中与垂直居中)。 transform: translate(-50%, -50%);
中的 -50%,是参照父元素的宽高偏移还是参照子元素的宽高偏移? 除了上面的问题,其实还问了挺多的,只是一时想不起来,只能列出一些印象深刻的。整体自我感觉一面还好,有一些自认为理解的问题,还有些欠缺,一些问题是之前写了博文总结过的,也想了好一会儿。看来,在日常学习之余,还要时常总结复习之前的学习内容。
一面之后,直接就安排了二面。二面面试官一开始也没随便吧啦吧啦,直接切入正题。
foo(A, B)
,若A认识B返回true,若A不认识B返回false,试设计一种算法找出明星,并给出时间复杂度。 二面就问了两个算法题,二面回答的很糟糕,第一题一开始想到好几种时间复杂度都是O(n*n)的方法,好不容易在面试官的提示下才堪堪想出一个 O(n) 的方法。第二题则完全没想出来,gg。最后在两天后接到了被拒的邮件,我想大概率就是栽在了二面上,以后在学习前端知识的同时,还要注意算法等基础方面的能力。(二面题目的解析,后面我会单独发解析的文章)。