手撕面包

十三、手写new

十二、柯里化函数

溯源历史

这个思想可以追溯到19世纪数学家Gottlob Frege,但组合逻辑创始人 Haskell Curry对其进行系统化研究和发展,所以用了他的名字 Curry 命名。

函数柯里化从数学引入计算机领域,主要原因是函数式编程范式的兴起、λ演算的理论基础、提供了更灵活的函数组合方式:

过程式语言如C,因为设计哲学的原因,函数在这里不是“一等公民”,所以不支持柯里化。

概念与应用

概念:一种将多参数函数转化为一系列单参数函数的技术。每个函数接受一个参数并返回接受下一个参数的函数,直到所有参数都收集完毕才执行函数。

应用:参数复用(事件处理、配置函数等场景)、延迟执行、函数组合。linkopen in new window,搜'应用场景(前端特定)'

经典面试题

实现技术点:

  • 基于闭包:利用JS的闭包特性保存中间状态
  • 延迟执行:参数未收集完成时不执行实际计算
  • 函数组合友好:便于创建可复用的函数片段

经典面试题open in new window 题解:

function curryFn(fn) {
  if(typeof fn !== 'function'){
    throw new TypeError('curry requires a function')
  }
  return function curried(...args){
    // 如果传入的参数数量大于等于 原函数 需要的参数数量,直接调用原函数
    if(args.length >= fn.length){
      return fn.apply(this,args)
    }
    // 否则返回一个新函数,继续接收剩余参数
    return function (...nextArgs) {
      return curried.apply(this,args.concat(nextArgs))
    }
  }
}

十一、实现九宫格布局

考察CSS的布局和运用的理解能力,包括Flexbox、Grid、float、table.应用场景:电商产品图展示,功能入口网络、游戏界面、数据展示等。衍生问题:

  • Flexbox vs Grid 各自的优缺点?
  • 如何选择适合的布局方案?
  • 不同方案的浏览器兼容性如何?

Flex box适合一维布局(单行或单列),Grid适合二维布局;实际开发中可能会结合使用,移动端采用flex,大屏设备使用grid.这样既能保证浏览器的兼容性,又能保证现代浏览器的强大功能。

Flexbox

.container{
  display:flex;
  flex-wrap:wrap;
  width:300px;
  height:300px;
}
.item{
  width: 33.33%;
  height: 33.33%;
  box-sizing: border-box;
  border: 1px solid #ccc;
}

Grid 布局(现代推荐)

.container{
  display: grid;
  /* repeat是重复函数,表示重复3次,fr 单位表示网格容器中可用空间的一部分。
  1fr表示意味着网格容器被分为3列,每列宽度相等,各占可用空间的1/3。 */
  grid-template-columns: repeat(3,1fr);
  grid-template-rows: repeat(3,1fr);
  width: 300px;
  height: 300px;
  gap: 1px;
  background: #ccc;
}
.item{
  background: purple
}

float(传统方案)

.container{
  width: 300px;
  height: 300px;
  background: #ccc;
  overflow: hidden;
}
.item{
  background: purple;
  float: left;
  width: 33.33%;
  height: 33.33%;
  /* 浮动布局中元素要加上box-sizing:border-box的写法 因为是为了解决盒模型计算的问题
  浮动布局依赖精确的宽度计算,百分比宽度配合 border-box 可以确保布局准确。 */
  box-sizing: border-box;
  border: 1px solid #ccc;
}

table布局不做解释,它的语义不符合主流写法。

十、用css实现三角

标准答案有八种三角形实现,但我觉得只需要知道核心原理、实现能力(写出1-2种三角形)、扩展思维(举一反三推出其他三角形实现)就可以了。

css实现

<div class="triangle"></div>
<style>
  .triangle{
    width:0;
    height:0;
    /* 向上的三角形,代码里就写下,反过来的,朝向左右也同理 */ 
    border-bottom:50px solid #333;
    border-left: 50px solid transparent;
    border-right: 50px solid transparent;

    /* 向下的三角形 */
    border-top:50px solid #333;
    border-left: 50px solid transparent;
    border-right: 50px solid transparent;
  }      
</style>

clip-path方法

clip-path是CSS3的属性,用于裁剪元素的显示区域,polygon()用于定义多边形的坐标;坐标点可以按顺时针或逆时针顺序排列,但必须连续且有序;%是相对于元素自身的宽高,当然也可以用px表示。

