1. 一直在 window 上面挂东西是否有什么风险?
-
风险:
- 全局污染:可能与其他库或代码的全局变量冲突。
- 内存泄漏:未正确清理的全局变量会导致内存无法回收。
- 安全性:暴露敏感数据或方法给外部。
-
解决方案:
- 使用模块化(如 ES6 Modules)或闭包隔离作用域。
- 通过命名空间(如
window.myApp = {})组织变量。
2. 深度 SEO 优化的方式有哪些(技术层面)?
-
技术优化:
- 服务端渲染 (SSR) :提升首屏加载速度和爬虫可读性。
- 预渲染 (Prerendering) :生成静态 HTML。
- 结构化数据:使用 JSON-LD 或 Microdata。
- 合理使用
<meta>标签:如description、canonical。 - 优化加载速度:压缩资源、CDN 加速、懒加载。
- 语义化 HTML:合理使用
<header>、<article>等标签。
3. 小程序为什么会有两个线程?
-
双线程模型:
- 视图层 (WebView) :负责 UI 渲染。
- 逻辑层 (JSCore) :处理业务逻辑和数据。
-
优势:
- 提升性能(逻辑与渲染分离)。
- 防止恶意脚本操作 DOM,增强安全性。
4. Web 应用中如何对静态资源加载失败的场景做降级处理?
-
方案:
-
备用资源:使用
onerror回退到备用 URL。<img src="image.jpg" onerror="this.src='fallback.jpg'">运行 HTML
-
CDN 回源:自动切换至源服务器。
-
资源预加载:提前加载关键资源。
-
错误监控:上报失败资源路径。
-
5. HTML 中前缀为 data- 开头的元素属性是什么?
-
作用:自定义数据属性,用于存储私有数据。
-
访问方式:
// HTML: <div data-id="123"></div> const element = document.querySelector('div'); console.log(element.dataset.id); // "123"
6. 移动端如何实现上拉加载,下拉刷新?
-
实现方案:
- 原生方案:监听
touchstart、touchend事件,计算滑动距离。 - 第三方库:如
better-scroll、mescroll.js。 - CSS 动画:结合
transform实现过渡效果。
- 原生方案:监听
7. 如何判断 DOM 元素是否在可视区域?
-
方法 1:Intersection Observer API(推荐):
const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { console.log('元素可见'); } }); }); observer.observe(element); -
方法 2:计算位置:
const rect = element.getBoundingClientRect(); const isVisible = rect.top < window.innerHeight && rect.bottom > 0;
8. 前端如何用 Canvas 做电影院选票功能?
-
步骤:
- 绘制座位图:用 Canvas 绘制网格表示座位。
- 点击事件监听:通过坐标计算选中座位。
- 状态管理:记录已选座位(如红色表示已选)。
javascript
复制
canvas.addEventListener('click', (e) => { const rect = canvas.getBoundingClientRect(); const x = e.clientX - rect.left; const y = e.clientY - rect.top; // 判断点击位置是否在座位区域内 });
9. 如何通过设置失效时间清除本地存储的数据?
-
方案:存储时记录时间戳,读取时检查过期。
// 存储数据 const data = { value: 'data', expires: Date.now() + 3600 * 1000 }; localStorage.setItem('key', JSON.stringify(data)); // 读取数据 const storedData = JSON.parse(localStorage.getItem('key')); if (storedData.expires < Date.now()) { localStorage.removeItem('key'); }
10. 不用脚手架,如何用 Webpack 构建一个 React 应用?
-
步骤:
- 初始化项目:
npm init -y npm install react react-dom webpack webpack-cli babel-loader @babel/core @babel/preset-react @babel/preset-env --save-dev- 配置
webpack.config.js:
module.exports = { entry: './src/index.js', module: { rules: [ { test: /.js$/, use: 'babel-loader', exclude: /node_modules/ } ] } };- 配置 Babel (
.babelrc) :
{ "presets": ["@babel/preset-env", "@babel/preset-react"] }
11. package.json 里面 sideEffects 属性的作用是啥?
-
作用:标记模块是否有副作用(如修改全局变量),供 Webpack 进行 Tree Shaking。
-
示例:
{ "sideEffects": false // 表示无副作用,可安全删除未使用的代码 }
12. script 标签上有哪些属性,作用是什么?
-
常用属性:
src:指定外部脚本 URL。async:异步加载脚本(不阻塞渲染,执行顺序不确定)。defer:延迟执行脚本(文档解析完成后按顺序执行)。type="module":支持 ES6 模块化。
13. 为什么 SPA 应用都会提供一个 hash 路由,好处是什么?
-
原因:
- 兼容性:Hash 变化不会触发页面重载(兼容旧浏览器)。
- 避免服务器配置:Hash 路由不依赖服务器端配置(如 Nginx 的
try_files)。 - 前端控制:完全由 JavaScript 管理路由逻辑。
14. [React] 如何进行路由变化监听?
-
方案:使用
history的listen方法或 React Router 的useLocation。import { useEffect } from 'react'; import { useLocation } from 'react-router-dom'; function App() { const location = useLocation(); useEffect(() => { console.log('路由变化:', location.pathname); }, [location]); }
15. 单点登录(SSO)是什么,具体流程是什么?
-
定义:用户只需登录一次,即可访问多个系统。
-
流程:
- 用户访问系统 A,未登录则跳转至 SSO 认证中心。
- 用户在认证中心登录,获取 Token。
- 系统 A 携带 Token 向认证中心验证,通过后允许访问。
- 用户访问系统 B,认证中心验证已有 Token,直接授权。
16. Web 网页如何禁止别人移除水印?
-
方案:
- CSS 覆盖:使用
position: fixed覆盖全屏。 - Canvas 绘制:将水印直接绘制到 Canvas 上。
- MutationObserver:监听 DOM 变化,防止水印被删除。
const observer = new MutationObserver(() => { if (!document.getElementById('watermark')) { addWatermark(); // 重新添加水印 } }); observer.observe(document.body, { childList: true }); - CSS 覆盖:使用
17. 用户访问页面白屏了,原因是啥,如何排查?
-
常见原因:
- JS 报错:检查浏览器控制台。
- 资源加载失败:检查 Network 面板。
- 路由配置错误:SPA 需配置服务器 Fallback。
- 兼容性问题:如 ES6 语法未转译。
-
排查步骤:
- 打开浏览器开发者工具,查看 Console 和 Network。
- 检查 HTML 是否正常返回。
- 逐步注释代码定位问题模块。
18. [代码实现] JS 中如何实现大对象深度对比?
-
递归比较:
function deepEqual(a, b) { if (a === b) return true; if (typeof a !== 'object' || typeof b !== 'object') return false; const keysA = Object.keys(a), keysB = Object.keys(b); if (keysA.length !== keysB.length) return false; return keysA.every(key => deepEqual(a[key], b[key])); } -
注意:需处理循环引用(可通过
WeakMap缓存已比较对象)。