位运算

var a;
奇偶 a&1

取相反数-n = ~(n - 1) = ~n + 1

将n的二进制表示中最右侧的一个1去掉 n & (n - 1)

firebase

in: FirebaseError: ‘IN’ supports up to 10 comparison values.

react

官方文档

Thinking in React : how to build a react app

https://react.dev/learn/thinking-in-react

Step 3: Find the minimal but complete representation of UI state

useEffect:

useEffect通过使用这个 Hook,你可以告诉 React 组件需要在渲染后执行某些操作。

所谓的**“副作用”**,举个通俗一点的例子,假如感冒了本来吃点药就没事了,但是吃了药发现身体过敏了,而这个“过敏”就是副作用。

放到React中,本来只是想渲染DOM展示到页面上,但除了DOM之外还有数据,而这些数据必须从外部的数据源中获取,这个“获取外部数据源”的过程就是副作用。

需要清除的 effect,可以防止引起内存泄露!

如果你的 effect 返回一个函数,React 将会在执行清除操作时调用它:

无参数,组件的初始化和更新都会执行

[]初始化调用一次之后不再执行,相当于componentDidMount

useEffect, useState 用来视图刷新。 不支持 异步

对象和数组是通过引用进行比较的

更新的是组件,

state只要变化,视图就会渲染,而useEffect只是渲染时候做些其他事情

  1. Counter内部状态改变,会使得Counter全都更新,
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
const BigNumber = ({ number }) => (
<div style={{ fontWeight: 700, fontSize: 36 }}>{number}</div>
);
const SomeDecoration = () => <div>Hooray!</div>

const Counter = () => {
const [count, setCount] = useState(0);
const handleButtonClick = useCallback(() => setCount(count => count + 1), []);

return (
<div>
<BigNumber number={count} />
<button onClick={handleButtonClick}>Increment</button>
<SomeDecoration />
</div>
);
};

const App = () => (
<>
<Counter />
<footer>
<a href="https://skk.moe/">Sukka</a>
</footer>
</>
);

01.React.createRef()

React 支持一种非常特殊的属性 Ref ,你可以用来绑定到 render() 输出的任何组件上。

(1)挂载HTML元素,返回真实的DOM
(2)挂载React元素,返回render后的实例对象

React.createRef() 调用后返回一个容器,该容器可以存储被ref标识的节点

  1. 组件式

像这样, 头像样式 到处用,

函数组件中使用

useRef

使用current 属性访问挂载的对象

ref.current 返回null

02. React.Suspense

React.Suspense 是一种虚拟组件(类似于 Fragment,仅用作类型标识)。通常用来包裹住延迟加载组件。

  • 提供 fallback 属性,用来在组件的延迟加载过程中显式某些 React 元素

03. props 和 state

如果下层组件需要使用上层组件的数据或方法,上层组件就可以通过下层组件的 props 属性进行传递,因此 props 是组件对外的接口。组件除了使用上层组件传递的数据外,自身也可能需要维护管理数据,这就是组件对内的接口 state

props 是组件的只读属性,组件内部不能直接修改 props,要想修改 props,只能在该组件的上层组件中修改。在组件状态上移的场景中,父组件正是通过子组件的 props,传递给子组件其所需要的状态。

state 的主要作用是用于组件保存、控制以及修改自己的状态,它只能在 constructor 中初始化,它是组件的私有属性,不可通过外部访问和修改,只能通过组件内部的 this.setState 来修改,修改 state 属性会导致组件的重新渲染。

04. 函数式组件和类组件

下面,是具体的 class 与 Hooks 的生命周期对应关系:

class 组件 Hooks 组件
constructor useState
getDerivedStateFromProps useState 里面 update 函数
shouldComponentUpdate useMemo
render 函数本身
componentDidMount useEffect
componentDidUpdate useEffect
componentWillUnmount useEffect 里面返回的函数
componentDidCatch
getDerivedStateFromError

05. classnames

1.在react中想要动态添加className时,通常会使用classnames这个库。

2.我们可以通过npm安装npm install classnames

2.classnames是一个函数,使用的形式较多,记住常用的使用方法即可:

(1)传入一个对象:classnames({class1:true,class2:false})true表示相应的class生效,反之false表示不生效。

(2)接受多个类名:classnames(class1,class2,{ class3:false })

06. React 组件通信

  • 父组件通过 props 给子组件传参,子组件通过触发父组件提供的回调函数来给父组件传递数据
  • React.Context
  • 自定义事件
  • redux/mobx 之类的状态管理器

状态props提升, 将数据都放置在最近父亲组件

