VK的秋招前端奇遇记(一)

这个系列主要是对自己秋招以来,笔试、面试过程中的问题进行记录和解决,希望自己能够”吃一堑长一智”

系列笔记:

1.VK的秋招前端奇遇记(一)

2.VK的秋招前端奇遇记(二)

3.VK的秋招前端奇遇记(三)

4.VK的秋招前端奇遇记(四)

5.番外篇:前端面试&笔试算法 Algorithm


参考资料:37 Essential JavaScript Interview Questions
有很多内容来自以上参考,真的可以说是非常经典了!

Css相关

1. display:none与visibility:hidden的区别(2018拼多多前端笔试真题)

答案:在视觉效果上,两者是相同的,但是对于操作dom上是不同的 。
dispaly:none 会让dom的整个宽、高等相关位置元素失效,整个消失;
visibility:hidden 只是让该元素不可见,但是width以及原有位置是不会改变的

javascript

1. 基本问题

1) 是否可以使用 typeof bar === 'object'来检测bar是不是object类型,有和风险?

答案: 有风险,js的基本数据类型有 String Number Boolean undefined null和一种复杂数据类型object(ES6新增了symbol)。

对于复杂数据类型object,其实typeof null返回的也是object,因为本质上null就是一个占位用的对象。另一方面,数组Array也不能用typeof检测数据类型,因为同样会返回object

因此,如果想要检测bar是不是object,可以这样子:

1
2
3
console.log((bar !== null) && (tiopnuiop[yuiop[]\\]poi456/ypeof bar ==='object'))
//当然,如果认为function也是 object,可以用下面的语句
console.log((bar !== nul)&& (typeof bar ==='object')||(typeof bar ==='function'))

除此以外,还有比如Array的情况,因为Array也会返回object,如果我们不像让Array被认为是Object,就必须真正的认清Array,人情Array的方法有:

1
2
3
console.log( bar instanceof Array)  // 如果数组,返回true
console.log( Array.isArray(bar)) //ES5方法
console.log( Ojbect.prototype.toString.call(arr) === '[object Array]')

2) 以下两个函数是否等价
1
2
3
4
5
6
7
8
9
10
11
12
13
14
function foo1()
{
return {
bar: "hello"
};
}

function foo2()
{
return
{
bar: "hello"
};
}

答案: 不等价!!
注意,第二个函数返回的是undefined

1
2
console.log(foo1()); // {bar : "hellp"}
console.log(foo2()); // undefined

这也是为什么函数返回对象时,或写大括号时,把{写在一边,因为第二个函数js会默认return后面返回的东西(是空),等价于

1
2
3
return undefined
{xxx}
//后面当然,当然是写了也白写

3) NaN是什么?它是什么类型?如何检测一个变量是不是NaN

答案: NaN即Not A Number,但实际上它是Number类型
typeof NaN 将会返回Number
这个东西比较厉害,因为

1
NaN === NaN  //false

你会发现,它自己都不等于它自己,因此判断变量是否是它,不能使用===
可以使用isNaN方法

1
2
3
//检查变量是否是nan
isNaN(bar);
Object.is(bar,NaN); //ES6方法,这个方法会修正JS中的一些小bug

Object.is()方法,要求严格相等,且Object.is(NaN,NaN)会返回true

2.作用域相关问题

以下程序的输出是什么:

1
2
3
4
5
(function(){
var a = b = 3;
})();
console.log("a defined? " + (typeof a !== 'undefined'));
console.log("b defined? " + (typeof b !== 'undefined'));

答案:
a defined? false
b defined? true
理解这道题的核心在于如何理解var a = b = 3这句话,实际上这句话等于

1
2
var a; 
b = 3;

这样子,实际上,b是声明在了全局变量中(编译器在预编译帮你声明了,然而在严格模式下是不行的)
a是局部变量,所以在函数之外是没有定义的。

3.this&对象&数组

1)下面程序输出是什么
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
var myObject = {
foo: "bar",
func: function() {
var self = this;
console.log("outer func: this.foo = " + this.foo);
console.log("outer func: self.foo = " + self.foo);
(function() {
console.log(this);
console.log("inner func: this.foo = " + this.foo);
console.log("inner func: self.foo = " + self.foo);
}());
}
};
myObject.func();


//答案
outer func: this.foo = bar
outer func: serl.foo = bar
inner func: this.foo = undefined
inner func: self.foo = bar

分析: 搞清楚this的指向。记住以下几种规则

  • 谁调用,this指向谁 xxx.fun()
  • new一个对象,this指向实例本身var c = new fun()
  • 使用call/apply/bind修改this指向。

看题目,outer func显然是第一种情况,谁调用,this指向谁,这个时候都是myOjbect。
而在立即执行函数中,在这里this是没有进行绑定指向的,自然从属于window,所以这里this.foo是undefied

补充关于箭头函数的this

1
2
3
4
5
6
7
8
function a() {
return () => {
return () => {
console.log(this)
}
}
}
console.log(a()()())

注意:箭头函数其实是没有 this 的,这个函数中的 this 只取决于他外面的第一个不是箭头函数的函数的 this。在这个例子中,因为调用 a 符合前面代码中的第一个情况,所以 this 是 window。并且 this 一旦绑定了上下文,就不会被任何代码改变。

2)数组的filter,以下输出结果是什么(2018拼多多前端原题)
1
2
3
4
5
6
7
8
var arr = [1,2,3];
arr[10] = 9;
arr.filter((item)=> {
return item === undefined?
})

//答案
[]

解析: 是的,答案的确是[],不是[undefined x 7]
首先,看下前两句执行后,arr是什么

1
2
3
4
console.log(arr)
//[1,2,3, emptyx7, 9]
console.log(arr[5])
//undefined

从上面结果可以看出,的确中间未定义的(显示为empty的是undefined)。那么,filter之后,不是应该返回为undefined的数据吗?

是的,但是,当数组中都是undefined时,数组就是空,或者说[empty x 7] === []

4. JS小数计算不准确的bug

以下代码返回值是什么

1
2
3
4
5
console.log(0.1 + 0.2);
console.log(0.1 + 0.2 == 0.3);

//答案: 0.30000000000000004
false

解析: 详细的解析见连接,这里说一下解决办法 0.1+0.2 != 0.3

1
2
//解决办法
parseFloat((0.1+0.2).toFixed(10));

5. 算法/思路相关

1) 讨论实现判断变量是否是整数的函数isInter(x)的实现

答案: 在ES6中,是有现成的方法Number.isInteger可以使用的。如果自己实现,思路是什么呢

1
2
3
4
5
6
7
8
9
10
//1 异或运算
function isInter(x) {
return x ^ 0 === x
}

//2 取整
return Math.round(x) === x //同样可以用floor ceil

//取余
return (typeof x === 'number')&&(x % 1 === 0)

2) 写一个sum方法,可以实现以下两种调用方式
1
2
console.log(sum(2,3)) //5
console.log(sum(2)(3)) //5

答案:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//方法1
var sum = function(x,y) {
if(y === undefined) {
return function(y) {
return x + y;
}
}else {
return x + y;
}
}

//方法2
var sum = function(x){
if( arguments.length === 1) {
return function (y) {
return x + y;
}
} else {
console.log('here');
return arguments[0] + arguments[1];
}
}

3) 使用递归的方法,将obj变为obj2的格式(拼多多2018前端笔试真题)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
obj = [
{id:1,parent:null},
{id:2,parent:1},
{id:3,parent:2}
]

obj2 = {
obj:{
id: 1,
parent: null,
child: {
id: 2,
parent: 1,
child: {
id: ,3,
parent: 2
}
}
}
}
0%