feat: migrate and organize documentation and blog posts

refactor(blog): restructure blog post layouts and metadata

docs: add markdown migration guide and project rules update

style(global.css): update typography theme variables

chore: move temp_docs to appropriate blog post locations
This commit is contained in:
joyzhao
2025-06-19 20:24:09 +08:00
parent c064c8a1c5
commit f8173fd706
14 changed files with 1613 additions and 37 deletions

View File

@@ -50,6 +50,17 @@ const finalReadingTime = readTime ? parseInt(readTime.replace(/\D/g, '')) : unde
<!-- Blog post header -->
<header class="mb-10">
<PostMeta
lang={lang}
publishDate={finalPublishDate}
readingTime={finalReadingTime}
tags={tags}
tagId={tagId}
category={category}
categoryId={categoryId}
className="justify-start mb-4"
/>
<h1 class="text-3xl sm:text-4xl lg:text-5xl font-bold text-foreground mb-6 leading-tight tracking-tight">
{title}
</h1>
@@ -59,21 +70,11 @@ const finalReadingTime = readTime ? parseInt(readTime.replace(/\D/g, '')) : unde
{description}
</p>
)}
<PostMeta
lang={lang}
publishDate={finalPublishDate}
readingTime={finalReadingTime}
tags={tags}
tagId={tagId}
category={category}
categoryId={categoryId}
className="justify-start"
/>
</header>
<!-- Blog post content with typography styles -->
<article class="prose prose-lg dark:prose-invert max-w-none prose-headings:scroll-mt-24 prose-headings:font-bold prose-headings:tracking-tight prose-h1:text-2xl sm:prose-h1:text-3xl prose-h2:text-xl sm:prose-h2:text-2xl prose-h3:text-lg sm:prose-h3:text-xl prose-h4:text-base sm:prose-h4:text-lg prose-p:text-base sm:prose-p:text-lg prose-p:leading-relaxed prose-p:mb-6 prose-a:text-primary prose-a:no-underline hover:prose-a:underline prose-strong:text-foreground prose-code:text-sm prose-code:px-2 prose-code:py-1 prose-code:rounded prose-pre:bg-muted prose-pre:border prose-pre:text-sm prose-blockquote:border-l-primary prose-blockquote:bg-muted/30 prose-blockquote:text-base prose-li:text-base sm:prose-li:text-lg prose-li:leading-relaxed">
<article class="prose prose-lg dark:prose-invert max-w-none prose-headings:scroll-mt-24 prose-headings:font-bold prose-headings:tracking-tight prose-h1:text-2xl sm:prose-h1:text-3xl prose-h2:text-xl sm:prose-h2:text-2xl prose-h3:text-lg sm:prose-h3:text-xl prose-h4:text-base sm:prose-h4:text-lg prose-p:text-base sm:prose-p:text-lg prose-p:leading-relaxed prose-p:mb-6 prose-a:text-primary prose-a:no-underline hover:prose-a:underline prose-strong:text-foreground prose-code:text-sm prose-code:px-2 prose-code:py-1 prose-code:rounded prose-pre:bg-muted prose-pre:border prose-pre:text-sm prose-blockquote:border-l-primary prose-blockquote:bg-muted/30 prose-blockquote:text-base prose-li:text-base sm:prose-li:text-lg prose-li:leading-relaxed
prose-code:before:content-none prose-code:after:content-none">
<slot />
</article>

View File

