18年9月面试心得
作为今年的应届生,虽说工作也已经一年多,但是,还是得给自己找点压力的,传说中的金九银十。由于需要工作,所以安排的面试不是很多。整理一下最近被问的比较多的几个前端问题。
js部分
1、生成一个数组,数组元素等于数组下标。形如: [0,1,2,…..]
常规思路循环
1 function arrCreate(){ 2 var s = []; 3 for(var i=0; i<100;i++){ 4 s[i]=i 5 } 6 console.log(s); 7 }
面试官接下来会说,如果不使用循环呢
方案1:
1 var creatArray = Object.keys(Array.apply(null,{length: 100})).map(function(item){
return +item
});
方案2:
1 var arrNew = Array.from({length: 100},(v,k)=>k);
方案3:setInterval
var s = []; var i = 0; var pushArray = setInterval(function(){ s[i] = i++; if (i >= 100){ clearInterval(pushArray); console.log(s); } },1);
方案4:递归
var s = []; var i =0; function array(num){ if(i<100){ s[i] = i++ array(num); } return s; }
2、数组反转
1 var arr1 = [ 1,2,3,4,5,6 ]; 2 arr1.reverse();
3、数组去重
数组去重之前有整理过一篇关于数组去重的文章。主要思路有:1、两个数组,循环数组,如果元素在新数组中不存在,添加到新数组。
链接地址:https://www.cnblogs.com/Vibge/p/9338001.html
4、字符串反转
基本思路,字符串转数组,反转
1 var str = 'klasd'; 2 var c = str.split("").reverse().join("") );
5、数组的深拷贝和浅拷贝
深拷贝和浅拷贝最根本的区别在于是否真的拷贝到实体,而不是引用。
浅拷贝仅仅是指向被拷贝的内存地址,如果原地址中对象发生改变,那么浅拷贝出来的对象也会相应的改变。
深拷贝是在计算机中开辟了一块新的内存地址用于存放拷贝的对象。
基本类型是按值传递,修改b的值,a的值是不会改变的
var a = 1;
var b = a;
b = 2;
console.log(a); //1
console.log(b);// 2
但是对象就不同,对象的传值是按引用传值。
var obj1 = {a:1,b:2,c:3};
var obj2 = obj1;
obj2.b = 4;
console.log(obj1); // {a:1,b:4,c:3}
console.log(obj2); // {a:1,b:4,c:3}
如果需要避免这种问题,可以采用深拷贝。
方案一:手动赋值
var obj1 = {a:1,b:2,c:3};
var obj2 = {a:obj1.a,b:obj1.b,c:obj1.c};
obj2.b = 4;
console.log(obj1); //{a:1,b:2,c:3}
console.log(obj2);// {a:1,b:4,c:3}
方案二:
对象只有一层的话可以使用:Object.assign()函数
var obj1 = {a:1,b:2,c:3};
var obj3 = {};
obj3 = Object.assign({},obj1);
obj3.b = 4;
console.log(obj3);//{a:1,b:2,c:3}
console.log(obj1);//{a:1,b:2,c:3}
方案三:
先转成json,再转回,缺陷:如果有函数将不会被复制,但是不会出错
var obj1 = {a:1,b:2,c:3};
var obj2 = JSON.parse(JSON.stringify(obj1));
obj2.b = 4;
console.log(obj1);//{a:1,b:2,c:3}
console.log(obj2);//{a:1,b:4,c:3}
方案四:递归拷贝,注意死循环
function deepClone(initObj,finalObj){
var obj = finalObj || {};
for(var i in initObj){
var prop = initObj[i];
if(prop === obj){
continue;
}
if(typeof prop === ‘object’){
obj[i] = (prop.constructor === Array)? [] : {};
arguments.callee(prop,obj[i]);
}else{
obj[i] = prop;
}
}
return obj;
}
var str = {};
var obj = {a:1,b:2,c:3};
deepClone(obj,str);
str.b = 4;
console.log(str);
console.log(obj);
6、数组排序
方案一:sort()方法
如果数组是普通数组,可采用sort(),默认是升序,可以传参,改变排序方式
var arr1 = [‘a’,’b’,’A’,’B’];
arr1.sort();
console.log(arr1); //[‘A’,’B’,’a’,’b’];
如果arr1 = [15,8,25,3];arr1.sort();得到的结果是15,25,3,8。这是因为在调用sort方法时,先将每个数组项toString,然后再对得到的字符串进行排序,所以出现这样的结果。
常用排序方法:
A.快速排序:基本思路:1、找基准,一般以中间项为基准 2、比大小,如果比基准大,放right,小于基准放左侧 3、递归
代码实现:参照 http://www.ruanyifeng.com/blog/2011/04/quicksort_in_javascript.html
if(arr.length <= 1){
return arr;
}
var pivotIndex = Math.floor(arr.length / 2);
var pivot = arr.splice(pivotIndex,1)[0];
var left = [];
var right = [];
for(var i = 0;i < arr.length; i++){
if(arr[i] < pivot){
left.push(arr[i]);
}else{
right.push(arr[i]);
}
}
return quickSort(left).concat([pivot], quickSort(right));
}
var arr2 = quickSort(arr1);
console.log(arr2);
var len = arr.length;
for(var i = 0;i < len;i++){
for(var j = 0;j < len-1-i;j++){
if(arr[j] > arr[j+1]){
var temp = arr[j+1];//元素交换
arr[j+1] = arr[j];
arr[j] = temp;
}
}
}
return arr;
}
var arr = [3,44,5,1,5];
console.log(bubbleSort(arr));
7、es5继承
es5继承的实现非常有趣,由于传统面向对象类的概念,JavaScript利用原型链的特性来实现继承。通过将子类构造函数的原型作为父类构造函数的实例,实现子类 — 子类原型–父亲,原型链的特点就是逐层查找,从子类开始一直往上直到所有对象的原型Object.prototype,找到属性方法之后就会停止查找,下层属性就会覆盖上层属性。
function extendClass(Child,Father){
//继承父类prototype 中定义的实例属性和方法
Child.prototype = Object.create(Father.prototype);
Child.prototype.constructor = Child;
//继承父类的静态属性方法
Object.keys(Father).forEach(function(key)){
Child[key] = Father[key];
}
es6继承
class Parent{
}
class Child1 extends Parent{
constructor(x,y,colors){
super(x,y);
this.colors = colors;
}
toString(){
return this.colors + ‘ ‘ + super.toString(); //调用父类的toString方法
}
}
8、promise和observable
状态:
promise具有3个状态:pending、resolved、rejected
observable具有N+3个状态:idle、pending、resolved_0、resolved_1….complete、error
总结:相比于promisse的有限状态机而言,Observable既可能是有限状态机,也可能是无限状态机(N为穷)。
调用情况:
Observable 具有可订阅性
Promise一经产生便开始起作用
结束:
promise仅有一个数据,故数据被获取即为promise完成,仅需要一个状态。
observable,可以有多个数据,因此需要一个额外的状态,一经完成后来便不再生成数据
运算符:
promise,由于有且只有一个数据,所以无需复杂的操作,仅需要一个简单的变换
Observable, 对于变换,需要使用.map方法,用来把Observable 中的某个元素转换成另一形式
对于组合,最简单的方式需要使用.mergeMap方法,用来把两个Observable整合为一个Observable,对于使用,需要使用subscribe方法,用来通知Observer我们需要它开始工作。
9、assign和map
Object.assign()方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象,它将返回目标对象。Object.assign(target,…sources),target是目标对象,sources是源对象。
var obj = {a:1};
var copy = object.assign({},obj);
console.log(copy); //{a:1}
合并对象。例如:
var o1 = {a:1};
var o2 = {b:2};
var o3 = {c:3};
var object = Object.assign(o1,o2,o3);
console.log(object); //{a:1,b:2,c:3}
注意assign属于浅拷贝,此时o1的属性也已经被更改。
合并具有相同属性的对象
var o1 = {a:1,b:2,c:3};
var o2 = {a:1,b:4};
var o3 = {c:3};
var object = Object.assign({},o1,o2,o3);
console.log(object); //{a:1,b:4,c:3}
Map对象保存键值对,任何值都可以作为一个或一个值。
new Map([iterable])
iterable可以是一个数组或者其他对象,其元素或为键值对,或者是两个元素的数组。null会被当做undefined。
var myMap = new Map();
myMap.set(0,’zero’);
myMap.set(1,’one’);
for(var [key,value] of myMap){
console.log(key + “=” + value);
}
for(var key of myMap.keys()){
console.log(key);
}
for(var vale of myMap.values()){
console.log(vale);
}
// Map也可以通过forEach()方法迭代
myMap.forEach(function(value,key){
console.log(key + ” = ” + value);
},myMap)
10、前端存储
localstorage:存储方式,以键值对的方式存储,永久存储,永不失效,除非手动删除。每个域名5M
sessionstorage:浏览器关闭时被清空。
11、json在什么时候会失败
12、异步和同步了解吗,有什么区别
13、递归优化方案
尾递归
14、如果有很多数据,需要排序,怎么处理
15、闭包,闭包的优缺点
闭包:能够读取其他函数内部变量的函数
优点:保护函数内的变量安全,加强了封装性,在内存中维持一个变量。
缺点:占用内存
css部分
1、三栏布局
2、水平垂直居中
flex布局:align-items:center;justify-content:center
3、文档流的概念。z-index属性
relative:脱离正常的文本流中,但其在文本流中的位置依然存在。
absolute:定位为absolute的层脱离正常文本流,在正常流中的位置不再存在。
static定位或无position定位的元素z-index属性是无效的。
4、元素不可见
思路较多,常见的几种:1、display:none; 2、visibillity:hidden; 3、margin:-99999999; 4、opacity
5、是否可以通过设置visibility来实现隐藏和显示的动画
貌似是不可行的
6、一般什么会影响页面的渲染
7、canvas操作
angular部分
1、说说angular的脏检查机制
angular使用zone.js跟踪异步任务,进行脏检查,zone.js给所有javascript异步事件提供了上下文。angular会在初始化的时候调用zone.js,当异步任务结束的时候,提示angular更新视图。
2、angular中component和directive有什么区别
component使用的注解@component修饰,directive使用注解@directive修饰
component是通过组件化思想,基于组件创建应用;directive是用来在已经存在的dom元素上实现一些行为。
component是可重复使用的组件,directive是可重复使用的行为
component有创建一个view,有template或者templateurl,directive则没有
3、angular中组件通信
父——>子 input
子——>父 output
事件通信
4、依赖注入
注入器:constructor(){}
提供器:provides
5、生命周期
constructor:构造器函数,一般用于注入服务
ngOnChanges:检测到输入数据变化,首次出发发生在ngOninit前
ngOninit:组件初始化
ngDoCheck:手动触发更新检查
ngAfterContentInit:内容初始化到组件之后
ngAfterContentCheck:内容变更检测之后
ngAfterViewInit:视图初始化之后
ngAfterViewChecked:视图发生变化检测之后,可以用来保证视图的及时更新
ngOndestroy:组件注销
6、angular和其他框架的区别
7、angular的双向绑定
附链接 https://www.cnblogs.com/Vibge/p/9250196.html
http
1、未授权登录失败401
2、http和https的区别
https协议需要到ca申请证书
http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议
http和https使用的是完全不同的连接方式,端口也不一样,前者是80,后者是443
http的连接简单,无状态连接,https协议是由ssl+http协议构建的进行加密传输
3、了解过跨域嘛
参考文章:
4、http response 和 header
其他
1、12个小球,有一个重量不一样,怎么用最快的方式找到这个不一样的小球
这个问题,主要是看面试官怎么问了,有的是直接说有一个偏重/偏轻,但也有不明确说明的
2、有一堆蜡烛,形状各异,生命周期都是1小时,在只有打火机的情况下获取一根只有半小时寿命的蜡烛
其实这个问题在面试官问的时候呢,做了限制说只有一个打火机的情况下,思路是一根蜡烛点两头,另一根蜡烛点燃,然后当一根蜡烛燃烧结束的时候,熄灭另一根蜡烛即为所求。感觉有很多弊端,例如说,一般蜡烛的燃烧速度并不是不受外界影响的,风向啥啥啥的,而且两根点燃的蜡烛就想知道你是放在哪里呢,还有蜡烛的另一端怎么就确定一定会有烛芯的呢,诸多疑问,但是还是不敢怼面试官的哟。
3、简述职业规划
4、说说项目的架构图(流程图)
一般是自己做过的项目这个流程还是清晰地,面试官当时给出的建议是,一边画一边讲解。
5、目前找工作主要考虑什么