今天看啥  ›  专栏  ›  Zzmbulldog

六月份面试小记

Zzmbulldog  · 掘金  ·  · 2019-07-17 04:00
阅读 32

六月份面试小记

六月并不是一个换工作的好时候,部分公司关闭了HC通道,加上三伏天的闷热,以及还是在职。写这篇文章主要是想记录这段时间来的面试经验,如果有类似情况的同学欢迎讨论。 只适合工作0-2年同学阅读,大佬请点击右上角的'X'

个人背景:base武汉,两年经验,非计算机相关专业,小211,投出简历30-40封,只收到面试邀请5家(惨==),正式offer 2家,口头offer 2家,未过 1家。

废话少说,进入下面的面试题。


1.请详细说出判断js类型的方式

(1)typeof

可以判断出'string','number','boolean','undefined','symbol'

但判断 typeof(null) 时值为 'object'; 判断数组和对象时值均为 'object'

(2)instanceof

原理是 构造函数的prototype属性是否出现在对象的原型链中的任何位置

eg:function A() {}
let a = new A();
a instanceof A     //true,因为 Object.getPrototypeOf(a) === A.prototype;
复制代码

(3)Object.prototype.toString.call()

常用于判断浏览器内置对象,对于所有基本的数据类型都能进行判断,即使是 null 和 undefined

(4)Array.isArray()

用于判断是否为数组

2.为什么要用到浅拷贝和深拷贝?两者区别和常用方法?

因为js中存在复杂数据类型

浅拷贝会将对象的属性值一一复制,当某属性值是引用类型时,复制的是它的引用,如果引用指针指向的对象被改变时,拷贝下来的值也会跟着改变。

而深拷贝则会递归到该属性值为基本类型再复制,拷贝前后的两者互不影响。

浅拷贝:

  • Object.assign()
  • Array.prototype.slice()
  • 扩展运算符 ...

深拷贝:

请阅大佬文章--详细解析赋值、浅拷贝和深拷贝的区别

3.三种数组去重的方法(尽量使用ES6)?

(1)[...new Set(arr)]

(2)let newArr = arr.filter((item,index) => {
        return arr.indexOf(item,0) === index;
    });
    
(3)let newArr = [];
    for(let i of arr){
        !newArr.includes(i) && newArr.push(i);    
    }
复制代码

这题还可以改为数组的扁平化(自然是不能只用flat()的),数组相关的知识还是比较喜欢问的吧。

4.浏览器存储的方式有哪些?区别是什么?

alt
(图片来源网络,侵删)

还简单说了下cookie原本并不是用来储存的而是用来与服务端通信的,需要自行封装api;

而localStorage则自带getItem和setItem方法,使用更方便。

4.1 如果遇上禁用setItem的浏览器怎么办?

先使用try...catch

5.DOM事件有哪些阶段?谈谈对事件代理的理解?

分为三大阶段:捕获阶段--目标阶段--冒泡阶段

事件代理简单说就是:事件不直接绑定到某元素上,而是绑定到该元素的父元素上,进行触发事件操作时(例如'click'),再通过条件判断,执行事件触发后的语句(例如'alert(e.target.innerHTML)');

好处:(1)使代码更简洁;(2)节省内存开销

6.transform、translate、transition分别是什么属性?CSS中常用的实现动画方式?有没有用过rAF(requestAnimationFrame)?

6.1 三者属性说明

transform是指变换、变形,是css3的一个属性,和width,height属性一样;

translate是transform的属性值,是指元素进行2D(3D)维度上位移或范围变换;

transition是指过渡效果,往往理解成简单的动画,需要有触发条件。

这里可以补充下transition和animation的比较,前者一般定义开始结束两个状态,需要有触发条件;而后者引入了关键帧、速度曲线、播放次数等概念,更符合动画的定义,且无需触发条件

6.2 对rAF的阐述

定时器一直是js动画的核心技术,但它们不够精准,因为定时器时间参数是指将执行代码放入UI线程队列中等待的时间,如果前面有其他任务队列执行时间过长,则会导致动画延迟,效果不精确等问题。