.triangle{
  width:100px;
  height:100px;
  background:#333;
  clip-path:polygon(100% 0,50% 100%,0 0)
}

canvas实现

<canvas id="myCanvas" width="100" height="100"></canvas>

<script>
const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');

// 方法1:路径绘制
ctx.beginPath();
ctx.moveTo(50, 0);    // 起点:顶部中点
ctx.lineTo(0, 100);   // 左下角
ctx.lineTo(100, 100); // 右下角
ctx.closePath();      // 自动回到起点
ctx.fillStyle = '#333';
ctx.fill();

// 方法2:更简洁的写法
ctx.beginPath();
ctx.moveTo(50, 0);
ctx.lineTo(0, 100);
ctx.lineTo(100, 100);
ctx.fill(); // 自动闭合路径并填充
</script>

九、文字溢出

文字溢出与文本溢出

  • 文字溢出 重点是单个字符的视觉表现和排版

先展示单行方案,强调这是最基础最重要的; 再展示多行方案,说明WebKit限制和替代方案; 重点体现对CSS基础属性的熟练掌握;

  • 文本溢出 重点是段落内容的布局和结构处理

重点展示兼容性更好的定位方案; 详细说明伪元素的实现原理; 讨论背景色匹配、行高计算等细节问题; 体现解决实际问题的能力;

单行文字实现

.text{
  text-overflow: ellipsis;/*ellipsis 省略*/
  overflow: hidden ;
  white-space: nowrap;/*nowrap 换行*/
}

多行文字实现

即第八、旧版弹盒法

八、文本溢出

前端开发中使用场景:内容列表展示、卡片布局。有两种方式,如果对兼容性要求高,需要支持所有现代浏览器,使用定位伪元素遮盖;若用户使用的是Chrome或Safari,使用旧版弹盒法

定位伪元素遮盖

.father{/*父元素*/
  postion:relative;/*子绝父相 给伪元素定位*/
  overflow:hidden;
  text-align:justify;
  line-height:20px;
}
.father::after{
  position:absolute;
  right:0;
  bottom:0;
  content:'...';/*插入省略文本*/
  width:1em;/*为了遮盖时正好遮住原来一个字的大小*/
  background-color:''/*设置和父元素背景相同的颜色*/
}

伪元素vs伪类

伪元素:创建不在文档树中的虚拟元素,::

伪类:选择已有元素的状态,:

旧版弹性盒法

.box{
  display: -webkit-box;
  /* 弹性盒子元素垂直排列 */
  -webkit-box-orient: vertical;
  /* 控制要显示的行数 */
  -webkit-line-clamp: 3;
  overflow: hidden;
}

七、三栏布局

解释

将页面水平分为三份,表现形式:左右固定中间自适应(常见,经典圣杯布局、双飞翼布局)、左右自适应中间固定、三个都自适应(比例一般1:2:1)、一个固定两个自适应(少见)

实现方式

绝对定位不推荐,脱离文档流

‌relative‌:不脱离文档流,不影响其他元素布局。absolute‌:脱离文档流,根据父元素或根元素定位。 ‌

<div class="container">
  <div class="main">中间自适应</div>
  <div class="left">左侧固定</div>
  <div class="right">右侧固定</div>
</div>
<style>
 .contain{
    padding: 0 200px;
    overflow: hidden;
  }
  .main,.left,.right{
    float: left;
    position: relative;
    min-height: 300px;
  }
  .main{
    background-color: pink;
    width: 100%;
  }
  .left{
    background-color: plum;
    margin-left: -100%;/* 移动到上一行的最左侧 */
    right: 200px;/* 相对定位调整到正确位置 */
    width: 200px;
  }
  .right{
    background-color: aquamarine;
    width: 200px;
    /* 为什么不用margin-right?
    因为所有栏都设置了float:left 元素从左到右排列 一定要用margin-left 移动到上一行的最右侧*/
    margin-left: -200px;
    left: 200px;/* 相对定位调整到正确位置 */
  }
</style>
<div class="double-wing">
  <div class="main-wrapper">
    <div class="main">中间内容(自适应)</div>
  </div>
  <div class="left">左侧边栏(固定200px)</div>
  <div class="right">右侧边栏(固定200px)</div>
