基础 | HTML语义、CSS3新特性、浏览器存储、this、防抖节流、重绘回流、date排序、calc
1. HTML 语义化标签的作用
graph TD
A[语义化标签] --> B[SEO]
A --> C[可访问性]
A --> D[代码可读性]
A --> E[自动化工具]
⚡这一步暗藏BUG?——用 <div class="header">
也能做头部,但屏幕阅读器会迷路!
Q1: 为什么 <article>
比 <div>
更适合博客正文?
A1: <article>
自带独立内容含义,RSS/爬虫可直接识别,SEO 权重↑。
Q2: 🤯你以为懂了?那 <section>
和 <article>
能互相嵌套吗?
A2: 可以,但语义要自洽:<section>
表章节,<article>
表完整故事,别套娃到逻辑混乱。
2. 举例 CSS3 新特性
- 布局:Flexbox、Grid
- 视觉:border-radius、box-shadow、linear-gradient
- 动画:transition、@keyframes、transform: translateZ(0) 硬件加速
- 响应式:@media、clamp()
Q3: Grid 和 Flexbox 何时一起用?
A3: 外层 Grid 做二维骨架,内层 Flexbox 做一维对齐,电商商品列表常用。
3. 浏览器存储方案对比
特性 | cookie | localStorage | sessionStorage |
---|---|---|---|
大小 | ~4KB | ~5MB | ~5MB |
生命周期 | 可设过期 | 永久 | 标签页关闭 |
随请求携带 | 是 | 否 | 否 |
适用场景 | 登录态 | 主题/缓存 | 表单草稿 |
Q4: 如何防止 localStorage 被 XSS 窃取?
A4: 存敏感信息前做加密(如 AES),并设置 Content-Security-Policy 禁止内联脚本。
4. JS 变量提升
console.log(a); // undefined(声明提升,赋值不提升)
var a = 1;
Q5: let/const
真的不提升吗?
A5: 也提升,但存在「暂时性死区」,在声明前访问直接抛 ReferenceError。
5. this 关键字 & 箭头函数
- 普通函数:运行时绑定,谁调用指向谁
- 箭头函数:词法作用域,定义时捕获外层 this
- call/apply/bind:显式绑定,区别只在传参方式
const obj = { x: 1 };
function show() { console.log(this.x); }
show.call(obj); // 1
show.apply(obj, []); // 1
const bound = show.bind(obj);
bound(); // 1
Q6: 箭头函数能用 call 改 this 吗?
A6: 不能,箭头函数 this 固化,call/apply/bind 无效。
6. typeof vs instanceof
typeof [] // "object"(数组也是对象)
[] instanceof Array // true
Q7: 🤯如何准确判断 NaN?
A7: Number.isNaN(NaN)
,因为 typeof NaN === 'number'
。
7. 防抖 vs 节流
// 防抖:停止触发后 wait 毫秒执行
const debounce = (fn, wait) => {
let timer;
return (...args) => {
clearTimeout(timer);
timer = setTimeout(() => fn.apply(this, args), wait);
};
};
// 节流:每 wait 毫秒最多执行一次
const throttle = (fn, wait) => {
let last = 0;
return (...args) => {
const now = Date.now();
if (now - last > wait) {
last = now;
fn.apply(this, args);
}
};
};
Q8: 搜索框输入用哪个?
A8: 防抖,避免每敲一次就请求。
8. 重绘 vs 回流
- 回流(reflow):几何变化,如宽高、位置
- 重绘(repaint):外观变化,如颜色、阴影
性能优化:读写分离、transform 合成层、避免 table 布局
Q9: 如何强制触发一次回流?
A9: 读取 offsetHeight
、getComputedStyle
等会 flush 队列。
9. 代码题:表格 date 字段正序/倒序
<table id="t">
<thead><tr><th onclick="sortTable()">Date</th></tr></thead>
<tbody>
<tr><td>2023-10-01</td></tr>
<tr><td>2022-05-20</td></tr>
</tbody>
</table>
<script>
let asc = true;
function sortTable() {
const tbody = t.querySelector('tbody');
const rows = [...tbody.rows].sort((a, b) => {
const d1 = new Date(a.cells[0].textContent);
const d2 = new Date(b.cells[0].textContent);
return asc ? d1 - d2 : d2 - d1;
});
asc = !asc;
rows.forEach(r => tbody.appendChild(r)); // 复用节点,减少回流
}
</script>
10. 代码题:calc 最大乘积拆分
function calc(n) {
if (n < 2) return [];
const res = [];
let k = 2;
while (n >= k) {
res.push(k);
n -= k++;
}
// 把余数均匀加到后面几项,避免 1
for (let i = res.length - 1; n > 0; i--) {
res[i]++;
n--;
}
return res;
}
console.log(calc(10)); // [3,3,4] 3*3*4=36 最大
Q10: 边界:n=2 时返回 [2] 还是 [1,1]?
A10: [2],乘积更大且不含 1。