跳到主要内容

递归 和 Memorization

· 阅读需 2 分钟
素明诚
Full stack development

为什么要在递归中使用记忆化:

  1. 避免重复计算:许多递归问题的子问题是重复的,这意味着在递归过程中会多次计算相同的子问题。通过存储这些子问题的结果并在需要时检索它们,可以避免这种重复计算,从而节省时间。
  2. 减少递归深度:对于某些问题,使用记忆化可以减少递归调用的数量和深度,从而避免栈溢出。
  3. 转换为动态规划:记忆化是将递归算法转换为动态规划算法的一个常见步骤。动态规划是一种特殊的递归,其中每个子问题只解决一次,并将其结果存储在一个表格中,以便后续使用。

下面是一个简单的例子:斐波那契数列。原始的递归解决方案会有很多重复的计算,但使用记忆化可以避免这些重复。

1. 不使用记忆化的递归方法:

function fibonacci(n) {
if (n <= 1) return n;
return fibonacci(n - 1) + fibonacci(n - 2);
}

这个方法的问题是,对于较大的 n,它会进行大量的重复计算。

2. 使用记忆化的递归方法:

为了实现记忆化,我们需要一个数据结构(通常是一个数组或对象)来存储已经计算过的子问题的解。

function fibonacciWithMemo(n, memo = {}) {
// 如果已经计算过这个值,直接从 memo 中返回
if (n in memo) return memo[n];

// 基础情况
if (n <= 1) return n;

// 递归计算并将结果存储到 memo 中
memo[n] = fibonacciWithMemo(n - 1, memo) + fibonacciWithMemo(n - 2, memo);

return memo[n];
}

在这个版本中,使用一个名为 memo 的对象来存储已经计算过的斐波那契数。当函数再次被调用时,它首先检查 memo 对象中是否已经有了该数的值。如果有,则直接返回这个值,从而避免了不必要的重复计算。

packagejson 文件配置详解

· 阅读需 2 分钟
素明诚
Full stack development

yarnyarn init 的时候 生成的 package.json 文件用来配置项目的信息、名称、版本号、描述信息等,还可以定义项目所需要的各种依赖包。

创建 package.json 文件

核心字段

nameversionpackage.json 中最重要的两个必需字段,如果没有它们那么包将无法被安装,两者一起用来创建一个唯一的 id。

name

包的名字,在 URL 中作为命令行参数,作为 node_modules 里的目录名使用。由小写字母组成,尽量简洁。

version

包的当前版本号。

author

作者信息。

description

是一个字符串,可以帮助我们了解软件包的用途,也可以在包管理中搜索包时使用它。

keywords

是一个字符串数组,在包管理器中搜索包时起作用。

license

许可证,以方便用户知道他们是在什么授权下使用此包,以及此包还有哪些附加限制。

main

项目的入口文件,默认为 index.js

scripts

定义自动化开发相关任务的好方法,比如使用一些简单的构建过程或开发工具。可以通过 yarn run <script> 命令来执行。

dependencies

包的开发版和发布版都需要的依赖。

devDependencies

只在包开发期间需要,但是生产环境不会被安装的包。

config

配置你的脚本的选项或参数。

homepage

包的项目主页或者文档首页。

bugs问题反馈系统的 URL,或者是 email 地址之类的链接,用户通过该途径向你反馈问题。

repository

代码托管的位置。

contributors

贡献者信息,可以是多个人。

files

项目包含的文件,可以是单独的文件、整个文件夹,或者通配符匹配到的文件。

directories

当我们的包安装时,可以指定确切的位置来放二进制文件、man pages、文档、例子等。

团队中如何落实TDD

· 阅读需 2 分钟
素明诚
Full stack development

团队准备

  • 内部宣导:首先,确保团队理解 TDD 的价值。可以举办内部分享会、研讨会或引入外部专家进行培训。
  • 技能培训:不仅要教团队 TDD 的理念,还要教他们具体如何编写有效的单元测试。

工具和环境设置

  • 测试环境:确保有一个稳定的测试环境,可以模拟真实的生产环境。
  • 自动化工具:自动化测试运行和报告工具,如 Jenkins、Travis CI 等,使团队可以及时获得反馈。

逐步引入

  • 选择项目中的一个模块或部分开始应用 TDD,让团队逐渐适应这种开发方式。
  • 在团队逐渐习惯后,扩大 TDD 的应用范围。

编写测试

  • 现实场景:测试不仅要覆盖基础功能,还要考虑边界条件、异常情况等。
  • 测试数据:确保有一组能够全面覆盖各种场景的测试数据。

反馈机制

  • 除了持续集成工具外,还要确保团队有一个反馈机制,可以快速知道哪些测试失败,并进行修复。
  • 鼓励团队成员之间的交流,共同找出问题的原因并解决。

