ITPub博客

首页 > IT职业 > IT职场 > 记录一次糟糕的面试

记录一次糟糕的面试

原创 IT职场 作者:fadein52123 时间:2026-01-02 21:29:38 0 删除 编辑

先介绍下本人情况,base 西安,20 年民本金融学毕业,在教培晃荡两年被优化,遂在某培训班转型前端开发,包了两年经验,后面入职了一家初创自研,成功混了两年后项目停住被优化,从去年 11 月到现在躺了一年多,期间入职一家小公司天天加班到 11 点,一周后老板跑路,目前正在仲裁,最近在重拾面试题,前几天面试了软通推的一个项目,回答的非常糟糕,期间自己都没绷住,把回忆起的面试题分享给大家,希望能帮助到和我一样在求职的小伙伴;下面是我回忆的面试题,后面我会给出答案。

/…

flex 布局怎么实现左边固定,右边自适应?

react 中常见的 hook

webpack 中 loader 和 plugin 的区别

写一个深拷贝

写一个数组去重

后台项目中怎么做权限

im 通讯中怎么做心跳检测

defer 和 async 的区别

什么是 treeshake

js 事件循环机制

ts 中的 interface 和 type 的区别和使用场景

什么是宏任务?什么是微任务?

讲讲 promise?

怎么让元素页面居中

…/

1. flex 布局怎么实现左边固定,右边自适应?

Flex 布局实现该效果核心是利用 flex 属性的分配规则,有两种常用方案:

方案 1:基础版(推荐)

/* 容器 */
.container {
  display: flex;
  width: 100%;
  height: 500px;
}
/* 左侧固定 */
.left {
  width: 200px; /* 固定宽度 */
  flex: none; /* 禁止伸缩 */
  background: #eee;
}
/* 右侧自适应 */
.right {
  flex: 1; /* 占据剩余所有空间 */
  background: #ddd;
}

方案 2:进阶版(兼容特殊场景)

.container {
  display: flex;
  width: 100%;
}
.left {
  flex-basis: 200px; /* 固定基准宽度 */
  flex-shrink: 0; /* 禁止缩小 */
}
.right {
  flex-grow: 1; /* 允许放大占满剩余空间 */
  flex-shrink: 1; /* 允许缩小(适配容器不足场景) */
}

核心原理: flex:1 等价于 flex-grow:1; flex-shrink:1; flex-basis:0%,表示右侧元素可伸缩并占据剩余空间;左侧通过固定宽度 + 禁止伸缩保证尺寸不变。

2. React 中常见的 Hook

React Hook 是 React 16.8 新增特性,用于在函数组件中使用状态和生命周期等特性,核心常用 Hook 如下:

| Hook 名称             | 核心作用                                               | 使用场景                                       |

| ----------------------- | -------------------------------------------------------- | ------------------------------------------------ |

| useState        | 声明状态变量,返回[状态, 修改状态的方法]               | 管理组件内部简单状态(如输入框值、开关状态)   |

| useEffect       | 处理副作用(DOM 操作、请求、订阅),替代类组件生命周期 | 数据请求、监听窗口大小、清理定时器             |

| useRef          | 创建可变的引用对象,值更新不触发组件重渲染             | 获取 DOM 元素、保存定时器 ID、跨渲染周期保存值 |

| useContext      | 接收上下文对象,跨组件共享数据(无需 props 逐层传递)  | 全局状态(如主题、用户信息)共享               |

| useReducer      | 替代 useState,处理复杂状态逻辑(类似 Redux)          | 状态逻辑复杂、多个子值的状态管理               |

| useMemo         | 缓存计算结果,避免重复计算                             | 复杂数据处理、避免子组件不必要重渲染           |

| useCallback     | 缓存函数引用,避免函数重复创建                         | 传递给子组件的回调函数(配合 memo 使用)       |

| useLayoutEffect | 同步执行副作用,在 DOM 更新后、浏览器绘制前触发        | 需要同步修改 DOM 的场景(如获取 DOM 尺寸)     |

3. Webpack 中 loader 和 plugin 的区别

Loader 和 Plugin 是 Webpack 核心扩展机制,但定位和作用完全不同:

| 维度                                                                                 | Loader                                                                         | Plugin                                                                                               |

| -------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ |

| 核心作用                                                                   | 转换模块代码(处理非 JS 文件)                                                 | 扩展 Webpack 生命周期功能(打包优化、资源管理)                                                      |