@@ -0,0 +1,100 @@
---
layout: "@/layouts/BlogPostLayout.astro"
title: "浏览器的运行原理"
description: "本文详细介绍了浏览器渲染页面的七个阶段HTML解析、样式计算、布局、分层、绘制、分块、光栅化以及reflow回流、repaint重绘的概念和transform效率高的原因。"
date: "2023-08-10"
image: "https://images.unsplash.com/photo-1510511459019-5dda7724fd87?q=80&w=1470&auto=format&fit=crop"
tags: ["浏览器", "前端", "渲染原理"]
tagId: ["browser", "frontend", "rendering"]
category: "前端开发"
categoryId: "frontend"
readTime: "7 min read"
---
浏览器渲染页面的过程可以分为七个阶段:
### 1. HTML解析
浏览器接收到服务器响应的HTML文档后会首先解析HTML文档构建DOM树。DOM树是由DOM元素及属性节点组成的树的根是document对象。
### 2. 样式计算
浏览器会解析CSS文件和元素上的inline样式计算出DOM节点的样式。这个过程包括
- 把CSS转换为浏览器能够理解的结构
- 计算出DOM节点的具体样式
### 3. 布局
布局阶段会计算出DOM树中可见元素的几何位置这个过程叫做布局或重排。
### 4. 分层
浏览器会根据布局后的DOM树将其分为多个图层。这个过程主要是为了处理页面中的复杂效果如3D变换、页面滚动等。
### 5. 绘制
在分层的基础上,浏览器会为每个图层生成绘制列表,并将其提交到合成线程。
### 6. 分块
合成线程会将图层划分为图块这些图块的大小通常是256x256或者512x512。
### 7. 光栅化
合成线程会按照视口附近的图块来优先生成位图,这个过程叫做光栅化。光栅化过程中,会将图块转换为位图。
## 回流Reflow和重绘Repaint
### 回流Reflow
当我们对DOM的修改引发了DOM几何尺寸的变化比如修改元素的宽、高或隐藏元素等浏览器需要重新计算元素的几何属性然后再将计算的结果绘制出来。这个过程就是回流也叫重排
引起回流的操作包括:
- 页面首次渲染
- 浏览器窗口大小发生改变
- 元素尺寸或位置发生改变
- 元素内容变化(文字数量或图片大小等等)
- 元素字体大小变化
- 添加或者删除可见的DOM元素
- 激活CSS伪类例如:hover
- 查询某些属性或调用某些方法
一些常用且会导致回流的属性和方法:
- clientWidth、clientHeight、clientTop、clientLeft
- offsetWidth、offsetHeight、offsetTop、offsetLeft
- scrollWidth、scrollHeight、scrollTop、scrollLeft
- scrollIntoView()、scrollIntoViewIfNeeded()
- getComputedStyle()
- getBoundingClientRect()
- scrollTo()
### 重绘Repaint
当我们对DOM的修改导致了样式的变化、但未影响其几何属性比如修改了颜色或背景色浏览器不需要重新计算元素的几何属性、直接为该元素绘制新的样式。这个过程叫做重绘。
相比回流,重绘的性能开销较小,因为重绘只是重新绘制元素的外观,而不需要重新计算元素的位置。
## 为什么transform效率高
transform是通过创建一个新的复合图层来实现的这个复合图层会单独进行绘制然后再与其他图层进行合成。这样当我们使用transform进行变换时只需要重新绘制这个复合图层而不需要重新绘制整个页面。
使用transform可以避免回流和重绘因为它不会影响到DOM的布局只会影响到最终的渲染结果。这就是为什么使用transform进行动画会比直接修改元素的top、left等属性效率高的原因。
## 优化策略
为了减少回流和重绘,我们可以采取以下策略:
1. **批量修改DOM**使用DocumentFragment或者先将元素设为display: none然后进行多次修改最后再显示。
2. **避免频繁读取会引发回流/重绘的属性**:如果必须多次读取,就将值缓存起来。
3. **使用transform和opacity来实现动画效果**:这两个属性不会触发回流。
4. **使用will-change属性**:这个属性可以提前告知浏览器元素将要发生的变化,浏览器可以提前做好优化工作。
5. **使用绝对定位或固定定位**:绝对定位和固定定位的元素发生变化时,只会影响自身,不会影响其他元素。
通过理解浏览器的渲染原理和优化策略,我们可以编写出更高效的前端代码,提升用户体验。

View File

