美文网首页
一年前端面试打怪升级之路(四)

一年前端面试打怪升级之路(四)

作者: 如意同学Try | 来源:发表于2018-03-05 13:23 被阅读0次

    掘金传送门:

    一年前端面试打怪升级之路(一)

    一年前端面试打怪升级之路(二)

    题外话:前面两篇文章掘金评论下展开了热烈的讨论,让我深切感受到掘金社区技术氛围的浓厚,同时也很感谢各位大佬对文章中的问题进行答疑解惑,感觉本菜鸟的前端经验值进度条又涨了不少~

    之后面试了一家知名上市通信公司,一家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. 事件委托的应用场景
    1. 需要对一个页面中不存在的元素设置事件的时候,就需要把事件委托到父元素上。

    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. 优化性能的方法

    其实原题她问的是,优化性能的步骤。我觉得步骤这个东西并没有一个标准,需求不同肯定侧重不同了,所以说了我的看法后,我回答的是优化性能的方法

    1. 尽可能减少对服务器资源请求的次数,制定合理的接口
    2. 尽可能减少资源的大小,比如优化图片、样式等资源
    3. 按需加载资源
    4. 尽可能减少页面dom的结构纵深,做到标签语义化
    5. 制定合理的标签Id和类名,避免使用复杂的css选择嵌套
    6. 合理使用预编译器
    7. 减少冗余代码,做好通用方法的封装
    8. 操作页面时尽量减少重排重绘的次数

    前端性能优化其实是个很大的话题,当时脑子里没有一套体系,看上去回答了不少点,但是应该是比较乱。关于这个话题,我想我会再额外做一个总结。

    下列是近期看的相关文章

    2018前端性能优化清单(一)

    2018前端性能优化清单(二)

    2018前端性能优化清单(三)

    2018前端性能优化清单(四)

    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.callthis,这里的call作用就是改变this的指向,让回调Functionthis指向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 4a 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()
    

    优化点:

    1. 闭包内定义变量,循环时重复创建,消耗大量内存(闭包内的变量常驻内存)。应该把变量提升到闭包外部
    2. 选择器querySelector可以换成getElementById,效率更高

    相关文章

      网友评论

          本文标题:一年前端面试打怪升级之路(四)

          本文链接:https://www.haomeiwen.com/subject/vsvoxftx.html