6月的"寒冬"里,落魄程序员聊聊前端面试

1/20/2023 杂记面试

会写这篇文章是因为前不久看到大白的我裸辞了 (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:数据不能超过4k 同时因为每次http请求都会携带cookie

# 导入样式时,使用link和 @import 区别

  • link属于HTML标签,而@importcss提供的;
  • 页面被加载时,link会同时被加载,而@import引用的css会等到页面被加载完再加载;
  • @import只在IE5以上才能识别,而linkXHTML标签,无兼容问题;
  • 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
}
1
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
*   函数默认参数
*   展开
1
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

# new 的实现原理

Last Updated: 5/30/2023, 8:59:26 PM