前端面试

191 阅读17分钟

自我介绍

面试官下午好,我叫xxx,今天来应聘贵公司的前端工程师岗位。我在学校学习的是前端开发,参与过一些项目如博客、电商管理后台等的开发。平常喜欢逛一些技术社区丰富自己的技术,像掘金、CSDN之类的。我性格比较温和,跟同学朋友相处融洽,在工作中代码开发时我喜欢全心全意地投入,对工作我总抱着认真负责的态度。面试官,以上是我的介绍,谢谢。

项目具体介绍

电商后台管理系统

HTML、CSS相关

语义化标签

header、nav、main、article、section、aside、footer

语义化意味着:合理正确的使用语义化的标签来创建页面结构,从标签上即可以直观的知道这个标签的作用,而不是滥用div。

优点:

  • 代码结构更加清晰,利于开发与维护

  • 方便其他设备解析(如屏幕阅读器)根据语义渲染网页

  • 有利于搜索引擎优化,搜索引擎爬虫会根据不同的标签来赋予不同的权重

浏览器渲染机制:重绘、重排

网页生成过程:

  • HTML被HTML解析器解析成DOM树

  • CSS被CSS解析器解析成CSSOM树

  • 结合DOM树和CSSOM树,生成一颗渲染树(Render Tree)

  • 生成布局(flow),即将所有渲染树的节点进行平面合成

  • 将布局绘制(paint)在屏幕上

**重排(回流):**当DOM的变化影响了元素的几何信息(DOM对象的位置和尺寸大小),浏览器需要重新计算元素的几何属性,将其安放在界面中的正确位置,这个过程叫做重排。

触发重排(回流):

  1. 添加或删除

    可见

    的DOM元素

  2. 元素尺寸改变——边距、填充、边框、宽度和高度

**重绘:**当一个元素的外观发生改变,但没有改变布局,重新把元素外观绘制出来的过程,叫做重绘。

**触发重绘:**改变元素的color、background、box-shadow等属性

重排优化建议

  1. 分离读写操作

  2. 样式集中修改

  3. 缓存需要修改的DOM元素

  4. 尽量只修改position:absolute或fixed元素,对其他元素影响不大

  5. 动画开始GPU加速,translate使用3D变化

transform不重绘,不回流是

因为transform属于合成属性

,对合成属性进行transition/animate动画时,将

会创建一个合成层

。这使得动画元素在一个独立的层中进行渲染。当元素的内容没有发生改变,就没有必要进行重绘。浏览器会通过重新复合来创建动画帧。

CSS盒子模型

所有的HTML元素看作盒子,盒子是由content-padding-border-margin组成,但盒子内容宽度/高度计算范围有所不同

两种盒模型:

  • 标准盒模型:宽高content

  • IE盒模型:宽高:content-padding-border

可以通过设置box-sizing来改变盒模型

css样式优先级

!importance > style > id > class > 标签 > 通配

BFC

BFC即块级格式化上下文。它是一个CSS布局的概念,是一个环境,重点是里面的元素不会影响到外面的元素。

布局规则:BOX是CSS布局的对象和基本单位,页面是由若干个BOX组成的。元素的类型和display属性,决定了这个Box的类型。不同类型的Box会参与不同的Formatting Context。

特性:

  1. 在BFC中,块级盒子依然垂直排列

  2. 在BFC中上下相邻的两个容器margin会重叠,创建新的BFC可避免

  3. 计算高度时,浮动元素的高度也必须计算

  4. BFC区域不会与浮动的容器发生重叠

创建BFC的方式:

  1. display设置为:inline-block

  2. position设置为:absolute/fixed

  3. overflow不设置为hidden

DOM、BOM对象

BOM对象(浏览器对象模型),使用BOM,开发者可以移动窗口、改变状态栏中的文本以及执行其他与页面内容不直接相关的动作。使JavaScript有能力与浏览器“对话”。

DOM对象(文档对象模型),通过DOM,可以访问HTML文档的所有元素。DOM是W3C(万维网联盟)的标准。

DOM定义了访问HTML和XML文档的标准:“W3C文档对象模型(DOM)是中立于平台和语言的接口,它允许程序和脚本动态地访问和更新文档大的内容、结构和样式。”

W3C DOM标准被分为3个不同部分:

  • 核心DOM - 针对任何结构化文档的标准模型

  • XML DOM - 针对XML文档的标准模型(定义了所有XML元素的对象和模型,以及访问它们的方法)

  • HTML DOM -针对HTML文档的标准模型(定义了所有HTML元素的对象和模型,以及访问它们的方法)

JS相关

数据类型、typeof、instanceof

