本轮要点: 本次面试主要考察校招生的基础内容
本轮共 15 道题。答案默认折叠,便于先自行作答。
1. 自我介绍
题目要点
自我认知。
参考答案
您好!我是一名对前端开发充满热情的工程师,拥有[X]年的开发经验。我熟练掌握HTML、CSS和JavaScript等前端技术,并在多个项目中运用Vue、React等框架构建用户友好的应用。在大学期间,我主修计算机科学,这为我打下了坚实的编程基础。通过参与各类项目,我不仅提升了技术能力,还培养了良好的团队协作和问题解决能力。我热爱学习新技术,经常阅读技术博客并参与开源项目。在之前的实习和工作中,我积累了丰富的实战经验,能够独立完成项目开发并优化性能。我期待能在贵公司继续我的前端开发之旅,为团队贡献我的技能和热情。
2. 什么时候开始接触前端?
题目要点
学习经历。
参考答案
我是在大学二年级的时候开始接触前端开发的。当时,我选修了一门网页设计与开发的课程,这让我对前端开发产生了浓厚的兴趣。从那时起,我便开始系统地学习HTML、CSS和JavaScript等前端技术,并通过大量的实践项目不断提升自己的技能。毕业后,我继续深入学习前端框架和工具,如Vue、React等,并在实际工作中不断积累经验。
3. 复杂度比较高的项目有哪些
题目要点
项目经验。
参考答案
我参与过一个大型电商平台的前端开发,该项目的复杂度较高,主要体现在以下几个方面:
1. 技术栈丰富:项目中使用了Vue.js、Vuex、Vue Router、Vite、TypeScript等技术,结合了 Vuex 进行状态管理,Vue Router 实现了复杂的路由管理,Vite 作为构建工具提高了开发效率。
2. 性能要求高:由于平台需要支持大量的商品列表和用户并发访问,对性能的要求极高。我们通过代码分割、懒加载、图片优化等手段确保了页面的快速加载和流畅交互。
3. 功能模块复杂:涉及商品展示、购物车、订单管理、用户中心等多个功能模块,各模块之间需要紧密协作和数据共享。
4. 跨团队协作:前端团队与后端团队、设计团队紧密合作,确保项目的顺利交付。
4. 实习中的全栈部分做了什么
题目要点
全栈开发能力。
参考答案
在实习期间,我参与了多个全栈开发项目,主要负责以下工作:
1. 后端接口开发:使用Node.js和Express框架开发RESTful API接口,与前端进行数据交互。我设计并实现了用户认证、商品管理、订单处理等功能的API。
2. 数据库设计与操作:负责MySQL数据库的设计和优化,包括表结构设计、索引优化和查询性能提升。编写SQL语句进行数据的增删改查操作。
3. 前端与后端的联调:确保前后端数据格式的一致性和接口的稳定性,处理可能出现的跨域问题和数据验证问题。
4. 部署与运维:参与项目的部署工作,使用Docker容器化应用,并通过Nginx进行反向代理配置。监控应用的运行状态,及时处理线上问题。
5. Vue 和 React 都是什么时候开始接触的
题目要点
技术学习历程。
参考答案
我是在大学期间开始接触Vue和React的。具体来说:
1. Vue:在大三时,我通过一个个人项目开始学习Vue。当时,我被Vue简洁的语法和强大的组件化特性所吸引,于是深入研究了Vue的文档,并通过实践项目掌握了Vue的基本使用方法,包括组件的创建、数据绑定、事件处理等。
2. React:在大四时,我为了扩展自己的技术栈,开始学习React。我通过官方文档和在线教程了解了React的组件化思想、JSX语法以及Hooks的使用。通过一个小型的社交媒体项目,我实践了React的单向数据流和状态管理。
6. 对原生 JS 如何学习的,掌握程度怎么样
题目要点
JavaScript能力。
参考答案
我对原生JavaScript的学习始于大学二年级,通过以下方式逐步深入:
1. 基础学习:从《JavaScript高级程序设计》等经典书籍入手,系统学习了JavaScript的基本语法、数据类型、函数、对象等核心概念。
2. 在线课程:参加了Coursera和Udemy上的JavaScript课程,通过视频讲解和实践练习巩固知识。
3. 项目实践:通过个人项目和开源项目实践所学知识,如开发简单的游戏、待办事项应用等。
4. 深入学习:研究JavaScript的高级特性,如闭包、原型链、异步编程等,并通过阅读技术博客和参与社区讨论加深理解。
5. 社区参与:在GitHub上参与开源项目,贡献代码并与其他开发者交流,及时了解JavaScript的最新发展和最佳实践。
6. 掌握程度:我能够熟练使用原生JavaScript进行前端开发,包括DOM操作、事件处理、AJAX请求等。对ES6+的新特性(如解构赋值、箭头函数、Promise等)也有深入的理解和实践。在面试过程中,我可以通过代码示例展示我对原生JavaScript的掌握,例如实现防抖函数、深拷贝函数等。
7. 了解过 Vue 和 React 的源码嘛
题目要点
框架理解深度。
参考答案
是的,我曾深入研究过Vue和React的源码,以更好地理解其内部工作机制。对于Vue,我重点研究了其响应式系统(Reactive System)和虚拟DOM(Virtual DOM)的实现原理。通过阅读Vue的源码,我了解到Vue如何通过Object.defineProperty(Vue 2)和Proxy(Vue 3)来实现数据的响应式绑定,以及如何通过虚拟DOM的diff算法高效地更新DOM。对于React,我研究了其虚拟DOM和Fiber架构的实现,理解了React如何通过Fiber实现渐进式渲染和任务调度。这些研究帮助我在实际项目中更好地优化性能和解决复杂问题。
8. Vue 如何实现双向绑定的
题目要点
Vue框架。
参考答案
Vue的双向绑定是通过其响应式系统和编译器实现的。具体来说:
1. 响应式系统:Vue通过`Object.defineProperty`(Vue 2)或`Proxy`(Vue 3)对数据对象进行劫持,当数据发生变化时,能够通知视图进行更新。
2. 编译器:Vue的编译器会将模板中的绑定表达式(如`v-model`)编译成相应的更新函数。在数据变化时,这些更新函数会被调用,从而更新视图。
3. `v-model`指令:在模板中使用`v-model`指令绑定输入元素(如`<input>`、`<textarea>`或`<select>`)与Vue实例中的数据属性。Vue会根据输入元素的类型监听相应的DOM事件(如`input`事件对于`<input>`元素),并在事件触发时更新数据属性。同时,响应式系统会检测到数据的变化,并触发视图的更新。
9. 原生 DOM API 熟悉嘛
题目要点
DOM操作。
参考答案
我对原生DOM API有深入的了解,能够熟练操作DOM元素。以下是一些常见的DOM操作示例:
1. 选取元素:
const element = document.getElementById('myElement');
const elements = document.querySelectorAll('.myClass');
2. 操作元素属性:
element.setAttribute('data-id', '123');
const id = element.getAttribute('data-id');
3. 操作元素样式:
element.style.color = 'red';
element.style.display = 'none';
4. 操作元素类名:
element.classList.add('active');
element.classList.remove('inactive');
element.classList.toggle('highlight');
5. 创建和插入元素:
const newElement = document.createElement('div');
newElement.textContent = 'Hello, world!';
document.body.appendChild(newElement);
6. 事件监听:
element.addEventListener('click', function(event) {
console.log('Element clicked:', event.target);
});
10. JS 继承的几种方式,有什么差异度
题目要点
JavaScript继承。
参考答案
JavaScript中有多种实现继承的方式,每种方式都有其特点和适用场景:
1. 原型链继承:
1. 实现:通过将子类的原型设置为父类的实例来实现继承。
2. 示例:
function Parent() {}
Parent.prototype.method = function() {};
function Child() {}
Child.prototype = new Parent();
Child.prototype.constructor = Child;
3. 特点:子类实例可以访问父类的原型方法和属性。但父类构造函数不会被执行,无法继承父类的实例属性。
2. 构造函数继承:
1. 实现:在子类构造函数中调用父类构造函数。
2. 示例:
function Parent(name) {
this.name = name;
}
function Child(name, age) {
Parent.call(this, name);
this.age = age;
}
3. 特点:子类实例可以继承父类的实例属性。但无法继承父类的原型方法和属性。
3. 组合继承:
1. 实现:结合原型链继承和构造函数继承。
2. 示例:
function Parent(name) {
this.name = name;
}
Parent.prototype.method = function() {};
function Child(name, age) {
Parent.call(this, name);
this.age = age;
}
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;
3. 特点:子类实例可以继承父类的实例属性和原型方法。是最常用的继承方式之一。
4. ES6类继承:
1. 实现:使用`class`和`extends`关键字。
2. 示例:
class Parent {
constructor(name) {
this.name = name;
}
method() {}
}
class Child extends Parent {
constructor(name, age) {
super(name);
this.age = age;
}
}
3. 特点:语法简洁,底层仍基于原型链继承。子类实例可以继承父类的实例属性和原型方法。
5. 寄生组合继承:
1. 实现:优化的组合继承方式,避免多次调用父类构造函数。
2. 示例:
function inheritPrototype(Child, Parent) {
const prototype = Object.create(Parent.prototype);
prototype.constructor = Child;
Child.prototype = prototype;
}
function Parent(name) {
this.name = name;
}
Parent.prototype.method = function() {};
function Child(name, age) {
Parent.call(this, name);
this.age = age;
}
inheritPrototype(Child, Parent);
3. 特点:避免了组合继承中父类构造函数被调用两次的问题。
6. 差异度总结:
| 1. 继承方式 | 2. 是否继承实例属性 | 3. 是否继承原型属性 | 4. 构造函数是否被执行 | 5. 实现复杂度 |
|---|---|---|---|---|
| 6. 原型链继承 | 7. 否 | 8. 是 | 9. 否 | 10. 中 |
| 11. 构造函数继承 | 12. 是 | 13. 否 | 14. 是 | 15. 低 |
| 16. 组合继承 | 17. 是 | 18. 是 | 19. 是(两次) | 20. 中 |
| 21. ES6类继承 | 22. 是 | 23. 是 | 24. 是 | 25. 低 |
| 26. 寄生组合继承 | 27. 是 | 28. 是 | 29. 是(一次) | 30. 高 |
11. 聊聊你对不同网络请求 Method 的理解
题目要点
HTTP方法。
参考答案
不同的HTTP请求方法(Method)用于表示客户端对服务器资源的不同操作意图,它们在语义和使用场景上有明显的区别:
1. GET:
1. 定义:请求获取指定资源的信息。
2. 特点:
1. 安全性:GET请求不会修改服务器上的资源状态,被认为是安全的操作。
2. 幂等性:多次发送相同的GET请求会产生与一次请求相同的效果。
3. 缓存性:GET请求可以被浏览器、代理服务器或服务器端缓存,提高性能。
4. 限制:请求数据量有限(受URL长度限制),不适合发送大量数据。
3. 适用场景:获取资源(如HTML页面、JSON数据)、检索搜索结果。
4. 示例:
fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => console.log(data));
2. POST:
1. 定义:向服务器提交数据,可能创建新的资源或触发特定处理。
2. 特点:
1. 非安全性:POST请求会修改服务器上的资源状态。
2. 非幂等性:多次发送相同的POST请求可能会产生不同的结果(如多次创建资源)。
3. 无缓存性:POST请求通常不会被缓存。
4. 数据量:可以在请求体中发送大量数据。
3. 适用场景:提交表单数据、上传文件、创建新资源。
4. 示例:
fetch('https://api.example.com/data', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ key: 'value' })
})
.then(response => response.json())
.then(data => console.log(data));
3. PUT:
1. 定义:向服务器提交数据,替换目标资源的全部内容。
2. 特点:
1. 非安全性:PUT会修改资源状态。
2. 幂等性:多次发送相同的PUT请求会产生相同的结果。
3. 数据量:可以在请求体中发送大量数据。
3. 适用场景:更新资源的全部内容、创建新资源(如果资源不存在)。
4. 示例:
fetch('https://api.example.com/data/1', {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ key: 'updatedValue' })
})
.then(response => response.json())
.then(data => console.log(data));
4. PATCH:
1. 定义:向服务器提交数据,对目标资源进行部分修改。
2. 特点:
1. 非安全性:PATCH会修改资源状态。
2. 非幂等性:多次发送相同的PATCH请求可能产生不同结果。
3. 效率:只发送需要更新的部分数据,减少传输量。
3. 适用场景:更新资源的部分内容。
4. 示例:
fetch('https://api.example.com/data/1', {
method: 'PATCH',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ key: 'updatedValue' })
})
.then(response => response.json())
.then(data => console.log(data));
5. DELETE:
1. 定义:请求服务器删除指定资源。
2. 特点:
1. 非安全性:DELETE会修改资源状态。
2. 幂等性:多次发送相同的DELETE请求会产生相同的效果。
3. 适用场景:删除资源。
4. 示例:
fetch('https://api.example.com/data/1', {
method: 'DELETE'
})
.then(response => console.log('Deletion successful'));
6. HEAD:
1. 定义:请求获取指定资源的元信息(如头部信息),不返回资源主体。
2. 特点:
1. 安全性:HEAD不会修改资源状态。
2. 幂等性:多次请求效果相同。
3. 数据量:无响应主体,适合快速获取资源信息。
3. 适用场景:检查资源是否存在、获取资源头部信息(如内容长度、最后修改时间)。
4. 示例:
fetch('https://api.example.com/data', { method: 'HEAD' })
.then(response => console.log('Content-Length:', response.headers.get('Content-Length')));
7. OPTIONS:
1. 定义:请求获取目标资源支持的HTTP方法和通信选项。
2. 特点:
1. 安全性:OPTIONS不会修改资源状态。
2. 幂等性:多次请求效果相同。
3. 适用场景:跨域请求预检(CORS预飞行请求)、获取资源支持的操作方法。
4. 示例:
fetch('https://api.example.com/data', { method: 'OPTIONS' })
.then(response => console.log('Allowed methods:', response.headers.get('Allow')));
12. 聊聊天 URL 输入到页面展示的过程
题目要点
网络与浏览器原理。
参考答案
从在浏览器地址栏输入URL到页面展示的完整过程涉及多个复杂的步骤,以下是详细的流程:
1. URL解析:
1. 浏览器解析输入的URL,提取出协议(如HTTP、HTTPS)、域名、端口(可选)和路径等信息。
2. DNS解析:
2. 浏览器检查本地DNS缓存,寻找域名对应的IP地址。
3. 如果本地缓存未命中,浏览器查询操作系统DNS缓存。
4. 如果仍未命中,浏览器向配置的DNS服务器(通常是ISP的DNS或用户自定义的DNS)发送DNS查询请求。
5. DNS服务器进行递归查询,依次查询根DNS服务器、TLD(顶级域)DNS服务器、权威DNS服务器,最终获取域名对应的IP地址并返回给浏览器。
3. 建立TCP连接:
6. 浏览器与目标服务器的IP地址和端口(默认为80或443)建立TCP连接。这涉及三次握手过程:
1. 客户端发送SYN包:浏览器向服务器发送SYN(同步序列号)包,请求建立连接。
2. 服务器回应SYN-ACK包:服务器收到SYN包后,回应一个SYN-ACK(同步-确认)包,确认收到SYN包并同步序列号。
3. 客户端发送ACK包:浏览器收到SYN-ACK包后,发送ACK(确认)包,完成三次握手,建立TCP连接。
4. HTTPS握手(如果适用):
7. 如果URL使用HTTPS协议,浏览器和服务器将在TCP连接上进行TLS握手,过程如下:
1. Client Hello:客户端(浏览器)向服务器发送`Client Hello`消息,包含支持的TLS版本、加密套件列表、随机数等信息。
2. Server Hello:服务器回应`Server Hello`消息,选择一个加密套件,发送自己的TLS证书、随机数以及会话ID。
3. 证书验证:浏览器验证服务器证书的有效性,包括证书颁发机构(CA)签名、域名匹配、证书有效期等。
4. 密钥交换:基于选择的加密套件,浏览器和服务器进行密钥交换。例如,使用RSA加密时,浏览器生成随机前主密钥(pre-master secret),用服务器公钥加密后发送给服务器;服务器用私钥解密并计算出会话密钥。
5. Finished消息:双方发送`Finished`消息,验证握手过程的完整性。消息内容为之前握手消息的哈希值,使用会话密钥加密。
6. 安全连接建立:TLS握手完成,双方通过安全通道进行数据传输。
5. 发送HTTP请求:
8. 浏览器通过建立的TCP(或TLS)连接向服务器发送HTTP请求。请求包含方法(如GET)、路径、HTTP版本、请求头(如`Host`、`User-Agent`、`Accept`)等信息。例如:
GET /path/resource.html HTTP/1.1
Host: www.example.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Connection: keep-alive
Upgrade-Insecure-Requests: 1
6. 服务器处理请求:
9. 服务器接收HTTP请求,由Web服务器(如Nginx、Apache)进行初步处理,如解析请求头、路由匹配等。
10. 请求被转发到相应的后端应用服务器(如Node.js、Django、Spring Boot应用)。
11. 后端应用根据请求路径和参数,执行相应的业务逻辑,可能涉及数据库查询、文件读写等操作。
12. 如果请求需要访问数据库,后端应用将执行SQL查询,获取所需的数据。
13. 后端应用将数据整理成响应内容,生成HTTP响应体(如HTML、JSON、XML格式)。
14. 后端应用设置HTTP响应头(如`Content-Type`、`Content-Length`、`Cache-Control`)。
7. 发送HTTP响应:
15. 服务器将HTTP响应发送回浏览器。响应包含状态行(如`200 OK`)、响应头和响应体。例如:
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 12345
Date: Tue, 05 Jul 2023 12:00:00 GMT
Server: nginx/1.21.3
Cache-Control: max-age=3600
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Example Page</title>
</head>
<body>
<h1>Welcome to Example Page</h1>
</body>
</html>
8. 浏览器接收响应并解析:
16. 浏览器接收HTTP响应,首先解析响应头,判断响应状态码和内容类型。
17. 如果状态码为2xx(成功),浏览器开始解析响应体内容。
18. 如果内容类型为`text/html`,浏览器开始构建DOM树:
1. 词法分析与解析:浏览器的HTML解析器将HTML代码分解为标记(tokens),如`<html>`、`<head>`、`<body>`等。
2. DOM树构建:根据标记构建DOM树,每个节点代表一个元素或文本片段。
3. 样式计算:浏览器加载并解析相关的CSS文件(内联样式、`<link>`标签引用的外部CSS),计算每个DOM节点的样式属性。
4. 布局(reflow):确定每个DOM节点的几何信息(位置、大小),基于页面的布局模型(如CSS盒模型)。
5. 绘制(paint):将DOM节点绘制到屏幕上,生成可见的页面内容。
9. 资源加载:
19. 在解析HTML时,浏览器会遇到如`<link>`(CSS)、`<script>`(JavaScript)、`<img>`(图片)等标签,触发额外的资源请求:
1. 对于CSS文件,浏览器会阻塞页面渲染直到CSSOM构建完成,以确保页面样式正确。
2. 对于JavaScript文件,如果脚本是阻塞的(默认行为),浏览器会暂停DOM解析直到脚本下载并执行完成。如果脚本使用`async`或`defer`属性,浏览器可以异步加载脚本,避免阻塞DOM解析。
3. 图片和其他媒体资源在DOM解析完成后按需加载。
20. 浏览器使用并行下载和预加载机制加速资源加载。例如,现代浏览器可以同时打开多个TCP连接到同一个域名,减少资源加载时间。
10. 页面加载完成:
21. 当所有资源加载完成,页面完全渲染,浏览器触发`load`事件,标志着页面加载过程结束。
22. 此时,用户可以看到完整的页面内容,并可以与页面进行交互。
11. 后续交互:
23. 用户与页面进行交互(如点击链接、提交表单),浏览器根据页面的事件处理程序和JavaScript代码,可能发起新的HTTP请求或更新页面内容。
24. 页面可以通过AJAX技术在不重新加载整个页面的情况下与服务器交换数据并更新部分页面内容。
13. 在项目中接触过 XSS 和跨域的场景嘛
题目要点
网络安全。
参考答案
是的,我在项目中接触过XSS(跨站脚本攻击)和跨域问题,并采取了相应的措施来解决这些问题。
1. XSS防护:
1. 输入验证和转义:对用户输入进行严格的验证和转义,确保特殊字符(如`<`、`>`、`&`、`"`)被转换为HTML实体,避免恶意脚本的注入。例如,在Vue中使用`v-html`时,仅允许可信内容;在React中,使用JSX的自动转义功能。
2. 内容安全策略(CSP):通过设置HTTP响应头`Content-Security-Policy`,限制页面可加载的资源类型和来源,防止XSS攻击。例如:
Content-Security-Policy: default-src 'self'; script-src 'self' https://trusted-cdn.com; img-src *; style-src 'self' 'unsafe-inline'
3. 使用安全的库和框架:选择具有内置XSS防护功能的前端框架和库,如Vue、React等,它们在模板引擎中自动转义表达式内容。
2. 跨域解决方案:
1. CORS(跨源资源共享):在后端设置`Access-Control-Allow-Origin`、`Access-Control-Allow-Methods`、`Access-Control-Allow-Headers`等HTTP头,允许前端从不同源访问资源。例如,在Express中:
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', 'https://client-domain.com');
res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
next();
});
2. JSONP:对于仅需GET请求的场景,使用JSONP技术。通过动态创建`<script>`标签,绕过浏览器的同源策略限制。例如:
function jsonDataCallback(data) {
console.log(data);
}
const script = document.createElement('script');
script.src = 'https://api.example.com/data?callback=jsonDataCallback';
document.head.appendChild(script);
3. 代理服务器:在前端和后端之间设置代理服务器,将跨域请求转发到目标服务器。例如,在Vue项目中使用Vue CLI的代理配置:
module.exports = {
devServer: {
proxy: {
'/api': {
target: 'https://api.example.com',
changeOrigin: true,
pathRewrite: { '^/api': '' }
}
}
}
};
4. Service Worker:在PWA项目中,使用Service Worker拦截和处理跨域请求,实现更灵活的缓存和请求管理策略。
14. 手写实现 Promise.all
题目要点
JavaScript异步控制。
参考答案
function PromiseAll(iterable) {
// 将输入转为数组,支持类数组对象
const array = Array.from(iterable);
return new Promise((resolve, reject) => {
const results = [];
let completed = 0;
// 检查输入是否为空
if (array.length === 0) {
resolve([]);
return;
}
// 遍历每个Promise
array.forEach((promise, index) => {
Promise.resolve(promise).then(
(value) => {
results[index] = value;
completed++;
// 所有Promise完成时,返回结果数组
if (completed === array.length) {
resolve(results);
}
},
(error) => {
reject(error);
}
);
});
});
}
15. 用 CSS 实现一个自适应九宫格布局
题目要点
CSS布局。
参考答案
<div class="grid-container">
<div class="grid-item">1</div>
<div class="grid-item">2</div>
<div class="grid-item">3</div>
<div class="grid-item">4</div>
<div class="grid-item">5</div>
<div class="grid-item">6</div>
<div class="grid-item">7</div>
<div class="grid-item">8</div>
<div class="grid-item">9</div>
</div>
<style>
.grid-container {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 10px; /* 设置网格间距 */
max-width: 500px;
margin: 0 auto;
}
.grid-item {
background-color: #f0f0f0;
padding: 20px;
text-align: center;
border-radius: 5px;
}
</style>