@@ -0,0 +1,129 @@
---
layout: "@/layouts/BlogPostLayout.astro"
title: "Docusaurus v3中使用Tailwind CSS的样式"
description: "本文详细介绍了如何在Docusaurus v3中集成和配置Tailwind CSS包括安装依赖、配置tailwind.config.js、创建tailwind.css和postcss.config.js等步骤。"
date: "2023-11-05"
image: "https://images.unsplash.com/photo-1555066931-4365d14bab8c?q=80&w=1470&auto=format&fit=crop"
tags: ["Docusaurus", "TailwindCSS", "前端框架"]
tagId: ["docusaurus", "tailwindcss", "frontend-framework"]
category: "前端开发"
categoryId: "frontend"
readTime: "4 min read"
---
## 安装相关依赖
```bash
npm install tailwindcss
```
## 配置tailwind.config.js
```js
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
"./src/**/*.{js,jsx,ts,tsx,md,mdx}",
"./docs/**/*.{md,mdx}",
],
theme: {
screens: {
xs: '480px',
sm: '576px',
md: '768px',
lg: '998px',
xl: '1200px',
'2xl': '1400px',
},
extend: {
fontFamily: {
sans: 'var(--ifm-font-family-base)',
firacode: 'var(--font-family-firacode)',
kaiti: 'var(--font-family-kaiti)',
},
colors: {
'font-color': 'var(--ifm-font-color-base)',
'link-color': 'var(--ifm-link-color)',
'link-hover-color': 'var(--ifm-link-hover-color)',
primary: 'var(--ifm-color-primary)',
'primary-light': 'var(--ifm-color-primary-light)',
'primary-lighter': 'var(--ifm-color-primary-lighter)',
'primary-lightest': 'var(--ifm-color-primary-lightest)',
'primary-dark': 'var(--ifm-color-primary-dark)',
'primary-darker': 'var(--ifm-color-primary-darker)',
'primary-darkest': 'var(--ifm-color-primary-darkest)',
},
boxShadow: {
nysm: '0 0 2px 0 rgb(0 0 0 / 0.05)',
ny: '0 0 3px 0 rgb(0 0 0 / 0.1), 0 0 2px - 1px rgb(0 0 0 / 0.1)',
nymd: '0 0 6px -1px rgb(0 0 0 / 0.1), 0 0 4px -2px rgb(0 0 0 / 0.1)',
nylg: '0 0 15px -3px rgb(0 0 0 / 0.1), 0 0 6px -4px rgb(0 0 0 / 0.1)',
spread: '0 5px 40px rgb(0 0 0 / 0.1)',
},
},
},
plugins: [],
darkMode: ["class", '[data-theme="dark"]'],
corePlugins: {
preflight: false,
},
blocklist: ["container"],
}
```
## 创建tailwind.css
`src/css`目录下创建`tailwind.css`文件,并写入以下内容:
```css
@tailwind base;
@tailwind components;
@tailwind utilities;
```
**注意创建完成后是需要在custom.css中导入tailwind.css的否则tailwind样式不会生效**
## 创建postcss.config.js
在项目根目录下创建`postcss.config.js`文件,并写入以下内容:
```js
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
}
}
```
## 在custom.css中导入tailwind.css
找到项目中的`src/css/custom.css`文件,在文件顶部添加以下内容:
```css
@import './tailwind.css';
```
## 使用Tailwind CSS
现在你可以在项目中使用Tailwind CSS的样式了。例如
```jsx
<div className="flex flex-col items-center justify-center p-4 bg-gray-100 dark:bg-gray-800 rounded-lg shadow-md">
<h2 className="text-2xl font-bold text-primary mb-2">Hello Tailwind CSS</h2>
<p className="text-gray-700 dark:text-gray-300">This is a paragraph styled with Tailwind CSS</p>
</div>
```
## 注意事项
1. 由于Docusaurus已经有自己的CSS样式所以我们在配置Tailwind CSS时禁用了`preflight`,这样可以避免样式冲突。
2. 我们使用了`darkMode: ["class", '[data-theme="dark"]']`配置这样可以让Tailwind CSS的暗黑模式与Docusaurus的暗黑模式保持一致。
3. 我们在`theme.extend.colors`中添加了一些变量这些变量使用了Docusaurus的CSS变量这样可以让Tailwind CSS的颜色与Docusaurus的主题颜色保持一致。
4. 我们在`blocklist`中添加了`container`这是因为Docusaurus已经有自己的容器样式我们不希望Tailwind CSS的容器样式覆盖它。
## 总结
通过以上步骤我们成功地在Docusaurus v3中集成了Tailwind CSS。现在我们可以使用Tailwind CSS的所有功能同时保持与Docusaurus主题的一致性。
希望这篇文章对你有所帮助!如果你有任何问题,欢迎在评论区留言。

View File