| 处理对象                                                                   | 单个文件(模块),专注“文件转换”                                             | 整个打包流程,专注“流程控制”                                                                       |

| 执行时机                                                                   | 模块解析阶段(module 阶段)                                                    | 打包的各个生命周期钩子(compiler/hook)                                                              |

| 使用方式                                                                   | 配置在 module.rules 数组中                                                 | 配置在 plugins 数组中(需实例化)                                                                |

| 示例                                                                       | css-loader(解析 CSS)、babel-loader(转译 ES6+)、file-loader(处理静态资源) | HtmlWebpackPlugin(生成 HTML)、MiniCssExtractPlugin(提取 CSS)、CleanWebpackPlugin(清理输出目录) |

| 开发方式                                                                   | 导出函数,接收源码返回处理后代码                                               | 基于 Tapable 钩子,通过 compiler 对象注册事件                                                        |

| 核心总结:Loader 解决“文件怎么转”,Plugin 解决“打包流程怎么扩展”。 |                                                                                |                                                                                                      |

4. 写一个深拷贝

完整版深拷贝(支持常见类型 + 循环引用)

function deepClone(target, map = new WeakMap()) {
  // 1. 处理基本类型和null
  if (target === null || typeof target !== 'object') {
    return target;
  }
  // 2. 处理循环引用
  if (map.has(target)) {
    return map.get(target);
  }
  // 3. 处理日期/正则
  if (target instanceof Date) {
    const newDate = new Date(target);
    map.set(target, newDate);
    return newDate;
  }
  if (target instanceof RegExp) {
    const newReg = new RegExp(target.source, target.flags);
    map.set(target, newReg);
    return newReg;
  }
  // 4. 处理数组/对象
  const cloneTarget = Array.isArray(target) ? [] : {};
  map.set(target, cloneTarget); // 缓存当前对象,解决循环引用
  // 5. 递归拷贝属性
  Reflect.ownKeys(target).forEach(key => {
    cloneTarget[key] = deepClone(target[key], map);
  });
  return cloneTarget;
}
// 测试示例
const obj = { a: 1, b: [1, 2], c: { d: 3 } };
obj.self = obj; // 循环引用
const newObj = deepClone(obj);
console.log(newObj); // 完整拷贝,无循环引用问题

核心特性:支持基本类型、数组、对象、日期、正则,解决循环引用问题,兼容 Symbol 键名。

5. 写一个数组去重

方案 1:ES6 简洁版(推荐,性能优)

function uniqueArr(arr) {
  // 利用Set的唯一性,支持基本类型去重
  return Array.isArray(arr) ? [...new Set(arr)] : [];
}

方案 2:兼容版(支持复杂场景,可自定义去重规则)

function uniqueArr(arr) {
  if (!Array.isArray(arr)) return [];
  const result = [];
  const map = new Map();
  arr.forEach(item => {
    // 处理引用类型:JSON.stringify转换(或自定义唯一标识)
    const key = typeof item === 'object' ? JSON.stringify(item) : item;
    if (!map.has(key)) {
      map.set(key, true);
      result.push(item);
    }
  });
  return result;
}
// 测试
console.log(uniqueArr([1, 2, 2, 3, '3', { a: 1 }, { a: 1 }]));
// 输出:[1, 2, 3, '3', { a: 1 }]

适用场景:方案 1 适合基本类型数组;方案 2 适合包含引用类型的数组。

6. 后台项目中怎么做权限

后台系统权限控制需覆盖 路由、菜单、按钮、接口四层,核心方案如下:

1. 权限设计思路

采用“RBAC(基于角色的访问控制)”模型:用户 → 角色 → 权限(菜单/按钮/接口)。

2. 具体实现步骤

(1)登录鉴权

  • 登录后获取用户信息 + 权限列表(如 permissions: ['user:list', 'user:add']),存储在 localStorage/ Vuex/ Redux 中。
  • 路由守卫(如 Vue 的 router.beforeEach)校验登录状态,未登录跳转登录页。

(2)路由权限

  • 静态路由:通用路由(登录页、404)直接注册。
  • 动态路由:根据权限列表过滤路由表,通过 router.addRoute 动态添加可访问路由。
// Vue示例:动态注册路由
const asyncRoutes = [/* 所有需要权限的路由 */];
// 过滤有权限的路由
const accessibleRoutes = asyncRoutes.filter(route => {
  return store.getters.permissions.includes(route.meta.permission);
});
// 动态添加
accessibleRoutes.forEach(route => router.addRoute(route));

