目录
一、HTML
src与href区别
对html语义化理解
语义化标签有哪些?
script中的defer与async区别
行内元素与块级元素有哪些?
canvas与svg区别
SEO优化
html5新特性
二、CSS
盒模型
选择器优先级
伪元素与伪类
隐藏元素几种方式
水平/垂直居中方式
清除浮动
外边距合并与塌陷
对BFC的理解
flex布局与flex属性
grid网格布局
css单位有哪些
link与@import区别
实现三角形
画一条0.5px的线
移动端1px问题
z-index什么情况下失效?
css3新特性
三、JavaScript
数据类型有哪些
Map和weakMap区别
var let const区别
作用域与作用域链,变量提升
说说你对闭包的理解
垃圾回收机制
事件流与事件委托
箭头函数
this指向
自动装箱
浅拷贝与深拷贝
判断数组类型
构造函数,原型对象与实例对象
原型链
讲讲promise
async与await
事件循环
宏任务与微任务
浮点数精度
定时器精度
大文件上传
CommonJS与ESM区别
ES6+新特性
一、HTML
src与href区别
src和href都用于加载外部资源,浏览器解析时,src会下载外部资源并嵌入到当前标签位置,同时会阻塞其他资源的加载和解析;而href则是建立与外部资源的引用关系,也就是链接,同时不会阻塞其他资源的加载和解析。
src:<script>、<img> href:<a>、<link>
对html语义化理解
HTML语义化是指根据内容选择合适的标签,优点是浏览器爬虫能更好的识别内容,网页结构清晰,代码可读性强,有利于团队的开发和维护
语义化标签有哪些?
布局结构:<header>, <footer>, <nav>, <aside>, <article>, <section>
内容分组:<figure>(配图), <figcaption>(图片说明), <time>(时间)
文本标注:<mark>(高亮), <blockquote>(引用), <cite>(引用来源)
script中的defer与async区别
defer和async都表示异步加载外部js脚本,defer会等待页面解析完成后再执行,而async会立即执行;多个defer标签保证按先后顺序加载,而多个async标签不能保证顺序
行内元素与块级元素有哪些?
行内元素(display: inline):
<span>, <a>, <strong>, <em>, <img>, <input>
特点:不独占一行;无法直接设置宽高;边距仅水平有效。
块级元素(display: block):
<div>, <p>, <h1>~<h6>, <ul>,<ol>, <li>, <section>,列表,表格,表单,语义化标签
特点:独占一行;可设置宽高/边距。
canvas与svg区别
Svg和canvas都能用来表示图形,Svg基于XML语法通过数学公式定义图形,而canvas基于像素操作,通过js直接在画布上绘制图形;Svg无限缩放不失真而canvas放大失真;Svg适用于交互复杂或无限缩放不失真;Canvas适用于高频重绘以及像素操作,如高性能游戏和动画
SEO优化
SEO是指通过技术优化和内容策略,提升网站在搜索引擎中的自然排名,从而获取更多流量的过程。
关键HTML优化点:
使用title、meta description等语义化标签;h1到h6层级清晰,h1仅一个;图片加上alt属性,帮助爬虫理解图片
html5新特性
HTML5新增语义化标签,多媒体音视频标签,本地存储local storage和session storage,还有canvas、webSocket、拖拽、表单属性等
二、CSS
盒模型
盒模型由四部分组成,分别为Content内容,padding内边距border边框,margin外边距。盒模型分为标准盒模型和IE盒模型,他们的主要区别在于标准盒模型的width等于内容宽度,而IE盒模型的width等于内容加内边距加边框,box-sizing:content-box是标准盒模型,box-sizing:border-box是IE盒模型。
选择器优先级
选择器优先级从高到低依次为:
- !important(覆盖所有)
- 内联样式(style="...",权重 1000)
- ID 选择器(#id,权重 100)
- 类/伪类/属性选择器(.class, :hover,权重 10)
- 元素/伪元素选择器(div, ::after,权重 1)
- 通配符/关系选择器(*, >, +,权重 0)
伪元素与伪类
伪类用于选择处于特定状态的元素,用单引号,常见的伪类包括:
:hover,:first-child,:last-child,:nth-child(n),:focus。
伪元素用于创建虚拟元素,用双引号,常见的伪元素包括:
::before,::after,::first-letter,::first-line。
隐藏元素几种方式
- display: none 不占位
- visibility: hidden 占位
- opacity: 0 占位,可交互
- position: absolute + left: -9999px 移出屏幕
- z-index: -999 利用其它元素遮盖
- clip-path 裁剪
- transform: scale(0) 将元素缩放至0
水平/垂直居中方式
水平居中:
行内元素:text-align: center
块级元素:margin: 0 auto(需定宽)
垂直居中:
单行文本:line-height: 容器高度
水平垂直居中:
Flex:align-items: center; justify-content: center
Grid:place-items: center; / align-items: center; justify-items: center
绝对定位 + transform
绝对定位 + 负边距
清除浮动
原因:浮动元素脱离文档流,导致父容器高度塌陷无法被撑开。
方法:
空元素法:<div style="clear:both"></div>
伪元素法(推荐):
.clearfix::after {content: '';display: block;clear: both;
}
父元素 BFC
外边距合并与塌陷
合并:相邻块级元素的垂直外边距会合并,取其中的较大值
塌陷:父元素与子元素的垂直外边距接触,比如子元素添加上外边距会导致父元素一起下移
解决方法:
父元素添加内边距或边框
父元素触发BFC
对BFC的理解
BFC块级格式化上下文,是一个独立的渲染区域,内部元素的布局不影响外部元素。
触发条件:
float: left | right
overflow: hidden | scroll | auto; (不是visible)
display: flow-root | inline-block | flex | grid 等( 非none 非inline 非block)
position: absolute | fixed ;( 非relative)
flex布局与flex属性
flex弹性布局能够根据不同的屏幕尺寸的变化来始应大小,实现响应式布局
容器属性:
flex-direction(主轴方向)
justify-content(主轴对齐)
align-items(交叉轴对齐)
align-content(多行对齐)
flex-wrap(换行)
flex: <grow> <shrink> <basis> 【放大比例、缩小比例、初始基本尺寸】
默认值:flex: 0 1 auto
flex: 1 = flex-grow: 1 = flex: 1 1 auto(扩展并填充剩余空间)
flex: 0 0 100px(固定宽高,不缩放)
grid网格布局
display: grid; 二维布局
grid-template-columns/rows:定义网格轨道
弹性单位:fr 表示剩余空间的分配比例
函数:repeat(3, 1fr) 表示重复3列,每列宽度相等
grid-gap:行列间距
grid-template-areas:通过命名区域定义布局
grid-area:项目占位区域
css单位有哪些
px 像素
% 相对于父元素的百分比
相对单位em和rem,em相对于父元素字体大小,而rem是相对于根元素的字体大小
与视口相关的单位vw和vh,vw相对于视口的宽度,vh相对于视口的高度
vmin和vmax,分别表示vw和vh中的较小值和较大值
link与@import区别
link不仅可以加载CSS文件,还可以定义RSS等属性;link是并行加载不会阻塞,而import会阻塞后续资源加载;import有兼容性问题而link没有
实现三角形
.box1 {width: 0;height: 0;border: 10px solid transparent;border-bottom: 10px solid #666;
}
画一条0.5px的线
transform: scaleY(0.5)
使用 meta viewport 设为0.5,只针对移动端
移动端1px问题
1px边框在高分辨率屏幕上会显得较粗
设备像素比 = 物理像素 / 逻辑像素
在retina屏的手机上若dpr为2,css里写的1px宽度映射到物理像素上则为2px
解决方案:
使用媒体查询,直接写为0.5px
使用伪元素::after + transform进行缩放
其他方案:使用图片,使用viewport和rem,使用渐变linear-gradient或box-shadow
z-index什么情况下失效?
元素没有设置position属性
元素设置了浮动float
父元素z-index小于子元素z-index
父元素设置了position: relative
解决方法:
设置position属性(除了static)
清除浮动
提高父元素z-index
父元素的position改为绝对定位absolute
css3新特性
布局:Flexbox、Grid。
动画:transition、@keyframes 动画。
变换:transform(旋转、缩放)。
视觉:圆角(border-radius)、阴影(box-shadow)、渐变(linear-gradient)。
响应式:媒体查询(@media)。
字体:@font-face 自定义字体。
新单位:vw、vh、rem。
三、JavaScript
数据类型有哪些
基本类型(7种):
string、number、boolean、null、undefined、symbol、bigint
特点:值直接存储在栈中
引用类型:
object(包括 Array、Function、Date 等)
特点:值存储在堆内存中,栈中存内存地址
Map和weakMap区别
Map和weakMap都是ES6引入的键值对集合,Map的键可以是任意类型,而weakMap的键必须是对象;weakMap对键是弱引用,如果键对象没有其他引用,键值对会被垃圾回收器回收;Map支持遍历而weakMap不可遍历也没有size属性
var let const区别
var和let const的主要区别为var是函数作用域,而let和const是块级作用域;var存在变量提升可以先使用后声明,而let和const存在暂时性死区必须先声明后使用;var可以重复声明,而let和const不能;
let和const的区别为const不能重新赋值,但对象中的值可以修改,因为栈中存储的是地址,值存储在堆中。
暂时性死区是指使用let或const声明变量时,从代码块开始到声明语句执行前的这个区域,在这个区域内访问对象会报错
作用域与作用域链
作用域分为全局作用域、函数作用域和块级作用域。
作用域链:当访问变量时,js会从当前作用域开始查找,逐层向外形成链式查找,直到找到变量或抛出错误
说说你对闭包的理解
闭包是函数与其词法作用域的组合。简单来说,闭包等于内层函数加外层函数的变量。
函数在定义时会关联一个词法环境,记录其作用域链。由于内层函数使用了外层函数的变量,所以即使外层函数执行完毕,其作用域链仍被内层函数引用,无法被垃圾回收。
因此,闭包如果处理不当,可能会造成内存泄露。同时,闭包可以封装私有变量以及保存上下文状态。
垃圾回收机制
可以自动回收不再使用的内存
标记清除法:标记阶段从根对象出发递归遍历并标记所有可到达对象,清除阶段回收未标记的对象
引用计数法:记录每个对象的引用次数,引用次数为零时回收
V8引擎分代回收优化策略:把内存分为新生代和老生代,新生代将内存分为空闲区和使用区,清除时将存活对象复制到空闲区,然后清空使用区;老生代则使用标记清除和标记整理法
事件流与事件委托
事件流描述了事件从触发到处理的完整过程,分为三个阶段:
捕获阶段:事件从根元素window逐渐向下传递到目标元素的父级元素,依次触发各层级的捕获事件,默认不会触发,需要将addEventListener的第三个参数设为true设为捕获监听。
目标阶段:到达目标元素,触发目标事件。
冒泡阶段:从目标元素逐层向上传递,直到根元素window,依次触发各层级的冒泡事件,默认就是冒泡阶段触发监听器。
冒泡模式下会先执行子元素事件,再执行父元素事件,捕获模式相反。
可以使用stopPropagation阻止冒泡。
事件委托:利用事件冒泡机制将子元素事件监听绑定到父元素身上。
通过这种方式,使得父元素能够统一处理子元素事件,适用于动态生成元素以及大量处理同类元素的场景。
事件从子元素冒泡到父元素时,通过event.target获取触发事件的子元素,event.currentTarget是指父元素本身。
箭头函数
箭头函数与普通函数的区别:箭头函数使用起来更简洁,箭头函数自身无this指向的是外层作用域的this;箭头函数没有arguments对象,且不能作为构造函数,没有prototype属性
this指向
this指向由调用方式决定:
new调用:指向新对象
call/apply/bind:指向绑定的对象
对象方法调用:指向调用对象
普通函数/定时器调用:非严格模式指向 window,严格模式为 undefined
箭头函数:指向外层作用域的 this
自动装箱
当我们尝试访问原始值的属性或方法时,js会创建一个临时的包装对象,从而允许我们访问对应的属性或方法,在执行完毕后会立即销毁该对象
本地存储、cookie、Token
本地存储:存储在浏览器本地。LocalStorage永久存储,sessionStorage会话级存储。
Cookie是服务器发送给客户端的一小段数据,存储在浏览器中,每次请求自动携带,不能跨域。
Token是服务器生成的加密字符串,可存储在缓存中,也可以存储在数据库中,可以跨域,安全性更高。
浅拷贝与深拷贝
浅拷贝:复制对象的第一层属性,适用于简单数据结构。
数组浅拷贝:slice()、concat()、扩展运算符。
对象浅拷贝:Object.assign()、扩展运算符。
深拷贝:复制原对象的所有属性,且彼此之间完全独立。JSON.parse(JSON.stringify()) 缺点是不能处理循环引用以及特殊类型。
手写实现或使用第三方库。
判断数组类型
1. Array.isArray(arr);
2. arr instanceof Array;
3. Object.prototype.toString.call(arr) === '[object Array]';
4. arr.constructor === Array;
5. Object.getPrototypeOf(arr) === Array.prototype;
构造函数,原型对象与实例对象
构造函数是用于创建对象的函数,通过new调用。
原型对象是构造函数的一个属性,用于给所有实例共享属性和方法。
实例对象是通过new创建的对象,继承原型对象的属性和方法。
原型链
当我们访问对象的属性或方法时,js会先查找对象自身的属性,如果没有就去查找其原型对象,如果还没有的话就一直递归向上查找,直到Object.prototype,其原型对象为null,查找结束。
讲讲promise
Promise是js中处理异步操作的标准方案,它解决了回调地域问题,使代码逻辑更清晰。
Promise对象用于管理一个异步操作的最终状态和结果,一共有三种状态:pending等待,fulfilled成功,rejected失败,并且一旦状态确定,就无法再改变。
使用new Promise来创建Promise实例并处理异步操作,使用resolve()和reject()来改变promise的状态,使用.then和.catch来获取结果,可以链式调用。
回调地狱:当异步操作需要按顺序处理,并且前一个异步操作的结果是后一个异步操作的输入时,代码会变成嵌套的回调函数,呈金字塔形。这会导致代码难以维护,且难以处理错误。
可以使用promise解决回调地狱,使用then方法将异步操作的结果按顺序执行,前一个then中返回一个promise对象传递给下一个then,可以用一个统一的catch来捕获错误。
还可以使用async和await来出解决回调地狱。
Promise.all 全部成功则成功,任一失败则立即失败。
Promise.race 取第一个完成的结果(无论成功或失败)。
Promise.allSettled 等待所有任务完成,返回每个任务的结果状态。
Promise.any 取第一个成功的任务,全部失败则聚合错误。
async与await
async和await是处理异步任务的语法糖,基于promise实现,旨在让异步操作的代码写法更接近于同步逻辑。
语法:函数前面加async,函数内部promise操作前加await。
函数始终返回一个 Promise 对象,若函数返回非 Promise 值,会自动包装为 Promise.resolve(value)。
函数内部统一使用try catch来捕获错误。
当执行到await语句时,会暂停当前函数的执行,等待异步操作执行完成,但不会阻塞函数外的代码执行。
事件循环
Js是单线程语言,但通过事件循环实现了非阻塞异步执行。
事件循环:
执行调用栈中的所有同步代码,遇见宏任务放进宏任务队列,遇见微任务放进微任务队列。
执行所有微任务队列中的微任务。
从宏任务队列中取出一个宏任务来执行。
然后执行所有的微任务,然后执行一个宏任务......依次循环
宏任务与微任务
微任务:
Promise.then catch finally
MutationObserver
process.nextTick
宏任务:
I/O操作、UI渲染
setTimeout/setInterval
严格来讲requestAnimationFrame既不是宏任务也不是微任务,它在渲染之前被调用
微任务优先级高于宏任务,因为微任务一般用于紧急更新,要确保在渲染前完成更新。
执行所有同步任务。
执行所有微任务。
执行 requestAnimationFrame 回调。
浏览器进行重绘。
执行所有宏任务。
浮点数精度
在js中,所有数字都基于IEEE754标准,以64位浮点数形式存储。
由于浮点数无法精确表示某些十进制数,例如0.1和0.2在二进制中是无限循环,因此相加后会产生误差。
解决方法:
将浮点数转为整数运算
使用toFixed
使用第三方库
定时器精度
由js是单线程,定时器必须等待当前同步代码执行完毕后才执行,而且定时器是宏任务,优先级低于微任务和渲染任务。
解决方法:
使用performance.now()
使用setTimeout + 时间偏移校正
使用requestAnimationFrame
使用Web Worker
大文件上传
分片上传:将文件切分为多个小块(如 2MB/片),并行上传
断点续传:服务器记录已上传分片,客户端上传前先校验
Web Worker:在后台线程处理文件分片计算,避免阻塞主线程
CommonJS与ESM区别
CommonJS(Node.js):
同步加载,语法:require() / module.exports,运行时加载
ESM(浏览器/Node.js):
可以异步加载,语法:import / export,编译时解析
ES6+新特性
let/const、箭头函数、解构赋值、扩展运算符、参数默认值、剩余参数
Promise、async/await、Map/Set、class、Proxy、Reflect、Symbol
可选链(?.)、空值合并(??)