当前位置: 首页 > news >正文

面试版-前端开发核心知识

一、DOM操作与事件处理:用户交互的基石

1.1 原生点击事件的三种绑定方式

前端与用户的交互始于事件,而点击事件是最基础的交互方式。原生JavaScript绑定点击事件主要有以下三种方式:

(1)HTML内联绑定(不推荐)

直接在HTML标签中通过onclick属性定义事件逻辑:

<button onclick="handleClick()">点击我</button>
<script>function handleClick() {console.log('内联事件触发');}
</script>

​缺点​​:HTML与JS逻辑耦合,无法动态修改事件,维护成本高。

(2)DOM属性绑定(单事件)

通过JS获取元素后,直接为onclick属性赋值:

const btn = document.getElementById('btn');
btn.onclick = function() {console.log('DOM属性事件触发');
};

​特点​​:只能绑定一个同类型事件(后绑定的会覆盖前一个),适合简单场景。

(3)addEventListener(推荐)

通过addEventListener方法绑定事件,支持多事件监听、事件冒泡/捕获控制:

const btn = document.getElementById('btn');
// 第三个参数:useCapture(布尔值,默认false=冒泡阶段)
btn.addEventListener('click', function(e) {console.log('冒泡阶段触发');
}, false);// 捕获阶段绑定(需设置为true)
document.body.addEventListener('click', function(e) {console.log('捕获阶段触发');
}, true);

​优势​​:

  • 支持同一元素绑定多个同类型事件(按注册顺序执行);
  • 可通过removeEventListener精准解绑;
  • 支持事件流控制(冒泡/捕获)。

1.2 如何获取DOM元素?

要操作DOM元素,首先需要获取其引用。以下是8种常用方法:

方法说明示例
getElementById()根据ID获取单个元素(唯一)document.getElementById('box')
querySelector()CSS选择器获取​​首个匹配​​元素document.querySelector('.btn')
querySelectorAll()CSS选择器获取​​所有匹配​​元素(返回NodeList)document.querySelectorAll('li')
getElementsByClassName()根据类名获取元素集合(HTMLCollection,动态更新)document.getElementsByClassName('item')
getElementsByTagName()根据标签名获取元素集合(HTMLCollection,动态更新)document.getElementsByTagName('div')
getElementsByName()根据name属性获取元素集合(NodeList,静态)document.getElementsByName('user')
document.body直接获取<body>元素const body = document.body
document.documentElement直接获取<html>元素const html = document.documentElement

1.3 事件传播机制:捕获→目标→冒泡

当点击一个元素时,事件会经历三个阶段:

  1. ​捕获阶段​​:事件从window开始,逐层向下传播到目标元素的父节点;
  2. ​目标阶段​​:事件到达目标元素本身;
  3. ​冒泡阶段​​:事件从目标元素开始,逐层向上传播到window

​关键操作​​:

  • 阻止事件冒泡:e.stopPropagation()
  • 阻止默认行为(如链接跳转):e.preventDefault()
  • 停止事件传播(同时阻止冒泡和默认行为):e.stopImmediatePropagation()(仅适用于当前元素的其他监听器)。

​示例:阻止表单提交​

const form = document.querySelector('form');
form.addEventListener('submit', function(e) {e.preventDefault(); // 阻止表单默认提交行为console.log('表单验证通过,异步提交');
});

二、数据存储:从Cookie到现代存储方案

2.1 Cookie的本质与局限

Cookie是服务器通过Set-Cookie响应头写入客户端的​​键值对数据​​,随每次HTTP请求自动携带到服务器。其核心特性如下:

特性说明
存储容量约4KB(不同浏览器略有差异)
生命周期默认会话结束失效(可通过ExpiresMax-Age设置持久化)
作用域Domain(主域+子域)和Path(路径)控制
安全性明文传输(易被篡改),可通过HttpOnly(禁止JS访问)防XSS,Secure(仅HTTPS传输)
同步性每次请求自动携带,可能影响性能

​典型场景​​:用户登录状态(如sessionId)、购物车临时数据。

2.2 现代存储方案对比

随着前端应用复杂度提升,Cookie的局限性逐渐显现,以下是更常用的替代方案:

