6月的"寒冬"里,落魄程序员聊聊前端面试
会写这篇文章是因为前不久看到大白的我裸辞了 (opens new window)
这样看来,距离我离职至今也快三月了,是那种面试时候 hr 都要多问一句,"你看,你离职至今也两个多月了,为什么当初没有先找好再离职呢"
这句话仿佛也可以这样翻译,"你 gap 这么长时间找不到工作,是不是能力有问题?",或者,"你这么长时间没找到,是不是要求薪资太高了"。后者尤其在最后 hr 面的谈薪阶段多提这样一句,极具杀伤力。
关于为啥我会在这个时间点离职,就好像那句话说的:打工人离职,无非就是2种情况:一是钱没给够;二是受委屈了。
仔细想想,我好像都不能算是,老东家其实还是挺好的,至少我所处的部门同事关系融洽,工作中所做的事情我也挺喜欢的,关于钱没给够,好像确实能够这么理解,毕竟谁不喜欢钱多呢,尽管每年都给调薪 10%~20%,但由于入职时候的 base 太低,所以在离职前可能我的 base 还不如绝大部分刚工作的应届生。
所以我离开只是单纯的想离开了,想着,该开启下个阶段了。
这下好了,下个阶段就是:失业快三个月。
其实不是没有面试,也并非没有拿到 offer,在我开始开放简历的第一周里就有接到两个口头 offer,但我都在她们下发 offer 前给拒了。
一个是大小周
一个是外包
而关于面试,可能是我要的目标薪资并不高,也可能是我在上家公司所做的工作并不都是单纯的 crud 业务,也有可能是我简历"美化"的还行,所以多的时候,我一天得安排三个面试,上午下午各一个线下面(广州绝大部分中小公司都得线下面),回到出租屋还得参加一个线上面。
而其中这些线下面的还不乏需要先来场笔试,一天跑下来整个人精疲力尽,感觉比起以前上班后再加班到10点都有过之而无不及。
我想也许是我还没准备好
# html 篇
html 相关的其实比较少考,更多的是在当有笔试时候才会遇到
# 如何理解语义化标签
- 对机器有好:更好的seo
- 对人友好:语意化,便于团队代码维护
# html5 有哪些新特性、移除了哪些元素
新增
- 语义化标签:nav、header、footer、aside、section、article
- 音频、视频标签:audio、video
- 数据存储:localStorage、sessionStorage
- canvas(画布)、Geolocation(地理定位)、websocket(通信协议)
- input标签新增属性:placeholder、autocomplete、autofocus、required
移除
- 纯表现的元素:basefont,big,center,font, s,strike,tt,u;
- 对可用性产生负面影响的元素:frame,frameset,noframes;
# property和attribute的区别
Attribute就是 DOM 节点自带的属性,例如 html 中常用的 id、class、title、align 等;
Property 是这个 DOM 元素作为对象,其附加的内容,例如childNodes、firstChild 等。
# script 标签中 defer 和 async 的区别
script + async 解析 html 过程中会异步下载脚本,下载成功后立马执行,可能会阻碍 html 的解析,多个带有 async 属性的脚本无法保证执行顺序
script + defer ,脚本在 HTML 文件解析完成后被执行,多个带有 defer 属性的脚本会按顺序在文档解析完成后依次执行,且在 DOMContentLoaded 事件之前完成。
# 行内元素有哪些?块级元素有哪些? 空(void)元素有那些?
- 行内元素:a、input、span、img、strong
- 块级元素:dive、p、ul、li、h1-h5
- 空元素:br、hr、img、input、link、meta
# 本地存储 sessionStorage、localStorage 和 cookie 区别
- sessionStorage:窗口会话级别
- localStorage:持久数据,始终有效
- cookie:数据不能超过4k 同时因为每次http请求都会携带cookie
# 导入样式时,使用link和 @import 区别
link
属于HTML
标签,而@import
是css
提供的;- 页面被加载时,
link
会同时被加载,而@import
引用的css会等到页面被加载完再加载; @import
只在IE5
以上才能识别,而link
是XHTML
标签,无兼容问题;link
方式的样式的权重高于@import
的权重。
# CSS篇
# CSS3新特性
- 新增选择器:CSS3 引入了一些新的选择器,例如属性选择器、伪类选择器、结合选择器等
- 圆角:border-radius:8px
- 文本效果:CSS3 引入了新的文本效果,如 text-shadow、word-wrap、word-break 等
- 盒子模型:新增了 box-sizing 属性
- 媒体查询:CSS3 引入媒体查询(Media Queries)技术,使得网页可以根据设备屏幕大小调整布局和样式,以适应不同的设备、屏幕和分辨率。
- 文本效果:如 text-shadow、word-wrap、word-break 等
# CSS 选择器及优先级
- !important
- 内联样式(1000)
- ID选择器(0100)
- 类选择器/属性选择器/伪类选择器(0010)
- 元素选择器/伪元素选择器(0001)
- 关系选择器/通配符选择器(0000)
# CSS3 开启硬件加速
- transform不为none
- 使用 opacity 属性:对于需要进行渐变或半透明效果的元素,可以使用 opacity 属性进行硬件加速。
- 用 will-change 属性:该属性用于告知浏览器即将有元素被修改,在元素被修改前可以先创建一个新的图层,从而避免频繁地重排和重绘。
# 盒子模型
- 标准盒子模型(box-sizing:context-box):width = 内容宽度(content) + border + padding + margin
- 怪异盒子模型(box-sizing:border-box):width = 内容宽度(content + border + padding)+ margin
# position 的值及定位原点
- relative(相对定位): 生成相对定位的元素,定位原点是元素本身
- absolute(绝对定位):定位原点是离自己这一级元素最近的一级
position
设置为absolute
或者relative
的父元素的左上角为原点的。 - fixed(固定定位):相对于浏览器窗口
- sticky(粘性定位):元素先按照普通文档流定位,然后相对于该元素在流中的flowroot(BFC)和containing - block(最近的块级祖先元素)定位。而后,元素定位表现为在跨越特定阈值前为相对定位,之后为固定定位。
- static(默认):正常的布局流中
- inherit:从父元素继承
# BFC的理解
块级格式化上下文,BFC 是一个独立的渲染区域,其中的元素布局不受外界的影响
作用:
- 清除浮动
- 外边距塌陷
如何创建 BFC
- float属性不为none
- position为absolute或fixed
- overflow不为visible(默认)
- display为inline-block、table-cell、
- table-caption、flex、inline-flex
# 如何清除浮动
- 父级设置height
- 最后加空div,并 clear:both
- 父级添加overflow属性
- 伪类选择器清除浮动
# 回流(重排)和重绘
- 重排:元素的规模尺寸,布局,隐藏等布局信息改变时
- 重绘:只影响元素的外观属性改变,即元素的样式改变时,浏览器需要重新绘制它们的外观
追问:如何减少回流、重绘
- 避免频繁操作style,而是用切换 class 代替
- 动画可以使用 absolute 或 fixed,让其脱离文档流
- 避免使用 table 布局
- 避免频繁的dom操作,可以创建文档片段 documentFragement,在里面操作完后再添加到文档中
- 元素设置 先 display: none,操作结束再显示
# 水平垂直居中
宽高固定
- 父 relative 子 absolute + 负 margin(自身一半,考虑盒子模型是否+padding、border)
- 父 relative 子 absolute ,top、left、bottom、right 都为0 + margin: auto
- 父 relative 子 absolute + calc(left: calc(50% - 50px); top: calc(50% - 50px);)
宽高不固定
- 父 relative 子 absolute (top: 50%; left: 50%;)+ transform: translate(-50%, -50%);
- flex布局
- grid布局:父 display:grid;,子 margin : auto
# flex:1 的含义
表示:flex: 1 1 0%(默认为 0 1 auto);
当一个容器设置display:flex变成一个flex容器后,如果容器没有被占满,换言之有剩余空间,则flex-grow起作用。相反,若空间不足,则flex-shrink起作用。
分别所代表的含义:
- flex-grow: 1,放大比例为1,若存在剩余空间,将放大以适应剩余空间
- flex-shrink: 1,缩小比例为1,即如果空间不足,该项将缩小
- flex-basis: 0 ,将该项在主轴方向上的初始大小设置为0,表示该项的大小由容器的剩余空间决定
# JS篇
# 数据类型
- 基础数据类型(存放在栈中)
Undefined、Null、Boolean、Number、String、Symbol(es6 新增,表示独一无二的值)和 BigInt(es10 新增);
Symbol:代表独一无二的值,最大的用法是用来定义对象的唯一属性名。 BigInt:表示任意大小的整数
- 引用数据类型(栈中存放指针,指向存放值的堆)
Object(Object 本质上是由一组无序的键值对组成的),里面包含 function、Array、Date 等
# 数据类型的判断
- typeof
能判断所有值类型,函数。不可对 null、对象、数组进行精确判断,因为都返回 object
- instanceof
能判断复杂数据类型,不能判断基本数据类型,原理:其内部运行机制是判断在其原型链中能否找到该类型的原型
手写 instanceof
function myInstanceOf(obj, constructorFunc) {
let proto = Object.getPrototypeOf(obj); // 获取传入对象的原型
while (proto !== null) { // 当遍历到顶级原型时停止
if (proto === constructorFunc.prototype) { // 检查原型是否指向指定的构造函数的原型
return true;
}
proto = Object.getPrototypeOf(proto); // 向上转移原型链
}
return false; // 如果没有检测到匹配,则返回false
}
2
3
4
5
6
7
8
9
10
11
12
- Object.prototype.toString.call()
推荐使用
能判断所有数据类型
可能的追问:为什么要 .call:所有对象都继承了 Object 类型中的 toString 方法,但是,对于自定义的其他对象(例如数组、函数等),其 toString() 方法通常已经被重写以提供更有用的输出信息,.call 改变 Object.prototype.toString 的执行上下文(this 指向)。
# ES6 有哪些新特性
* 块作用域
* 类
* 箭头函数
* 模板字符串
* 加强的对象字面
* 对象解构
* Promise
* 模块
* Symbol
* 代理(proxy)Set
* 函数默认参数
* 展开
2
3
4
5
6
7
8
9
10
11
12
# Set ,WeakSet,Map 和 WeakMap
- Set:是一种无序且唯一的集合,它不能包含重复元素
- WeakSet:是一个与Set相似的集合,只能包含对象,对象值都是被弱引用,不能遍历,也拿不到所有的值
- Map:是一种存储键值对的集合。它的键和值可以是任意类型的JavaScript对象
- WeakMap: 是一组键值对的集合,其中的键是弱引用对象(null除外,不接受其他类型的值作为键名),而值可以是任意,不能遍历
Vue源码多处利用了 WeakMap 是弱引用这一特点,来存储临时的对应关系,以便在对象被销毁时,自动删除对应的映射关系,避免内存泄漏
# 数组常用方法
添加/删除元素:
- push():从结尾添加(改变原数组)
- pop():从结尾删除(改变原数组)
- shift():从结尾删除(改变原数组)
- unshift():从开头添加(改变原数组)
- splice(index,deleteCount,...item):从 index 开始,删除 deleteCount 个元素,有第三个参数时表示在当前位置插入元素(改变原数组)
- concat(...items):返回新数组,复制当前数组所有元素并向添加 items
查询元素:
- indexOf/lastIndexOf():从数组中找到对应的值,返回其下标,没找到则返回 -1
- findIndex():和 find() 类似,但返回的是下标
- includes(value):如果数组有value,则返回 true,否则返回 false
- find/filter(func):通过 func 过滤元素,返回符合条件的第一个值/符合filter 函数的所有值
转换数组:
- map(func):从每个元素调用
func
的结果创建新数组 - sort(func):将数组倒序排列,并返回(改变原数组)
- reverse():原地倒转数组,并返回(改变原数组)
- split/join():将字符串转换为数组,返回
- reduce(func,initialValue):为每个元素调用
# for of 和 for in
- for of
遍历的是可迭代对象的键值,包括数组、字符串、Set、Map 等,不适合遍历对象
- for-in
遍历的是对象的可枚举属性(键),包括自身属性和继承属性,不适合遍历数组和字符串。
# 作用域和作用域链
作用域:作用域是定义变量的区域 作用域链:(查找变量的这层关系)从当前作用域开始一层层往上找某个变量,如果找到全局作用域还没找到,就放弃寻找 。这种层级关系就是作用域链。
# 原型和原型链
原型:把所有的对象共用的属性全部放在堆内存的一个对象(共用属性组成的对象),然后让每一个对象的 __proto__存储这个「共用属性组成的对象」的地址。而这个共用属性组成的对象就是原型,原型出现的目的就是为了减少不必要的内存消耗。
原型链:原型链就是对象通过__proto__向当前实例所属类的原型上查找属性或方法的机制,如果找到Object的原型上(直到找到null)还是没有找到想要的属性或者是方法则查找结束,最终会返回undefined
__proto__是所有对象(包括函数对象)都有的一个属性(当然只是逻辑上有这么个概念),当我们说“原型链”的时候,就是指对象通过这个属性互相连接而形成的链状结构。原型链也就是继承链。prototype是只有函数(准确地说是构造函数)才有的一个属性,例如对于对于某个函数Fun。它的意义在于,当你用var obj = new Fun() 得到一个对象obj时,这个obj的原型就是Fun.prototype。即(new Fun()).proto === Fun.prototype