写在前面
唉,我还是前端小渣渣一个。
最近一次的面试:
是一家云服务产品公司,面试流程也比较简单,前端负责人拿了一块白板和记号笔,心想一会要手写代码了。。。。
不过这种面试方式还是不错的。
去之前以为自己准备的差不多,其实准备的远远不够充足啊。
关于自我介绍
一开始一般会让你进行一个简单的自我介绍,我就主要说了一下上家公司的工作经历,描述了一下我负责过的项目,每个项目的业务功能,主要详细介绍每个项目用到的技术。
虽然我说了很多,但是事后觉得我在表达的时候,语言的条理性、逻辑性、准确性都不是很好,表达能力的强弱也是面试官比较看中的一部分,毕竟有可能以后和他共事交流工作内容,探讨技术等,所以,自我介绍这一块,觉得也挺重要的,自我介绍代表了面试官对你的第一印象,即便你面试很多次了,也说过很多次了,这方面还是应该好好梳理下自己的语言。
接下来考察js了,面试官慢慢的拿起了他的小白板,我的心里默默的有点小紧张。。。。
考察方式也比较中规中矩,按照js里的大类挨个考察。
- 首先是函数方面
for (var i = 0; i < 5; i++) {
setTimeout(function() {
console.log(i);
}, 1000);
}
“咦?。。。,上一次的面试不是也碰到了这个?”
然后我淡定的说出了答案:
“setTimeout
函数会延迟执行,那么等到执行console.log()
的时候,i
已经变成5了,所以最后会一次性打印出5个5;”
问:“那我要输出0~4呢?”
“怎么也有这个问题?是不是要问我有几种改法。。。”
我直接说var
改成let
就可以了
for (let i = 0; i < 5; i++) {
setTimeout(function() {
console.log(i);
}, 1000);
}
或者加个闭包:
for (var i = 0; i < 5; i++) {
(function(i) {
setTimeout(function() {
console.log(i);
}, 1000);
})(i)
}
或者这样:
for(var i = 1;i < 5;i++){
var a = function(){
var j = i;
setTimeout(function(){
console.log(j);
},1000)
}
a();
}
这也是用了闭包的方法,其实就相当于把var化成了let效果一样,这样i的值一开始不会被默认绑定,每执行一次循环的时候都会给i赋予新值。
问:“如果去掉function
里的 i
呢?”
“这样其实对内存没有保持引用, i 最后还是5。”
由于类似的面试题频繁遇到,整理了一些相关的面试题:
比如这个:
for (var i = 0; i < 5; i++) {
setTimeout((function(i) {
console.log(i);
})(i), i * 1000);
}
延时函数的第一个参数变成了一个立即执行函数,在这里应该是一个undefined
,等价于:
setTimeout( undefined, … )
;
立即函数会立马执行,所以是立马就输出0~4;
Promise考察:
setTimeout(function() {
console.log(1)}, 0);
new Promise(function executor(resolve) {
console.log(2);
for( var i=0 ; i<10000 ; i++ ) {
i == 9999 && resolve();
}
console.log(3);
}).then(function() {
console.log(4);
});
console.log(5);
考察运行机制,首先Promise
是异步的,Promise
只有三中状态,pending、fulfilled(成功)、rejected(失败)
,后两者统称为resolve
(已定型),一旦状态定下句就无法再改变。
第一个延时函数首先会设置一个定时,在定时结束后传递这个函数将它放到任务队列中去,因此一开始不会输出1;
Promise
里的函数会按顺序执行,输出2 3 ,Promise
里的then
就是会异步执行,放到当前Promise
任务队列的最后执行,而console.log(5)
是按顺序执行的,所以先输出5,再输出4。Promise.then()
里面的回调属于 microtask, 会在当前 Event Loop 的最后执行, 而 SetTimeout
内的回调属于 macrotask, 会在下一个 Event Loop 中执行
最后,才会输出1。
最后输出: 2 3 5 4 1
- 对象考察
先来个最简单的
var obj = {
a: "1"
};
var obj2 = obj;
obj2.a = "2";
console.log(obj.a);
“肯定是输出 2 啊”
ojb2只是对obj实例的一个引用,到最后还是修改的obj的值。
this指针
name = "name of window";
function show() {
var name = "name in function show()";
alert(this.name);
}
show();
这里定义了一个全局变量 name
,这个变量是属于 window
的,在 show
函数里也声明了一个name
变量。
this
的定义是指向调用当前函数的那个对象, show()
函数是在全局被调用的,所以this
应该指向的是当前 window
对象。
再看下一个:
var myObj = {
name: " my Object",
show: function() {
var name = "my Object in function";
alert(this.name);
},
};
myObj.show();
这次,调用 myObj.show()
的对象是 myObj
, 所以就会输出 my Object
- 数组Array
先来个排序吧:
var arr = [ 2, 4, 50, 20, 3 ];
冒泡排序:
var arr = [ 2, 4, 50, 20, 3 ];
for(var i = 0 ; i < arr.length-1; i ++){
for(var j = 0; j < arr.length-i; j++ ){
var ls;
if(arr[j] > arr[j+1]){
ls = arr[j];
arr[j] = arr[j+1]
arr[j+1] = ls
}
}
}
console.log(arr);
其实我要开始想到的是用sort()
,但是sort
排出来的不是很稳定,他默认排序是根据字符串Unicode码点。
还问我sort有几个参数,第二个参数是什么?
我当时没想起来,后续整理出来吧!
可选参数是一个比较函数, compareFunction
,用来指定按某种顺序进行排列的函数。如果省略,元素按照转换为的字符串的各个字符的Unicode位点进行排序。
- 如果
compareFunction(a, b)
小于 0 ,那么 a 会被排列到 b 之前;
- 如果
compareFunction(a, b)
等于 0 , a 和 b 的相对位置不变;
- 如果
compareFunction(a, b)
大于 0 , b 会被排列到 a 之前。 compareFunction(a, b)
必须总是对相同的输入返回相同的比较结果,否则排序的结果将是不确定的。
要比较数字而非字符串,比较函数可以简单的以 a 减 b,如下的函数将会将数组升序排列
function compareNumbers(a, b) {
return a - b;
}
所以上边那个排序就可以简单的写成:
var arr = [ 2, 4, 50, 20, 3 ];arr.sort(function (a, b) {
return a - b;
});
console.log(arr);
或者更简洁一点:
var arr = [ 2, 4, 50, 20, 3 ];
arr.sort((a, b) => a -b );
console.log(arr);
又给我改了一下,说怎么用sort 来排序一个对象?
var obj = [
{ name: 'a', value: 21 },
{ name: 'b', value: 37 },
{ name: 'c', value: 45 },
{ name: 'd', value: -12 },
{ name: 'e' }
];
应该是这样:
obj.sort(function (a, b) {
return (a.value - b.value);
});
零零碎碎的问了不少,其他的记不太清了,都是一些知识性的东西,不罗列了。
然后问了一些react、 redux相关的技术原理,生命周期、单向数据流、虚拟DOM等等。。。
这些我回答的还好,因为工作天天用这个,也比较熟悉,js基础类的一些题回答的不太好,我也知道我js基础不扎实,再者,面试题看少了,虽然这些基础的知识点在工作中用的不多,有的记不清楚的就google了,也不会影响开发进度,但是,即便react 用的再熟练,重中之重的js基础!才是最重要的,框架都是js写的。
反思一下,之前工作中碰到了一些不会的或者生疏不常用的技术,google出来答案后直接就用上了,也没有仔细的去研究其中的原理,知其然不知其所以然!
事后也没有总结出来,下次再碰到这个技术点,可能又要google了。。。
不说废话了!
整理一些网上看到的不错的面试题:(转载)
- 关于变量声明提升和函数声明提升
alert(a);
a();
var a=3;
function a(){
alert(10)
}
alert(a);
a=6;
a();
果不其然,我自己看一遍的时候就分析错了。
关键的一点就是:var 声明的变量 和function生命的函数都会提前,只是提前到作用域开始的位置,但不会进行赋值操作;
function a(){alert(10)}
,就会看到这个函数。2.
a()
,执行函数,就是出现alert(10)
3.执行了
var a=3;
所以alert(a)
就是显示3
4.由于
a
不是一个函数了,所以往下在执行到a()
的时候, 报错。 再来看:
alert(a);
a();
var a=3;
var a=function(){
alert(10)
}
alert(a);
a=6;
a();
区别是,函数这次用var声明了,根据原理,他只是声明被提前,但a 没有被赋值为一个函数,
所以,一开始alert(a) 是undefined
;
a() 报错;
类似的题目:
var a=0;
function aa(){
alert(a);
var a=3;
}
aa();
在aa函数里面,有var a=3,那么在aa作用域里面,就是把a这个变量声明提前,但是不会赋值,所以是undefined
;
var a=0;
function aa(a){
alert(a);
var a=3;
};
aa(5);
alert(a);
//5,0
在函数体内,参数a的优先级高于变量a ;
var a=0;
function aa(a){
alert(a);
a=3;
alert(a);
}
aa();
alert(a);
首先没有传参数进去,aa()
是 undefined
;
a=3,实际上修改的是形参a的值,并不是全局变量a,往下alert(a)
也是形参a;
最后的alert(a)
; 是全局的a;
写在最后
不说了!。。。
我要去刷面试题,继续啃我的JavaScript 语言精粹了。