初次面试之旅--良好体验+学习成长+战胜自我

1,876 阅读14分钟

src=http___upload-images.jianshu.io_upload_images_11633898-4e3da1f02f8f9965.jpg&refer=http___upload-images.jianshu.jpg

前言

做为一名前端小白,终于迎来了个人的第一次面试,内心的起伏可谓波澜壮阔,是紧张,是激动,是忐忑,亦或是胆怯,带着这些,我开启了面试之旅,接受了面试官的灵魂拷问!......一个多小时下来,体验感还好,面试官挺好的,挺温柔的,中途卡住了提醒,遇到不会的会说没事的,没关系。就是自己拉跨了,哈哈哈,很多问题都没有答全,更有直接卡住的,在电话面前更是不知如何是好,尴尬至极。但这个过程却是学习成长+战胜自我

面试题

1. 如何实现水平垂直居中

center.jpg

水平居中

  • 对于行内元素: text-align: center;

  • 对于确定宽度的块级元素:

    1.width和margin实现。margin: 0 auto;

    2.绝对定位和margin-left: -width/2, 前提是父元素position: relative

  • 对于宽度未知的块级元素:

    1.table标签配合margin左右auto实现水平居中。使用table标签(或直接将块级元素设值为display:table),再通过给该标签添加左右margin为auto。

    2.inline-block实现水平居中方法。display:inline-block和text-align:center实现水平居中。

    3.绝对定位+transform,translateX可以移动本身元素的50%。

    4.flex布局使用justify-content:center

垂直居中

1.利用line-height实现居中,这种方法适合纯文字类

2.通过设置父容器相对定位,子级设置绝对定位,标签通过margin实现自适应居中

3.弹性布局flex:父级设置display: flex; 子级设置margin为auto实现自适应居中

4.父级设置相对定位,子级设置绝对定位,并且通过位移transform实现

5.table布局,父级通过转换成表格形式,然后子级设置vertical-align实现。(需要注意的是:vertical-align: middle使用的前提条件是内联元素以及display值为table-cell的元素)。

6.flex方案: align-items: center;

详细可见

2. 重绘和重排

重排(回流):

GPU拿到渲染树后,进行布局绘制叫做重排

怎样触发重排:

  • 页面首次渲染

  • 添加/删除可见的DOM元素

  • 改变元素的位置

  • 改变元素的尺寸

  • 改变窗口大小

  • offsetWidth offset ...... clientTop client...

重绘:

当页面上的DOM节点发生非布局变更时GPU需要再次绘制叫做重绘

怎样触发重排:

  • 当页面上的DOM改变了非几何信息的属性时

注意: 重排一定重绘,重绘不一定重排

详细可见

3. 盒模型

23e29b091add4944a177ba290043379a_tplv-k3u1fbpfcp-watermark.image

盒模型分为IE盒模型和W3C标准盒模型

W3C 标准盒模型:

属性width,height只包含内容content,不包含border和padding。

IE 盒模型:

属性width,height包含border和padding,指的是content+padding+border。

width = border + padding + 内容的宽度

height = border + padding + 内容的高度

注意:当前W3C标准中盒模型是可以通过box-sizing自由的进行切换的。(笔者在这吃了亏)

详细可见

4. ES6的新特性

  • 不一样的变量声明:const和let

  • 模板字符串: 基本的字符串格式化,将表达式嵌入字符串中进行拼接。用${}来界定; ES6反引号(``)直接搞定;

  • 箭头函数: 箭头函数就是函数的一种简写形式,使用括号包裹参数,跟随一个 =>,紧接着是函数体;

  • 函数的参数默认值

// ES6之前,当未传入参数时,text = 'default';
function printText(text) {
    text = text || 'default';
    console.log(text);
}

// ES6;
function printText(text = 'default') {
    console.log(text);
}

printText('hello'); // hello
printText();// default
  • 二进制和八进制字变量:ES6 支持二进制和八进制的字面量,通过在数字前面添加 0o 或者0O 即可将其转换为八进制值:
let oValue = 0o11;
console.log(oValue); // 9
 
let bValue = 0b11; // 二进制使用 `0b` 或者 `0B`
console.log(bValue); // 3

  • 对象和数组解构
// 对象
const student = {
    name: 'Jack',
    age: 20,
    sex: '男'
}
// 数组
// const student = ['Jack', 20, '男'];

// ES5;
const name = student.name;
const age = student.age;
const sex = student.sex;
console.log(name  + age + sex);

