面试查漏补缺

最近在找工作去面试,换工作是一件要认真考虑和谨慎的事情,我从年前开始我这个念头准备换一个城市去体验一下别的地方的生活,然后考虑了一段时间,问了父母的意见,最后决定去另外一个地方看看,其中也是受到了《一个人的朝圣》这本书的影响。

后面就开始投简历,去面试,才发现面试真的是除了工作之外最能查漏补缺的一个方法,只要问到的问题你模棱两可就说明你对这里还不熟悉,你就应该更深入的去了解。主要就是记录一下面试当中遇到的一些知识上的漏洞。

垂直居中的方法

老生常谈的问题,我答出了几种没有说全,这里大概说一下:

  1. 使用display:table-cell; vertical-align: middle;
  2. top: 50%; margin-top: 高度一半这种方法居中的这个容器高度必须固定
  3. top: 50%; transform:translateY (-50%)这种方法和上面类似,但是不容固定高度了
  4. position:absolute; 上下左右都是0 (margin: auto)或者 margin: 0 auto
  5. height:10px; line-height:10px只是文本可以用
  6. display:flex; justify-content:center;align-items: center这种方法移动端很好,pc端会有兼容方面问题

参考文章:链接在此 说了每种方式的优缺点建议看一下。

判断一个引用类型的种类

这个我基本答全了,只是做一下回顾。

如果是判断一个基本的类型用typeof就是可以的

1
2
3
4
5
6
7
8
9
typeof ''; // string 有效
typeof 1; // number 有效
typeof true; //boolean 有效
typeof undefined; //undefined 有效
typeof null; //object 无效
typeof [] ; //object 无效
typeof new Function(); // function 有效
typeof new Date(); //object 无效
typeof new RegExp(); //object 无效

如果判断的是引用类型的话

1 instanceof是可以的

1
2
3
[] instanceof Array; //true
{} instanceof Object;//true
new Date() instanceof Date;//true

但是也有一点坑,他也会检测原型链

1
2
[] instanceof Object; //true
new Date() instanceof Object;//true

因为他们都属于对象。

2 Object.prototype.toString().call

1
2
3
4
5
6
7
8
9
10
Object.prototype.toString.call('') ;   // [object String]
Object.prototype.toString.call(1) ; // [object Number]
Object.prototype.toString.call(true) ; // [object Boolean]
Object.prototype.toString.call(undefined) ; // [object Undefined]
Object.prototype.toString.call(null) ; // [object Null]
Object.prototype.toString.call(new Function()) ; // [object Function]
Object.prototype.toString.call(new Date()) ; // [object Date]
Object.prototype.toString.call([]) ; // [object Array]
Object.prototype.toString.call(new RegExp()) ; // [object RegExp]
Object.prototype.toString.call(new Error()) ; // [object Error]

*还有一个 constructor 但是这个会有不好的地方还是不用最好(见第二篇参考),Object.prototype.toString().call()这个方法还是最靠谱的

参考文章: JS 判断数据类型的三种方法如何检查JavaScript变量类型?

深复制一个对象

这道题如果真的让我手写我真是写不出来,当时也只是说了一下大概的需要判断每种类型来做处理。现在还是来写一下吧。

首先我记得在百度ife中是有这道题的,所以我先翻出了原来的答案。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/**
* 对一个object进行深度拷贝
*
* 使用递归来实现一个深度克隆,可以复制一个目标对象,返回一个完整拷贝
* 被复制的对象类型会被限制为数字、字符串、布尔、日期、数组、Object对象。不会包含函数、正则对象等
*
* @param {Object} source 需要进行拷贝的对象
* @return {Object} 拷贝后的新对象
*/

function cloneObject (source) {
var result = source, i, len;
if (!source
|| source instanceof Number
|| source instanceof String
|| source instanceof Boolean) {
return result;
} else if (isArray(source)) {
result = [];
var resultLen = 0;
for (i = 0, len = source.length; i < len; i++) {
result[resultLen++] = cloneObject(source[i]);
}
} else if (isPlain(source)) {
result = {};
for (i in source) {
if (source.hasOwnProperty(i)) {
result[i] = cloneObject(source[i]);
}
}
}
return result;
}

这个答案是比较清楚明了的,看完之后感觉下次遇到之后思路会更清晰一些。

然后又去看了一篇博客,深入剖析 JavaScript 的深复制,相信大家看了之后会和我一样有很大启发。

函数四种调用方式和this的指向

其实当看到每种this的指向的时候还是知道的,但也应该清楚到底有哪几种。

1.方法调用模式

1
2
3
4
5
6
7
8
9
10
11

var obj = {
val: 0,
count: function(){
this.val ++;
console.log(this.val);
}
};

obj.count(); // 1
obj.count(); // 2