代码审查与 TDD

  • 代码审查时,除了功能代码外,测试代码的质量和完整性也是审查的重点。
  • 鼓励团队成员相互审查测试代码,确保没有遗漏。

持续改进

  • 定期组织回顾会议,讨论 TDD 的实践中遇到的问题和挑战,以及可能的解决方案。
  • 考虑引入更先进的工具或方法,如行为驱动开发(BDD),进一步提高开发效率和代码质量。

文档与知识共享

  • 尽管 TDD 鼓励以测试作为文档,但团队仍然应该记录和分享他们在 TDD 实践中的经验和教训。
  • 创建一个内部知识库,团队成员可以在其中查找和分享关于 TDD 的最佳实践、常见问题和解决方案。

ECharts版本升级指南结合ECharts 4的地图与ECharts 5的新功能

· 阅读需 1 分钟
素明诚
Full stack development

问题

  1. ECharts5以上的版本不提供china.js,虽然我们可以从github上找到china.js这个文件,但你就不可以使用ECharts5的诸多新功能。
  2. 那么怎么才能使用ECharts4提供的地图和ECharts5的新功能呢?

提示

ECharts4的地图没有按照中国测量标准进行测量,如果在比较正式项目上使用可能会存在法律问题。你可以考虑自己修改或者去上网找修改优化后的版本。

解决 4~5 版本问题

安装两个版本

a3a9d72cdfa57096ff55bead9ce54cdf

import * as echarts5 from "echarts5.2.0";
import * as echarts4 from "echarts";

JavaScript数组方法修改原数组的原因是什么

· 阅读需 2 分钟
素明诚
Full stack development

修改原数组的方法

这些方法之所以会修改原数组,是因为它们的操作本质上会改变数组的内容

  1. push()pop():添加和删除元素会改变数组的长度和内容,因此这两个方法会修改原数组。
  2. unshift()shift():在数组的开头添加和移除元素都会导致数组中其他元素的索引发生变化,因此这两个方法会修改原数组。
  3. splice()splice() 方法既可以添加、删除、替换元素,也可以截取数组的一部分。这些操作都会导致数组内容的变化,因此 splice() 方法会修改原数组。
  4. reverse():颠倒数组中的元素顺序会改变数组的内容,所以 reverse() 方法会修改原数组。
  5. sort():排序数组的元素会改变它们的顺序,因此 sort() 方法会修改原数组。
  6. fill():用指定的值填充数组的元素会改变数组的内容,所以 fill() 方法会修改原数组。
  7. copyWithin():将数组中的一部分元素复制到另一个位置会改变数组内容,因此 copyWithin() 方法会修改原数组。

不修改原数组的方法

  • concat():合并两个数组或更多数组,并返回一个新数组
  • slice():复制原数组的一部分并返回一个新数组
  • join():将数组元素以指定的分隔符拼接为一个字符串
  • map():遍历数组,并返回一个新数组
  • filter():遍历数组,返回符合条件的元素组成的新数组
  • reduce():遍历数组,将数组元素累加或累乘,并返回一个值。

总结

各位可以看出,修改原数组的方法,往往是要对数组中的元素进行操作。或者说是这种操作影响到了元素的位置。这种情况下的方法,是要修改原数组的。

不修改原数组的方法,往往是想对整个数组进行操作。并不是想改变数组元素,而是对整个数组进行遍历、合并、转化等。

Javascript 中 minjs 和 js 文件的区别

· 阅读需 2 分钟
素明�诚
Full stack development

.js 内容

824330ef14867968c3ed52a7b71c03d6## min.js 内容
4c3148e90d52507e4c22c2a94f449aaa

JavaScript 文件:常规 vs 最小化

在 Web 开发中,JavaScript 是一个不可或缺的元素。开发者在构建和部署应用程序时,经常会遇到两种类型的 JavaScript 文件:.js.min.js。了解它们的区别和各自的优缺点是至关重要的。

.js 文件

优点

  • 代码是原始的,未经过任何压缩处理,这使得开发者可以轻松地阅读、理解和修改代码内容。

缺点

  • 由于包含了所有格式化内容(如空格、缩进和注释),文件的体积相对较大,这导致其在网络上的加载和传输时间增加。

.min.js 文件

优点

  • 体积较小,因此传输和加载速度更快,为用户提供了更快的响应时间。
  • 由于代码混淆,一般人很难理解其内容,这为源代码提供了一定程度的保护,减少了被窃取的风险。

缺点

  • 代码的可读性差,这使得它在调试和修改时可能会遇到困难。

JavaScript 文件压缩的原理