// ES6
const { name, age, sex } = student;
console.log(name + age + sex);
  • 对象超类

  • for...of和for...in for...of 用于遍历一个迭代器,如数组:

let letter = ['a', 'b', 'c'];
letter.size = 3;
for (let letter of letters) {
  console.log(letter);
}
// 结果: a, b, c

for...in 用来遍历对象中的属性:

stu.size = 3;
for (let stu in stus) {
  console.log(stu);
}
// 结果: Jack, 20, 男
  • ES6中的类:ES6 中支持 class 语法,不过,ES6的class不是新的对象继承模型,它只是原型链的语法糖表现形式。

  • Spread/Rest操作符

详细可见

5. 暂时性死区

let const 声明的变量不存在变量提升,其作用域都是块级作用域,凡是在声明变量之前使用变量就会报错,所以,在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区

if (true) {
    // 死区开始
    z = 'lut'; //  ReferenceError
    console.log(z); //  ReferenceError
    // 开始声明变量,死区结束
    let z; 
    console.log(z); // undefined
    z = 520;
    console.log(z); // 520
  }

这里就不得不深入到letconstvar的区别了:

  • 变量提升方面:var声明的变量存在变量提升,即变量可以在声明之前调用,值为undefined。

    let和const不存在变量提升问题(注意这个‘问题’后缀,其实是有提升的,只不过是let和const具有一个暂时性死区的概念,即没有到其赋值时,之前就不能用),即它们所声明的变量一定要在声明后使用,否则报错。

  • 块级作用域方面:var不存在块级作用域,let和const存在块级作用域

  • 声明方面:var允许重复声明变量,let和const在同一作用域不允许重复声明变量。其中const声明一个只读的常量一旦声明,常量的值就不能改变。

6. 对防抖和节流的理解和认识

防抖

防抖这个技术点允许我们将多个相似的调用分成一组,或者可以理解为多个相同的事件最后只执行一次。 防抖函数的作用就是控制函数在一定时间内的执行次数。防抖意味着 N 秒内函数只会被执行一次(最后一次),如果 N 秒内再次被触发,则重新计算延迟时间。

<button id="btn">防抖提交</button><!-- 设置表单 -->
    <script>
        function success(e){
            console.log('提交成功')//设置success函数,并且打印结果
        }
        // 防抖函数
        const debounce=(fn,delay)=>{// 1 创建防抖函数debounce
            let timer=null  // 创建一个标记用来存放定时器的返回值
            return (...args)=>{//4  进行解构
            clearTimeout(timer)//5  每当用户输入的时候把前一个setTimeout 清除掉
            timer = setTimeout(()=>{//3 然后又创建一个新的setTimeout, 这样就能保证输入字符后的 interval 间隔内如果还有字符输入的话,就不会执行fn 函数
                    fn.apply(this,args)//6 绑定this作用域和接受success参数
                },delay)
            }
        }
        const oDebounce=debounce(success,2000)//2 设置间隔2秒执行一次  success被debounce修饰为oDebounce 然后调用
        let btn=document.getElementById('btn')
        btn.addEventListener('click',oDebounce) // 防抖 click调用oDebounce
    </script>

节流

节流函数的实现原理是,将即将被执行的函数用定时器延时一段时间后执行。如果本次延时执行还没有完成,则忽略调用函数的请求。节流函数接受两个参数,第一个是 需要被延时执行的函数,第二个是需要延迟的时间。 节流函数的作用是规定一个单位时间,在这个单位时间内最多只能触发一次函数执行,如果这个单位时间内多次触发函数,只能有一次生效。

<button id="btn">节流提交</button> <!-- 设置表单 -->
    <script>
        function success(e){
            console.log('提交成功')//设置success函数,并且打印结果
        }
        //节流函数
        const throttle =(fn,delay)=>{//1 创建节流函数throttle
            let flag=true//5 通过闭包保存一个标记
            return (...args)=>{//4
                if(!flag) return  // 在函数开头判断标记是否为true,不为true则return
                flag=false//6  立即设置为false
            setTimeout(()=>{//3 将外部传入的函数的执行放在setTimeout中
                fn.apply(this,args) // 最后在setTimeout执行完毕后再把标记设置为true(关键)表示可以执行下一次循环了。
                    flag=true               //当定时器没有执行的时候标记永远是false,在开头被return掉
                },delay)
            }
        }
        const oThrottle=throttle(success,2000)//2 设置间隔2秒执行一次  success被throttle修饰为oThrottle 然后调用
        let btn=document.getElementById('btn')
        btn.addEventListener('click',oThrottle) // 节流 click调用oThrottle
    </script>