socket.io 在react 中

https://socket.io/how-to/use-with-react

context

  1. 创建context, context是一个存储数据的对象
1
2
import React, { createContext, useState, useContext } from 'react';
const NodeContext = createContext(); // 创建一个新的 Context
  1. 创建provider, 通过provider组件的value 向组件传递数据,向组件暴露state,
1
2
3
4
5
6
7
8
export const NodeProvider = ({ children }) => {
const [nodeUrl, setNodeUrl] = useState('http://localhost:3001'); // 定义共享状态
return (
<NodeContext.Provider value={{ nodeUrl, setNodeUrl }}>
{children} {/* children 是指包含的所有子组件 */}
</NodeContext.Provider>
);
};
  1. 使用context
1
const { nodeUrl, setNodeUrl } = useContext(NodeContext);
  1. (额外) 将其包装为一个自定义hook
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// NodeContext.js
import React, { createContext, useState, useContext } from 'react';
const NodeContext = createContext();
export const useNode = () => useContext(NodeContext); // 自定义钩子,方便使用
export const NodeProvider = ({ children }) => {
const [nodeUrl, setNodeUrl] = useState('http://localhost:3001');

return (
<NodeContext.Provider value={{ nodeUrl, setNodeUrl }}>
{children}
</NodeContext.Provider>
);
};
// 使用
const { nodeUrl, setNodeUrl } = useNode(); // 获取 context 中的值

自定义hook和context联系区别

  1. 使用自定义hook内部状态:
  • 适用于在单个组件中管理状态,不需要共享状态;
  • 适用于状态只需要在自定义hook内部使用的情况,不需要暴露给其他组件;
  • 适用于状态更新只需要在自定义hook内部处理,不需要通知其他组件。
  1. 使用Context共享状态:
  • 适用于需要在多个组件中共享状态的情况;
  • 适用于需要在不同的组件之间传递数据的情况;
  • 适用于需要监听状态变化并及时通知其他组件更新的情况。

问题

1. 在 useEffect、useCallback、useMemo 中获取到的 state、props 为什么是旧值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function Counter() {
const [count, setCount] = useState(0);

useEffect(() => {
const handleClick = function() {
console.log('count: ', count);
}
window.addEventListener('click', handleClick, false)

return () => {
window.removeEventListener('click', handleClick, false)
};
}, []);

return <p onClick={() => setCount(count + 1)}>clicked {count} times</p>;
}

还是上一个例子,如果此时给 useEffect 设置空数组为依赖项,那么无论 count 改变了多少次,点击 window,打印出来的 count 依然是 0

2. useEffect 事件注册的闭包陷阱

1
2
3
4
5
6
7
8
9
useEffect(() => {
AppStore.on("send-msg", ()=>{
console.log("Event: send-msg",chatId)
update(chatId)
})
return () => {
AppStore.off("send-msg", update)
}
}, [])

原因:事件函数获取到的chatId永远是旧的

办法:[chatId]保证是最新值

3.Warning: React has detected a change in the order of Hooks called by DialogDetails. This will lead to bugs and errors if not fixed. For more information, read the Rules of Hooks: https://reactjs.org/link/rules-of-hooks

Previous render Next render

  1. useContext useContext
  2. undefined useState

MUI

mui5的menu anchorEl什么意思?

在mui5中,Menu组件是一个弹出式菜单,它可以在点击一个按钮或一个链接时弹出,然后允许用户从菜单中选择一个选项。

anchorEl是Menu组件中的一个属性,它指定了Menu组件相对于哪个元素进行定位。当用户点击指定的元素时,Menu组件将相对于该元素弹出。

例如,如果你想在一个按钮上创建一个Menu组件,你可以将这个按钮的元素作为anchorEl属性的值。这样当用户点击按钮时,Menu组件将会弹出在按钮的位置上。

进度和问题

  • [x] 刚开始,消息列表没有滑倒底部。:分清数据更新,视图更新流程: 更新数据后useEfffect准确视图

  • [x] 基本聊天刷新已经实现

  • [ ] react子组件异步函数有时候获取不到props值

  • [ ] 数据库速度慢,有时候刚插入,就要获取更新, 数据库还没插进去呢

CSS

word-wrap:属性允许长单词或 URL 地址换行到下一行。

text-overflow:;当文本溢出包含它的元素时,应该如何显示。

white-space属性指定元素内的空白怎样处理。是否环行

flex-grow: 1; 当父元素有剩余空间时,如何占用,默认为0

flex-basis 指定了 flex 元素在主轴方向上的初始大小。