(3)菜单权限

  • 菜单渲染时根据权限列表过滤,无权限的菜单不渲染。
<!-- Vue示例 -->
<template>
  <el-menu>
    <el-menu-item
      v-for="menu in menuList"
      :key="menu.id"
      v-if="hasPermission(menu.permission)"
    >
      {{ menu.name }}
    </el-menu-item>
  </el-menu>
</template>
<script>
export default {
  methods: {
    hasPermission(permission) {
      return this.$store.getters.permissions.includes(permission);
    }
  }
}
</script>

(4)按钮权限

  • 封装权限指令,无权限的按钮隐藏/禁用。
// Vue自定义指令示例
Vue.directive('permission', {
  inserted(el, binding) {
    const { value } = binding;
    const permissions = store.getters.permissions;
    if (value && !permissions.includes(value)) {
      el.parentNode.removeChild(el); // 移除按钮
    }
  }
});
// 使用:<button v-permission="'user:delete'">删除</button>

(5)接口权限

  • 请求拦截器携带 Token,后端校验 Token 及权限,无权限返回 403,前端跳转无权限页。

7. IM 通讯中怎么做心跳检测

心跳检测用于维持 IM 长连接、检测连接状态,核心是“定时双向通信”,实现方案如下:

1. 核心原理

客户端定时发送“心跳包” → 服务端接收后立即回复“心跳响应” → 客户端超时未收到响应则判定连接断开,触发重连。

2. 具体实现(WebSocket 示例)

class IMHeartbeat {
  constructor(wsUrl) {
    this.ws = null;
    this.wsUrl = wsUrl;
    this.heartbeatInterval = 30000; // 30秒发一次心跳
    this.heartbeatTimer = null; // 心跳定时器
    this.reconnectTimer = null; // 重连定时器
    this.reconnectMaxTimes = 5; // 最大重连次数
    this.reconnectCount = 0; // 已重连次数
  }
  // 初始化连接
  init() {
    this.ws = new WebSocket(this.wsUrl);
    this.bindEvent();
  }
  // 绑定事件
  bindEvent() {
    // 连接成功
    this.ws.onopen = () => {
      console.log('连接成功');
      this.startHeartbeat(); // 启动心跳
      this.reconnectCount = 0; // 重置重连次数
    };
    // 接收消息
    this.ws.onmessage = (e) => {
      const data = JSON.parse(e.data);
      // 收到心跳响应,重置定时器
      if (data.type === 'heartbeat') {
        this.resetHeartbeat();
      }
    };
    // 连接关闭
    this.ws.onclose = () => {
      console.log('连接关闭,开始重连');
      this.stopHeartbeat();
      this.reconnect();
    };
    // 连接错误
    this.ws.onerror = (err) => {
      console.error('连接错误', err);
      this.ws.close();
    };
  }
  // 启动心跳
  startHeartbeat() {
    this.heartbeatTimer = setInterval(() => {
      if (this.ws.readyState === WebSocket.OPEN) {
        // 发送心跳包
        this.ws.send(JSON.stringify({ type: 'heartbeat', time: Date.now() }));
      }
    }, this.heartbeatInterval);
  }
  // 重置心跳定时器(收到响应后)
  resetHeartbeat() {
    clearInterval(this.heartbeatTimer);
    this.startHeartbeat();
  }
  // 停止心跳
  stopHeartbeat() {
    clearInterval(this.heartbeatTimer);
    this.heartbeatTimer = null;
  }
  // 重连逻辑
  reconnect() {
    if (this.reconnectCount >= this.reconnectMaxTimes) {
      console.log('重连次数耗尽,停止重连');
      return;
    }
    this.reconnectTimer = setTimeout(() => {
      this.reconnectCount++;
      console.log(`第${this.reconnectCount}次重连`);
      this.init();
    }, 5000); // 5秒重连一次
  }
}
// 使用
const im = new IMHeartbeat('ws://localhost:8080/im');
im.init();

3. 服务端配合

  • 服务端接收心跳包后,立即返回 { type: 'heartbeat', code: 200 }。
  • 服务端也可主动检测:超时未收到客户端心跳则主动断开连接,避免无效连接占用资源。

4. 优化点

  • 心跳间隔根据网络环境动态调整(弱网增大间隔)。
  • 重连采用指数退避策略(第一次 5 秒,第二次 10 秒,第三次 20 秒)。
  • 断线时缓存未发送的消息,重连后补发。

8. defer 和 async 的区别