7.谈谈垃圾回收机制

JavaScript 具有自动垃圾收集机制,执行环境会负责管理代码执行过程中使用的内存。

原理:找出那些不再继续使用的变量,然后释放其占用的内存。为此,垃圾收集器会按照固定的时间间隔(或代码执行中预定的收集时间),周期性地执行这一操作。

通常有以下两个策略:

  • 标记清除(最常用):当变量进入环境(例如,在函 数中声明一个变量)时,就将这个变量标记为“进入环境”。 而当变量离开环境时,则将其 标记为“离开环境”。

    过程:

    • 给存储在内存中的所有变量都加上标记;
    • 去掉环境中的变量以及被环境中的变量引用的变量的标记;
    • 之后再被加上标记的变量将被视为准备删除的变量;
    • 销毁那些带标记的值并回收它们所占用的内存空间。
  • 引用计数(不常见):当声明了一个变量并将一个引用类型值赋给该变量时,则这个值的引用次数就加1;如果包含对这个值引用的变量又取得了另外一个值,则这个值的引用次数减1。当这个值的引用次数变成 0时,则说明没有办法再访问这个值了,因而就可以将其占用的内存空间回收回来。

    缺点:有循环引用的问题。

笔者在被问到时直接懵圈了,尴尬至极

详细可见

8. OSI体系结构

image.png

image.png OSI是Open System Interconnect的缩写,意为开放式系统互联。其各个层次的划分遵循下列原则:

  • 一层中的各网络节点都有相同的层次结构,具有同样的功能。

  • 同一节点内相邻层之间通过接口进行通信。

  • 七层结构中的每一层使用下一层提供的服务,并且向其上层提供服务。

  • 不同节点的同等层按照协议实现对等层之间的通信。

熟记OSI模型结构的顺序,笔者被问到该知识点支支吾吾的,不知如何是好........

9.TCP和UDP的区别

TCP是一个面向连接的、可靠的、基于字节流的传输层协议。

UDP面向无连接,UDP协议只是数据报文的搬运工,不保证有序且不丢失的传递,UDP没有任何流量控制算法,相对TCP来说比较轻便

  • 面向无连接

    在发送端,应用层将数据传递给传输层的UDP协议,UDP只负责给数据只增加一个UDP标识,然后就传递给网络层

    在接收端,网络层将数据传给传输层,UPD去除IP报文头就传给应用层,不会进行任何拼接操作

  • 不可靠性

    接收到什么数据就传递什么数据,并且不会备份数据,发送数据也不会关系对象是否接收到

    UDP没有拥塞控制,一直会以恒定的速度发送数据,即使网络不好,也不会进行调整(会导致包丢失)

  • 高效

    比TCP轻量,头部开销小(只有8字节),传输数据很快

10. 从输入url到页面的渲染过程

  • 首先做 DNS 查询,进行DNS 解析的,会提供访问速度最快的 IP 地址回来

  • 接下来是 TCP 握手

  • TCP 握手结束后会进行 TLS 握手,然后就开始正式的传输数据

  • 数据在进入服务端之前,可能还会先经过负责负载均衡的服务器,它的作用就是将请求合理的分发到多台服务器上,这时假设服务端会响应一个 HTML 文件

  • 浏览器开始解析文件,如果是 gzip 格式的话会先解压一下,然后通过文件的编码格式知道该如何去解码文件

  • 文件解码成功后会正式开始渲染流程,先会根据 HTML 构建 DOM 树,有 CSS 的话会去构建 CSSOM 树。

  • 初始的 HTML 被完全加载和解析后会触发 DOMContentLoaded 事件

  • CSSOM 树和 DOM 树构建完成后会开始生成 Render 树,这一步就是确定页面元素的布局、样式等等诸多方面的东西

  • 在生成 Render 树的过程中,浏览器就开始调用 GPU 绘制,合成图层,将内容显示在屏幕上了

一套流程下来,如能一气呵成,那是相当完美

你会发现在面试当中TTTP的知识必会灵魂拷问,推荐神三元的文章

11. cookie、sessionstorage和localstorage的区别

生命周期

cookie:可设置失效时间,没有设置的话,默认是关闭浏览器后失效

localStorage:除非被手动清除,否则将会永久保存。

sessionStorage: 仅在当前网页会话下有效,关闭页面或浏览器后就会被清除。