object-fit 属性指定元素的内容应该如何去适应指定容器的高度与宽度。一般可以对这些元素进行保留原始比例的剪切、缩放或者直接进行拉伸等。

user-select 属性规定是否能选取元素的文本。

flex: 1 1 75%; /* 三个值:flex-grow | flex-shrink | flex-basis */

align-self 属性定义flex子项单独在侧轴(纵轴)方向上的对齐方式。

mask:url() 允许使用者通过遮罩或者裁切特定区域的图片的方式来隐藏一个元素的部分或者全部可见区域。

swagger

swagger-ui-express 是一个用于在 Express.js 应用中集成 Swagger UI 的中间件。
Swagger UI 是一个前端界面,根据document生成,使得开发者可以方便地查看和测试 API。
swagger-jsdoc 是document 文档

1
2
3
4
5
6
7
8
9
10
11
12
const express = require('express');
const swaggerUi = require('swagger-ui-express');
const swaggerDocument = require('./swagger.json'); // 你的 Swagger 文档

const app = express();

app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument));

app.listen(3000, () => {
console.log('服务器运行在端口 3000');
});

Nodejs

多线程

worker_threads模块:

如mine挖矿while循环会占用阻塞线程,如果放在主线程,那么就会阻塞其他网络请求异步线程的返回。

  1. 主线程管理
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
const { Worker } = require('worker_threads');

// 创建一个新的 Worker 线程,执行 miner.js 中的代码
const worker = new Worker('./miner.js');

// 接收 Worker 线程发送的消息
worker.on('message', (msg) => {
console.log('Message from worker:', msg);
// 在此处处理挖矿的结果
});

// 监听 Worker 线程的错误事件
worker.on('error', (error) => {
console.error('Worker error:', error);
});

// 监听 Worker 线程的退出事件
worker.on('exit', (code) => {
if (code !== 0) {
console.error(`Worker stopped with exit code ${code}`);
}
});

// 向 Worker 线程发送消息,开始挖矿
worker.postMessage({ start: true });

  1. worker线程
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const { parentPort } = require('worker_threads');

// 接收主线程发送的消息
parentPort.on('message', (message) => {
if (message.start) {
// 挖矿逻辑
let mined = false;
while (!mined) {
// 这里是挖矿逻辑的示例
// 假设我们挖到了一个区块,退出循环
mined = true;

// 向主线程发送挖矿结果
parentPort.postMessage({ mined: true, block: {/* ... block data ... */} });
}
}
});

workerdata基于消息机制通信,所以workerdata都是字符串或者基本类型传输,是浅拷贝,不能传递复杂对象。 可以通过序列化反序列化完成。

parentPort.postMessage({ type: “newBlock”, newBlock }); 可以直接传递对象

websocket

WebSocket 是一种在单个 TCP 连接上进行全双工通信的协议。它被设计为可以在客户端和服务器之间建立一个长时间存在的连接,这样客户端和服务器可以在任何时间相互发送数据,而不需要传统的 HTTP 请求和响应机制。
socket._socket.remoteAddress + ':' + socket._socket.remotePort

启动本地webserver

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
const WebSocket = require('ws');

// 创建 WebSocket 服务器,监听 8080 端口
const wss = new WebSocket.Server({ port: 8080 });

wss.on('connection', function connection(ws) {
console.log('A new client connected');

// 监听客户端发送的消息
ws.on('message', function incoming(message) {
console.log('Received:', message);

// 发送消息给客户端
ws.send('Hello from server');
});

// 连接关闭时触发
ws.on('close', function () {
console.log('Client disconnected');
});

// 发生错误时触发
ws.on('error', function (error) {
console.error('WebSocket error observed:', error);
});

// 发送欢迎消息给客户端
ws.send('Welcome new client!');
});

console.log('WebSocket server is running on ws://localhost:8080');

连接到对端

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
const newPeer = 'ws://localhost:8080';

// 创建一个新的 WebSocket 连接
const socket = new WebSocket(newPeer);

// 当连接打开时触发
socket.addEventListener('open', function (event) {
console.log('WebSocket is connected');
// 发送数据到服务器
socket.send('Hello Server!');
});

// 当接收到服务器数据时触发
socket.addEventListener('message', function (event) {
console.log('Message from server:', event.data);
});

// 当连接关闭时触发
socket.addEventListener('close', function (event) {
console.log('WebSocket is closed now.');
});

// 当发生错误时触发
socket.addEventListener('error', function (event) {
console.error('WebSocket error observed:', event);
});

