林间有风

郭朝夕的日记小站

  • 首页
  • 关于
  • 标签
  • 归档

npm的一些知识点

发表于 2023-03-06

npm 内部机制与核心原理

npm 最重要的任务是安装和维护开源库。它会优先安装依赖包到当前的项目目录,使得不同的项目的依赖各成体系,同时还能减轻包作者的 API 兼容性压力,但是这样做的缺陷也很明显:如果项目 A 和项目 B 都依赖相同的公共库 C,那么公共库 C 将会在项目 A 和项目 B 中各被安装一次。这就说明,同一个依赖包可能在电脑上多次安装。

npm 的安装机制

当我们执行npm install命令以后,首先检查 config,获取 npm 配置。这里的优先级为:项目级的.npmrc 文件 > 用户级的.npmrc 文件 > 全局的.npmrc 文件 > npm 内置的.npmrc 文件。

然后检查项目中有无 package-lock.json 文件(简称 lock 文件)

如果有 package-lock.json 文件,那么就检查 package-lock.json 和 package.json 文件中声明的版本是否一致。

  • 一致,直接使用 package-lock.json 中的信息,从缓存或者网络资源中加载资源。

  • 不一致,那么根据 npm 版本进行处理(5.4.2 以上会按照 package.json 安装,并更新 package-lock.json)

如果没有 package-lock.json 文件,那么根据 package.json 文件递归构建依赖树,然后按照构建好的依赖树下载完整的依赖资源,在下载时会检查是否有相关缓存。

  • 有缓存,将内容解压到 node_modules 中。

  • 没有,先从 npm 远程仓库中获取包资源,检查包的完整性,并将其添加到缓存,同时解压到 node_modules 中。

最后生成 package-lock.json 文件。

npm 缓存机制

阅读全文 »

leetcode几道算法题

发表于 2023-03-04

字符串

反转字符串

1
2
3
4
5
6
7
export default (str) => {
let arr = str.split(' ')
let result = arr.map((item) => {
return item.split('').reverse().join()
})
return result.join(' ')
}

344.反转字符串

1
2
3
4
5
6
7
8
9
10
11
// hello
// olleh
export default (str) => {
const n = str.length
let left = 0
let right = n - 1
for (lft, right; left < right; left++, right--) {
;[str[left], str[right]] = [str[right], str[left]]
}
return str
}

541.反转字符串 II

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 输入:s = "abcdefg", k = 2
// 输出:"bacdfeg"

const reverseStr = (s) => {
const n = s.length
const arr = Array.from(s)
for (let i = 0; i < n; i += 2 * k) {
reverse(arr, i, Math.min(i + k, n) - 1)
}
return arr.join('')
}

const reverse = (arr, left, right) => {
while (left < right) {
const temp = arr[left]
arr[left] = arr[right]
arr[right] = temp
left++
right--
}
}
阅读全文 »

js的错误处理与调试

发表于 2023-03-03

错误处理在编程中的重要性毋庸置疑。所有主流 Web 应用程序都需要定义完善的错误处理协议,大多数优秀的应用程序都有自己的错误处理策略,尽管主要逻辑是放在服务端的。事实上,服务器团队通常会花很多精力根据错误类型、频率和其他重要指标来定义规范的错误日志机制。最终实现通过简单的数据库查询就可以了解应用程序的运行状态。

try/catch

try/catch 语句,作为在 js 中处理异常的一种方式。基本语法如下所示:

1
2
3
4
5
try {
// 可能出错的代码
} catch (error) {
// 出错时要做什么
}

任何可能出错的代码都应放到 try 块中,而处理错误的代码则放在 catch 块中,如下所示:

1
2
3
4
5
try {
window.someNonexistenFunction()
} catch (error) {
console.log('An error happened')
}

错误对象中暴露的实际信息因浏览器而异,但是至少包含保存错误消息的 message 属性,所以可以像下面的代码这样必要时显示错误消息:

1
2
3
4
5
try {
window.someNonexistenFunction()
} catch (error) {
console.log(error.message)
}

finally 子句

1
2
3
4
5
6
7
8
9
function testFinally() {
try {
return 2
} catch (error) {
return 1
} finally {
return 0
}
}

finally 块的存在会导致 try 块中的 return 语句被忽略,因此无论什么时候调用该函数都会返回 0。如果去掉了 finally 子句,那么该函数会返回 2.如果写出了 finally 子句,那么 catch 块就变成了可选的。

finally 子句会让 try 块或者 catch 块中的 return 语句被忽略。

阅读全文 »

如何提交一个pr

发表于 2023-03-02

选定一个开源库

找到你想要提 pr 的开源仓库,然后将它 fork 到你的仓库,如图所示:
fork一个开源库

在本地修改

阅读全文 »

开发一个eslint插件

发表于 2023-03-02

先创建一个 eslint 插件使用的空项目,ESlint 推荐使用的是Yeoman Generator,首先我们来全局安装一下 Yeoman,安装命令如下:

1
npm install -g yo

Yeoman是一款通用的初始化工具,想要初始化 ESlint 插件,我们还要安装 ESlint 模板,安装命令如下:

1
npm install -g generator-eslint

接下来,我们新建一个目录,命令如下:

阅读全文 »

发布一个vscode插件

发表于 2023-03-01

安装依赖

1
2
3
4
5
6
7
8
// 全局安装
npm install -g yo generator-code

// 初始化
yo code

// 打开代码文件夹
open with code

插件市场注册账户

阅读全文 »

不同模块的功能描述和配置表

发表于 2023-02-22
模块 功能描述 关联配置
root 公共文件 name, npmname, username
build 构建类,包含 rollup.js 和 Babel name, test.mocha
prettier 格式化 prettier
eslint ESlint 配置 eslint, prettier
commitlint 提交信息检验 commitlint.commitlint, commitlint.standard-version
test 单元测试类,包含 Mocha 和 nyc test.mocha, test.puppeteername
husky Git hook 检验 husky, eslint, commitlint.commitlint
ci 持续集成,包含 Github Actions ci, commitlint.commitlint

pinia入门教程

发表于 2023-02-22

安装

1
npm i pinia

定义 store

1
2
3
4
5
6
7
8
9
10
11
12
13
// src/store/index.js
import { defineStore } from 'pinia'

export const mainStore = defineStore('main', {
state: () => {
return {
count: 0,
msg: 'hello world',
}
},
getters: {},
actions: {},
})

使用 pinia

1
2
3
4
// src/main.js
import { createPinia } from 'pinia'
const pinia = createPinia()
app.use(pinia)

在页面中使用 store

1
2
3
4
5
6
7
8
<template>
<div>{{store.count}}</div>
</template>

<script setup>
import { mainStore } from '../store/index'
const store = mainStore()
</script>

解构 Store

1
2
3
4
5
6
7
8
9
10
11
12
13
<template>
<div>{{store.count}}</div>
<br />
<h2>使用storeToRefs来解构store</h2>
<div>{{count}}</div>
</template>

<script setup>
import { mainStore } from '../store/index'
import { storeToRefs } from 'pinia'
const store = mainStore()
const { count } = storeToRefs(store)
</script>

修改 Pinia 数据状态

简单数据修改

简单数据直接通过在方法中操作store.属性名来修改

1
2
3
4
5
6
7
8
9
10
11
12
13
<template>
<div>{{store.count}}</div>
<button @click="handleClick">简单数据修改</button>
</template>

<script setup>
import { mainStore } from '../store/index'
const store = mainStore()

const handleClick = () => {
store.count++
}
</script>

多条数据修改

通过store.属性名的方式逐行修改是可以的,但是 pinia 官网推荐使用$patch来修改多条数据。

$patch接受两个类型的参数,分别为对象和函数

  1. $patch + 对象
  2. $patch + 函数:通过函数方式去使用的时候,函数接受一个 state 的参数,state 就是 store 仓库中的 state
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<template>
<div>{{store.count}}</div>
<div>{{store.msg}}</div>
<button @click="onObjUpdate">简单数据修改</button>
<button @click="onFuncUpdate">简单数据修改</button>
</template>

<script setup>
import { mainStore } from '../store/index'
const store = mainStore()

const onObjUpdate = () => {
store.$patch({
count: state.count + 2,
msg: state.msg === 'hello world' ? 'hello guozhaoxi' : 'hello world',
})
}

const onFuncUpdate = () => {
store.$patch((state) => {
;(state.count = state.count + 2),
(state.msg =
state.msg === 'hello world' ? 'hello guozhaoxi' : 'hello world')
})
}
</script>

通过 action 修改数据

在 store.actions 中添加一个changeState方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import { defineStore } from 'pinia'

export const mainStore = defineStore('main', {
state: () => {
return {
msg: 'hello world',
count: 0,
}
},
getters: {},
actions: {
changeState() {
this.count++
this.msg = this.msg === 'hello world' ? 'hello guozhaoxi' : 'hello world'
},
},
})

在组件中使用store.方法名的方式调用该方法

1
2
3
4
5
6
7
8
9
10
11
12
<template>
<button @click="handleClick">actions修改多个状态</button>
</template>

<script setup>
import { mainStore } from '../store/index'
const store = mainStore()

const handleClick = () => {
store.changeState()
}
</script>

Pinia 中的 getters

Pinia 中的 getter 和 Vue 中的计算属性几乎一样,在获取 State 值之前做一些逻辑处理。

  1. getter 中的值有缓存特性,如果值没有改变,多次使用也只会调用一次

添加 getter 方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import { defineStore } from 'pinia'

export const mainStore = defineStore('main', {
state: () => {
return {
msg: 'hello world',
count: 0,
}
},
getters: {
getCountBuff(state) {
console.log('getter被调用')
return `${state.count}***${state.count}`
},
},
actions: {
changeState() {
this.count++
},
},
})