所以处理动画循环的关键是知道延迟多长时间合适:时间要足够短,才能让动画看起来比较柔滑平顺,避免多余性能损耗;时间要足够长,才能让浏览器准备好变化渲染。

这个时候rAF就出现了,采用系统时间间隔(大多浏览器刷新频率是60Hz,相当于1000ms/60≈16.6ms),保持最佳绘制效率,不会因为间隔时间过短,造成过度绘制,增加开销;也不会因为间隔时间太长,使用动画卡顿不流畅,让各种网页动画效果能够有一个统一的刷新机制。并且rAF会把每一帧中的所有DOM操作集中起来,在一次重绘或回流中就完成。

7.vue的nextTick的原理是什么?

7.1 为什么需要nextTick

Vue是异步修改DOM的并且不鼓励开发者直接接触DOM,但有时候业务需要必须对数据更改--刷新后的DOM做相应的处理,这时候就可以使用Vue.nextTick(callback)这个api了。

7.2 理解原理前的准备

首先需要知道事件循环中宏任务和微任务这两个概念(这其实也是面试常考点)请阅大佬文章--彻底搞懂浏览器Event-loop

常见的宏任务有script, setTimeout, setInterval, setImmediate, I/O, UI rendering

常见的微任务有process.nextTick(Nodejs),Promise.then(), MutationObserver;

7.3 理解nextTick

而nextTick的原理正是vue通过异步队列控制DOM更新和nextTick回调函数先后执行的方式。如果大家看过这部分的源码,会发现其中做了很多isNative()的判断,因为这里还存在兼容性优雅降级的问题。可见Vue开发团队的深思熟虑,对性能的良苦用心。

如果你比较了解了前面的事件循环原理,推荐你看看这篇文章 请阅大佬文章--全面解析Vue.nextTick实现原理

8.描述下vue从初始化页面--修改数据--刷新页面UI的过程?

当Vue进入初始化阶段时,一方面Vue会遍历data中的属性,并用Object.defineProperty将它转化成getter/setter的形式,实现数据劫持(暂不谈Vue3.0的Proxy);另一方面,Vue的指令编译器Compiler对元素节点的各个指令进行解析,初始化视图,并订阅Watcher来更新试图,此时Watcher会将自己添加到消息订阅器Dep中,此时初始化完毕。

当数据发生变化时,触发Observer中setter方法,立即调用Dep.notify(),Dep这个数组开始遍历所有的订阅者,并调用其update方法,Vue内部再通过diff算法,patch相应的更新完成对订阅者视图的改变。

请阅大佬文章--手写Vue双向绑定

请阅大佬文章--Vue之Virtual Dom和Diff算法

9.谈谈日常工作中是如何使用vue组件化的?

这个问题主要是因为简历中有写到,我的回答如下(仅是个人理解,非标答):

首先我认为组件化有3大要素:

  • prop---组件接受的参数,简单说也就是数据。最好使用对象的形式,这样可以规定类型type和校验规则validator
  • event---组件间传递消息的方法
  • slot---灵活使用具名和匿名插槽,给组件动态插入某些内容或组件

然后我补充到因为工作中Echarts用的比较多,而Echarts每个图表的配置参数又比较复杂,所以从统一性上来说,提取页面中各个图表元素的共同点,作为默认配置写入组件;从差异性上来说,总会有些特(qi)性(pa)需求需要实现或者线上环境的特殊数据需要适配,这就考验到组件化的兼容性和容错率。

我们工程中图表组件的个性化基本配置都是通过json文件key--value形式传递的,如果某一属性为空则取默认值;有时会存在某一图表联动另一图表的情况,则可以在json里传一个flag标志位。

举个栗子
如下图中5项数据指标,其中1项特别大,其他4项特别小的时候,视觉上会不太直观
我们会在组件里判断是否要在饼图的下面动态生成数字卡片,如下图
综上:组件化的使用需要前期做好充足的分析调查,目的即代码解耦、复用

请阅大佬文章--封装Vue组件的一些技巧

请阅大佬文章--写过『通用前端组件』吗?

10.vue-cli替我们做了哪些工作?