// 发送消息给服务器
socket.send('Another message to server');

send 和 write 区别

  • sendrecv:更通用,可以在 TCP 和 UDP 套接字中使用,支持额外的标志位。
  • writeread:更常用于流式套接字(如 TCP),在 Node.js 中常用于 TCP 套接字。
    通常使用 writeread(或 data 事件)处理 TCP 套接字,而使用 sendmessage 事件处理 WebSocket。

express

### app.get(‘/blocks’, function (req, res) {})

app.listen([port], [hostname], [backlog], [callback])

返回一个 http.Server 实例。提供各种方法控制服务器。
如server.close

app.use 注册中间件

// 解析 application/json 类型的请求体
app.use(bodyParser.json());

模板引擎:

使用:

  1. 设置
  • views, the directory where the template files are located. Eg: app.set('views', './views'). This defaults to the views directory in the application root directory.
  • view engine, the template engine to use. For example, to use the Pug template engine: app.set('view engine', 'pug').
  1. index.pug
1
2
3
4
5
html
head
title= title
body
h1= message
  1. 渲染
1
2
3
app.get('/', function (req, res) {
res.render('index', { title: 'Hey', message: 'Hello there!' })
})

app.locals

locals 对象中的变量可以在整个应用程序中访问,并且在渲染视图时自动传递给模板引擎。

eg. formatters是自定义的属性变量

1
2
3
app.locals.formatters = { 
uppercase: str => str.toUpperCase(), lowercase: str => str.toLowerCase()
};

fs-extra

socket.io

Websocket 是一种自然的全双工、双向、单套接字连接,解决了 HTTP 协议中不适合于实时通信的问题。

客户端

const io = require(‘socket.io-client’);

io(url[, options])


  • url (字符串)默认的指向widnow.location
  • option (Object)forceNew (布尔型)是否重用当前已存在的链接。
  • Return Socket

密码库

elliptic 库 : 专门用来椭圆算法ECC
crypto库:更加复杂广泛

密钥对生成格式:

  • SPKI:主要用于存储和传输公钥,常用于 X.509 证书等。
  • PKCS8:主要用于存储和传输私钥,可以选择性地加密私钥。

ECDSA:
签名值格式为(r,s), 不同系统库使用不同编码格式表示值,最常见的两种格式是 IEEE P1363(windows web)DER (openssk)

如p-256曲线,r,s均为32字节。
IEEE P1363 和 DER 编码格式的区别:

IEEE P1363 格式

  • 结构rs 被简单地连接在一起,形成一个固定长度的字节串。
  • 长度rs 的每个值都被填充到固定的长度,具体长度取决于椭圆曲线的大小。例如,对于 P-256 曲线,rs 都是 32 字节长(共 64 字节)。
  • 简单性:没有额外的元数据或长度信息,因此非常简单,但缺乏灵活性。

DER 格式

  • 结构:DER(Distinguished Encoding Rules)是一种 ASN.1 编码规范。rs 被编码为两个整数(INTEGER 类型),并通过 SEQUENCE 结构打包在一起。
  • 灵活性:DER 格式灵活地表示整数长度(没有固定的字节数限制),并包括元数据(如类型标识和长度)。
  • 序列化:DER 格式的签名通常比 IEEE P1363 格式稍长,因为它包含了类型和长度信息。

r = 0x1234567890abcdefs = 0xfedcba0987654321

IEEE P1363 格式0000000000000000000000000000000000000000000000001234567890abcdef000000000000000000000000000000000000000000000000fedcba0987654321

der格式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// r 的 DER 编码
02 // INTEGER 类型标识符
08 // r 的长度为 8 字节
1234567890abcdef // r 的值

// s 的 DER 编码
02 // INTEGER 类型标识符
08 // s 的长度为 8 字节
fedcba0987654321 // s 的值

// 完整的 DER 编码签名
30 // SEQUENCE 类型标识符
12 // 总长度为 18 字节
02 08 1234567890abcdef // r 的编码
02 08 fedcba0987654321 // s 的编码

.env

异步

Buffer vs ArrayBuffer

  • 都是用来处理二进制数据的,比如文件读写、网络、加解密。
  • 前者是Nodejs的,后者是标准JS对象。

定时器