组件内多次调用 getter

1
2
3
4
5
6
7
8
<template>
<h2>getter 获取数据</h2>
<p>{{ store.getCountBuff }}</p>
<p>{{ store.getCountBuff }}</p>
<p>{{ store.getCountBuff }}</p>
<p>{{ store.getCountBuff }}</p>
<p>{{ store.getCountBuff }}</p>
</template>

打开浏览器控制台我们发现,多次调用同一个 getter 函数的时候,只会执行一次,说明 getter 是具有缓存性的。

  1. getter 中不仅可以传递 state直接改变数据状态,还可以使用 this 来改变数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
mport { defineStore } from 'pinia'

export const mainStore = defineStore('main', {
state: () => {
return {
msg: 'hello world',
count: 0,
}
},
getters: {
getMsgWithThis(state) {
return `${this.msg}***${this.msg}`
},
},
actions: {
changeState() {
this.count++
},
},
})

store 之间的相互调用

我们定义一个新的 store

1
2
3
4
5
6
7
8
9
10
11
import { defineStore } from 'pinia'

export const bookStore = defineStore('book', {
state: () => {
return {
books: ['语文', '数学', '英语'],
}
},
getters: {},
actions: {},
})

在mainStore中引入使用我们上面刚刚定义好的bookStore

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import { defineStore } from 'pinia'
import { bookStore } from './book'

export const mainStore = defineStore('main', {
state: () => {
return {
msg: 'hello world 123',
count: 0,
}
},
getters: {
getCountBuff(state) {
console.log('getter被调用')
return `${state.count}***${state.count}`
},
getBooks() {
return bookStore().books
},
},
actions: {
changeState() {
this.count++
},
},
})

在组件中使用

1
2
3
4
5
6
7
8
9
<template>
<h2>获取另一个store中的数据</h2>
<p>{{ store.getBooks }}</p>
</template>

<script>
import { mainStore } from '../store/index'
const store = mainStore()
</script>

抽象一个参数扩展库

发表于 2023-02-21
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import { type } from '@jslib-book/type'
import { clone } from '@jslib-book/clone'

function hasOwnProp(obj, key) {
return Object.prototype.hasOwnProperty.call(obj, key)
}

export function extend(defaultOpt, customOpt) {
defaultOpt = clone(defaultOpt) // 拷贝一份defaultOpt,隔离数据

for (let name in customOpt) {
const src = defaultOpt[name]
const copy = customOpt[name]

// 非可枚举属性 直接停止
if (!hasOwnProp(customOpt, name)) {
continue
}

if (copy && type(copy) === 'object') {
// 如果default上不存在值时,会自动创建空对象
const clone = src && type(src) === 'object' ? src : {}
// 递归合并
defaultOpt[name] = extend(clone, copy)
} else if (typeof copy !== 'undefined'){
// 非对象类型且值不为undefined的时候
defaultOpt[name] = copy
}
}
return defaultOpt
}

抽象一个严格相等库

发表于 2023-02-21
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
import { type } from '@jslib-book/type'

function equalArray(value, other, enhancer) {
// 如果两个数组的长度不相等 那么直接返回false
if (value.length !== other.length) {
return false
}

// 遍历数组的每一项,进行比较,如果不相等返回false
for (let i = 0; i < value.length; i++) {
if (!isEqual(value[i], other[i], enhancer)) {
return false
}
}

// 默认返回true
return true
}

function equalObject(value, other, enhancer) {
// 拿到两个对象的Keys
const vKeys = Object.keys(value)
const oKeys = Object.keys(other)

// 如果两者keys数组的长度不一样 也没有比较的必要了
if (vKeys.length !== oKeys.length) {
return false
}

// 循环遍历两个对象的值
for (let i = 0; i < vKeys.length; i++) {
const v = value(vKeys[i])
const o = other[oKeys[i]]
// 如果两个对象的值不相等,那么返回false
if (!isEqual(v, o, enhancer)) {
return false
}
}

// 默认返回true
return true
}

export function isEqual(value, other, enhancer) {
const next = () => {
// 如果相等,返回true
if (value === other) {
return true
}

// 拿到两个参数的type值
const vType = type(value)
const oType = type(other)

// 类型不同
if (vType !== oType) {
return false
}

// 如果是数组类型就按照数组判断的逻辑往下进行
if (vType === 'array') {
return equalArray(value, other, enhancer)
}
// 如果是对象类型就按照对象判断的逻辑往下进行
if (vType === 'object') {
return equalObject(value, other, enhancer)
}
// 比较两者是否相等并返回结果
return value === other
}

if (type(enhancer) === 'function') {
return enhancer(next)(value, other)
}

return next()

}
上一页1…567下一页

62 日志
19 标签
© 2025 郭朝夕
冀ICP备18008237号