首先需要知道vue-cli是什么?它是基于Vue.js进行快速开发的完整系统,也可以理解成是很多npm包的集合。

其次,vue-cli完成的功能有哪些?

  • .vue文件 --> .js文件
  • ES6语法 --> ES5语法
  • Sass,Less,Stylus --> CSS
  • 对jpg,png,font等静态资源的处理
  • 热更新
  • 定义环境变量,区分dev和production模式
  • 。。。

如果开发者需要补充或修改默认设置,需要在package.json同级下新建一个vue.config.js文件 (这题我觉得答的不太好,个人在查阅Vue官网和搜索后也没能总结出比较满意的答案)

11.模块化解决了哪些问题?url-loader和file-loader的区别?

  • 文件依赖
  • 代码复用
  • 全局污染,命名冲突

url-loader封装了file-loader,但url-loader并不依赖于file-loader;两者都是在Webpack中处理图片或者图标字体文件。

file-loader返回的是url;url-loader会根据limit对文件分情况处理。当小于limit时,会返回base64;当大于limit时,会调用file-loader

12.webpack-dev-server和http服务器如nginx有什么区别? HRM(HotModuleReplacement)的好处是什么?

webpack-dev-server使用内存来存储webpack开发环境下的打包文件,并且可以使用模块热更新,相比传统http服务器开发更加简单高效。

好处就是在保存当前页面状态前提下(例如Tab条的第n个tab),局部更新代码

13.Hash和History两种路由模式的根本区别是什么?

这道题是我答的最尴尬的一道题,我当时的回答是这样的:

Hash是指url的#以及后面的字符串,hash值变化并不会向服务器发送请求,而是触发hashchange事件;

History是HTML5新增内容,需要服务端配合使用,有pushState,replaceState相关api,可以直接在控制台输入window.history.back()或者.forward()实现页面得前进或者后退。并且Hash兼容ie8,History只能兼容ie10...

当我噼里啪啦说完这些后,面试官淡淡得说了一句:你好像没听明白我的问题,我是问两者的根本区别是什么?

我当时想了20s,回答说:不好意思,我想我不太清楚答案,麻烦您告知一下。

面试官说:Hash模式下会随机生成一个值,而History下前后url都会记录在浏览器中。这种基本的问题应该是知道的呀!(好吧==,我比较菜)

14.说一下实际工作中解决异步的方式及相应的优缺点?

  • callback:回调地狱;
  • Promise: .then()链式写法,较callback更加优雅,.catch()捕获异常错误。缺点是无法暂停(个人认为如果业务逻辑比较复杂,Promise写起来多少又像是变回了回调地狱);
  • async和await:同步的方式写异步,更直观清晰。但缺少并发性,因为await会阻塞代码;

考察更细一点的话,还可以问:

14.1 一句话描述下什么是Promise? 答:现在未执行的事情将来一定会发生。Promise就是一个状态机,特点是状态(pending,rejected,fulfilled)的传递。

14.2 手写一个简易版的Promise? 请阅大佬文章---JavaScript手写代码无敌秘籍


综上,个人认为这些面试题都比较常规吧(应该是因为都不是大厂,所以要求比较一般),好好准备下80%是可以回答上的。准备面试和参加面试都是一种学习方式,不仅能查漏补缺,对脱离业务之外的个人水平也有不小的提高。

最后我想说几句心里话:今年年初就在吹寒冬来袭,我个人认为中上游的公司对招聘者依旧饥渴,中下游的公司随着业务调整并不急得招人,而是不紧不慢,慢挑细选(最终找到差不多水平最便宜的那一位),在此我想diss一家叫做 东*网力(规模还挺大)的公司,面试前后都挺客气,过了几天问结果说是:已经在走发offer审批流程了,耐心等几天。再过几天就没有然后了,WX发消息不回,有合适的人直说就是,hr这种行为是个什么操作。

祝愿还在找或者准备找工作的小伙伴们都能得到比较满意的结果。感谢阅读,欢迎吐槽留言点赞三连击~




原文地址:访问原文地址
快照地址: 访问文章快照