场景:while 挖矿占用过高,通过settimeout限制。 但是settimeout是异步的,导致会直接返回undefined

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
function generateNextBlock(data) {
  var timestamp = new Date().toUTCString();
  var hash = "";
  let nouce = 0;
  function whileNounce() {
    hash = Block.caculateHash(
      info.index,
      timestamp,
      data,
      info.previousHash,
      info.difficulty,
      nouce
    );
    if (hasMatchesDifficulty(hash, info.difficulty)) {
      // 外部需要从这里返回的构建
      return new Block(
        info.index,
        timestamp,
        info.difficulty,
        nouce,
        data,
        info.previousHash,
        hash
      );
    } else {
      nouce ++;
      setTimeout(whileNounce, 100) // 防止while占用过高,0.1s while一次
    }
  }
  return whileNounce();

}

解决: 不直接返回。只在符合条件返回。

  1. 回调函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function generateNextBlock(data, callback) {
// 。。。。。。
function whileNounce() {
    if (hasMatchesDifficulty(hash, info.difficulty)) {
      // 外部需要从这里返回的构建
      const newblock = new Block(
        info.index,
        timestamp,
        info.difficulty,
        nouce,
        data,
        info.previousHash,
        hash
      );
      callback(newblock)
    } else {
      nouce ++;
      setTimeout(whileNounce, 100) // 防止while占用过高,0.1s while一次
    }
  }
  whileNounce();
}
  1. Promise异步 (async/await)
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
function generateNextBlock(data) {
return new Promise((resolve, reject) => {
var timestamp = new Date().toUTCString();
var hash = "";
let nonce = 0;

function whileNounce() {
hash = Block.caculateHash(
info.index,
timestamp,
data,
info.previousHash,
info.difficulty,
nonce
);
if (hasMatchesDifficulty(hash, info.difficulty)) {
const newBlock = new Block(
info.index,
timestamp,
info.difficulty,
nonce,
data,
info.previousHash,
hash
);
resolve(newBlock); // 使用 resolve 返回结果
} else {
nonce++;
setTimeout(whileNounce, 100);
}
}

whileNounce();
});
}

// 使用 Promise 处理结果
generateNextBlock(data)
.then(newBlock => {
console.log('生成的区块:', newBlock);
})
.catch(err => {
console.error('挖矿出错:', err);
});

JavaScript

ArrayBuffer:
字节数组
Uint8Array: 无符号数组,

Map

const

const 关键字用于声明一个常量引用,这意味着一旦声明,变量的引用不能被重新赋值。但是,这并不意味着它所引用的对象或数组的内容是不可变的。可以使用 const 来声明类的实例,这个实例的引用不能被改变,但实例本身的属性和方法仍然可以被修改。

数组

a.concat(b) 将当前元素(子数组)合并到累积器 a

[1, 2].concat([3, 4]) 的结果是 [1, 2, 3, 4]

flat() 嵌套数组 扁平化:.

JavaScript 的数组是一种泛型容器,它可以容纳任意类型的对象,但它并不保持对象的构造函数信息或类类型。
类对象放入数组 再拿出来就是Object丢失类型了

1
class Person { constructor(name, age) { this.name = name; this.age = age; } greet() { return `Hello, my name is ${this.name}.`; } }

json只是一种数据格式, 可以表示字符串, 也可以表示js对象

unicode: 符号集,规定了符号对应的二进制。

utf-8:unicode的一种格式,规定unicode二进制的存储 划分方式。

UTF-8 的编码规则很简单,只有二条:

  1. 对于单字节的符号,字节的第一位设为0,后面 7 位为这个符号的码点。因此对于英语字母,UTF-8 编码和 ASCII 编码是相同的。

  2. 对于n字节的符号(n > 1),第一个字节的前n位都设为1,第n + 1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的码点。

bitArray: 32-bit words

toBits():

​ 符号的unicode二进制, 组装为bitArray

partial():

​ 将不足32-bit的,扩充为bitArray

DOM

Element.scrollIntoView()

方法会滚动元素的父容器,使被调用 scrollIntoView() 的元素对用户可见。

类型判断

判断是否是数组:
if (Array.isArray(data)) {
console.error(“Invalid Transactions data”);
return data; // 创世区块不是数组
}

typeof 数组 返回的是object

Array

1
2
3
4
5
6
const ages = [32, 33, 16, 40];
const result = ages.filter(checkAdult);

function checkAdult(age) {
return age >= 18;
}

扩展运算符(…)是ES6的语法,用于取出参数对象的所有可遍历属性,然后拷贝到当前对象之中。

导入导出

exports 用于js
nodejs导入:require、module.exports

JavaScript 和 Node.js有不同的模块系统:

JavaScript(ES6模块)

导出

允许在一个文件定义变量、函数、类,并导出

  1. 命名导出 (Named Export):
    可以导出多个值,每个值有一个名字。