JavaScript 文件的压缩并不是一个简单的过程,它涉及多个步骤,以确保文件尽可能小,同时代码仍然能够正常运行。

  1. 删除无用内容:所有不必要的注释、空格、换行符和其他格式化内容都被移除,从而减小文件大小。
  2. 代码混淆:为了进一步减小文件大小并提供源代码的一定保护,变量和函数名被更改为短而没有实际意义的名称。此外,没有使用的代码、内联函数和等价语句也可能被删除或替换。

总之,选择使用 .js 还是 .min.js 文件取决于你的实际需求。在开发和调试过程中,使用常规 .js 文件更为合适。但在生产环境中,为了提供更快的加载速度和保护源代码,使用 .min.js 文件通常是更好的选择。

中文对齐全角空格的神奇力量

· 阅读需 2 分钟
素明诚
Full stack development

在处理中文排版时,特别是在 Web 开发中,经常会遇到需要对齐中文文本的情况。虽然有许多预定义的 HTML 字符实体可以帮助我们添加空格,但不是所有的空格都适合处理中文文本。

以下是一些常见的 HTML 字符实体及其描述:

  • &nbsp;:这是最常用的非换行空格。它的宽度是英文半角空格,经常用于英文文本中。
  • &ensp;:这个空格的宽度是半个中文字符。它常用于需要较细微调整的地方。
  • &emsp;:这个空格的宽度是一个完整的中文字符,但在某些情况下可能并不完美。

然而,有一个不太为人知的字符实体&#12288;,它是中文的全角空格。它的宽度完美地等于一个中文字符,因此在对齐中文文本时,它就像一个“隐形”的汉字。这使得文本在视觉上更加均匀和整齐。

为什么使用全角空格?

在设计良好的中文网页或文档中,文本的对齐和间距是非常关键的。如果使用不恰当的空格,可能会导致文本看起来不整齐或难以阅读。全角空格提供了一个简单而有效的方法,使中文文本保持整齐的对齐,无论是在标题、段落还是列表中。

结论

虽然 HTML 提供了多种空格选项,但对于中文文本,全角空格&#12288;往往是最佳选择。它简单、有效,并能确保中文文本始终保持整齐的对齐。

如何检测阅读用户阅读到底

· 阅读需 1 分钟
素明诚
Full stack development

scrollHeight

2b7c0705117329fc823801bb1926ef0e## scrollTop

属性可以获取或设置一个元素的内容垂直滚动的像素数

一个元素的scrollTop值是这个元素的内容顶部(卷起来的)到它的视口可见内容(的顶部)的距离的度量。当一个元素的内容没有产生垂直方向的滚动条,那么它的scrollTop值为0

在使用显示比例缩放的系统上,scrollTop可能会提供一个小数。

clientHeight

89f578be8847e299ba29b0c564859de2## 公式

parseInt(scrollHeight) - parseInt(scrollTop) == parseInt(clientHeight);

使用parseInt可以保证在移动端上忽略小数部分的影响。

解决Vue页面使用插值表达式闪烁

· 阅读需 1 分钟
素明诚
Full stack development

描述

5014ae02dc71ebee8466c20960517da8## 方法 1

使用Vue自带的指令

注意,该指令不兼容IE,而且会导致IE白屏,建议使用方法2解决问题

    [v-cloak] {
display: none;
}

方法 2

使用v-text或者v-html来代替

<div class="report3" v-text="fPprice">{{fPprice}}</div>

GitHub Actions 的工作流文件的主要模块

· 阅读需 1 分钟
素明诚
Full stack development

名称 (name): 描述工作流程的名称,这在 GitHub 的操作 UI 中是可见的。

name: My CI/CD Workflow

触发器 (on): 定义什么时候运行工作流程。它可以是 GitHub 事件(如 pushpull_request)或者定时任务。

 on: [push]

或者更复杂的触发器:

on:
push:
branches:
- main
pull_request:
branches:
- main

工作 (jobs): 工作是一组要在同一个运行环境中执行的步骤。你可以定义多个工作,它们可以并行执行或按照特定的依赖顺序执行。

jobs:
build:
runs-on: ubuntu-latest
steps:
...
deploy:
needs: build
runs-on: ubuntu-latest
steps:
...

步骤 (steps): 步骤是在工作中执行的单个任务。每个步骤可以是执行命令、运行脚本或使用 GitHub Actions 市场上的现有操作。

 steps:
- name: Check out code
uses: actions/checkout@v2
- name: Run tests
run: npm test

环境变量和路径 (env 和 with): 为步骤或整个工作设置环境变量或输入参数。

env:
NODE_ENV: production
steps:
- name: Use Node.js
uses: actions/setup-node@v2
with:
node-version: '14'

策略 (strategy): 定义工作的策略,例如矩阵构建,它可以同时测试多个版本或配置。

 strategy:
matrix:
node-version: [12.x, 14.x, 16.x]