存放数据大小

cookie:4KB左右

localStorage和sessionStorage:可以保存5MB的信息。

http请求

cookie:每次都会携带在HTTP头中,如果使用cookie保存过多数据会带来性能问题

localStorage和sessionStorage:仅在客户端(即浏览器)中保存,不参与和服务器的通信

易用性

cookie:需要程序员自己封装,源生的Cookie接口不友好

localStorage和sessionStorage:源生接口可以接受,亦可再次封装来对Object和Array有更好的支持

详细可见

12. git常见命令及回滚操纵

初学者对于git只知道git add .、 git commit -m 'lianxi'git push origin main这三个招式,其实git的招式还有很多,奉上下图

image.png

git通用流程图

image.png

当被问到git回滚操作时,我脑海里搜索着点滴的记忆,硬是想不起来.........

回滚操作:

  git reset origin/master --soft

详细可见

详细可见

13. Koa和Express的区别

因为之前用这两个框架配置过环境,但未曾想上来就碰到了......

请看:

image.png

koa2

  • 基于node的一个web开发框架,利用co作为底层运行框架,利用Generator的特性,实现“无回调”的异步处理;

  • 更小、更富有表现力、更健壮的基石;

  • 利用async函数、Koa丢弃回调函数,增强错误处理;

  • 很小的体积,因为没有捆绑任何中间件;

  • 类似堆栈的方式组织和执行;

  • 低级中间件层中提供高级“语法糖”,提高了互操性、稳健性;

Express

  • Node的基础框架,基础Connect中间件,自身封装了路由、视图处理等功能;

  • 线性逻辑,路由和中间件完美融合,清晰明了;

  • 弊端是callback回调方式,不可组合、异常不可捕获;

  • connect的执行流程:connect的中间件模型是线性的,即一个一个往下执行;

对于这两个开发框架,笔者用的也不是很多,日后还得深入学习,详细可见

14. 谈谈数据库中的事务

事务就是要保证一组数据库操作要么全部成功 要么全部失败。不是所有的数据库引擎都支持事务,MyISM 不支持事务,InnoDB 支持事务

事务具有四个特性 ACID

  • A 原子性 要么全部成功要么全部失败

  • C 一致性 确保一个事务执行之前和执行之后必须处于一致的状态

  • I 隔离性 一个事务在提交之前是否能够被其他事务可见

  • D 持久性 一旦一个事务提交了,那么这个改变就是永久性的

事务隔离具有四种

  • 读未提交 一个事务还没有提交,其他事务能够看到它做的变更

  • 读提交 一个事务提交之后,其他事务才能看到变更

  • 可重复读 一个事务在执行过程中,看到的数据总是跟这个事务在启动时看到的数据一致

  • 串行化 事务不可并行执行,后访问的事务必须等前一个事务完成,才能继续执行

事务的启动方式

  • 显示启动事务 begin 启动, commit 提交, rollback 回滚

  • 程序会自动提交事务

对数据库的扫盲可见

15. 谈谈对Set的认识

ES6中的Set主要的应用场景在于数组去重和数据存储,Set是一种叫做集合的数据结构

集合

  • 集合是由一组无序且唯一(即不能重复)的项组成的,可以想象成集合是一个既没有重复元素,也没有顺序概念的数组

  • ES6提供了新的数据结构Set。它类似于数组,但是成员的值都是唯一的,没有重复的值

  • Set 本身是一个构造函数,用来生成 Set 数据结构

Set实例的属性和方法

Set的属性:

  • size:返回集合所包含元素的数量

Set的方法:

  • 操作方法

    • add(value):向集合添加一个新的项

    • delete(value):从集合中移除一个值

    • has(value):如果值在集合中存在,返回true,否则false

    • clear(): 移除集合里所有的项

  • 遍历方法

    • keys():返回一个包含集合中所有键的数组

    • values():返回一个包含集合中所有值的数组

    • entries:返回一个包含集合中所有键值对的数组(感觉没什么用就不实现了)

    • forEach():用于对集合成员执行某种操作,没有返回值

总结

面试当中还问了有关React生命周期和React-hooks的问题以及数个排序算法的原理,在这里给大家推荐一波: React全家桶以及十大排序算法

面试面试即为当面展示自我,可能我此次面试展示的并不是很好,但对我这个小白而言,却是一次成长的体验,是一次学习成长的经历,更是一次战胜自我的过程。

希望各位指出其中的错误(翻看各种资料,只能算偏完整),我会不断学习,未来可期。