1
2
3
4
5
// myModule.js
export const name = 'Alice';
export function sayHello() {
console.log('Hello');
}
  1. 默认导出 (Default Export):
    一个文件(模块)只能有一个默认导出,常用于导出主要功能或值
1
2
3
// myModule.js
const mainFunction = () => { /* ... */ };
export default mainFunction;

导入

  1. 导入 命名导出:
1
import {name, sayHello} from './module.js'
  1. 导入 默认导出:
1
import mainFunc from './module.js'
  1. 重命名导入 命名导出:
1
import {name as myname, sayhello as hello} from './module.js'

Nodejs(CommanJS模块)

同样的,可以导入导出变量、函数、类

导出

使用module.exports导出, exports只是他的简写

1
2
3
4
5
6
7
module.exports = {
name: 'alice', // 导出变量
hello: ()=>{
console.log('hello')
},
Student, // 导出类
}

module.exports = new EventEmitter(); 单例,只有第一次加载时候创建

导入

使用require导入。

  • 导入整个模块
1
2
3
const mymodule = require('./module.js')
mymodule.name
mymodule.hello()
  • 导入模块一部分
1
const {name,hello} = require('./module.js')

区别

  1. 语法:
  • ES6 模块是语言层级的特性,支持静态分析,能够提前知道依赖关系。
  • CommonJS 模块在运行时解析依赖。

ramda库

时间

在 JavaScript 中,Date 对象提供了多种方法来操作和格式化日期和时间。

  1. toISOString

    • 返回一个 ISO 格式的日期字符串 (UTC 时间)。
    • 格式为:YYYY-MM-DDTHH:mm:ss.sssZ
    1
    2
    const date = new Date();
    console.log(date.toISOString()); // e.g., "2024-07-15T12:34:56.789Z"
  2. toUTCString

    • 返回一个基于世界时(UTC)的字符串表示形式。
    • 这种格式通常用于 HTTP 标头等应用。
    1
    2
    const date = new Date();
    console.log(date.toUTCString()); // e.g., "Mon, 15 Jul 2024 12:34:56 GMT"
  3. toLocaleString

    • 返回一个表示日期的字符串,根据本地时间格式化。
    • 可以接受两个可选参数,用于指定语言和格式化选项。
    1
    2
    3
    const date = new Date();
    console.log(date.toLocaleString()); // e.g., "7/15/2024, 12:34:56 PM"
    console.log(date.toLocaleString('en-GB')); // e.g., "15/07/2024, 12:34:56"
  4. toDateString

    • 返回一个表示日期部分的字符串,不包含时间部分。
    1
    2
    const date = new Date();
    console.log(date.toDateString()); // e.g., "Mon Jul 15 2024"
  5. toTimeString

    • 返回一个表示时间部分的字符串,不包含日期部分。
    1
    2
    const date = new Date();
    console.log(date.toTimeString()); // e.g., "12:34:56 GMT+0000 (Coordinated Universal Time)"
  6. toLocaleDateString

    • 返回一个表示日期部分的字符串,根据本地时间格式化。
    • 可以接受两个可选参数,用于指定语言和格式化选项。
    1
    2
    3
    const date = new Date();
    console.log(date.toLocaleDateString()); // e.g., "7/15/2024"
    console.log(date.toLocaleDateString('en-GB')); // e.g., "15/07/2024"
  7. toLocaleTimeString

    • 返回一个表示时间部分的字符串,根据本地时间格式化。
    • 可以接受两个可选参数,用于指定语言和格式化选项。
    1
    2
    3
    const date = new Date();
    console.log(date.toLocaleTimeString()); // e.g., "12:34:56 PM"
    console.log(date.toLocaleTimeString('en-GB')); // e.g., "12:34:56"
  8. getTime

    • 返回自 1970 年 1 月 1 日 00:00:00 UTC 以来的毫秒数。
    1
    2
    const date = new Date();
    console.log(date.getTime()); // e.g., 1626356096789
  9. getTimezoneOffset

    • 返回当前时间与 UTC 时间的分钟差。
    1
    2
    const date = new Date();
    console.log(date.getTimezoneOffset()); // e.g., -120 (for UTC+2)
  10. Date.now

    • 返回自 1970 年 1 月 1 日 00:00:00 UTC 以来的毫秒数(静态方法)。
    1
    console.log(Date.now());  // e.g., 1626356096789

Promise