8种:number、boolean、String、Object、Null、undefined、Symbol、BigInt

typeof可以对值类型、函数进行判断。但不能精确判断null、对象、数组,其结果都是Object

instanceof可以对引用类型进行判断。不能判断基本数据类型,其运行原理是在原型链上能否找到该类型的原型(就是顺着原型链进行查找,如果能找到,即xxx.prototype = true)

Object.prototype.toString.call(要判断的类型)

:所有原始类型都能判断

闭包(重点)

基本概念:函数+函数内部能够访问到的变量的总和。正常情况下,函数执行完成,内部变量会销毁。内部函数没有执行完,外部函数变量不会被销毁。

上级作用域内变量的生命周期,因为被下级作用域内引用,而没有被释放。就导致上级作用域内的变量,等到下级作用域执行完以后才正常得到释放。

作用域链

应用:

  1. 能够访问函数定义时所在的词法作用域(阻止其被回收)

  2. 私有化变量

  3. 模拟块级作用域

  4. 创建模块

**缺点:**会导致函数的变量一直保存在内存中,过多的闭包可能会导致内存泄漏

原型、原型链(重点)

四个概念+两准则

  • 4概念

    1. JS分为函数对象和普通对象,所有的对象都有_proto_属性,但是只有函数对象有prototype属性

    2. Object、function都是JS内置的函数

    3. 属性_proto_是一个对象,它有两个属性,constructor和_proto_

    4. 原型对象prototype有一个默认的constructor属性,用于记录实例是由哪一个构造函数创建

  • 2准则

    1. 原型对象(对象名.prototype)的constructor指向构造函数本身

    2. 实例的_proto_和原型对象指向同一个地方

原型对象(对象名.prototype)的作用:

存放实例中共有的那部分属性、方法,可以大大减少内存消耗

 function Person(name,age){   this.name = name;   this.age = age; } Person.prototype.motherland = "China" Person.prototype.sayHi = function (){   console.log("我们是中国人") } ​ let person1  = new Person("小李",19) let person2 = new Person("小林",20) ​ console.log(person1.motherland) console.log(person2.motherland)

image.png

this指向、new关键字

this

this对象是执行上下文的一个属性,它指向最后一次调用这个方法的对象,在全局函数中,this等于window,而当函数被作为某个对象调用时,this等于那个对象。

在实际开发中,this的指向可以通过四种调用模式来判断

  1. 函数调用,当一个函数不是一个对象的方法时,直接作为函数来调用,此时this指向全局对象window

  2. 方法的调用,如果一个函数作为对象的方法来调用,this指向这个对象

  3. 构造函数的调用,this指向这个用new新创建的对象

  4. apply、call、bind调用模式,这三个方法都可以显示的指定调用函数的this指向。

    1. apply接受参数是数组

    2. call接收参数列表

    3. bind方法通过传入一个对象,返回一个this绑定了传入对象的新函数。这个函数this指向除了使用new时会被改变,其他情况下都不会改变。

new

  1. 首先创建了一个新的空对象

  2. 根据原型链,设置空对象的_proto_为构造函数的prototype(准则2)

  3. 构造函数的this指向这个对象,执行构造函数的代码(为这个新对象添加属性)

  4. 判断函数的返回值类型,如果是引用类型,就返回这个引用类型的对象

    function myNew(context){ const obj = new Object(); obj.proto = context.prototype; const res = context.apply(obj, [...arguments].slice(1)); return typeof res === "object" ? res : obj; }

补充构造函数:

  1. 构造函数是什么?

    构造函数是一张产品设计图,通过设计图,就可以不断制造出相同的产品。

    在JS中,构造函数的函数名首字母需要大写,通过new构造函数,得到实例对象。ES6出的class,是语法糖。

         //函数名大小写不影响构造函数的功能     function factory() {       this.name = '这是factory构造函数';     } ​     function Factory() {       this.name = '这是Factory构造函数';     }     let a = new factory();     let b = new Factory();     console.log(a);//factory {name: '这是Factory构造函数的实例'}     console.log(b);//Factory {name: '这是Factory构造函数的实例'}
    
  2. 关键字new的作用是什么?

     没有new     function Factory() {       this.name = '这是Factory构造函数';     }     let a = Factory();     console.log(a);//undefined //a的值为undefined,说明关键字new给函数Factory隐式return了一个值。 ​     function Test1() {}     var a = new Test1();     console.log(a); //Test1 {} ​     function Test2() {       return '这是test2构造函数'     }     var b = new Test2();     console.log(b); //Test2 {} ​ //new关键字 会隐式返回一个值,这个值必须是对象。
    

EventLoop

