掘金传送门:
题外话:前面两篇文章掘金评论下展开了热烈的讨论,让我深切感受到掘金社区技术氛围的浓厚,同时也很感谢各位大佬对文章中的问题进行答疑解惑,感觉本菜鸟的前端经验值进度条又涨了不少~
之后面试了一家知名上市通信公司,一家A轮初创企业,一家跨境电商,其实有不少问题和前面的有重复,所以我会挑取其中有分享意义的部分,并且放在一个篇幅下。
其中跨境电商问的技术问题也不多,主要是想要了解我会使用哪些技术,然后针对做过的项目做了一些提问,两个面试官哥哥好像半小时不到就开始互相干瞪眼,没什么要问我了。。在我猜测我应该是GG了的时候,hr姐姐又进来了,拉着我聊了将近1个多小时。
通信公司
技术面+hr面,历时2个多小时
第一次遇到女性技术面试官,面试中全程板着脸,不太敢皮了,把我给紧张的...
项目问题
由于公司与我上家公司所在业务类似,所以对我所做的项目做了很多追问。这部分还是无压力的,每个人的项目都有自己不同的回答角度,答案并不是重点,重要的是有自己的思考过程
1. 项目用了什么技术?为什么要做这样的技术选型
2. (针对一个纯数据展示的地图平台)讲一下项目的数据流走向和传递
3. 期间遇到过什么难题,你是怎么解决的
4. 你觉得这个项目最复杂的地方在哪里
5. 你们部门的开发流程是怎样的
数组扩展问题
因为我所做的项目是处理大量的数据,会涉及到很多对数组的操作,面试官对数组进行了一些提问
1. 数组去重方法,至少两种
//第一种方法
function Fn(arr){
if(Array.isArray(arr)){
var newArr = [];
newArr.push(arr[0]);
for(var i = 0 ; i < arr.length ; i++)
if( newArr.indexOf(arr[i]) < 0 ){
newArr.push(arr[i]);
}
return newArr;
}else{
return arr + "不是数组"
}
}
//第二种方法
[...new Set(arr)]
2. map和forEach有什么区别
返回值不同。两者都是对数组中的每一项进行操作。map返回新数组,forEach返回undefined
3. [1,2,3].push(4)返回什么
返回4,push返回的是新数组的长度
其他扩展问题
1. JQ中的eq(0)和first()方法哪个性能更好
我按我自己的理解,eq()应该是一个循环方法,而first相当于直接取第一个不需要遍历。我答first性能应该会更好一点。
后来去查了源码
first: function() {
return this.eq( 0 );
}
eq: function( i ) {
var len = this.length,
j = +i + ( i < 0 ? len : 0 );
return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] );
},
我???这不是一样吗,难道是eq效率更高?因为first多了一步引用?求解答...
2. 事件委托的应用场景
-
需要对一个页面中不存在的元素设置事件的时候,就需要把事件委托到父元素上。
-
还有就是当父元素下有多个标签的时候,也可以用事件委托,就不需要对每个标签设置事件
3. 闭包的应用场景
当需要一个变量常驻内存的时候。
看着面试官毫无波澜的表情真的很没底啊,我又补充了一句相当于是一个私有的概念,一个可以在全局访问的局部变量。
然后又说了工作中的使用场景,曾经使用闭包封装过一个工具
4. JQ和vue的使用场景,什么时候用jq什么时候用vue
没做过场景使用的归纳,知道个大概但是一时不知道怎么组织,偷换概念我答了JQ和vue的对比
JQ:数据和页面是耦合的,在原生的基础上提高了对dom元素的操作效率
vue:通过操作数据去渲染页面,不需要直接操作页面dom
后来去查了下也没什么特别出彩的,网上也尽是两者对比。按我理解的话,如果涉及到数据交互,vue更加便捷,但如果是展示性页面,还是JQ会更方便点
关于jQ和vue的讨论我其实听了很多观点。有些公司的人会认为JQ虽然现在依然是主流,但在MVVM大行其道的时代,它是一个迟早要被淘汰的框架(从2017年三大框架使用情况可以看出)。面试的时候会对我之前所在公司还在使用JQ表现出不解,甚至是不屑;而有些公司就不喜欢vue或者react比JQ更强的言论,认为需求至上,需要根据场景选择不同的框架。
天秤座的我就不站立场了,但是我很想听听来自各方不同的言论
5. vue的特色是什么
我答了组件通信和双向绑定,文档上也提到了这两点是vue的两个很强的优势所在。
不过面试官引导了一会儿,强调和JQ相比,vue的特色是什么,为什么虚拟DOM更好。我从性能角度上回答,她好像不太满意。难道是希望我回答跨平台?恩真的要回去撸vue底层了..
6. 优化性能的方法
其实原题她问的是,优化性能的步骤。我觉得步骤这个东西并没有一个标准,需求不同肯定侧重不同了,所以说了我的看法后,我回答的是优化性能的方法
- 尽可能减少对服务器资源请求的次数,制定合理的接口
- 尽可能减少资源的大小,比如优化图片、样式等资源
- 按需加载资源
- 尽可能减少页面dom的结构纵深,做到标签语义化
- 制定合理的标签Id和类名,避免使用复杂的css选择嵌套
- 合理使用预编译器
- 减少冗余代码,做好通用方法的封装
- 操作页面时尽量减少重排重绘的次数
前端性能优化其实是个很大的话题,当时脑子里没有一套体系,看上去回答了不少点,但是应该是比较乱。关于这个话题,我想我会再额外做一个总结。
下列是近期看的相关文章
7. 了解哪些设计规范
我实话实说,回答没有很系统地了解过,只知道一些基本的输入校验,兼容性处理,边界处理,条件封闭处理等等
这里有一篇我收藏的比较有意思的文章为什么你的工作经验不值钱,的确工作经验其实不能以年来衡量。在工作中总结,并且提高思维方式才是正确的打开方式
重复问题
1. 什么是重排重绘
2. 哪些操作会导致重排重绘
hr面
依旧是一个很严肃的大姐姐,问了一些常规问题,还让我讲了下成就感最高的项目,估计是想看看表达能力。期间有感受到她的施压,比如故意用严厉的语气指出你的缺点,然后问你觉得自己凭什么能胜任这份岗位。心理防线不坚挺的人估计就歇菜了。大公司的hr果然还是不好应付啊
电话面试
因为当时还处于在职的状态,请假成本有点高,所以这次我提出先进行电话面试,某天的中午面试官就打来了电话。历时约1个小时。
1. 如何区分JQ对象和js对象
instanceof可以区分,JQ对象的原型是jQuery
&elem instanceof jQuery
2. jQ的silce()方法实现原理
jQ的silice()是用于获取元素集合的指定子集
$elem.slice(0,2) //获取选择对象的前两个元素
我第一反应是扩展数组slice方法。后来查了源码3.3.写法如下,应该也不算答错了吧?
slice: function() {
return this.pushStack( slice.apply( this, arguments ) );
},
//pushStack应该是一个存储栈,用于存放选择的JQ对象
pushStack: function( elems ) {
// Build a new jQuery matched element set
var ret = jQuery.merge( this.constructor(), elems );
// Add the old object onto the stack (as a reference)
ret.prevObject = this;
// Return the newly-formed element set
return ret;
},
3. 最近在看什么书,印象最深刻的一点是什么
《dom编程艺术》:渐进增强和平稳退化的概念,在处理兼容问题的两种开发思维
《js面向对象编程指南》:Js中的一切都是对象,从对象的角度重新认识了数据类型
4. vue的父子组件通信实现方式
- 父——>子: 子组件中,使用prop用于接收父组件的data
props:{
data1:{
type:String, //数据类型
requried:true //是否为必须字段
}
}
- 子——>父: 在子组件中利用事件监听,使用emit自定义指令,通过参数传递向父组件提交数据
methods:{
event1(e){
this.$emit('event1',e);
}
}
5. ES6,for循环中let的作用域链是怎么样的
这个在阮老师的es6文档有详细的说明,运气也好这块有仔细读过
for循环的特殊情况在于,设置循环变量的那部分是一个父作用域,循环体是一个子作用域。
使用let声明循环变量,相当于每次循环都在创建一个新的变量,所以可以获取到每个步骤的变量
所以在我的这个系列第一篇一年前端面试打怪升级之路(一)中提到的输出1-10,其实最简单的方法就是使用let声明循环变量
for(let i = 1 ; i <= 10 ; i++){
setTimeout(function(){
console.log(i)
});
}
6. 不使用插件,你会如何实现目录树
简历中有提到项目中使用了插件treeview
我说我自己写的话,应该会用遍历和递归吧
重复问题:
1. 垂直居中实现方式
2. vue双向绑定原理
3. 项目问题
之后我询问了他们的技术方向,人员构成等问题,这次面试就结束了。让我等待交叉面试通知。不过就没有然后了。
我觉得电话面试毕竟没有建立起你整个人的形象,除非回答的很出彩,否则很难给人留下很深的印象。多跑跑,没毛病
B轮互联网公司
主技术栈react,在这之前我完全没看过react,可以说是技术栈不符了。面试官在掘金上看到我的文章,还是让我过去聊了聊。
历时一个多小时,面完的感受DXY出来一致,互联网企业会问的非常细,看重底层和Js基本功
在自我介绍后,开始做现场笔试题,面试官就在旁边处理业务。随后的提问都是针对题目展开
1. promise的机制
下列处理有什么不对的地方,怎么处理(对promise不熟啊还有道题目没记下来)
var promise = new Promise promiseProject(){}
promise.then(function(){
dosomething()
dosomethingErrorExpect()
})
这里考察promise的成功和异常处理。之后展开的各种异步处理都不会,我说我只会ajax(捂脸)
map的参数,call
输出什么,说明理由
var arr = [" abc","c d "];
function F(arr){
return arr.map(
Function.prototype.call,
String.prototype.trim
)
}
F(arr)
结果是string的trim方法生效,输出["abc","c d"];
题目给了个提示,map的第2个参数代表回调的this。
首先,根据提示题目中的String,prototype.trim
就是Function .prototype.call
的this
,这里的call
作用就是改变this
的指向,让回调Function
的this
指向String,prototype.trim
。
map回调的第一个参数是遍历数组的元素elem,这里就是分别传入" abc"
和"c d"
最后相当于是对每个elem执行了trim
两边去空格的方法
输出["abc","cd"]
;
bind和call的区别是什么
变量提升
写出执行结果
var a = 1;
function F(){
var a = 2;
c = 4;
return function g(){
console.log(a++);
console.log(b++);
console.log(c++);
}
}
console.log(a);
console.log(b);
console.log(c);
var b = 3;
var g = F();
g();
console.log(a);
console.log(b);
console.log(c);
分析:
- step1. 这题涉及4个变量,a,b,c,g。其中a,b,g都使用关键字
var
声明,c没有使用关键字声明,相当于是一个全局window的属性,可在全局访问 - step2. 使用var声明的变量,会把声明提前,所以全局中一开始就存在a,b,g,在对它们赋值前都是
undefined
。 - step3. 在第一次console.log的时候,a已被赋值,b已存在,但未赋值,c不存在(F()还未被调用)。这是程序执行到
console.log(c);
会报错,并停止执行
假设把报错语句console.log(c);
注释掉,接下去会如何执行?
- step4. 执行到
var g = F()
的时候,相当于调用F()函数,新增了c = 4
,但是还没执行return
中的内容 - step5. 执行
g()
,也就是执行F()
return中的内容。a++
是先使用再赋值,这里先输出a的值,再进行自加操作。b和c同理。所以这一步的打印结果:2 3 4
。a b c
实际值分别为3,4,5
- step6. 也就是上一步的最后分析结果,打印结果为
3 4 5
c和var a的区别
一个是创建全局属性,一个是声明变量
主要区别在于是不是有可删除属性
创建全局变量可以使用delete
删除
声明变量不可以删除
translate内部机制。不会涉及重排重绘
//两段代码的区别,哪个更好
#elem{
position:absolute;
top:30px;
left:100px;
animation: myAnimate easing 4s
}
@keyframe myAnimate{
50%{
transfrom: translate(100px 100px)
}
}
<!-- —————— --!>
#elem{
position:absolute;
top:30px;
left:100px;
animation: myAnimate easing 4s
}
@keyframe myAnimate{
50%{
top:130px;
left:200px
}
}
Linux读写权限?
sudo chmod -R 777 /var/emmweb/
-
-R 文件夹以及文件夹下面所有的子文件夹
-
777 读写执行
-
/var/emmweb/ : 操作的文件夹
权限码描述
sudo chmod 600 ××× (只有所有者有读和写的权限)
sudo chmod 644 ××× (所有者有读和写的权限,组用户只有读的权限)
sudo chmod 700 ××× (只有所有者有读和写以及执行的权限)
sudo chmod 666 ××× (每个人都有读和写的权限)
sudo chmod 777 ××× (每个人都有读和写以及执行的权限)
-R表示包含设置所有子目录
冒泡排序
遍历数组,每次进行相邻两个数比较,大的放在左边,小的放右边,遍历n次,保证所有区域处于有序状态
//大概写了一个
function sort(arr){
if(Array.isArray(arr)){
for(var i = 0 ; i < arr.length ; i++){
arr.forEach(function(ele,index){
if(arr[index + 1] > ele){
var flag = arr[index];
arr[index] = arr[index + 1];
arr[index + 1] = flag;
}
});
}
return arr;
}
}
优化下列代码
function F(){
var count = 0;
function g(){
var elem = document.querySelector("#elem");
elem.textContent = count++;
setTimeout(g, 1000);
}
g();
}
F()
优化点:
- 闭包内定义变量,循环时重复创建,消耗大量内存(闭包内的变量常驻内存)。应该把变量提升到闭包外部
- 选择器
querySelector
可以换成getElementById
,效率更高
网友评论