Promise 是一种用于处理异步操作的对象。它代表一个在未来某个时间点可能会完成或失败的操作及其结果值。

  1. Promise 构造器函数
  • 主要用于包装不支持 promise(返回值不是 Promise)的函数。
  • setTimeout(()=>{},3000);返回值是定时器的编号。(异步操作)
  • 构造器参数实为一个异步函数,在内部进行异步任务,并且设定promise对象的状态:resolved,reject
  • 构造promise对象时,将参数(异步函数、成功函数、拒绝函数)绑定在promise对象上, 并且执行:异步操作、设定promise状态
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const myFirstPromise = new Promise((resolve, reject) => {
// do something asynchronous which eventually calls either:
//
// resolve(someValue) // fulfilled
// or
// reject("failure reason") // rejected
});

function myAsyncFunction(url) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest()
xhr.open("GET", url)
xhr.onload = () => resolve(xhr.responseText)
xhr.onerror = () => reject(xhr.statusText)
xhr.send()
});
}

2.then()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// using a resolved promise, the 'then' block will be triggered instantly,
// but its handlers will be triggered asynchronously as demonstrated by the console.logs
const resolvedProm = Promise.resolve(33);

let thenProm = resolvedProm.then(value => {
console.log("this gets called after the end of the main stack. the value received and returned is: " + value);
return value;
});
// instantly logging the value of thenProm
console.log(thenProm);

// using setTimeout we can postpone the execution of a function to the moment the stack is empty
setTimeout(() => {
console.log(thenProm);
});


// 上面的代码会依次返回:
// Promise {[[PromiseStatus]]: "pending", [[PromiseValue]]: undefined}
// "this gets called after the end of the main stack. the value received and returned is: 33"
// Promise {[[PromiseStatus]]: "resolved", [[PromiseValue]]: 33}

3.catch()

Promise rejected 时 ,处理

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
// 抛出一个错误,大多数时候将调用 catch 方法
var p1 = new Promise(function(resolve, reject) {
throw 'Uh-oh!';
});

p1.catch(function(e) {
console.log(e); // "Uh-oh!"
});

// 在异步函数中抛出的错误不会被 catch 捕获到
var p2 = new Promise(function(resolve, reject) {
setTimeout(function() {
throw 'Uncaught Exception!';
}, 1000);
});

p2.catch(function(e) {
console.log(e); // 不会执行
});

// 在 resolve() 后面抛出的错误会被忽略
var p3 = new Promise(function(resolve, reject) {
resolve();
throw 'Silenced Exception!';
});

p3.catch(function(e) {
console.log(e); // 不会执行
});

Promise.all()

背景:map里面每个元素都要异步函数返回

1
2
3
4
5
6
7
tx.inputs = tx.inputs.map(async (txin, index) => {
console.log(`sign txin ${index}`)
txin.signature = await MyCrypto.sign(tx.id, privateKey)
console.log(`signed txin ${index} with signature ${txin.signature}`)
return txin;
});

这样写法不正确,每个返回值是promise

Promise.all() 会等待所有这些promise完成,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
async function signTransaction(tx, privateKey) {
// `tx.inputs` 是一个数组,`map` 生成一个包含 Promise 的数组
const signedInputs = await Promise.all(tx.inputs.map(async (txin, index) => {
txin.signature = await MyCrypto.sign(tx.id, privateKey);
return txin;
}));

// 确保所有的签名操作完成,并将结果赋值给 `tx.inputs`
tx.inputs = signedInputs;

// 添加公钥
tx.publicKey = address;

return tx;
}

await等待Promise.all返回结果

1
2
3
4
5
6
7
8
9
10
const promise1 = Promise.resolve(3);
const promise2 = 42;
const promise3 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'foo');
});

Promise.all([promise1, promise2, promise3]).then(values => {
console.log(values); // [3, 42, 'foo']
});

async/await

简化promise写法,async返回值是ProMise,

1
2
3
4
5
6
7
8
9
10
// 创建一个简单的 Promise,2秒后成功
async function asyncFunction() {
try {
const result = await someAsyncOperation();
console.log(result);
} catch (error) {
console.error('Error:', error);
}
}

一旦底层有异步函数async<上面所有调用都是async吗?
取决于你是否需要使用 await 关键字来等待异步操作完成。
如果一个函数中需要等待一个异步操作的完成并获取结果,那么这个函数必须使用 async 声明,并在需要的位置使用 await 关键字。await 只能在 async 函数中使用。

对象原型

  1. prototype 属性的值是一个对象,我们希望被原型链下游的对象继承的属性和方法,都被储存在其中。

而不在prototype中的属性,只能被构造器自身使用。

构造器本身就是函数,你怎么可能在构造器这个函数中定义一个方法呢?