当当做对象的方法去调用的时候,this是指向这个对象的。问题又来了,那如果那个方法是一个箭头函数呢?

1
2
3
4
5
6
7
8
9

var obj = {
val: 0,
count: () => {
console.log(this.val);
}
};

obj.count(); // undefined

箭头函数内部没有this,他的this就是定义是外部this的指向,指向window。

2.函数调用模式

被当做函数调用的时候,this会指向window。

3.构造函数调用模式

this会指向这个构造函数。

1
function foo(a) {
     this.a = a;
 }
 var bar = new foo(2);
 console.log( bar.a ); // 2

4.Apply 调用模式

1
function foo() {
     console.log( this.a );
	}
	var obj = { a:2
 };
 foo.apply( obj ); // 2

清除浮动五种方式

说是有五种方法,但其实思路上其实就是三种:

一种是:就是给之后的元素清除浮动(clear:both可以添加一个多余的dom,可以给伪类元素,可以给之后相邻的元素)

一种是:给浮动的容器,overflow:hidden

一种是:给浮动的容器也一起去浮动了

一般常用的一种就是伪类元素上清除浮动:

1
2
3
4
5
6
7
8
div:after {
display:block;
content: '.';
width: 0;
height: 0;
clear: both;
visibility: hidden;
}

点击穿透的原理及解决方法

原理方面其实搜索一下都可以找到,详细原理就不赘述了,后面给出链接。

主要的原理是因为Safari浏览器的300ms延迟的问题(在touchend后等待300ms确认没有双击就去触发click事件),当出现一个mask遮罩层的你去点击这个mask,然后mask消失300ms后会触发click,但是mask已经消失就会触发mask下方绑定有click事件的元素(也就是下层绑定了click事件或click时会触发的事件(focus focusout)的元素,或点击时有默认形为的标签元素,如a input等。)

解决办法:

  1. 使用fastclick避免300ms延迟,这样也就不会出现点击穿透了。
  2. CSS3的 pointer-events 属性

    属性 | 含义
    —-|——
    auto | 默认值,鼠标或触屏事件不会穿透当前层
    none | 元素不再是target,监听的元素变成了下层的元素(如果子元素设置成 auto,点击子元素会继续监听事件)

  3. 使mask在300ms之后消失掉(加些动画效果使他消失变慢)

参考资料:也来说说touch事件与点击穿透问题

移动端click延迟及zepto的穿透现象

几道判断输出的题

几题都是平时不太会注意的点

稀疏数组和Array.prototype.filter()

1
2
3
4
5
6
7
8
9
10

//filter函数返回的结果是什么
var ary = [0, 1, 2];
var ary[10] = 10;
ary.filter(function(x){
return x === undefined;
})

//你以为返回的结果是[undefined,..., undefined](一共七个)
//其实是[]

考察点:

  1. 当指定数组的索引比数组长度大的时候,会返回一个稀疏数组
  2. filter当中的callback是不会处理稀疏数组中缺失的元素,正因为他不会处理稀疏数组中确实的元素,所以其实callback只传递了0,1,2,10这几个值,所以返回一个[]

this指向问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var length  = 1
function b () {
console.log(this.length)
}
var c = {
length: 3,
fun: function (fn) {
console.log(this.length)
fn()
arguments[0]()

}
}
c.fun(b,1) //会输出什么
//3
//1
//2

这个其实就是上面说过的this指向的几种方式吧,首先是当做对象的方法调用所以指向所以输出3,后面是当做一个函数去调用所以指向window所以输出1,最后一个有一点特殊,最后一个this其实是指向arguments这个内置对象的,所以this.length是指参数的长度故为2 。

类型转换

1
2
3
4
5
6
var a = [0];
if ([0]) {
console.log(a == true);
} else {
console.log("wut");
}

这道题涉及类型转换:

  • Boolean([0]) === true

  • [0] == true

  • true 转换为数字 => 1

  • [0] 转化为数字失败, 转化为字符串 ‘0’, 转化成数字 => 0

  • 0 !== 1

输出false

这种题怎么说呢,说要掌握吧平常工作当中谁会这么写代码,说不必要了解吧有人就要考这些。

map和||

1
2
3
4
5
6
7
8
9
10
11
function isOdd(num) {
return num % 2 == 1;
}
function isEven(num) {
return num % 2 == 0;
}
function isSane(num) {
return isEven(num) || isOdd(num);
}
var values = [7, 4, '13', -9, Infinity];
values.map(isSane);

前三个应该都没问题,-9 % 2 => -1所以和两个比较都不相等返回false,Infinity % 2 => NaN所以也返回false,所以结果为[true, true, true, false, false]

(未完,今天太晚了,会一直去更新,直到找到工作哈哈哈哈 )