是的,我失业了,在这个各行业都是寒冬的时间,本想着当一条躺平的咸鱼度过这个环境,但是没招,直接看题吧。。。。。。
以下问题均为个人整理回答,码字不易,转发和发布请携带发布者
面试问题有误可联系修改
一、前端如何实现截图?
前端实现截图功能主要依赖于canvas api及相关技术,常用两种解决方案: 1、使用第三方库html2canvas
- 原理:通过获取HTML的某个元素,然后生成Canvas,再调用Canvas的toDataURL()方法生成图片。
- 步骤:获取当前页面的标签节点,渲染画布Canvas,调用toDataURL()方法生成图片。
- 注意:跨域问题,html2canvas默认不会加载跨域的图片资源,通过设置useCORS: true来启用跨域请求支持。
2、使用Canvas API手动绘制
- 创建一个Canvas元素,并设置其宽高和样式。
- 使用Canvas API在Canvas上绘制需要截图的内容。
- 调用Canvas的toDataURL()方法将Canvas转化为base64编码的图片数据。
二、js超过Number最大值的数怎么处理?
在JavaScript中,当处理的数字超过Number类型的最大值(即Number.MAX_VALUE,大约是1.7976931348623157e+308),或者小于Number类型的最小值(即Number.MIN_VALUE,大约是5e-324),就会出现精度丢失的问题,因为JavaScript中的Number类型是基于IEEE 754标准的双精度浮点数表示的。
- 使用字符串表示大数,需要手动实现大数的加、减、乘、除等操作。
- 使用BigInt类型,BigInt不能与普通的Number类型进行混合运算,你需要显式地将它们转换为相同的类型。
- 使用第三方库:bignumber.js或decimal.js等。
三、使用同一个链接,如何实现pc打开是web应用,手机打开时h5应用?
两种解决方案,一种是配合服务器重定向,一种是纯前端使用媒体查询,通过多套样式适配不同屏幕尺寸:
- 使用JavaScript检测用户的User-Agent,判断访问设备是否为移动设备,若检测为移动设备,则重定向到H5应用页面,反之则重定向到pc页面,在服务器端,如使用Node.js的Express框架,可以根据User-Agent返回不同的页面或数据,以实现设备适配。
- 通过@media only screen设置多种屏幕尺寸的样式,对多尺寸屏幕做适配,规定尺寸越多兼容性适配性越高。
四、前端如何保证用户的使用体验?
- 提升页面加载速度:通过优化代码、减少HTTP请求、使用CDN、利用浏览器缓存等方法,可以有效提高页面加载速度,减少用户等待时间。
- 优化界面布局与导航:简洁明了的布局和直观易用的导航,能够使用户更容易找到所需信息,提升使用体验。
- 注重交互设计:提供清晰的导航、合理的布局、一致的设计以及友好的错误提示,这些都能增强用户的交互体验。
- 关注性能优化:包括代码与资源优化、网络性能优化以及渲染性能优化,确保应用运行流畅,不卡顿。
五、如何解决页面请求接口大规模并发问题?
- 优化用户体验和减轻服务器压力:采用懒加载技术,确保用户滚动到特定内容时才加载该部分内容;使用分页与无限滚动技术,限制每次请求的数据量,提供更好的用户体验。
- 利用缓存机制:存储常用资源,避免重复请求;使用Service Worker缓存静态资源或重要数据,提供离线访问支持。
- 减少HTTP请求:合并CSS和JavaScript文件,使用图片精灵技术减少图片请求。
- 使用CDN:提高资源加载速度和可用性。
- 前端限流:控制事件触发的频率,如搜索、评论等操作。 代码分割与按需加载:利用现代前端框架的代码分割功能,按需加载组件。
六、如何设计一套全站请求耗时统计工具?
- 确定需要统计哪些请求的耗时,例如API请求、静态资源加载等,确定统计的粒度,例如是否需要统计每个请求的耗时,或者只需要统计某些特定请求的耗时。
- 对于AJAX请求,可以在请求发送前和响应接收后分别记录时间,然后计算差值得到耗时。
- 在发送请求前,记录当前时间作为开始时间。在请求完成后(无论是成功还是失败),再次记录当前时间作为结束时间。计算结束时间和开始时间的差值,得到请求的耗时。
- 将统计到的耗时数据存储在合适的地方,例如localStorage、IndexedDB或者自定义的存储方案中。定时或者在满足特定条件时,将存储的耗时数据上报到后端服务器进行分析和处理。
- 在后端服务器对收集到的耗时数据进行处理和分析后,可以通过可视化工具(如Grafana、ECharts等)将数据显示出来,以便更好地理解和优化请求耗时。
- 在设计和实现统计工具时,要注意保护用户的隐私和数据安全。
七、大文件上传了解多少?
- 分片上传:将大文件切割成多个小文件片段,分别上传,然后在服务端组合。这种方式可以提高上传速度和可靠性,但需要额外的前后端开发和维护工作。
- 断点续传:在上传过程中,如果发生中断,可以从上次中断的地方继续上传,而不是重新上传整个文件。这需要前端记录上传进度,并在需要时继续上传未完成的部分。
- 并发上传:利用多线程或多进程并发上传文件片段,以提高上传效率。
- 用户体验优化:显示上传进度条,提供网络波动处理和失败重试机制,以提升用户体验。 可移步另外一片文章查阅相关步骤
八、h5如何解决移动端适配问题?
- 使用viewport标签:通过设置viewport标签的meta属性,控制页面的缩放比例和宽度,以适配不同的设备。
- 使用CSS3的媒体查询:根据不同的设备宽度设置不同的样式,以实现响应式设计。
- 使用rem单位:将px转化为rem单位,根据不同的设备字体大小设置不同的样式,以实现适配。
- 使用flexible布局方案:将px转化为rem单位,并且动态计算根节点的字体大小,以适配不同的设备。
- 使用postcss-px-to-viewport插件:自动将px单位转换为视窗单位,简化适配过程。
八、站点一件换肤的实现方式有哪些?
- 使用CSS变量:定义变量控制颜色、字体等,切换主题时动态修改这些变量的值。
- 使用class切换:在HTML根元素上添加不同的class名称,每个名称对应不同的主题样式,切换主题时更改class名称。
- 使用JavaScript切换:动态修改页面的样式,如背景颜色、字体颜色等。
- 使用CSS预处理器:如Less/Sass,通过预处理器提供的变量、函数等功能实现主题切换。
九、如何实现网页加载进度条?
- 在HTML中添加一个用于显示进度条的元素,比如一个div,通过CSS设置该元素的样式,包括宽度、高度、背景色等,以使其看起来像一个进度条。
- 使用JavaScript监听页面的加载事件,比如load事件,当页面开始加载时,可以设置一个标志,表示进度条开始工作。
- 在页面加载过程中,可以通过JavaScript动态地更新进度条的宽度或样式,以反映加载的进度,可以通过window.performance对象计算已经加载的资源与总资源之间的比例来实现。
- 当页面完全加载时,通过监听load事件的完成,将进度条填充到100%或隐藏进度条。确保在页面完全可用时,用户不再看到进度条。
- 可以添加一些动画效果,使进度条看起来更加平滑和吸引人。确保进度条的更新不会阻塞页面的主要加载过程
十、常见图片懒加载方式有哪些?
- 使用HTML的loading属性:通过设置
标签的loading="lazy"属性,浏览器会自动延迟加载屏幕外的图片,直到用户滚动到它们附近。这种方式简单且无需额外的JavaScript代码,但需注意浏览器兼容性。
- Intersection Observer API:这是一种现代且高效的懒加载技术,可以异步监听元素与视口的交集变化,从而决定是否加载图片。相比监听滚动事件,它不需要频繁计算和比较位置,性能更优。
- 监听滚动事件:通过JavaScript监听滚动事件,计算图片元素与视口的位置关系,从而决定是否加载图片。这种方式较为传统,但性能上可能不如Intersection Observer API,且需要处理滚动事件的频繁触发问题。
- 使用第三方库:如lozad.js、layzr.js等,这些库封装了懒加载的逻辑,提供了简单易用的API,只需按照文档引入和配置即可实现懒加载。
十、Cookie的构成主要包括以下几个部分?
- 名称(Name):用于标识Cookie的唯一字符串。
- 值(Value):与名称相关联的数据,可以是字符串、数字或布尔值。
- 域(Domain):可以访问该Cookie的域名,包括完整域名或子域名。
- 路径(Path):可以访问该Cookie的URL路径,包括完整路径或目录路径。
- 过期时间(Expires/Max-Age):Cookie的有效期,可以是具体的日期和时间或相对的时间间隔。
- 安全标志(Secure):指示浏览器只在通过加密协议(如HTTPS)发送请求时才发送该Cookie。
- HttpOnly标志:指示浏览器只在通过HTTP请求时发送该Cookie,增加安全性。
十一、扫码登录的实现方式?
- 前端请求网页后,服务端开启session,生成随机字符串,并将字符串和sessionid存入redis,服务端返回包含字符串的认证二维码链接给前端,前端展示二维码。
- 用户使用手机扫描二维码,手机端向服务器发送确认登录的请求。
- 前端页面通过轮询方式不断向服务器发送请求,查询扫码结果,一旦服务器返回扫码成功的响应,前端页面进行相应跳转,保存对应token信息。
- 服务器在收到手机端的确认登录请求后,通知网页客户端完成用户的登录过程。
十二、DNS协议了解多少?
- 定义与作用:DNS(Domain Name System)是域名系统的缩写,用于将人类可读的URL转换为机器可理解的IP地址,实现域名和IP地址的相互映射。
- 报文类型:DNS定义了两种报文,一种为查询报文,另一种是对查询报文的响应,称为响应报文。
- 协议特点:DNS协议采用分层架构设计,具有高效、简单、可用的特点。它使用UDP作为传输层协议,知名端口为53。
- 域名空间结构:DNS的域名空间结构呈现为树形结构,包括根服务器、顶级域名等,体现了分布式管理的优点。
十三、函数式编程了解多少?
前端函数式编程主要有以下几种应用场景和体现方式:
- ES6函数应用:利用ES6中的map、filter、reduce等函数进行数据处理,体现了函数式编程的思想。
- React与Vue中的函数式编程:React的函数式组件和hooks,以及Vue3中的组合式API,都是函数式编程在前端框架中的应用。
- JS库中的函数式编程:如RxJS、Lodash和Ramda等JavaScript库,提供了丰富的函数式编程工具和方法。
- 中间件/插件中的函数式编程:如Redux中的applyMiddleware中间件实现,也是函数式编程的一种应用。
十四、前端水印了解多少?
前端水印主要用于防止信息泄露或知识产权被侵犯,一般通过以下方式实现:
- 明水印:通过绝对定位将水印覆盖到页面之上,使用pointer-events: none属性使水印不阻挡页面操作。水印可以是纯HTML元素(如div),也可以是背景图(通过canvas/svg生成)。
- 背景图水印:使用canvas或svg生成水印图片,然后设置为页面或元素的背景图,通过background-repeat: repeat实现平铺效果。
十五、一直在window上面挂东西是否有什么危险?
- 命名冲突:window对象是浏览器的全局对象,包含许多内置属性和方法。在全局命名空间中定义的变量或函数可能与现有的全局对象属性或方法发生冲突,导致意外行为或错误。
- 安全漏洞:在全局window对象上挂载的代码可以访问和修改全局的数据和功能,可能导致安全漏洞,特别是当这些操作被恶意利用时。
- 代码维护性:过多地依赖全局window对象可能导致代码的维护困难,全局状态的过度共享可能导致代码变得难以理解和调试。
十五、深度seo优化方式有哪些,spa应用从技术层面上说?
- 服务端渲染(SSR):通过在服务器端生成初始的HTML内容,使搜索引擎爬虫更好地理解和抓取页面的关键信息,改善SPA页面在搜索引擎中的可见性。
- 预渲染:提前生成一些关键页面的静态HTML文件,这些预渲染的页面可以被搜索引擎爬虫抓取和索引。
- 动态注入关键信息:在前端代码中动态注入页面标题、描述、关键词等,提高页面在搜索引擎中的可识别性。
- 优化页面结构和内容:确保页面有清晰的层次结构、合理的标题和段落划分,以及有价值的内容呈现,这也是提高SEO效果的重要因素。
十六、小程序为什么会有两个线程?
小程序的双线程设计主要出于性能与安全考虑。具体来说:
- 性能优化:
- 小程序通过双线程架构,将逻辑处理和界面渲染分离,确保在处理用户交互和界面渲染时能够保持流畅性,从而提升用户体验。
- 渲染线程专注于页面渲染,不受逻辑线程影响,提高了渲染效率。
- 安全保障:
- 小程序需要独立于微信客户端迭代,不能依赖微信版本更新,双线程模型有助于实现这一需求。
- 与Web网站相比,小程序更注重安全和性能,双线程模型有助于保障小程序不会对微信App产生安全隐患。
十七、web应用中如何对静态资源加载失败的场景做降级处理?
- 使用多个CDN链接:在HTML中配置多个静态资源链接,浏览器会按照优先级顺序尝试加载,若某个链接失败,则自动尝试下一个链接。
- 使用备用资源路径:在JavaScript中监听资源加载的onerror事件,当主路径加载失败时,切换到备用路径,确保资源可靠加载。
- 动态加载和错误处理:通过JavaScript动态加载静态资源,并在加载失败时执行相应的错误处理逻辑,如切换到备用资源或显示错误提示。
十八、html中前缀data-开头的元素属性是什么?
HTML中前缀data-开头的元素属性是自定义数据属性。
- 作用:用于存储页面或应用程序的私有自定义数据,可以在HTML标记中添加额外的信息,而不会影响到页面的布局。
- 命名规则:属性名不应该包含任何大写字母,并且在前缀“data-”之后必须有至少一个字符。
- 属性值:可以是任意字符串。
- 访问方式:可以通过JavaScript访问和操作,使用dataset可以获取到data-开头的所有属性。
十九、移动端如何实现上拉加载,下拉刷新?
- 使用第三方库:
- 可以利用一些流行的移动端UI库(如iScroll、BetterScroll、Ant Design Mobile等),这些库提供了易于使用的API和配置选项,可以轻松集成上拉加载和下拉刷新功能。
- 自定义实现:
- 上拉加载:监听滚动事件,判断当前滚动位置是否已经到达页面底部,从而触发上拉加载的操作。
- 下拉刷新:监听原生触摸事件(如touchstart、touchmove、touchend等),当用户下拉页面时,触发刷新操作。
二十、如何判断dom元素是否在可视区域?
- 使用Element.getBoundingClientRect()方法:这个方法返回元素的大小及其相对于视口的位置。如果返回的对象的top和bottom属性都在0到视口高度之间,或者left和right属性都在0到视口宽度之间,那么该元素就在可视区域内。
- 使用Intersection Observer API:这是一个浏览器提供的API,用于异步观察目标元素与其祖先元素或顶级文档视窗的交叉状态。通过注册一个观察者对象,可以在元素进入或离开可视区域时得到通知。
- 计算滚动位置:可以通过window.scrollX和window.scrollY获取当前的滚动位置,然后结合元素的offsetTop、offsetLeft、offsetHeight和offsetWidth属性来判断元素是否在可视区域内。
- 使用jQuery等库:如果使用jQuery等库,可以利用它们提供的方法来判断元素是否在可视区域内,如$(element).is(':visible')。
二十一、前端如何使用canvas来做电影院选票功能?
<canvas id="cinemaCanvas" width="800" height="600"></canvas>
const canvas = document.getElementById('cinemaCanvas');
const ctx = canvas.getContext('2d');
// 绘制座位图
const rowCount = 10;
const columnCount = 15;
const seatWidth = 40;
const seatHeight = 40;
for (let i = 0; i < rowCount; i++) {
for (let j = 0; j < columnCount; j++) {
ctx.fillStyle = '#ff0000'; // 红色表示座位未选
ctx.fillRect(j * seatWidth, i * seatHeight, seatWidth, seatHeight);
}
}
//监听座位点击事件
canvas.addEventListener('click', function(event) {
const x = event.offsetX;
const y = event.offsetY;
const row = Math.floor(y / seatHeight);
const column = Math.floor(x / seatWidth);
const seatIndex = row * columnCount + column;
// 切换座位状态
// 假设有一个数组seats来存储座位状态
seats[seatIndex] = !seats[seatIndex];
drawSeat(row, column, seats[seatIndex]);
});
function drawSeat(row, column, isSelected) {
ctx.fillStyle = isSelected ? '#00ff00' : '#ff0000'; // 绿色表示座位已选
ctx.fillRect(column * seatWidth, row * seatHeight, seatWidth, seatHeight);
}
二十二、如何通过设置失效时间清除本地储存的数据?
本地存储(如localStorage)本身不提供直接设置失效时间的功能。但是,你可以通过一些简单的策略来模拟这个功能。示例:
// 存储数据时添加失效时间
function setItemWithExpiry(key, value, ttl) {
const now = new Date();
// `ttl` 应该以毫秒为单位
const item = {
value: value,
expiry: now.getTime() + ttl,
};
localStorage.setItem(key, JSON.stringify(item));
}
// 获取数据时检查失效时间
function getItemWithExpiry(key) {
const itemStr = localStorage.getItem(key);
// 如果找不到该项,则返回null
if (!itemStr) return null;
const item = JSON.parse(itemStr);
const now = new Date();
// 比较当前时间和项的失效时间
if (now.getTime() > item.expiry) {
// 如果已过期,删除该项并返回null
localStorage.removeItem(key);
return null;
}
return item.value;
}
// 使用示例
// 设置一个10分钟后过期的项
setItemWithExpiry('key', 'value', 10 * 60 * 1000); // ttl为10分钟
// 获取该项
const value = getItemWithExpiry('key');
console.log(value);
// 如果立即获取,将打印'value'。如果等待超过10分钟再获取,将打印null。
二十三、如果不使用脚手架,如何使用webpack构建一个自己的vue应用?
不使用脚手架,使用webpack构建一个自己的vue应用,可以按照以下步骤进行:
- 初始化项目:创建一个新文件夹,并通过npm init -y初始化项目。安装webpack及相关依赖,包括webpack, webpack-cli, vue-loader, vue-template-compiler等。
- 配置webpack:创建webpack.config.js文件,配置入口文件、输出文件、loader和插件等。设置入口文件为main.js,输出文件为bundle.js。配置loader以处理Vue文件、CSS文件等。
- 创建Vue应用:创建main.js作为Vue应用的入口文件。创建Vue组件,并在main.js中引入和使用这些组件。
- 打包和运行:使用webpack命令进行打包。通过webpack-dev-server或其他方式运行和测试Vue应用。
二十四、用node.js实现一个命令行工具,统计输入目录下面指定代码的行数
要使用Node.js实现一个命令行工具来统计输入目录下指定代码的行数,可以使用Node.js的文件系统模块(fs)和路径模块(path)来遍历目录和读取文件,以下是简单示例:
// 初始化项目:
mkdir code-line-counter
cd code-line-counter
npm init -y
// 创建脚本,在项目根目录下创建一个名为countLines.js的文件
const fs = require('fs');
const path = require('path');
function countLinesOfCode(dir, ext) {
let totalLines = 0;
const files = fs.readdirSync(dir, { withFileTypes: true });
files.forEach(file => {
if (file.isDirectory()) {
totalLines += countLinesOfCode(path.join(dir, file.name), ext);
} else if (file.name.endsWith(ext)) {
const filePath = path.join(dir, file.name);
const content = fs.readFileSync(filePath, 'utf8');
totalLines += content.split(/\r\n|\n/).length;
}
});
return totalLines;
}
const [,, ...args] = process.argv;
if (args.length < 2) {
console.log('Usage: node countLines.js <directory> <extension>');
process.exit(1);
}
const [directory, extension] = args;
const lines = countLinesOfCode(directory, extension);
console.log(`Total lines of code in ${directory} with extension ${extension}: ${lines}`);
// 运行脚本, 示例
node countLines.js ./my-project .js
二十五、package.json里面sideEffects属性的作用是什么?
sideEffects属性用于标记模块是否有副作用。这是webpack4新增的特性,它帮助tree-shaking优化构建过程。当sideEffects设为false时,未使用的模块及其中的副作用(如额外的全局定义)也会被移除。然而,实际项目中需谨慎处理,确保不会误删必要的副作用,如样式文件。通过设置sideEffects数组,可以指定保留某些有副作用的文件或模式。sideEffects属性对webpack构建过程有很大影响,对npm模块尤为重要。使用中需要特别注意声明的正确性,以确保不会误删必要的代码或导致运行时错误
二十六、h5双指缩放的原理是什么?
H5双指缩放的原理主要依赖于处理触摸事件,特别是touchmove事件,来检测用户手指在屏幕上的移动和距离变化。当用户用两个手指在屏幕上进行捏合或展开操作时,可以通过计算这两个触摸点之间的距离变化来判断用户是在进行放大还是缩小操作,并据此调整页面元素的大小。代码示例:
<div id="zoom-container">
<div id="zoom-content">
缩放我!
</div>
</div>
let container = document.getElementById('zoom-container');
let content = document.getElementById('zoom-content');
let scale = 1;
let lastDistance = 0;
function calculateDistance(touches) {
let x0 = touches.pageX;
let y0 = touches.pageY;
let x1 = touches.pageX;
let y1 = touches.pageY;
let dx = x0 - x1;
let dy = y0 - y1;
return Math.sqrt(dx * dx + dy * dy);
}
container.addEventListener('touchmove', function(event) {
if (event.touches.length === 2) {
let currentDistance = calculateDistance(event.touches);
if (lastDistance === 0) {
lastDistance = currentDistance;
} else {
let scaleDiff = currentDistance / lastDistance;
scale *= scaleDiff;
scale = Math.max(1, Math.min(scale, 10)); // 限制缩放范围
content.style.transform = `scale(${scale})`;
lastDistance = currentDistance;
}
}
}, { passive: false });
二十七、断网了应该怎么处理,请求和页面如何做离线化处理?
Web前端断网处理及请求、页面离线化处理主要包括检测网络状态、缓存设置、以及离线包方案。
- 网络状态检测:可通过HTML5的navigator.onLine属性或Vue中的网络状态监听来实现,以便在网络断开时及时响应用户操作,如跳转到断网提示页面。
- 缓存设置:前端页面的静态资源(如图片、JS、CSS等)应设置缓存,以提高页面响应速度。同时,前端接口的缓存也需考虑,确保在网络请求失败时,仍能从缓存中获取数据并正常展示页面。
- 离线包方案:将HTML/JS/CSS等静态资源打包到一个压缩包内,用户访问前预先下载并解压。访问时,WebView容器会拦截请求,若资源已在离线包内,则直接使用本地资源响应,实现秒开和断网浏览。
二十八、script标签上有哪些属性,分别作用是啥?
- async:可选。表示立即下载脚本,但不妨碍页面中的其他操作。只对外部脚本文件有效,用于异步加载脚本并执行。不保证脚本按指定顺序执行。
- charset:可选。表示通过src属性指定的代码的字符集。大多数浏览器会忽略此值。
- defer:可选。表示脚本可以延迟到文档全部被解析和显示之后再执行。只对外部脚本文件有效,用于延迟脚本执行,直到整个页面解析完毕。
- anguage:已废弃。原用于表示代码编写的脚本语言,大多数浏览器会忽略此属性。
- src:可选。表示包含要执行代码的外部文件。
- type:可选。表示编写代码使用的脚本语言的内容类型(MIME类型)。
二十九、为什么SPA应用都会提供一个hash路由,好处是什么?
- 无页面刷新:hash路由可以实现页面的无刷新更新,从而提供更流畅的用户体验。
- 浏览器历史兼容:浏览器原生支持hash变化监听,当hash改变时,可以触发hashchange事件,使SPA能够在不刷新页面的情况下响应URL的变化。
- 易于实现:相比于HTML5的History API,hash路由更容易实现,因为它不需要服务器端的特殊配置来处理404错误页面并重定向回入口HTML文件。
- SEO友好:尽管服务器不解析hash部分的URL,但SPA可以通过一些策略(如服务端渲染或预渲染)来生成SEO友好的页面。
三十、单点登录是什么,具体流程是什么?
单点登录是一种用户身份验证和授权的技术,允许用户在多个应用或网站间使用同一账号和密码登录,无需重复输入或注册,旨在提高用户体验,降低维护成本,并增强安全性。
- 用户访问受限资源:用户尝试访问系统1的受保护资源,系统1发现用户未登录,跳转至SSO认证中心,并传递自己的地址作为参数。
- 用户登录:用户在SSO认证中心输入用户名和密码进行登录。
- 创建会话与令牌:SSO认证中心验证用户信息,创建全局会话和授权令牌,然后带着令牌跳转回最初的请求地址(系统1)。
- 令牌验证与局部会话创建:系统1使用令牌在SSO认证中心进行验证,验证通过后,创建与用户的局部会话,并返回受保护资源。用户访问其他系统时,流程类似。