​ 构造器函数也是一个对象类型,

  1. 对象的 __proto__ 属性 = = 父亲的 proptotype属性 ,指向一个对象。 原型对象是一个内部对象,应当使用 __proto__ 访问

原型链找完了, 还没找到属性, 返回undefined.

1
2
3
4
5
6
7
function Person(first, last, age, gender, interests) {

// 属性与方法定义

};
var person1 = new Person('Bob', 'Smith', 32, 'male', ['music', 'skiing']);
person1.valueOf()
  • 浏览器首先检查,person1 对象是否具有可用的 valueOf() 方法。
  • 如果没有,则浏览器检查 person1 对象的原型对象(即 Person构造函数的 prototype 属性所指向的对象)是否具有可用的 valueof() 方法。
  • 如果也没有,则浏览器检查 Person() 构造函数的 prototype 属性所指向的对象的原型对象(即 Object构造函数的 prototype 属性所指向的对象)是否具有可用的 valueOf() 方法。这里有这个方法,于是该方法被调用。
image-20221221131221491

window.subtle.crypto

前端window.crypto
crypto.webcrypto 是nodejs端对浏览器window.crypto实现

在密码学中,密钥的存储和表示有多种格式。这些格式用于定义密钥的结构和编码方式,以便在不同的系统和应用之间传递和使用密钥。以下是关于 rawpkcs8spkijwk 这些密钥格式的详细解释:

1. Raw 格式

  • 描述: raw 格式表示原始的二进制密钥数据,通常是未经过任何编码或包装的形式。
  • 用途: 主要用于对称加密算法的密钥,如 AES 等,因为这些密钥通常是简单的二进制数据。
  • 特征:
    • 简单、直接。
    • 没有元数据(如密钥长度、使用限制等)。

2. PKCS #8 格式

  • 描述: PKCS #8 (Public-Key Cryptography Standards #8) 是一种标准格式,用于存储私钥。它可以存储包括算法标识符在内的私钥信息,并且支持私钥加密保护。
  • 用途: 广泛用于存储私钥,包括 RSA、DSA 和 EC(椭圆曲线)私钥。
  • 特征:
    • 可以选择加密私钥,提供额外的安全层。
    • 一般使用 DER (Distinguished Encoding Rules) 或 PEM (Privacy Enhanced Mail) 编码。PEM 格式通常以 -----BEGIN PRIVATE KEY----- 开头,以 -----END PRIVATE KEY----- 结尾。

3. SPKI (SubjectPublicKeyInfo) 格式

  • 描述: SPKI 格式定义了公钥的结构,包括算法标识符和公钥值。它是 X.509 标准的一部分,用于描述公钥证书中的公钥信息。
  • 用途: 用于存储和传输公钥,特别是在 X.509 证书中。
  • 特征:
    • 包含算法标识符,使得接收方能够识别和使用公钥。
    • 同样可以使用 DER 或 PEM 编码。PEM 格式通常以 -----BEGIN PUBLIC KEY----- 开头,以 -----END PUBLIC KEY----- 结尾。

4. JWK (JSON Web Key) 格式

  • 描述: JWK (JSON Web Key) 是一种 JSON 数据结构,用于表示公钥或私钥。它是 JSON Web 系列标准的一部分,特别适合在现代 web 应用中使用。
  • 用途: 用于传输和存储公钥和私钥,特别是在 RESTful API 和现代 web 应用中。
  • 特征:
    • 基于 JSON 格式,易于人类读取和处理。
    • 支持多个密钥参数,如 kty (密钥类型)、alg (算法)、use (用途)、key_ops (密钥操作) 等。
    • 能够表示对称和非对称密钥,包括 RSA 和 EC 公钥、私钥。

应用场景和选择

  • Raw 格式: 适用于简单的对称密钥使用场景,不需要复杂的密钥管理。
  • PKCS #8: 常用于需要强安全性和私钥管理的场景,如 TLS/SSL 证书和加密邮件。
  • SPKI: 在公钥基础设施 (PKI) 和证书管理系统中非常常见。
  • JWK: 特别适合现代 web 应用,支持易于传输的 JSON 格式,常用于 OAuth 2.0 和 OpenID Connect 等协议。

网站

scrimba: youtube : freecodecamp

codewars

[freecodecamp](#

https://www.freecodecamp.org/learn/javascript-algorithms-and-data-structures/)

架构设计http://www.52im.net/thread-812-1-1.html

https://anran758.github.io/front-end-lab/topic/react.html#react-是单向数据流还是双向数据流-它还有其他特点吗