defer 和 async 是 <script> 标签的属性,用于异步加载 JS 文件,核心区别如下:

| 维度               | defer                                                | async                                  |

| -------------------- | ------------------------------------------------------ | ---------------------------------------- |

| 执行时机 | 文档解析完成后、 DOMContentLoaded 事件触发前执行 | 脚本下载完成后立即执行(暂停文档解析) |

| 执行顺序 | 按脚本在页面中的顺序执行                             | 谁先下载完谁先执行(无序)             |

| 适用场景 | 依赖 DOM、需按顺序执行的脚本(如 jQuery 插件)       | 独立无依赖的脚本(如统计、广告脚本)   |

| 加载特性 | 异步加载,不阻塞文档解析                             | 异步加载,不阻塞文档解析               |

可视化流程

// 正常脚本(阻塞)
解析HTML → 下载脚本 → 执行脚本 → 继续解析HTML
// defer
解析HTML → 异步下载脚本 → 解析完成 → 按顺序执行脚本 → DOMContentLoaded
// async
解析HTML → 异步下载脚本 → 下载完成 → 暂停解析 → 执行脚本 → 继续解析HTML

代码示例

<!-- defer:按顺序执行,DOM解析完执行 -->
<script src="a.js" defer></script>
<script src="b.js" defer></script> <!-- 一定在a.js之后执行 -->
<!-- async:无序执行,下载完立即执行 -->
<script src="a.js" async></script>
<script src="b.js" async></script> <!-- 可能先于a.js执行 -->

9. 什么是 Tree Shaking

Tree Shaking(摇树优化)是 Webpack/Rollup 等打包工具的优化技术,核心是 剔除代码中未被使用的死代码(dead code),减少打包体积。

1. 核心原理

  • 基于 ES6 模块的 静态分析特性(import/export 是静态的,编译时确定依赖关系)。
  • 打包时遍历所有模块依赖,标记未被引用的代码,最终从打包产物中删除。

2. 启用条件

  • 模块系统:必须使用 ES6 模块( import/export),CommonJS( require)不支持(动态加载,无法静态分析)。
  • 模式:Webpack 需设置 mode: 'production'(默认开启 Tree Shaking)。
  • 配置: package.json 中声明 sideEffects(标记无副作用的文件,可安全删除)。
// package.json
{
  "sideEffects": [
    "*.css", // CSS文件有副作用(样式生效),不删除
    "*.less"
  ]
}

3. 示例

// utils.js(源码)
export const add = (a, b) => a + b;
export const minus = (a, b) => a - b;
// index.js(业务代码)
import { add } from './utils.js'; // 仅引用add
console.log(add(1, 2));
// 打包后(Tree Shaking后)
// 仅保留add函数,minus被剔除
const add = (a, b) => a + b;
console.log(add(1, 2));

4. 注意事项

  • 副作用代码(如修改全局变量、DOM 操作)需标记 sideEffects,否则会被误删。
  • 仅对顶层导出有效,嵌套对象的未使用属性无法剔除。

10. JS 事件循环机制

JS 事件循环(Event Loop)是 JS 处理异步任务的核心机制,用于解决单线程下的异步执行问题,核心规则如下:

1. 核心概念

  • 执行栈:同步任务按顺序进入执行栈执行。
  • 任务队列:异步任务完成后,回调函数进入任务队列(分宏任务队列、微任务队列)。
  • 事件循环:执行栈为空时,先清空所有微任务队列,再从宏任务队列取一个任务执行,重复此过程。

2. 任务分类

| 任务类型            | 包含内容                                                                  | 执行优先级                 |

| --------------------- | --------------------------------------------------------------------------- | ---------------------------- |

| 宏任务(Macrotask) | script 整体代码、setTimeout、setInterval、I/O、UI 渲染、WebSocket         | 低(微任务执行完才执行)   |

| 微任务(Microtask) | Promise.then/catch/finally、async/await、queueMicrotask、MutationObserver | 高(宏任务执行完立即执行) |

3. 执行流程(可视化)

1. 执行同步代码(属于宏任务)→ 执行栈清空
2. 执行所有微任务 → 微任务队列清空
3. 执行一次UI渲染(可选)
4. 从宏任务队列取第一个任务执行 → 回到步骤1

4. 示例(理解执行顺序)

