base北京 百度 前端实习面经
部门:质量效能
投递渠道: BOSS 直聘
时间线
- 2024-02-27 一面
- 2024-02-27 二面
- 2024-03-06 三面
一面
- 实习经历业务介绍
1. Vue 响应式原理, 开始吟唱 😎
Vue 的响应式原理是其核心特性之一,它使得 Vue 能够实现数据驱动视图的更新。Vue 的响应式原理基于 ES6 的 Proxy 对象或者旧版本中的 Object.defineProperty 方法,实现了数据的双向绑定。
-
数据劫持: Vue 在初始化时会递归地遍历所有的 data 对象,使用 Object.defineProperty 或者 Proxy 对象对每个属性进行劫持。这样一来,当属性被读取或者修改时,Vue 就能够监听到,并触发相应的更新。
-
依赖收集: 当页面渲染时,模板中的指令会通过访问数据来获取相应的值。在这个过程中,Vue 会将数据与对应的 Watcher 建立关联,从而构建起一个依赖关系图。当数据发生变化时,Vue 就能够根据依赖关系图找到所有依赖这个数据的地方,并更新相应的视图。
-
异步更新: 当数据发生变化时,Vue 并不会立即更新视图,而是将更新放入队列中,等到适当的时机再一起进行批量更新。这样做可以避免频繁的 DOM 操作,提高性能。
-
虚拟 DOM: Vue 通过虚拟 DOM 来减少对真实 DOM 的操作次数。当数据发生变化时,Vue 首先将变化应用到虚拟 DOM 上,然后通过 diff 算法对比新旧虚拟 DOM 的差异,并只更新发生变化的部分到真实 DOM 上,从而减少了对真实 DOM 的操作,提高了性能。
总的来说,Vue 的响应式原理通过数据劫持、依赖收集、异步更新和虚拟 DOM 等技术实现了数据驱动视图的更新,使得开发者能够更加便捷地构建响应式的 Web 应用。
- Vue 常见的指令
【4. V-if 与 V-show 的区别
v-if 和 v-show 是 Vue.js 中用来控制元素显示与隐藏的两个指令,它们之间的区别主要体现在渲染方式和条件切换频率上:
-
渲染方式:
v-if:根据表达式的真假条件,动态地销毁或重新创建 DOM 元素。当条件为假时,元素不会被渲染到 DOM 中;当条件为真时,元素会被创建并插入到 DOM 中。v-show:根据表达式的真假条件,通过 CSS 控制元素的显示与隐藏。当条件为假时,元素的样式会被设置为display: none;;当条件为真时,元素的样式会被设置为display: block;或者display: inline;,根据元素原本的display属性决定。
-
条件切换频率:
v-if:适用于需要频繁切换条件的情况,例如条件可能在运行时变化,且条件不经常改变的情况。因为v-if是动态地销毁和创建元素,适合用于开销较大的组件。v-show:适用于需要频繁切换条件的情况,但是条件不经常改变的情况。由于v-show只是切换元素的显示与隐藏,不会销毁和重新创建元素,因此在性能消耗上通常比v-if更轻量级。
总的来说,如果条件切换频率较低或者条件不经常改变,推荐使用 v-show;如果条件切换频率较高或者条件经常改变,推荐使用 v-if。
6. 输入 URL 到页面展示的过程
7. 定义 CSS 的三种方式
在 HTML 中,可以使用三种方式来定义 CSS 样式:
-
内联样式(Inline Styles): 使用
style属性直接在 HTML 元素上定义样式。这种方式的样式仅适用于当前元素,并具有最高的优先级。<div style="color: red; font-size: 16px;">这是一个内联样式的示例</div> -
内部样式表(Internal Styles): 使用
<style>标签在 HTML 文档的<head>中定义样式表。这种方式的样式适用于整个文档,但仅在当前文档中有效。<head> <style> .example { color: blue; font-size: 18px; } </style> </head> <body> <div class="example">这是一个内部样式表的示例</div> </body> -
外部样式表(External Styles): 将样式定义在单独的 CSS 文件中,然后在 HTML 文档中通过
<link>标签引入外部样式表。这种方式的样式适用于整个网站,并且可以在多个页面中共享。<!-- index.html --> <head> <link rel="stylesheet" type="text/css" href="styles.css"> </head> <body> <div class="example">这是一个外部样式表的示例</div> </body>/* styles.css */ .example { color: green; font-size: 20px; }
使用这三种方式可以根据实际需求和情况来组织和管理 CSS 样式,使样式代码更加清晰、灵活和易于维护。
3. CSS 选择器与优先级
CSS 选择器是用来选择 HTML 元素并对其应用样式的一种机制。CSS 选择器根据不同的规则来匹配 HTML 元素,当多个选择器同时作用于同一个元素时,需要确定哪个样式规则应用于该元素。这就引出了 CSS 选择器的优先级。
CSS 选择器的优先级规则如下(优先级从高到低):
- !important:
!important关键字赋予样式规则最高优先级。当样式规则使用了!important关键字时,无论其在样式表中的位置如何,都会优先应用该样式规则。 - 内联样式:直接在 HTML 元素的
style属性中指定样式,内联样式具有比较高的优先级。 - ID 选择器:通过 HTML 元素的
id属性来选择元素,ID 选择器具有比较高的优先级。 - 类选择器、属性选择器、伪类选择器:这些选择器根据类名、属性或状态来选择元素,优先级相同,但比标签选择器优先级高。
- 标签选择器:通过 HTML 元素的标签名来选择元素,优先级较低。
- 通配符选择器:使用
*来选择所有元素,优先级最低。
当多个样式规则应用于同一个元素时,浏览器会按照上述规则确定哪个样式规则应用于该元素。如果两个样式规则具有相同的优先级,那么后面定义的规则将覆盖先前定义的规则。
例如:
/* ID 选择器 */
#container {
color: red; /* 优先级: 100 */
}
/* 类选择器 */
.text {
color: blue; /* 优先级: 10 */
}
/* 标签选择器 */
div {
color: green; /* 优先级: 1 */
}
在上面的示例中,如果一个元素同时具有 id="container" 和 class="text",则应用的样式为红色,因为 ID 选择器的优先级高于类选择器。
3. get 请求与 post 请求的区别, 传参格式与传参位置有什么区别
GET 请求与 POST 请求是 HTTP 协议中常用的两种请求方法,它们之间有以下区别:
-
传参位置:
- GET 请求的参数是以查询字符串的形式附加在 URL 的末尾,例如
http://example.com/api?name=value&age=20。 - POST 请求的参数是包含在请求的消息体中的,不会直接暴露在 URL 中。
- GET 请求的参数是以查询字符串的形式附加在 URL 的末尾,例如
-
传参格式:
- GET 请求的参数是以键值对的形式出现,键值对之间使用
&连接,键和值之间使用=连接,例如name=value&age=20。 - POST 请求的参数可以以多种格式传递,常见的有表单形式(
application/x-www-form-urlencoded)、JSON 格式(application/json)、FormData 格式(用于上传文件等特殊场景)等。
- GET 请求的参数是以键值对的形式出现,键值对之间使用
-
请求安全性:
- GET 请求的参数以明文形式暴露在 URL 中,不适合传输敏感信息,比如密码等。
- POST 请求的参数不会直接暴露在 URL 中,相对于 GET 请求更安全,可以用于传输敏感信息。
-
请求长度限制:
- GET 请求的参数长度有限制,不同浏览器和服务器对长度的限制不同,通常为几千个字符。
- POST 请求的参数长度一般没有限制,但是服务器和客户端都可能对消息体的大小做出限制。
-
幂等性:
- GET 请求是幂等的,即对同一 URL 的多次请求应该产生相同的结果。
- POST 请求不是幂等的,因为它可能会对服务器产生副作用,比如修改资源状态或提交表单数据。
总的来说,GET 请求适用于获取资源,而 POST 请求适用于提交数据、表单等场景。在实际开发中,根据请求的语义和传递的数据类型来选择使用 GET 请求还是 POST 请求。
- 跨域问题与解决方案
4. 设计实现七天免密登录
实现七天免密登录的基本思路如下:
- 用户首次登录时,勾选“记住密码”或类似选项,并成功登录后,在客户端设置一个持久化的凭证,如 token 或者 session id。
- 将该凭证保存在客户端的持久化存储中,比如使用 localStorage 或者 cookie 进行保存,设置有效期为七天。
- 用户在七天内再次访问站点时,检查客户端是否存在有效的凭证,如果存在,则自动登录,否则需要用户重新输入密码进行登录。
下面是一个简单的示例实现,以 localStorage 为例:
// 登录成功后设置 token
function login(username, password) {
// 模拟登录请求,验证用户名和密码
if (username === 'admin' && password === '123456') {
const token = generateToken();
localStorage.setItem('token', token);
return true;
}
return false;
}
// 生成 token
function generateToken() {
return Math.random().toString(36).substr(2); // 随机生成一个字符串作为 token
}
// 自动登录
function autoLogin() {
const token = localStorage.getItem('token');
if (token) {
// 模拟发送 token 到服务器进行验证
// 如果验证成功,则执行登录操作
console.log('自动登录成功');
return true;
}
return false;
}
// 模拟登录流程
if (!autoLogin()) {
// 如果没有自动登录,则显示登录界面
console.log('显示登录界面');
}
// 登出操作,清除 token
function logout() {
localStorage.removeItem('token');
console.log('已退出登录');
}
在这个示例中,当用户首次登录成功后,会生成一个随机的 token,并将其存储在 localStorage 中。在下一次访问站点时,会检查 localStorage 中是否存在有效的 token,如果存在,则自动登录,否则需要用户重新登录。当用户手动执行退出登录操作时,会清除 localStorage 中的 token。
3. 算法:括号合法性判断
括号合法性判断是指判断一个字符串中的括号是否能够正确匹配和闭合。例如,字符串 "()"、"()[]{}" 都是合法的,而 "([)]" 则是不合法的。
下面是一种简单的算法实现,使用栈来辅助判断括号的合法性:
- 遍历字符串的每个字符。
- 如果是左括号('('、'['、'{'),则将其压入栈中。
- 如果是右括号(')'、']'、'}'),则从栈顶弹出一个左括号,如果栈为空或者弹出的左括号与当前右括号不匹配,则返回 false。
- 遍历结束后,如果栈为空,则说明所有括号都能正确匹配,返回 true;否则,返回 false。
下面是 JavaScript 实现:
function isValidParentheses(s) {
const stack = [];
const mapping = {
')': '(',
']': '[',
'}': '{'
};
for (let i = 0; i < s.length; i++) {
const char = s.charAt(i);
if (char === '(' || char === '[' || char === '{') {
stack.push(char);
} else {
const top = stack.pop();
if (top !== mapping[char]) {
return false;
}
}
}
return stack.length === 0;
}
// 测试示例
console.log(isValidParentheses("()")); // true
console.log(isValidParentheses("()[]{}")); // true
console.log(isValidParentheses("(]")); // false
console.log(isValidParentheses("([)]")); // false
这段代码使用了一个栈来辅助判断括号的合法性,时间复杂度为 O(n),其中 n 是字符串的长度。
二面 15 min
- 为什么离职
- 输入 URL 到页面展示的过程(怎么又问一遍
1. 手写代码,原生实现输入框输入时, p 标签中同步显示输入内容
以下是一个简单的示例,演示了如何使用原生 JavaScript 实现输入框输入时,同步显示输入内容到 <p> 标签中:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Input Sync Demo</title>
</head>
<body>
<input type="text" id="inputField">
<p id="output">输入内容将会显示在这里</p>
<script>
// 获取输入框和 p 标签的引用
const inputField = document.getElementById('inputField');
const output = document.getElementById('output');
// 监听输入框的 input 事件
inputField.addEventListener('input', function(event) {
// 将输入框的值同步到 p 标签中
output.textContent = event.target.value;
});
</script>
</body>
</html>
在这个示例中,我们首先通过 getElementById() 方法获取了输入框和 <p> 标签的引用,然后使用 addEventListener() 方法监听输入框的 input 事件。每当用户在输入框中输入内容时,触发 input 事件,并通过 event.target.value 获取到输入框的值,然后将其同步更新到 <p> 标签中的 textContent 属性上,以实现实时显示输入内容的效果。
- 用过哪些 Linux 命令
- 看代码说结果:
var i = 0;
for (i = 1; i <= 3; i++)
setTimeout(function () {
console.log(i);
}, 0);
// 4 4 4
// 解释: 先执行完 for 循环, i 的值变为 4, 然后再执行宏任务
这段代码会输出 4 4 4。
解释:在循环中使用 setTimeout 创建了三个异步任务,这三个任务都会在当前事件循环结束后执行。因为 JavaScript 是单线程执行的,所以当 for 循环执行完毕后,i 的值已经变为了 4。而在执行异步任务时,它们都会访问同一个外部变量 i,此时 i 的值已经是 4,因此三个异步任务都会输出 4。
1. 什么是 XSS 攻击
XSS(Cross-Site Scripting)攻击是一种常见的Web安全漏洞,它允许攻击者向Web页面中注入恶意脚本代码,当用户访问包含恶意脚本的页面时,这些脚本将在用户的浏览器上执行,从而导致恶意行为的发生。
XSS 攻击通常分为三种类型:
-
存储型 XSS:攻击者将恶意脚本代码存储到服务器端,当其他用户访问包含这些恶意脚本的页面时,这些脚本会被从服务器端取出并在用户浏览器上执行。
-
反射型 XSS:攻击者将恶意脚本代码作为参数附加到URL中,当用户点击包含恶意脚本的URL时,这些脚本会被发送到服务器端,并从服务器端返回给用户浏览器,最终在用户浏览器上执行。
-
DOM 型 XSS:攻击者利用页面中存在的漏洞,将恶意脚本代码注入到页面的DOM结构中,当用户访问包含这些恶意脚本的页面时,这些脚本会被解析和执行。
XSS 攻击可以导致一系列危险的后果,包括盗取用户的个人信息(如Cookie、Session ID等)、篡改页面内容、重定向用户到恶意网站等。为了防止 XSS 攻击,开发者需要采取一系列安全措施,如过滤和转义用户输入、设置合适的 Content Security Policy(CSP)、使用安全的编程语言和框架等。
3. 如何理解 Promise, 有哪些常见的方法
Promise 是 JavaScript 中用于处理异步操作的一种机制,它可以更优雅地处理回调地狱(callback hell)问题,并提供了一种更便捷、更可控的方式来处理异步代码。
Promise 有三种状态:
- Pending(进行中):初始状态,表示异步操作尚未完成。
- Fulfilled(已完成):表示异步操作成功完成。
- Rejected(已失败):表示异步操作失败。
Promise 提供了以下几个常见的方法:
- then():用于指定异步操作成功时的回调函数,也可以指定异步操作失败时的回调函数。
- catch():用于指定异步操作失败时的回调函数,相当于 then(null, onRejected) 的别名。
- finally():用于指定异步操作无论成功或失败都会执行的回调函数,通常用于释放资源或清理操作。
- all():接收一个由 Promise 组成的数组作为参数,当数组中所有 Promise 都成功时,返回一个新的 Promise,它的成功值是一个包含所有 Promise 成功值的数组;如果数组中任意一个 Promise 失败,则返回的 Promise 会立即被拒绝。
- race():接收一个由 Promise 组成的数组作为参数,当数组中的任意一个 Promise 解决或拒绝时,返回的 Promise 会解决或拒绝,并将首先解决或拒绝的 Promise 的值作为它的值。
例如:
// 创建一个 Promise 对象
const myPromise = new Promise((resolve, reject) => {
// 模拟异步操作
setTimeout(() => {
const randomNumber = Math.random();
if (randomNumber > 0.5) {
resolve(randomNumber);
} else {
reject(new Error('Random number is too small'));
}
}, 1000);
});
// 使用 then() 指定成功和失败的回调函数
myPromise.then(
result => {
console.log('Promise resolved:', result);
},
error => {
console.error('Promise rejected:', error);
}
);
// 使用 catch() 指定失败的回调函数
myPromise.catch(error => {
console.error('Promise rejected:', error);
});
// 使用 finally() 指定无论成功或失败都会执行的回调函数
myPromise.finally(() => {
console.log('Promise finally executed');
});
通过使用这些方法,我们可以更加清晰地组织和处理异步代码,提高代码的可读性和可维护性。
三面 30min
- 实习难点
1. React 与 Vue 的区别
- 新项目技术选型, 可以从哪些维度考虑使用 React 或者 Vue
React 和 Vue 是当前流行的前端框架之一,它们在一些方面有共同之处,但也存在一些不同之处。下面是它们的主要区别和技术选型的考虑维度:
-
语法和模板:
- React 使用 JSX(JavaScript XML)作为组件的模板语法,将 HTML 和 JavaScript 结合在一起,使得组件的编写更加灵活和直观。
- Vue 使用基于 HTML 的模板语法,将模板和组件的逻辑分离开来,使得组件的编写更加简洁和易懂。
-
组件化和状态管理:
- React 使用单一的状态树(State)和单向数据流(Unidirectional Data Flow)来管理组件的状态和数据流动,通过 Context API 或 Redux 等库来实现状态的共享和管理。
- Vue 提供了自带的状态管理工具 Vuex,通过响应式数据和组件间的事件传递来管理状态和数据流动,使得状态管理更加简单和直观。
-
生态系统和工具链:
- React 生态系统相对更加庞大,有大量的第三方库和工具可供选择,如 Redux、React Router、Material-UI 等。
- Vue 生态系统也相当丰富,但规模较小,社区资源相对更加集中,Vue Router、Vuex、Vuetify 等是常用的 Vue 相关库和工具。
-
学习曲线:
- React 的学习曲线相对较陡,需要掌握 JSX 语法、单向数据流的理念、组件生命周期等概念。
- Vue 的学习曲线相对较缓,它的 API 设计更加友好,文档更加清晰,适合初学者快速上手。
-
性能和优化:
- 两者在性能方面没有明显的优劣之分,都可以通过优化技术来提升性能,如懒加载、代码拆分、缓存等。
- React 有更灵活的状态管理和虚拟 DOM 的设计,使得一些场景下可以实现更精细的性能优化。
考虑使用 React 还是 Vue 可以从以下几个维度进行考虑:
- 项目需求:根据项目的复杂度、规模和功能需求来选择适合的框架。
- 团队技术栈:考虑团队成员的技术能力和熟悉程度,选择团队中更熟悉或更擅长的框架。
- 社区支持:查看框架的社区活跃度、文档完善程度、第三方库和工具的支持情况等。
- 性能和优化:根据项目的性能需求和优化要求来选择更合适的框架。
- 未来发展:考虑框架的发展趋势、版本更新和维护情况,选择更有长期支持和发展潜力的框架。
作者:zbwer
链接:www.nowcoder.com/discuss/596…
来源:牛客网