从 border 透明到闭包缓存:两道“简单题”暴露了你的工程思维

56 阅读5分钟

大厂面试高频题解析:从 CSS 绘制多种图形到斐波那契数列的三种实现

在技术面试中,我们常常会遇到两类看似简单却暗藏玄机的问题:一类是前端基础能力考察(比如用纯 CSS 画各种图形),另一类则是算法思维与代码优化(比如经典的斐波那契数列)。本文将结合实际代码,带你一步步深入理解这些“小题”背后的“大智慧”。


一、CSS 篇:利用 CSS 绘制多种几何图形

原理简述

在 Web 开发中,利用 CSS 来绘制几何图形是一项基本技能。它不仅能展示你的创意,还能体现你对 CSS 布局和渲染机制的理解。

1. 三角形
.triangle {
    /* 三角形 */
    width: 5px;
    height: 5px;
    border: 10px solid transparent;
    border-top-color: #f00;

    /* 注释掉的其他边框颜色设置 */
    /* border-top: 100px solid #f00;
    border-left: 100px solid #0f0;
    border-right: 100px solid #00f;
    border-bottom: 100px solid #ff0; */
}
  • 解释:通过设置元素的宽高为 0 并使用不同方向的 border 属性来创建三角形。在这个例子中,我们仅设置了顶部边框的颜色,其余边框为透明,从而形成一个向上的红色三角形。
2. 扇形
.sector{
    width: 100px;
    height: 100px;
    border-radius: 100px 0 0;
    background-color: #00f;
    /* transform: rotate(45deg); */
}
  • 解释:通过设置特定的 border-radius 来创建扇形。这里我们将左上角的圆角半径设置为 100px,而其他三个角保持直角,背景色设为蓝色。
3. 另一种扇形
.sector2{
   border: 100px solid transparent;
   width: 0;
   border-radius: 100px;
   border-top-color: #f00;
}
  • 解释:这种方法利用了 border-radiusborder 的特性来创建扇形。这里通过设置 border-top-color 为红色,其他边框透明,再应用 border-radius 创建圆形效果的一部分。
4. 箭头
.arrow{
    width: 10px;
    height: 10px;
    border: 1px solid #000;
    border-bottom-color: transparent;
    border-left-color: transparent;
    transform: rotate(45deg);
}
  • 解释:箭头是通过设置矩形的两个边框为透明,并旋转45度来实现的。这种方法可以用来创建简单的箭头图标。
5. 椭圆
.oval{
    width: 100px;
    height: 50px;
    border-radius: 50px / 25px;
    background-color: #ff0;
}
  • 解释:椭圆可以通过设置不同的宽度和高度以及 border-radius 的比例来获得。这里的 border-radius 设置为 50px / 25px,意味着水平方向的半径是50px,垂直方向的半径是25px,从而形成了一个黄色的椭圆。
    效果总览:

image.png


二、算法篇:斐波那契数列的三种实现方式

斐波那契数列(Fibonacci Sequence)定义如下:

F(0) = 0
F(1) = 1
F(n) = F(n-1) + F(n-2) (n ≥ 2

这道题看似简单,却是考察 递归、时间复杂度、空间换时间、闭包 等核心概念的绝佳载体。下面我们将从最朴素的实现,逐步优化到工业级写法。


1️⃣ 普通递归:简洁但低效(指数级时间)

function fib(n) {
  if (n <= 1) return n;
  return fib(n - 1) + fib(n - 2);
}
console.log(fib(10)); // 55

优点:代码简洁,逻辑清晰,符合数学定义。
缺点:存在大量重复计算。例如 fib(5) 会多次计算 fib(3)fib(2) 等。

  • 时间复杂度:O(2ⁿ) —— 指数爆炸!
  • 空间复杂度:O(n) —— 递归栈深度。

🚫 在实际工程或面试中,这种写法通常会被面试官追问:“能优化吗?”


2️⃣ 记忆化搜索(Memoization):用空间换时间

const cache = {};

function fib(n) {
  if (n in cache) return cache[n];
  if (n <= 1) return n;
  cache[n] = fib(n - 1) + fib(n - 2);
  return cache[n];
}

console.log(fib(10)); // 55

优点

  • 每个 fib(k) 只计算一次,后续直接查表。
  • 时间复杂度降为 O(n) ,空间复杂度 O(n)。

缺点

  • cache 是全局变量,容易被外部污染或误改。
  • 不利于模块化和封装。

💡 这就是典型的“空间换时间”思想,在动态规划中广泛应用。


3️⃣ 闭包 + IIFE:封装记忆化逻辑,避免全局污染

const fib = (function () {
  const cache = {}; // 私有变量,外部无法访问
  return function (n) {
    if (n <= 1) return n;
    if (cache[n]) return cache[n];
    return cache[n] = fib(n - 1) + fib(n - 2);
  };
})();

优点

  • 利用 立即执行函数表达式(IIFE)  创建闭包,cache 成为私有状态。
  • 外部只能通过 fib(n) 调用,无法直接操作缓存。
  • 保持了记忆化的高效性,同时提升了代码的健壮性和可维护性。

🔍 这正是大厂面试官想看到的:不仅会写算法,还懂得工程化思维和封装意识


总结:小图形见功底,小递归见思维

前端面试中的“简单题”,往往藏着最真实的考察意图:

  • CSS 图形题(如三角形、扇形、箭头)
    不是让你炫技,而是检验你对 盒模型、border 渲染机制、border-radius 非对称用法、transform 坐标变换 的理解深度。能用纯 CSS 实现复杂形状,说明你真正“看见”了浏览器如何绘制像素。

  • 斐波那契数列
    表面是算法,实则考察三层能力:

    1. 基础编码能力(能否写出正确递归)
    2. 性能敏感度(是否意识到重复计算问题)
    3. 工程素养(能否用闭包封装状态,避免污染全局)
方案时间复杂度空间复杂度推荐度考察重点
普通递归O(2ⁿ)O(n)递归理解
全局缓存记忆化O(n)O(n)⚠️动态规划思想
闭包 + IIFE 封装O(n)O(n)模块化 + 数据私有化意识

💡 真正拉开差距的,从来不是“会不会”,而是“好不好”
能写出第一版是合格,能优化到第三版,才是大厂想要的候选人。