方案容量生命周期同步/异步典型用途API示例
localStorage5-10MB手动清除(永久有效)同步长期配置(主题、语言)localStorage.setItem('theme', 'dark')
sessionStorage5-10MB标签页关闭时失效同步临时会话数据sessionStorage.removeItem('token')
IndexedDB250MB+永久(需手动清理)异步大量结构化数据(如离线文档)const db = await indexedDB.open('myDB')
Cache API无限制手动控制(Service Worker管理)异步缓存静态资源(PWA)caches.open('v1').then(cache => cache.add('/img/logo.png'))

​选择建议​​:

  • 需长期保留的小量数据 → localStorage
  • 临时会话数据 → sessionStorage
  • 大量结构化数据或离线应用 → IndexedDB
  • 静态资源缓存 → Cache API(配合Service Worker)。

三、ES6+语法与异步编程:现代前端的基石

3.1 ES6核心语法速览

ES6(ECMAScript 2015)是前端语法的重要里程碑,以下是最常用特性:

(1)箭头函数(=>

简化函数写法,绑定词法作用域的this(无独立this):

// 传统函数
const add = function(a, b) { return a + b; };// 箭头函数(单表达式可省略大括号和return)
const add = (a, b) => a + b;// 多表达式需大括号
const double = (num) => {if (num > 0) return num * 2;return num;
};
(2)解构赋值

快速提取对象/数组的值,简化变量声明:

// 对象解构
const user = { name: 'Xback', age: 23 };
const { name, age } = user; // name='Xback', age=23// 数组解构
const [first, second] = [1, 2]; // first=1, second=2// 重命名
const { name: userName } = user; // userName='Xback'
(3)模板字符串(`

支持变量嵌入和多行字符串:

const message = `用户${user.name}(${user.age}岁)登录成功`;
// 输出:"用户Xback(23岁)登录成功"
(4)类(class

面向对象的语法糖,替代原型链:

class Person {constructor(name) {this.name = name;}sayHello() {console.log(`Hello, I'm ${this.name}`);}
}const alice = new Person('Xback');
alice.sayHello(); // "Hello, I'm Xback"

3.2 异步编程:从回调到async/await

前端应用中,网络请求、文件读写等操作均为异步,需避免阻塞主线程。ES6后的异步解决方案演进如下:

(1)回调地狱(Callback Hell)

早期通过回调函数处理异步,但多层嵌套会导致代码可读性差、错误难以捕获:

fetch('/api1').then(res => res.json()).then(data1 => {fetch(`/api2?id=${data1.id}`).then(res => res.json()).then(data2 => {// 更多嵌套...});});
(2)Promise:链式调用

Promise通过then/catch实现线性链式调用,解决回调地狱:

fetch('/api1').then(res => res.json()).then(data1 => fetch(`/api2?id=${data1.id}`)).then(res => res.json()).then(data2 => console.log(data2)).catch(err => console.error('请求失败', err));
(3)async/await:同步写法

基于Promise的语法糖,用async标记函数,await等待Promise解决,代码更接近同步逻辑:

async function fetchAllData() {try {const res1 = await fetch('/api1');const data1 = await res1.json();const res2 = await fetch(`/api2?id=${data1.id}`);const data2 = await res2.json();return [data1, data2];} catch (err) {console.error('请求失败', err);}
}// 调用
fetchAllData().then(([data1, data2]) => {console.log('所有数据加载完成', data1, data2);
});
(4)并发请求:Promise.all

若需同时发起多个请求(如获取用户信息、商品列表),可用Promise.all并行执行,提升效率:

async function fetchConcurrent() {const urls = ['/api/user', '/api/products', '/api/cart'];// 并行发起请求const promises = urls.map(url => fetch(url).then(res => res.json()));// 等待所有请求完成const [user, products, cart] = await Promise.all(promises);return { user, products, cart };
}

3.3 函数进阶:call/apply/bindProxy

(1)call/apply/bind:修改this指向

三者均可显式绑定函数的this,但参数传递和执行时机不同:

方法参数形式执行时机返回值典型场景
call参数列表(逗号分隔)立即执行函数返回值借用其他对象的方法
apply参数数组立即执行函数返回值传递数组参数(如Math.max
bind参数列表(可选)延迟执行绑定后的新函数事件回调固定this

​示例:​

const obj = { x: 10 };
function sum(y) { return this.x + y; }sum.call(obj, 5);    // 15(立即执行,参数列表)
sum.apply(obj, [5]); // 15(立即执行,参数数组)const boundSum = sum.bind(obj, 5);
boundSum();          // 15(延迟执行,参数部分预设)
(2)Proxy:对象代理

Proxy用于创建一个对象的代理,拦截并自定义对象的基本操作(如属性读取、赋值),是实现响应式数据(如Vue 3)、数据校验等功能的利器:

const target = { name: 'Alice', age: 25 };
const handler = {get(obj, prop) {if (prop in obj) {return obj[prop].toUpperCase(); // 读取时转换为大写}return '属性不存在';},set(obj, prop, value) {if (prop === 'age' && typeof value !== 'number') {throw new Error('年龄必须是数字');}obj[prop] = value; // 设置时校验类型return true; // 必须返回true表示设置成功}
};const proxy = new Proxy(target, handler);
console.log(proxy.name); // "ALICE"(触发get)
proxy.age = '26';        // 抛出错误(类型校验失败)

四、性能优化与工程实践

4.1 图片懒加载:提升首屏加载速度

图片懒加载的核心思想是:​​仅当图片进入可视区域时再加载真实资源​​,减少首屏请求量。

实现步骤:
  1. ​占位符替换​​:将<img>src属性替换为data-src(存储真实URL),避免初始加载;
  2. ​视口监听​​:使用Intersection Observer API监听图片是否进入视口;
  3. ​资源加载​​:当图片进入视口时,将data-src赋值给src,触发加载。

​代码示例:​

// 1. 获取所有带data-src的图片
const lazyImages = document.querySelectorAll('img[data-src]');// 2. 创建Intersection Observer实例
const observer = new IntersectionObserver((entries) => {entries.forEach(entry => {if (entry.isIntersecting) { // 图片进入视口const img = entry.target;img.src = img.dataset.src; // 加载真实图片img.removeAttribute('data-src'); // 移除占位符属性observer.unobserve(img); // 停止监听已加载的图片}});
});// 3. 开始监听所有图片
lazyImages.forEach(img => observer.observe(img));

​关键技术点​​:

  • Intersection Observer API:现代浏览器提供的视口监听接口,替代传统的滚动事件+getBoundingClientRect(性能更优);
  • data-*属性:HTML5自定义数据属性,用于存储额外信息。

4.2 内存泄漏:原因与解决方案

内存泄漏指程序中不再使用的内存未被释放,导致内存占用持续增长,最终可能引发页面卡顿或崩溃。常见原因及解决方法:

(1)未移除的事件监听

​原因​​:为元素添加事件监听后,若元素被移除但监听器未解绑,监听器仍会引用元素,导致其无法被垃圾回收。
​解决​​:在元素移除前调用removeEventListener解绑监听器,或使用once: true(仅触发一次后自动移除)。

(2)未释放的闭包

​原因​​:闭包会长期持有外部函数的变量引用,若闭包被全局变量引用,变量无法被回收。
​解决​​:避免不必要的闭包,或在闭包中使用weakMap/weakSet(弱引用,不阻止垃圾回收)。

(3)定时器未清除

​原因​​:setInterval未及时清除,导致回调函数持续引用上下文。
​解决​​:在组件卸载或不需要定时器时调用clearInterval/clearTimeout

(4)DOM引用残留

​原因​​:JS中保留了已移除DOM元素的引用(如cache对象),导致DOM无法被回收。
​解决​​:移除DOM后,同步清除JS中的引用(如delete cache[key])。

​检测工具​​:Chrome DevTools的Memory面板(记录堆快照,对比前后内存变化)。


五、前端工具链与生态

5.1 Git:版本控制的核心技能

Git是前端开发的必备工具,以下是常用命令及场景:

场景命令示例说明
克隆仓库git clone https://github.com/xxx/repo.git从远程仓库复制代码到本地
创建并切换分支git checkout -b feature/new-module新建feature/new-module分支并切换
添加修改git add .添加所有修改到暂存区
提交修改git commit -m "feat: 新增用户模块"提交暂存区的修改到本地仓库
推送分支到远程git push origin feature/new-module将本地分支推送到远程仓库
拉取远程更新git pull origin main拉取远程main分支并合并到本地
查看提交历史git log --oneline简洁查看提交记录
回退到指定版本git reset --hard abc123回退到哈希为abc123的提交(危险操作)

​可视化工具​​:VS Code内置Git面板、SourceTree(适合复杂操作,如合并冲突解决)。

5.2 调试技巧:定位问题的关键

调试是开发者的核心能力,浏览器开发者工具(DevTools)是最常用的工具。

(1)网络面板(Network)

​作用​​:监控所有网络请求,分析请求耗时、状态码、响应内容。

​关键信息​​:

  • ​状态码​​:200(成功)、404(资源不存在)、500(服务器错误);
  • ​请求头(Request Headers)​​:
    • User-Agent:浏览器/设备信息;
    • Cookie:当前请求携带的Cookie;
    • Content-Type:请求体数据类型(如application/json);
  • ​响应头(Response Headers)​​:
    • Cache-Control:缓存策略(如max-age=3600);
    • Set-Cookie:服务器设置的Cookie;
  • ​Timing​​:请求各阶段耗时(DNS查询、TCP连接、TTFB、下载)。
(2)元素面板(Elements)

​作用​​:查看和修改DOM结构、CSS样式,调试布局问题。

​常用功能​​:

  • 选择DOM元素(左上角箭头图标);
  • 实时编辑CSS(Styles面板);
  • 查看盒模型(Computed面板);
  • 断点调试(Event Listeners面板添加事件断点)。

六、框架与生态:从Vue到Uniapp

6.1 Uniapp与Vue的区别

Uniapp是基于Vue的跨端开发框架,目标是“一套代码,多端运行”(小程序、H5、App)。与标准Vue的主要差异:

特性Uniapp标准Vue(Web)
运行环境小程序引擎(如微信JSCore)、H5、App浏览器(JS引擎)
模板语法支持Vue模板,但部分指令受限(如v-html完整Vue模板语法
组件库需使用Uniapp组件(如<uni-list>可使用任意第三方Vue组件库
跨端适配自动处理不同端的API差异(如uni.request需手动适配不同浏览器
构建流程基于vue-cli,但增加多端编译步骤直接打包为浏览器可识别的代码

6.2 Element UI与TypeScript

Element UI是基于Vue的PC端组件库,而TypeScript(TS)是JavaScript的超集,添加了静态类型系统。

​TS的核心优势​​:

  • ​类型检查​​:编译时捕获类型错误(如函数参数类型不匹配);
  • ​代码提示​​:IDE(如VS Code)可自动推断变量类型,提升开发效率;
  • ​重构安全​​:修改变量名或类型时,TS会提示所有受影响的代码位置。

​示例:TS定义组件Props​

import { defineComponent, PropType } from 'vue';export default defineComponent({props: {// 定义用户对象(必传)user: {type: Object as PropType<{ name: string; age: number }>,required: true},// 定义可选数字(默认值10)count: {type: Number,default: 10}},setup(props) {console.log(props.user.name); // 类型推断:string}
});
http://www.dtcms.com/a/266393.html

相关文章:

  • HTML表格导出为Excel文件的实现方案
  • Excel 实现进制转换 Excel十进制转二进制 Excel 中文转unicode Excel实现Unicode转中文
  • 本地部署Dify并结合ollama大语言模型工具搭建自己的AI知识库
  • 面向开发者的API平台设计与选型建议【附源码示例】
  • flutter封装vlcplayer的控制器
  • 如何使用DeepSeek一键生成系统架构图?
  • 如何将大型视频文件从 iPhone 传输到 PC
  • 怎么更改cursor字体大小
  • 10分钟搭建 PHP 开发环境教程
  • VSCode 安装使用教程
  • SQL Server 进阶语法实战:从动态透视到存储过程的深度应用(第四课)
  • 高功率的照明LN2系列助力电子元件薄膜片检测
  • 推荐算法系统系列>推荐数据仓库集市的ETL数据处理
  • GaussDB权限管理:从RBAC到精细化控制的企业级安全实践
  • 设计模式(十)
  • [学习记录]Unity毛发渲染[URP]-Fin基础版
  • Django Channels WebSocket实时通信实战:从聊天功能到消息推送
  • Linux入门篇学习——Linux 帮助手册
  • 八、测试与调试
  • 万勋科技「柔韧机器人玻璃幕墙清洗」全国巡展@上海!引领清洗无人机智能化升级
  • Rovo Dev CLI Windows 安装与使用指南
  • 暑期数据结构第一天
  • CLIP的tokenizer详解
  • 2-jdk8环境下安装Kafka
  • 标签体系设计与管理:从理论基础到智能化实践的综合指南
  • chrome安装AXURE插件后无效
  • uniapp 微信小程序水印
  • c++游戏_小恐龙(开源)
  • Spring Boot + MyBatis/MyBatis Plus:XML中循环处理List参数的终极指南
  • MySQL安装报错解决