console.log('同步1'); // 同步代码,立即执行
setTimeout(() => { // 宏任务
  console.log('setTimeout');
}, 0);
Promise.resolve().then(() => { // 微任务
  console.log('Promise.then');
});
console.log('同步2'); // 同步代码,立即执行
// 执行结果:同步1 → 同步2 → Promise.then → setTimeout

11. TS 中的 interface 和 type 的区别和使用场景

interface(接口)和 type(类型别名)是 TS 中定义类型的核心方式,核心区别及场景如下:

1. 核心区别

| 特性               | interface                       | type                                               |

| -------------------- | --------------------------------- | ---------------------------------------------------- |

| 定义方式 | 只能定义对象/类的形状           | 可定义任意类型(基本类型、联合类型、交叉类型等)   |

| 扩展方式 | 用 extends 扩展,支持多继承 | 用交叉类型 & 扩展                              |

| 合并特性 | 支持重复声明自动合并            | 不支持重复声明(重复定义会报错)                   |

| 实现方式 | 类可通过 implements 实现    | 类只能实现对象类型的 type(基本类型/联合类型不行) |

| 索引签名 | 支持更灵活的索引签名            | 支持但语法稍繁琐                                   |

2. 代码示例

(1)interface 示例

// 定义对象类型
interface User {
  name: string;
  age: number;
}
// 扩展(继承)
interface Admin extends User {
  role: string;
}
// 重复声明自动合并
interface User {
  gender: string;
}
// 最终User:{ name: string; age: number; gender: string }
// 类实现
class Person implements User {
  name = '张三';
  age = 20;
  gender = '男';
}

(2)type 示例

// 定义基本类型
type Str = string;
// 定义联合类型
type Status = 'success' | 'error' | 'loading';
// 定义对象类型
type User = {
  name: string;
  age: number;
};
// 扩展(交叉类型)
type Admin = User & { role: string };
// 重复声明报错
// type User = { gender: string }; // 错误:标识符“User”重复

3. 使用场景

  • 优先用 interface:定义对象/类的形状、需要类型合并、需要被类实现的场景(如组件 Props、接口返回值)。
  • 优先用 type:定义基本类型、联合类型、交叉类型、元组,或需要给类型起别名的场景(如状态枚举、工具类型)。

12. 什么是宏任务?什么是微任务?

宏任务和微任务是 JS 异步任务的两大分类,是事件循环的核心,具体定义如下:

1. 宏任务(Macrotask)

  • 定义:执行时间较长、优先级较低的异步任务,会完整占用一次事件循环的执行周期。
  • 包含类型:
  • script 整体代码(最顶层的宏任务)
  • setTimeout/setInterval
  • setImmediate(Node.js 特有)
  • I/O 操作(文件读取、网络请求)
  • UI 渲染(浏览器特有)
  • WebSocket 回调

2. 微任务(Microtask)

  • 定义:执行时间短、优先级高的异步任务,宏任务执行完后会立即执行所有微任务,不会阻塞 UI 渲染。
  • 包含类型:
  • Promise.then/catch/finally
  • async/await(本质是 Promise 语法糖)
  • queueMicrotask(手动创建微任务)
  • MutationObserver(浏览器特有)
  • process.nextTick(Node.js 特有,优先级最高)

3. 核心区别

  • 执行优先级:微任务 > 宏任务(同一次事件循环中)。
  • 执行时机:微任务在当前宏任务执行完后立即执行;宏任务需等待下一轮事件循环。
  • 阻塞性:微任务执行完才会触发 UI 渲染,大量微任务会阻塞渲染;宏任务执行间隔可能触发渲染。

13. 讲讲 Promise?

Promise 是 JS 解决异步回调地狱的核心方案,用于表示异步操作的最终完成(或失败)及其结果值。

1. 核心特性

  • 状态不可逆:Promise 有三种状态,状态一旦改变无法回退:
  • pending(进行中)→ fulfilled(已成功)/ rejected(已失败)。
  • 链式调用:通过 then()/ catch()/ finally() 实现异步操作串行执行,避免回调嵌套。
  • 错误冒泡:链式调用中任意环节出错,可通过末尾的 catch() 统一捕获。

2. 基本使用

// 创建Promise
const promise = new Promise((resolve, reject) => {
  // 异步操作(如请求)
  setTimeout(() => {
    const res = { code: 200, data: '成功' };
    if (res.code === 200) {
      resolve(res.data); // 成功,触发then
    } else {
      reject('失败'); // 失败,触发catch
    }
  }, 1000);
});
// 调用
promise
  .then(res => {
    console.log('成功:', res);
    return res + '处理后'; // 传递给下一个then
  })
  .then(res => console.log('链式调用:', res))
  .catch(err => console.error('错误:', err))
  .finally(() => console.log('无论成功失败都执行'));