@@ -0,0 +1,152 @@
---
layout: "@/layouts/BlogPostLayout.astro"
title: "Git提交规范"
description: "本文详细介绍了Git提交规范包括Header、Body和Footer三个部分的具体内容和使用规则帮助团队成员更好地理解和遵循统一的提交标准。"
date: "2023-10-20"
image: "https://images.unsplash.com/photo-1618401471353-b98afee0b2eb?q=80&w=1476&auto=format&fit=crop"
tags: ["Git", "规范", "版本控制"]
tagId: ["git", "convention", "version-control"]
category: "开发工具"
categoryId: "dev-tools"
readTime: "5 min read"
---
### 为什么需要提交规范
在团队协作中如果Git的提交说明精准在后期协作以及Bug处理时会变得有据可查项目的开发可以根据规范的提交说明快速生成开发日志从而方便开发者或用户追踪项目的开发信息和功能特性。
### 提交说明的结构
提交说明包含三个部分Header、Body 和 Footer。
```
<Header>
<Body>
<Footer>
```
#### Header
Header部分包含三个字段type必需、scope可选和subject必需
```
<type>(<scope>): <subject>
```
##### type
type用于说明commit的类别只允许使用下面7个标识
- **feat**新功能feature
- **fix**修补bug
- **docs**文档documentation
- **style** 格式(不影响代码运行的变动)
- **refactor**重构即不是新增功能也不是修改bug的代码变动
- **test**:增加测试
- **chore**:构建过程或辅助工具的变动
如果type为feat和fix则该commit将肯定出现在Change log之中。其他情况docs、chore、style、refactor、test由你决定要不要放入Change log建议是不要。
##### scope
scope用于说明commit影响的范围比如数据层、控制层、视图层等等视项目不同而不同。
##### subject
subject是commit目的的简短描述不超过50个字符。
- 以动词开头使用第一人称现在时比如change而不是changed或changes
- 第一个字母小写
- 结尾不加句号(.
#### Body
Body部分是对本次commit的详细描述可以分成多行。
有两个注意点:
- 使用第一人称现在时比如使用change而不是changed或changes
- 应该说明代码变动的动机,以及与以前行为的对比
#### Footer
Footer部分只用于两种情况
##### 不兼容变动
如果当前代码与上一个版本不兼容则Footer部分以BREAKING CHANGE开头后面是对变动的描述、以及变动理由和迁移方法。
```
BREAKING CHANGE: isolate scope bindings definition has changed.
To migrate the code follow the example below:
Before:
scope: {
myAttr: 'attribute',
}
After:
scope: {
myAttr: '@',
}
The removed `inject` wasn't generaly useful for directives so there should be no code using it.
```
##### 关闭Issue
如果当前commit针对某个issue那么可以在Footer部分关闭这个issue。
```
Closes #234
```
也可以一次关闭多个issue。
```
Closes #123, #245, #992
```
### 示例
```
feat(browser): onUrlChange event (popstate/hashchange/polling)
Added new event to browser:
- forward popstate event if available
- forward hashchange event if popstate not available
- do polling when neither popstate nor hashchange available
Closes #123, #305, #392
```
```
fix(release): need to depend on latest rxjs and zone.js
The version in our package.json gets copied to the one we publish, and users need the latest of these.
```
```
docs(changelog): update change log to beta.5
```
```
style(router): fix linting errors
```
```
refactor(core): rename onInit to ngOnInit
```
```
chore(deps): bump rxjs from 5.0.0-beta.2 to 5.0.0-beta.6
```
### 总结
规范的Git提交说明可以帮助团队成员更好地理解和遵循统一的提交标准提高团队协作效率也为后期的项目维护提供了便利。

View File

@@ -0,0 +1,104 @@
---
layout: "@/layouts/BlogPostLayout.astro"
title: "利用Gitea actions创建项目部署的自动化流程"
description: "本文以部署一个前端项目为示例手把手教你如何利用Gitea actions创建项目部署的自动化流程对于不想使用Jenkins的小伙伴来说Gitea actions是一个不错的CI/CD解决方案。"
date: "2023-12-15"
image: "https://images.unsplash.com/photo-1607799279861-4dd421887fb3?q=80&w=1470&auto=format&fit=crop"
tags: ["Gitea", "Actions", "CI/CD", "自动化部署"]
tagId: ["gitea", "actions", "cicd", "automation-deployment"]
category: "DevOps"
categoryId: "devops"
readTime: "10 min read"
---
本文以部署一个前端项目为示例将手把手教你如何利用Gitea actions创建项目部署的自动化流程对于不想使用Jenkins的小伙伴来说Gitea actions是一个不错的`CI/CD`解决方案。
## 前言
在我们开发完一个项目后需要将项目部署到服务器上以便于用户可以访问。但是每次部署都需要手动操作这会浪费我们的时间和精力。因此我们可以利用Gitea actions创建一个自动化流程以便于我们快速部署项目。
## 什么是Gitea actions
Gitea actions是Gitea的一个功能它允许我们创建自动化流程以便于我们快速部署项目。Gitea actions可以执行各种任务例如构建、测试、部署等。Gitea actions可以使用各种编程语言和工具例如Python、Java、Docker等。并且Gitea actions在配置上尽量与GitHub actions的配置兼容因此如果你已经熟悉了GitHub actions那么你也可以轻松地使用Gitea actions。
详见官方文档:[Gitea actions](https://docs.gitea.com/zh-cn/usage/actions/overview)
## 准备工作
在我们开始创建此流程前,首先你需要准备以下资料:
1. 一台服务器,最好拥有root权限会安装一些工具
2. 一个已部署的Gitea仓库,版本至少需要>=`v1.19`,官方强烈建议使用`v1.20`或更高版本
3. docker环境非必须, 用在部署runner的主机上
> ps: 作者这里服务器准备的是:一台打包服务器 + 一台部署(目标)服务器, 你可以只用一台服务器,但注意环境的隔离
请在进行后续步骤前,确保已完成所有的准备工作,具体的安装配置,请参考官方文档,这里我不会再赘述。[安装](https://docs.gitea.com/zh-cn/category/installation)
如果你使用**1panel面板**,可直接在应用商店中一键完成安装,作者就就是使用此方式。
>注意:在版本 < `v1.21.0`之前的版本需要在配置文件中开启`actions`功能具体请参考官方文档[配置](https://docs.gitea.com/zh-cn/usage/actions/quickstart),之后的版本则是默认开启
本教程使用的Gitea版本为`v1.22.6` !
## 配置Runner
在Gitea actions中运行Job都是通过Runner来执行的因此我们需要先配置Runner以便于我们后续的部署流程有两种安装方式可直接安装到主机上也可以通过docker容器中这里作者将通过docker安装为避免过多的资源消耗可以将其安装到一个单独的主机中ps对于国内用户可以选择一台香港服务器这样运行job的速度会更快😄), 作者选择的主机就是一台香港的VPS
### 下载act_Runner
首先我们需要下载此工具用来注册或者生成配置[下载地址](https://gitea.com/gitea/act_runner/releases)请在此页面中选择与你的系统对应的版本进行下载下载完成后上传到服务器中这里我是上传到了服务器中的`/gitea_runner2`目录下也可以使用`curl`等工具直接下载, 可直接使用以下命令但注意名称和下载地址我的系统是`Debain12 x86_64`,因此下载的是`act_runner-0.2.11-linux-amd64`
```bash
curl -o act_runner2 https://gitea.com/gitea/act_runner/releases/download/v0.2.11/act_runner-0.2.11-linux-amd64
```
完成后设置下执行权限
```bash
chmod +x act_runner2 # 注意文件名,请根据实际情况修改
./act_runner --version # 看到版本信息就代表成功了
```
### 生成配置
```
./act_runner2 generate-config > config.yaml
```
一般情况下默认的配置就够了如果你有其他的需求请自行修改`config.yaml`
**由于作者选用docker安装的方式所以如果你选用直接在主机安装的方式可以跳过后续的安装步骤参考官方文档进行安装[直接安装](https://docs.gitea.com/zh-cn/usage/actions/quickstart)**
### 注册runner
这里我选择通过`docker-compose.yml`配置的方式进行注册
**注意: 将配置中的参数结合你自己的情况修改,以下配置仅供参考!!!**
```yaml
version: "3.8"
services:
runner:
image: gitea/act_runner:latest
environment:
CONFIG_FILE: /config.yaml
GITEA_INSTANCE_URL: "<your_gitea.com>"
GITEA_RUNNER_REGISTRATION_TOKEN: "<your_registration_token_here>"
GITEA_RUNNER_NAME: "act_vps_runner2"
GITEA_RUNNER_LABELS: "act_vps_runner2"
volumes:
- /gitea_runner2/config.yaml:/config.yaml
- /gitea_runner2/runner_data/data:/data
- /gitea_runner2/runner_data/cache:/root/.cache
- /var/run/docker.sock:/var/run/docker.sock
```
### 配置说明
**GITEA_RUNNER_REGISTRATION_TOKEN** 此参数为注册令牌需要从你的gitea中进行获取一共有三个级别我这里直接选用组织级别的在组织设置页中进行获取如下图所示
![image](https://images.unsplash.com/photo-1633356122102-3fe601e05bd2?q=80&w=1470&auto=format&fit=crop)
其他的实例配置页面及说明请参考官方文档有详细的说明
**如果您无法看到设置页面,请确保您具有正确的权限并且已启用 Actions, 检查Gitea版本 !!!**
### 运行并生成runner
由于作者使用1panel面板因此直接在容器选项中编排即可如果你没有使用此类的可视化工具就需要手动执行``docker-compose up -d``
成功后可查看容器的运行以及日志日志中会显示注册成功的信息如下图所示
![image](https://images.unsplash.com/photo-1607706189992-eae578626c86?q=80&w=1470&auto=format&fit=crop)
然后我们回到你获取runner令牌的页面进行刷新就能看到你的runner了

View File

@@ -0,0 +1,86 @@
---
layout: "@/layouts/BlogPostLayout.astro"
title: "JavaScript中map遍历数字的陷阱"
description: "本文详细解析了JavaScript中[\"1\",\"2\",\"3\"].map(parseInt)返回[1, NaN, NaN]的原因通过分析map和parseInt方法的工作原理揭示了这个常见的JavaScript陷阱。"
date: "2023-09-15"
image: "https://images.unsplash.com/photo-1579468118864-1b9ea3c0db4a?q=80&w=1470&auto=format&fit=crop"
tags: ["JavaScript", "函数式编程", "陷阱"]
tagId: ["javascript", "functional-programming", "trap"]
category: "前端开发"
categoryId: "frontend"
readTime: "3 min read"
---
在JavaScript中有一个经典的问题
```javascript
["1","2","3"].map(parseInt)
```
这段代码的返回值是什么?很多人可能会认为是`[1, 2, 3]`,但实际上是`[1, NaN, NaN]`。为什么会这样呢?让我们一起来分析一下。
### map方法的工作原理
首先,我们需要了解`map`方法的工作原理。`map`方法会为数组中的每个元素调用一次提供的函数,并使用函数的返回值创建一个新数组。
`map`方法的回调函数接受三个参数:
1. `currentValue`:当前正在处理的元素
2. `index`:当前元素的索引
3. `array`:调用`map`方法的数组
所以,当我们执行`["1","2","3"].map(parseInt)`时,实际上是在执行:
```javascript
["1","2","3"].map((item, index, array) => parseInt(item, index, array))
```
### parseInt方法的工作原理
接下来,我们需要了解`parseInt`方法的工作原理。`parseInt`方法解析一个字符串参数,并返回一个指定基数的整数。
`parseInt`方法接受两个参数:
1. `string`:要被解析的值。如果参数不是一个字符串,则将其转换为字符串。字符串开头的空白符将会被忽略。
2. `radix`一个介于2和36之间的整数表示上述字符串的基数。例如指定10表示使用十进制数值系统。始终指定此参数可以消除阅读该代码时的困惑并且保证转换结果可预测。当未指定基数时不同的实现会产生不同的结果通常将值默认为10。
### 分析问题
现在,让我们分析一下`["1","2","3"].map(parseInt)`的执行过程:
1. 对于第一个元素"1"`map`方法调用`parseInt("1", 0, ["1","2","3"])`。由于`radix`为0`parseInt`会根据字符串的前缀来决定基数。如果字符串不以"0x"或"0"开头则基数为10。所以`parseInt("1", 0)`返回1。
2. 对于第二个元素"2"`map`方法调用`parseInt("2", 1, ["1","2","3"])`。由于`radix`为1而有效的`radix`范围是2-36所以`parseInt("2", 1)`返回`NaN`
3. 对于第三个元素"3"`map`方法调用`parseInt("3", 2, ["1","2","3"])`。由于`radix`为2表示二进制而在二进制中只有0和1所以`parseInt("3", 2)`返回`NaN`
因此,`["1","2","3"].map(parseInt)`的返回值是`[1, NaN, NaN]`
### 如何正确使用
如果我们想要将字符串数组转换为数字数组,可以使用以下方法:
```javascript
["1","2","3"].map(Number) // [1, 2, 3]
```
或者使用箭头函数:
```javascript
["1","2","3"].map(item => parseInt(item)) // [1, 2, 3]
```
或者使用`parseInt`的绑定函数:
```javascript
["1","2","3"].map(parseInt.bind(null)) // [1, 2, 3]
```
### 总结
这个问题揭示了JavaScript中函数式编程的一个常见陷阱。当我们使用高阶函数如`map`时,需要注意回调函数的参数和行为。在这个例子中,`parseInt`函数接受的参数与`map`方法提供的参数不完全匹配,导致了意外的结果。
理解这个问题有助于我们更好地理解JavaScript中的函数式编程和类型转换。

View File

@@ -2,6 +2,11 @@
@import "tw-animate-css";
@plugin "@tailwindcss/typography";
@theme {
--typography-code-before-content: "";
--typography-code-after-content: "";
}
/* Blog List Component Styles */
.line-clamp-3 {
display: -webkit-box;