JS是单线程的,为了防止一个函数执行时间过长阻塞后面的代码,所以会先同步代码压入执行栈中,依次执行将异步代码推入异步队列,异步队列又分为宏任务队列和微任务队列,因为宏任务队列的执行时间较长,所以微任务队列要优先于宏任务队列。微任务队列的代表就是,Promise.then,MutationObserver,宏任务的话就是setImmediate,setTimeout、setInterval

原始Ajax

它是一种异步通信的方法,从服务端获取数据达到局部刷新页面的效果。

过程:

  1. 创建XMLHttpRequest对象

  2. 调用open方法传入三个参数,请求方式(GET/POST)、url、同步异步(true/false)

  3. 监听onreadystatechange事件,当readystate等于4时返回responseText

  4. 调用send方法传递参数

    Document

    Ajax 发送 get 请求

ES6

  1. 新增symbol类型,表示独一无二的值,用来定义独一无二的对象属性名

  2. const/let都是用来声明变量,不可重复声明,具有块级作用域。存在暂时性死区,也就是不存在变量提升。(const一般用来声明常量)

  3. 变量的解构赋值(包含数组、对象、字符串、数字及布尔值,函数参数),剩余运算符(..rest)

  4. 模板字符串(${data})

  5. 扩展运算符(数组、对象)

  6. 箭头函数

  7. Set和Map数据结构

  8. Proxy/Reflect

  9. Promise

  10. async函数

  11. Class

  12. Module语法(import/export)

Vue

什么是MVVM?

视图模型双向绑定

,是Model-View-ViewModel的缩写,也就是把MVC中的Controller演变成ViewModel。

Model层代表数据模型

View代表UI组件

ViewModel是View和Model层的桥梁

数据会绑定到ViewModel层并自动将数据渲染到页面中,视图变化时会通知ViewModel层更新数据。以前是操作DOM结构更新视图,现在是数据驱动视图。

优点:

  1. 低耦合。视图View可以独立Model变化和修改,一个Model可以绑定到不同的View上,当View变化的时候Model可以不变化,当Model变化的时候View也可以不变

  2. 可重用性。你可以把一些视图逻辑放在Model里面,让很多View重用这段视图逻辑

  3. 独立开发。开发人员可以专注于业务逻辑和数据的开发,设计人员可以专注于页面设计

  4. 可测试

谈谈对vue生命周期的理解?

每个Vue实例在创建时都会经过一系列的初始化过程,vue的生命周期钩子,就是说在达到某一阶段或条件时去触发的函数,目的是为了完成一些动作或者事件

  • create阶段:vue实例被创建

    • beforeCreate:创建前,此时data和methods中的数据都还没有初始化

    • created:创建完毕,data中有值,未挂载

  • mount阶段:vue实例被挂载到真实DOM节点

    • beforeMount:可以发起服务端请求,取数据

    • mounted:此时可以操作DOM

  • update阶段:当Vue实例里面的data数据变化时,触发组件的重新渲染

    • beforeUpdate

    • updated

  • destroy阶段:Vue实例被销毁

    • beforeDestroy:实例被销毁前,此时可以手动销毁一些方法

    • destroyed

computed与watch

watch属性监听是一个对象,键是需要观察的属性,值是对应的对调函数,主要用来监听某些特定数据的变化,从而进行某些具体的业务逻辑操作,监听属性的变化,需要在数据变化时执行异步或开销比较大的操作时使用

computed计算属性属性的结果会被缓存,当computed中的函数所依赖的属性没有发生改变的时候,那么调用当前函数的时候结果会从缓存中读取。除非依赖的响应式属性变化时才会重新计算,主要当作属性来使用computed中的函数必须用return返回最终的结果,computed更高效,优先使用

使用场景:

computed:当一个属性受多个属性影响的时候使用

watch:当一条数据影响多条数据的时候使用

浏览器从url到渲染页面,发生了什么?

三个方面:

  • 网络上:

    • 构建请求

    • 查找强缓存

    • DNS解析

    • 建立TCP连接(三次握手)-> 发送HTTP请求(网络请求后网络响应)

  • 浏览器解析上:

    • 解析HTML构建DOM

    • 解析CSS构建CSSOM树、样式计算

    • 生成布局树(Layout Tree)

  • 浏览器渲染上:

    • 建立图层树(Layer Tree)

    • 生成绘制列表

    • 生成图块并栅格化

    • 显示器显示内容

    • 最后断开TCP连接:TCP四次挥手

    (浏览器会将各层的信息发送给GPU,GPU会将各层合成,显示在屏幕上)

网络安全、HTTP协议

