面试中被问到过的前端八股(三)

125 阅读6分钟

1、React组件之间常用的通信方式

1. 父子组件通信(最常用!)

👉 方式:props
  • 父组件通过 props 向子组件传递数据、函数。
  • 子组件通过调用 props 中的函数向父组件“通信”。
// 父组件
function Parent() {
  const sayHi = () => alert("Hi from Parent!");
  return <Child name="React" onGreet={sayHi} />;
}

// 子组件
function Child({ name, onGreet }) {
  return (
    <div>
      Hello, {name}
      <button onClick={onGreet}>Greet</button>
    </div>
  );
}

🤝 2. 兄弟组件通信

👉 方式:
  • 提升状态到共同父组件
  • 或者使用全局状态(如 context、Redux)。
function Parent() {
  const [value, setValue] = useState("");

  return (
    <>
      <SiblingA onChange={setValue} />
      <SiblingB value={value} />
    </>
  );
}

function SiblingA({ onChange }) {
  return <input onChange={(e) => onChange(e.target.value)} />;
}
function SiblingB({ value }) {
  return <p>{value}</p>;
}

🏗 3. 祖孙组件通信

👉 方式:
  • React Context 来共享状态或函数。
const ThemeContext = React.createContext();

function App() {
  return (
    <ThemeContext.Provider value="dark">
      <Child />
    </ThemeContext.Provider>
  );
}

function Child() {
  return <GrandChild />;
}

function GrandChild() {
  const theme = useContext(ThemeContext);
  return <div>Current theme: {theme}</div>;
}

🌐 4. 跨组件/全局通信

👉 方式:
  • Redux / Zustand / Recoil 等全局状态管理;
  • React Context(适合轻量需求);
  • EventEmitter(非常规,但有用)。

📢 5. 其他方式(少用)

  • Ref 传递 + 调用子组件方法
    • 父组件获取子组件的 ref,调用其内部方法。
  • 自定义事件系统
    • 适合大型应用中解耦模块,或者页面外通信(如 WebSocket 推送通知)。

2、常用的React Hooks

🌟 核心 Hooks(必背!)

Hook 名称作用说明
useState声明状态变量
useEffect处理副作用(如:请求、订阅、定时器)
useContext使用上下文 context 的值
useRef获取 DOM 节点或保存可变值不触发渲染
useMemo缓存计算结果,避免重复计算(性能优化)
useCallback缓存函数引用,避免子组件不必要更新
useReducer更复杂状态管理逻辑(像 Redux 的 reducer)

🔁 生命周期类替代 Hook

class组件生命周期对应 Hook 使用方式
componentDidMountuseEffect(() => {}, [])
componentDidUpdateuseEffect(() => {...}, [依赖])
componentWillUnmountuseEffect(() => { return () => {...} }, [])

📦 其他常用 Hooks