</div>
<style>
.double-wing {
  overflow: hidden;
  min-height: 300px;
}
.main-wrapper, .left, .right {
  float: left;
  min-height: 300px;
}
.main-wrapper {
  width: 100%;
  background: pink;
}
.main {
  margin: 0 200px;/* 主要内容区域的内边距 */
  height: 100%;
  background: plum;
}
.left {
  width: 200px;
  margin-left: -100%;/* 移动到第一行最左边 */
  background: beige;
}
.right {
  width: 200px;
  margin-left: -200px;/* 移动到第一行最右边 */
  background: beige;
}
</style>
<div class="flex-container">
  <div class="left">左侧边栏(固定200px)</div>
  <div class="main">中间内容(自适应)</div>
  <div class="right">右侧边栏(固定200px)</div>
</div>
<style>
.flex-container{
  display: flex;
  min-height: 300px;
}
.left{
  width: 200px;
  order: 1;/*控制显示顺序*/
  background: plum;
}
.main{
  flex: 1;/*占据剩余所有空间*/
  order: 2;
  background: pink;
}
.right{
  width: 200px;
  order: 3;
  background: plum;
}
</style>
<div class="grid-container">
  <div class="left">左侧边栏(固定200px)</div>
  <div class="main">中间内容(自适应)</div>
  <div class="right">右侧边栏(固定200px)</div>
</div>
<style>
.grid-container{
  display: grid;
  grid-template-columns: 200px 1fr 200px; /* 左右固定,中间自适应 */
  min-height: 300px;
  gap: 0; /* 可选:去掉间距 */
}
.left{
  background: plum;
}
.main{
  background: pink;
}
.right{
  background: plum;
}
</style>

圣杯和双飞翼的名字由来

  • 圣杯:西方文化中象征着"神圣的追求目标"(耶稣晚餐用过的杯子 比作美好),这个布局在当时(2006年左右)被认为是CSS布局的"圣杯"——一个难以实现但非常理想的三栏布局目标。
  • 双飞翼:由淘宝UED团队提出,名字来源于"双翼",比喻中间内容区域像鸟的身体,左右两侧像翅膀一样展开。
  • 两者都是三栏布局,且最后呈现的视觉效果相同,但代码实现思路不同;
  • 双飞翼是圣杯的优化版本,解决了浏览器兼容问题;圣杯的html结构更简洁,双飞翼多一层包裹。
  • 注意:圣杯布局和双飞翼布局的中间栏div都是在html结构中先写的,这样写浏览器会优先解析展示中间内容,利于SEO.

六、两栏布局

解释

两栏布局是一种布局现象,并不是css种规定的专业名词,但行业通用。

最常见的是左侧固定、右侧自适应;除此之外,还有右侧固定、左侧自适应;两侧都自适应

<div class="container">
  <div class="left">左边浮动元素</div>
  <div class="right">右边普通元素</div>
</div>

实现方式

掌握浮动和Flex就足够应对大多数情况。

Grid布局比较新颖(语义化);绝对定位:不推荐,影响文档流;表格布局:display: table 已过时

/* 1.父元素加BFC,固定部分浮动并给出宽高,自适应部分使用margin-方向来固定 */
.container {
  border: 3px solid red; /* 用红色边框标识父容器范围 */
  overflow: hidden;
}

.left {
  float: left;
  width: 200px;
  background-color: gray;
  height: 400px;
}

.right {
  /* 注意:这里没有 margin-left */
  margin-left: 200px;
  background-color: lightgray;
  height: 200px;
}
/* 2.父元素flex,固定部分给出宽度,自适应部分用flex:1的属性拉满剩余空间 */
.container {
  border: 3px solid red; /* 用红色边框标识父容器范围 */
  display: flex;
}
.left {
  width: 200px;
  background-color: gray;
  height: 400px;
}
.right {
  flex: 1;/* 自适应部分占据剩余空间 */
  background-color: lightgray;
  height: 200px;
}
/* 3.Grid布局 新颖且语义化; */
.container {
  border: 3px solid red; /* 用红色边框标识父容器范围 */
  display: grid;
  grid-template-columns: 250px 1fr;/*第一列宽度250px 第二列宽度剩余空间的一部分*/
  grid-template-areas: "sidebar main";/*定义子元素语义化属性*/
}
.left {
  grid-area: sidebar;
  background: #f0f0f0;
  background-color: gray;
  height: 400px;
}

.right {
  grid-area: main;
  background-color: lightgray;
  height: 200px;
}