3. 常用静态方法

| 方法                       | 作用                                                          | 场景                                       |

| ---------------------------- | --------------------------------------------------------------- | -------------------------------------------- |

| Promise.resolve()    | 返回一个已成功的 Promise                                      | 快速创建成功的 Promise                     |

| Promise.reject()     | 返回一个已失败的 Promise                                      | 快速创建失败的 Promise                     |

| Promise.all()        | 接收 Promise 数组,全部成功才返回,一个失败则立即失败         | 并行执行多个异步任务(如同时请求多个接口) |

| Promise.race()       | 接收 Promise 数组,第一个完成的 Promise 决定结果              | 超时控制(如请求 5 秒未响应则超时)        |

| Promise.allSettled() | 接收 Promise 数组,等待所有任务完成(无论成败),返回所有结果 | 需知道所有异步任务的执行结果(如批量上传) |

| Promise.any()        | 接收 Promise 数组,第一个成功的 Promise 决定结果              | 多个备选接口,取第一个成功的               |

4. 解决的问题

  • 回调地狱:将嵌套的回调转换为链式调用,代码更清晰。
  • 异步操作统一管理:标准化异步操作的成功/失败处理。

14. 怎么让元素页面居中

元素居中是前端高频需求,分 水平居中、 垂直居中、 水平垂直居中,以下是常用方案:

1. 水平居中

| 元素类型              | 实现方案                                                      | 代码示例                                                  |

| ----------------------- | --------------------------------------------------------------- | ----------------------------------------------------------- |

| 行内元素(文字/span) | 父元素设置 text-align: center                            | .parent { text-align: center; }                     |

| 块级元素(固定宽度)  | 元素设置 margin: 0 auto                                  | .child { width: 200px; margin: 0 auto; }            |

| 块级元素(不定宽度)  | Flex 布局:父元素 display: flex; justify-content: center | .parent { display: flex; justify-content: center; } |

2. 垂直居中

| 实现方案          | 代码示例                                                                                                    | 适用场景           |

| ------------------- | ------------------------------------------------------------------------------------------------------------- | -------------------- |

| Flex 布局(推荐) | .parent { display: flex; align-items: center; }                                                       | 任意元素,兼容性好 |

| 定位 + transform  | .parent { position: relative; } .child { position: absolute; top: 50%; transform: translateY(-50%); } | 不定高度元素       |

| 行高(单行文字)  | .parent { line-height: 50px; height: 50px; }                                                          | 单行文字垂直居中   |

3. 水平垂直居中(常用方案)

方案 1:Flex 布局(推荐,简洁)

.parent {
  display: flex;
  justify-content: center; /* 水平居中 */
  align-items: center; /* 垂直居中 */
  width: 100vw;
  height: 100vh;
}
.child {
  width: 200px;
  height: 200px;
  background: #eee;
}

方案 2:定位 + transform(兼容旧浏览器)

.parent {
  position: relative;
  width: 100vw;
  height: 100vh;
}
.child {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%); /* 回移自身50% */
  width: 200px;
  height: 200px;
}

方案 3:Grid 布局(现代浏览器)

.parent {
  display: grid;
  place-items: center; /* 水平+垂直居中 */
  width: 100vw;
  height: 100vh;
}

总结

核心关键点回顾

  1. Flex 实现左固定右自适应:左侧固定宽度 + flex: none,右侧 flex: 1 占满剩余空间。
  2. React Hook 核心: useState(状态)、 useEffect(副作用)、 useRef(引用)、 useContext(上下文)是高频考点。
  3. Webpack:Loader 处理文件转换,Plugin 扩展打包流程。
  4. 深拷贝需处理:基本类型、引用类型、循环引用、特殊对象(日期/正则)。
  5. 事件循环核心:同步代码 → 微任务 → 宏任务,微任务优先级高于宏任务。
  6. TS 类型定义:interface 适合对象/类,type 适合基本类型/联合类型。
  7. 元素居中:Flex 布局是最简洁通用的方案,定位 +transform 兼容性更好。

来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/70049190/viewspace-3106893/ ,如需转载,请注明出处,否则将追究法律责任。

上一篇: 没有了~
请登录后发表评论 登录
全部评论

注册时间:2026-01-02

  • 博文量
    3
  • 访问量
    2967