Hook 名称用法说明
useLayoutEffectuseEffect 类似,但同步执行,适合操作 DOM 尺寸、位置
useImperativeHandle自定义 ref 暴露的实例方法(配合 forwardRef
useId (React 18+)用于生成唯一 ID,适合表单控件等
useTransition / useDeferredValue控制 UI 更新优先级(适合大数据量场景)

3、stopPropagation和preventDefault

event.preventDefault()

👉 作用:阻止默认行为

例子:
  • 阻止 <a href=""> 跳转
  • 阻止 <form> 提交
  • 阻止右键菜单弹出(context menu)
document.querySelector('a').addEventListener('click', (e) => {
  e.preventDefault(); // 不会跳转了!
});

event.stopPropagation()

👉 作用:阻止事件冒泡(不传递给父元素)

例子:
<div id="outer">
  <button id="inner">点我</button>
</div>
document.getElementById('outer').addEventListener('click', () => {
  console.log('外层被点了');
});
document.getElementById('inner').addEventListener('click', (e) => {
  e.stopPropagation();
  console.log('按钮被点了');
});

结果:点击按钮只会触发 inner 的事件,不会触发 outer


🎁 小贴士:可以一起用

有时候我们既不想让它有默认行为,又不想事件冒泡,比如:

input.addEventListener('keydown', (e) => {
  e.preventDefault();
  e.stopPropagation();
});

4、CSS实现居中对齐有哪些方式

💬 一、文本居中

text-align: center;

🧱 二、块级元素水平居中

1. margin: 0 auto;(最常见)

条件:元素要有固定宽度

.box {
  width: 300px;
  margin: 0 auto;
}

2. display: flex; 父容器居中
.parent {
  display: flex;
  justify-content: center;
}

适用于:子元素水平居中,配合 align-items 还能垂直居中👇

三、水平 + 垂直都居中

1. Flex
.parent {
  display: flex;
  justify-content: center;
  align-items: center;
}

元素无论宽高是否已知都能居中!

2. Grid 布局
.parent {
  display: grid;
  place-items: center;
}
3. 绝对定位 + transform
.child {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}

适用于:宽高未知的元素居中,经典必备技巧。

4. line-height 垂直居中(仅适用于单行文字)
.line-text {
  height: 50px;
  line-height: 50px;
  text-align: center;
}

📌 小结对照表:

方式用途是否支持宽高未知
margin: 0 auto块级元素水平居中❌ 需要固定宽度
text-align: center行内元素 / 文本
Flex任意居中
Grid任意居中
position + transform任意居中
line-height单行文字垂直居中

5、浏览器输入url后发生了什么

🌐 1. DNS 解析

浏览器要把域名 example.com 转换为 IP 地址。

流程是这样:

  1. 浏览器缓存中查找
  2. 操作系统缓存查找
  3. 本地 hosts 文件查找
  4. 找 DNS 服务器(可能是 ISP 的、也可能是你设置的 8.8.8.8 等公共 DNS)
  5. DNS 服务器查权威 DNS 得到最终 IP

🔎 最终得到比如:93.184.216.34


📡 2. 建立 TCP 连接(含 TLS)

  1. 建立 TCP 连接(三次握手)
  2. 若是 https://,则进入 TLS 握手阶段(证书验证 + 对称加密协商)

🔐 这时浏览器和服务器之间建立了一个安全的“隧道”


📨 3. 发起 HTTP 请求

浏览器构造 HTTP 请求并发送,比如:

GET / HTTP/1.1
Host: example.com
User-Agent: Mozilla/5.0...
Accept: text/html,...

服务器接收请求,准备响应。

🏭 4. 服务器处理请求

后端根据请求路径处理逻辑,比如:

  • 查询数据库
  • 处理业务逻辑
  • 渲染模板 / 返回 JSON
  • 读取静态资源文件

并最终返回一个响应,比如 HTML 页面:

HTTP/1.1 200 OK
Content-Type: text/html

<!DOCTYPE html>
<html>
  <head><title>Hello</title></head>
  <body>Hello World!</body>
</html>

📥 5. 浏览器接收响应并渲染

  1. 浏览器根据响应头判断内容类型,比如是 HTML
  2. 解析 HTML → 构建 DOM
  3. 遇到 <link> 加载 CSS,构建 CSSOM
  4. 遇到 <script> 加载 JS,执行逻辑
  5. 遇到 <img> 等资源继续发起请求

最终:

  • DOM + CSSOM → 合成渲染树
  • 计算布局(Layout)
  • 绘制页面(Paint)

🔁 6. 页面交互 & 后续请求

页面加载完后,JS 脚本可能会:

  • 监听用户事件
  • 发起 Ajax / Fetch 请求
  • 动态更新 DOM

🎁 总结一句话:

浏览器输入 URL → DNS → TCP/TLS → HTTP 请求 → 服务器响应 → 浏览器解析渲染 → 用户看到页面!

6、Symbol用途

Symbol 是 ES6 引入的一种原始数据类型,用来表示独一无二的值。它非常适合用在对象属性中,避免命名冲突,是一种创建私有属性的“技巧”。

✅ 1. 用作对象的唯一属性键,防止属性名冲突

const key1 = Symbol('key');
const key2 = Symbol('key'); // 和 key1 虽然描述一样,但值不同

const obj = {
  [key1]: 'hello',
  [key2]: 'world'
};

console.log(obj[key1]); // hello
console.log(obj[key2]); // world

✅ 2. 模拟私有属性

const secret = Symbol('secret');

class Person {
  constructor(name) {
    this.name = name;
    this[secret] = 'my secret';
  }

  getSecret() {
    return this[secret];
  }
}

const p = new Person('Tom');
console.log(p.secret); // undefined
console.log(p.getSecret()); // 'my secret'

👉 虽然不是完全私有(可以通过 Object.getOwnPropertySymbols() 拿到),但足以避免无意访问。

✅ 3. 内置 Symbol 提供特殊行为

JavaScript 提供了一些内置 Symbol,可以自定义对象在特定操作下的行为:

内置 Symbol作用
Symbol.iterator控制对象的可迭代行为(如 for...of)
Symbol.toStringTag控制 Object.prototype.toString.call(obj) 的结果
Symbol.toPrimitive控制对象转原始类型时的行为
Symbol.hasInstance控制 instanceof 行为
Symbol.matchSymbol.replace用于自定义字符串操作方法的行为

示例:

const obj = {
  [Symbol.toPrimitive](hint) {
    if (hint === 'number') return 42;
    return 'I am a Symbolic Object!';
  }
};

console.log(+obj); // 42
console.log(`${obj}`); // I am a Symbolic Object!

✅ 4. 用于实现常量枚举(避免魔法字符串)

const SHAPE_TYPE = {
  CIRCLE: Symbol('circle'),
  SQUARE: Symbol('square')
};

function draw(shape) {
  switch (shape) {
    case SHAPE_TYPE.CIRCLE:
      console.log('Drawing circle');
      break;
    case SHAPE_TYPE.SQUARE:
      console.log('Drawing square');
      break;
    default:
      throw new Error('Unknown shape');
  }
}

❗ Symbol 注意点:

  • 无法通过 for...inObject.keys() 枚举出来
  • 可以通过 Object.getOwnPropertySymbols() 访问
  • 无法隐式转换成字符串(需显式 .toString()
let s = Symbol('abc');
console.log(String(s)); // Symbol(abc)