1.盒模型
Q说一下对盒模型的理解
Q对IE盒模型的了解
两者的区别:
①对宽度、高度的计算
标准盒模型只包含content
IE盒模型包含content+padding+border三部分
②默认触发
标准:现代浏览器默认 需正确声明DOCTYPE
IE:IE6以下默认
Q对比一下这两个盒模型的应用场景:
标准:
需要精准控制内容区尺寸的场景
文本/媒体内容容器,需保证内容区尺寸固定不受外边框影响
需要动态调整内边距/边框的元素(如hover效果),但希望内容区尺寸保持稳定
第三方组件/插件集成
IE:
需要精准控制元素总尺寸的场景
网格/栅格布局
表单元素
固定尺寸容器
Q或者说我会选择哪一个 Q为什么不选择IE盒模型
IE盒模型符合直觉的尺寸控制应用更广泛
Q标准盒模型的优势在哪
对内容区尺寸的绝对掌控
2.元素水平垂直居中的实现
<div class="container">
<div class="content">垂直居中的内容</div>
</div>
①flexbox
.container {
display: flex;
justify-content: center; /* 水平居中 */
align-items: center; /* 垂直居中 */
height: 100vh; /* 容器高度 */
}
②grid
.container {
display: grid;
place-items: center; /* 垂直居中 */
height: 100vh; /* 容器高度 */
}
③绝对定位和transform 适用于单行内容
.container {
position: relative;
height: 100vh; /* 容器高度 */
}
.content {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%); /* 同时实现水平和垂直居中 */
}
④absolute+负margin
绝对定位的百分比是相对于父元素的宽高
但是是基于子元素的左上角
想要子元素居中显示需要设置负margin
.wp {
position: relative;
}
.box {
position: absolute;;
top: 50%;
left: 50%;
margin-left: -50px;
margin-top: -50px;
}
⑤css-table
3.vw和rem的区别
都是css布局中的长度单位
vw:视口宽度单位
1vw等于视口宽度的1%
视口指浏览器可见区域的宽度,不包含地址栏、工具栏
适用于页面中需要随窗口宽度等比例缩放的元素
快速实现整体布局的响应式
rem:根元素字体大小单位
1rem等于根元素的font-size值
实际开发中经常结合使用:
vw设置根元素的font-size,让rem简洁依赖视口宽度
4.对闭包的理解
在一个作用域中可以访问另一个函数内部的局部变量的函数
基本使用:
function makeFunc() {
var name = "Mozilla";
function displayName() {
alert(name);
}
return displayName;
}
var myFunc = makeFunc();
myFunc();
在displayName这个作用域下访问了另外一个函数makeFunc下的局部变量name
利用了js中作用域链的概念
在js中,在某作用域下访问某个变量时,如果不存在就一直向外层寻找,直到在全局作用域下找到
特性:
可以访问父级函数的变量
访问到父级函数的变量不会销毁
作用:
延伸了变量的作用范围
隐藏变量,避免全局污染
缺点:
因为垃圾回收机制,会导致出现不必要的性能消耗
不恰当的使用会出现内存泄漏
5.对原型链的理解
Q原型链的应用场景:
①实现对象间的继承
②共享方法和属性
③实现模块化和代码复用
例如将工具方法定义在公共原型上让多个构造函数共享
6.事件循环
Q正在执行微任务的时候又遇到一个微任务怎么处理 放到当前队列还是
会被直接添加到当前微任务队列的末尾 在当前微任务队列的执行周期内被处理
微任务队列的执行遵循 “连续执行到底” 的规则:
当事件循环进入 “处理微任务” 阶段时,会从微任务队列中取出第一个微任务执行
执行过程中产生了新的微任务,加到当前队列的尾部(而不是创建新队列)
继续从队列中取下一个微任务执行,直到整个队列被清空
只有当当前微任务队列完全清空后,事件循环才会进入下一个阶段(处理宏任务或渲染等)
7.var let const之间的区别
①作用域不同
var作用域是函数级 在函数外声明则为全局变量
let const作用域是块级,仅在声明它的代码块内有效(如if for {}等)
②变量提升和重复声明
var存在变量提升,变量声明被提升到作用域的顶部,赋值不会
可能导致未声明先使用时出现undefined
允许重复声明,后声明的会覆盖前一个
let和const不存在变量提升,必须先声明后使用否则报错
不允许重复声明
③可修改性
const声明的是常量,必须在声明时赋值,且赋值后不能重新赋值
Qvar为什么会存在变量提升:
本质上是js引擎编译阶段处理变量声明的机制导致的
js先编译后执行
先对代码进行词法分析语法分析生成执行上下文,此时var声明的变量被提升
执行阶段再逐行执行代码,处理赋值运算等逻辑
Q变量提升的好处/坏处:
好处:简化了早期的开发门槛
函数可以在声明前调用
坏处:变量覆盖和重复声明隐患
作用域混淆
可读性下降
8.tcp三次握手
第一次握手:客户端-->服务器端
将报文标志位SYN置为1,随机产生序列号seq=j
第二次握手:服务器端-->客户端
将报文标志位SYN和ACK都置1 ack=j+1 随机序号seq=k
第三次握手:客户端-->服务器端
报文标志位ACK置1,ack=k+1
Q第三次握手取消会怎么样:
连接无法正常建立
服务器:
在第二次握手后进入SYN_RECV状态,启动重传计时器
未收到ACK
按照预设的重试策略,每隔一段时间重传SYN+ACK报文,直到最大重试次数
仍超时,释放半连接
客户端:主动取消/被动未发送
SYN Flood攻击:大量第三次握手被恶意取消,服务端半连接队列被占满
无法接收新的正常SYN请求
9.浏览器输入url之后的事情
先解析url
url包括协议,主机名(域名/IP地址),端口号,路径,查询参数(key=value),锚点(#)
①DNS解析
域名解析成真实的IP地址
浏览器先检查自身的缓存
检查操作系统缓存
请求本地域名服务器(LDNS)
到Root Server服务器
②三次握手建立TCP连接
③浏览器向服务器发送HTTP请求
④浏览器收到服务器端的响应
⑤进行语法解析,渲染页面
解析HTML生成DOM树
解析CSS生成CSSOM树(样式树)
合并成渲染树
布局计算,绘制页面
浏览器回流和重绘
⑥四次挥手关闭TCP连接
10.强缓存弱缓存
强制缓存:
浏览器在第一次请求资源后,会将资源缓存到本地,记录缓存的有效期
有效期内再次请求该资源时,浏览器直接从本地缓存读取
不发送任何请求到服务器
header参数:
Expires:(已基本被cache-control替代)
过期时间,浏览器在设置的时间内直接读取缓存,不再请求
格式:Expires:<GMT时间>资源过期的具体时间
Cache-Control:(HTTP1.1 优先级更高)
格式:Cache-Control:[指令]
常用指令:
max-age=缓存有效期
public/private 资源可被任何缓存(浏览器、CDN等)存储/只能被浏览器缓存
no-cache:必须进入协商缓存
no-store:完全禁止缓存
协商缓存:
强制缓存过期后,浏览器会携带缓存标识向服务器请求,由服务器判断资源是否更新
未更新:服务器返回304Not Modified,浏览器使用本地缓存
已更新:返回新资源(200OK),并更新缓存标识
header参数:
请求头+响应头。
Last-Modifed/If-Modified-Since和Etag/If-None-Match成对出现的
响应头Last-Modifed:服务器返回资源的最后修改时间
请求头If-Modified-Since:
强制缓存过期后,浏览器将Last-Modifed的值作为该字段发送服务器,询问"资源在该时间后是否被修改"
缺陷:
精度仅到秒
某些操作会改变Last-Modifed,实际上资源未变
响应头ETag:服务器生成的资源唯一标识如哈希值,版本号
资源变化时ETag同步更新
请求头If-None-Match:
浏览器将ETag的值作为该字段发送给服务器
询问"资源标识是否仍为该值"
11.react hooks
对hooks的理解 实现原理 使用的时候需要注意的问题
12.react里状态逻辑复用的方案
状态逻辑复用:
将组件中可复用的状态管理逻辑(如数据请求、表单处理、定时器等)抽离出来,
供多个组件共享,减少代码冗余提高维护性
常见方案:HOC 自定义Hook Render Props
HOC
高阶组件是一个函数,接收一个组件作为参数,返回一个新的增强组件
通过包装组件的方式,注入复用的状态逻辑和props
// 定义高阶组件:处理计数器逻辑
function withCounter(WrappedComponent) {
return class extends React.Component {
state = { count: 0 };
increment = () => this.setState({ count: this.state.count + 1 });
render() {
// 将状态和方法通过 props 传递给被包装组件
return (
<WrappedComponent
count={this.state.count}
increment={this.increment}
{...this.props} // 透传外部 props
/> ); } };
}
// 使用高阶组件
const CounterButton = withCounter(({ count, increment, label }) => (
<button onClick={increment}>
{label}: {count}
</button>
));
// 复用:不同组件共享计数器逻辑
<CounterButton label="点赞数" />
<CounterButton label="收藏数" />
缺点:可能导致包装地狱(多层HOC嵌套)
静态方法需手动赋值,props可能被覆盖
自定义Hook
自定义Hook是一个以use开头的函数,内部可以调用其他Hook
组件通过调用自定义hook直接获取状态和方法
// 定义自定义 Hook:处理计数器逻辑
function useCounter(initialCount = 0) {
const [count, setCount] = React.useState(initialCount);
const increment = () => setCount(prev => prev + 1);
const decrement = () => setCount(prev => prev - 1);
return { count, increment, decrement }; // 返回状态和方法
}
// 组件中使用
function CounterDisplay() {
const { count, increment } = useCounter(); // 直接调用 Hook 获取逻辑
return <button onClick={increment}>计数:{count}</button>;
}
function DoubleCounter() {
const { count, increment } = useCounter(10); // 可传入初始值,灵活复用
return <button onClick={increment}>翻倍计数:{count * 2}</button>;
}
优势:简洁直观,可组合多个hook
缺点:必须遵循hook原则,只能在函数组件或自定义hook中使用,不能在条件语句中使用
Render Props
通过一个返回React元素的prop,将复用的状态逻辑传递给组件
组件通过调用该prop渲染内容,接收逻辑中的状态和方法
// 定义 Render Props 组件:处理鼠标位置逻辑
class MouseTracker extends React.Component {
state = { x: 0, y: 0 };
handleMouseMove = (e) => {
this.setState({ x: e.clientX, y: e.clientY });
};
componentDidMount() {
window.addEventListener('mousemove', this.handleMouseMove);
}
componentWillUnmount() {
window.removeEventListener('mousemove', this.handleMouseMove);
}
render() {
// 调用 render prop,将状态传递给外部
return this.props.render(this.state);
}
}
// 使用 Render Props
function MousePosition() {
return (
<MouseTracker
render={({ x, y }) => ( // 通过 render prop 接收状态
<div>鼠标位置:({x}, {y})</div>
)} /> );
}
// 复用:不同组件共享鼠标位置逻辑
function CatOnMouse() {
return (
<MouseTracker
render={({ x, y }) => (
<img
src="cat.png"
style={{ position: 'absolute', left: x, top: y }}
alt="跟随鼠标的猫"
/> )} /> );
}
13.diff算法
虚拟DOM技术中,通过比较新旧DOM树差异,计算最小更新范围的算法
只对有变化的部分进行操作,而非渲染整个DOM树
框架优化思路:
同层比较,不跨层级对比
节点类型不同则直接替换
同类型节点通过 “key” 标识复用
14.react router
Q实现 React 生态中用于实现单页应用(SPA)路由管理的核心库
在不刷新页面的情况下,根据 URL 变化渲染对应的组件,提供导航、路由参数、嵌套路由等功能
路由模式:基于浏览器API实现URL监听和修改
单页应用的路由本质:改变URL但不刷新页面
hash模式
利用URL中的哈希(#及后面的部分)作为路由标识
改变哈希不会触发页面刷新,且浏览器会记录哈希变化的历史
实现:
通过 window.location.hash 读取当前哈希值
监听 hashchange 事件,哈希变化时触发路由更新
导航时(如点击 Link 组件),通过修改 window.location.hash 改变 URL,避免页面刷新
history模式(browserrouter)
基于 HTML5 的 History API(window.history),通过 pushState、replaceState 等方法修改 URL 路径(不含 #),且不触发页面刷新
实现: 通过 window.history.pushState() 或 replaceState() 改变 URL(只修改历史记录,不发送请求)
监听 popstate 事件(用户点击前进 / 后退按钮触发),感知 URL 变化并更新路由
导航时,通过 history.push() 或 history.replace() 封装 pushState/replaceState,实现无刷新跳转
核心组件:
路由更新机制:
状态变化触发组件重渲染
当URL变化时:
URL改变,感知变化,更新location
重新匹配路由,渲染匹配组件
15.用过webpack吗
16.对babel的了解
17.代码题
手写深拷贝
function deepCopy(obj){
//不是引用类型就不拷贝
if(!(obj instanceof Object)) return obj
//如果形参obj是数组,就创建数组,如果是对象就创建对象
let objCopy = obj instanceof Array ? [] : {}
for(let key in obj){
if(obj instanceof Object){
objCopy[key] = deepCopy(obj[key])
} else{
if(obj.hasOwnProperty(key)){
objCopy[key] = obj[key]
}
}
}
return objCopy
}