TCP、UDP区别

  1. TCP向上层提供面向连接的可靠传输,UDP向上层提供面向无连接的不可靠传输

  2. 虽然UDP没有TCP传输准确,但是在很多实时性要求高的地方也能有所作为

  3. 对数据准确性要求高,传输速度可以相对较慢的,选用TCP

区别

UDP

TCP

是否连接

无连接

面向连接

是否可靠

不可靠传输,不使用流量控制和拥塞控制

可靠传输,使用流量控制和拥塞控制

连接个数

支持一对一,一对多,多对多通信

只能是一对一通信

传输方式

面向报文

面向字节流

首部开销

首部开销小,仅8个字节

首部最小20字节,最大60字节

适用场景

实时应用(IP电话、视频会议、直播等)

要求可靠传输的应用(文件传输)

Http和Https区别(高频)

区别

HTTP

HTTPS

URL开头

http://

https://

安全性

不安全

安全

端口

80

443

OSI网络模型中的工作层

工作在应用层

安全传输机制工作在传输层

数据传输加密

不加密

加密

证书

无需证书

需要CA机构wosign的颁发SSL证书

GET和POST的区别(高频)

区别

GET

POST

浏览器请求

浏览器回退不会再次发送请求

浏览器回退会再次发送请求

浏览器缓存

会被浏览器主动缓存

不会,需要手动设置

参数保留

完整保留在浏览器历史记录

不会保留

参数长度

有长度限制

没有限制

参数传递

通过URL传递

在Request Body中

安全性

不安全

安全

产生包

产生1个TCP包

产生2个TCP包

应用

查询信息

提交某种信息进行某些修改操作

三次握手和四次挥手

  • http三次握手

    1. 客户端发送SYN报文到服务端发起握手,发送完之后客户端处于SYN_Send状态

    2. 服务端收到SYN报文之后回复SYN和ACK报文给客户端

    3. 客户端收到SYN和ACK,向服务端发送一个ACK报文,客户端转为established状态,此时服务端收到ACK报文也处于established状态,此时双方已建立了连接

  • http四次挥手

    刚开始双方都处于established状态,假如是客户端先发起关闭请求,则

    1. 第一次挥手:客户端发送一个FIN报文,报文中指定一个序列号。此时客户端处于FIN_WAIT状态

    2. 第二次挥手:服务端收到FIN之后,会发送ACK报文,且把客户端的序列号+1作为ACK报文的序列号值,表明已经收到客户端的报文了,此时服务端处于CLOSE_WAIT状态。

    3. 第三次挥手:如果服务端也想断开连接了,和客户端的第一次挥手一样,发送FIN报文,且指定一个序列号。此时服务端处于LAST_ACK状态

    4. 第四次挥手:客户端收到FIN之后,一样发送一个ACK报文作为应答,且把服务端的序列号+1作为自己ACK报文的序列号,此时客户端处于TIME_WAIT状态。需要过一阵子以确保服务端收到自己的ACK报文之后才会加入CLOSED状态。

    5. 服务端收到ACK报文之后,就关闭连接了,处于CLOSED状态。

http如何实现缓存

  1. 强缓存==> expires(过期时间)/Cache-Control(no-cache)(优先级高)

    当浏览器向服务器发送请求的时候,服务器会将缓存规则放入HTTP响应的报文头中和请求结果一起返回给浏览器,控制强制缓存的字段分别是expires(过期时间)/Cache-Control(no-cache),其中Cache-Control的优先级比Expires高

  2. 协商缓存 ==> Last-Modfied/Etag(优先级高)Etag适用于经常改变的小文件,Last-Modfied适用于不怎么经常改变的大文件

    协商缓存就是强制缓存失效后,浏览器携带缓存标识向服务器发起请求,由服务器根据缓存标识决定是否使用缓存的过程

  3. 强缓存策略和协商缓存策略

    在缓存命中是都会直接使用本地的缓存副本,区别只在于**协商缓存会向服务器发送一次请求。**它们缓存不命中时,都会向服务器发送请求来获取资源。

    在实际的缓存机制中,强缓存策略和协商缓存策略是一起合作使用的。浏览器首先会根据请求的信息判断,强缓存是否命中,如果命中则直接使用资源。如果不命中则根据头信息向服务器发起请求,使用协商缓存,如果协商缓存命中的话,则服务器不返回资源,返回304,浏览器直接使用本地资源的副本;如果协商缓存不命中,则浏览器返回最新的资源给浏览器。

输入URL后请求的完整过程

建立TCP连接 -> 发送请求行 -> 发送请求头 -> (到达服务器)发送状态行 -> 发送响应头-> 发送响应数据-> 断开TCP连接