• parseInt

    parseInt永远将输入解析为字符串

    parseInt({toString: () => 2, valueOf: () => 1}); // -> 2
    Number({toString: () => 2, valueOf: () => 1}); // -> 1
    

    一个常见的栗子

    parseInt("apple"); // -> NaN
    parseInt("apple", 16); // -> 10
    

    上面这个例子是因为parseInt会一个个解析字符直到解析不了,所以解析十六进制中的a为10作为结果返回。

    parseInt Infinity

    parseInt("Infinity", 10); // -> NaN
    // ...
    parseInt("Infinity", 18); // -> NaN...
    parseInt("Infinity", 19); // -> 18
    // ...
    parseInt("Infinity", 23); // -> 18...
    parseInt("Infinity", 24); // -> 151176378
    // ...
    parseInt("Infinity", 29); // -> 385849803
    parseInt("Infinity", 30); // -> 13693557269
    // ...
    parseInt("Infinity", 34); // -> 28872273981
    parseInt("Infinity", 35); // -> 1201203301724
    parseInt("Infinity", 36); // -> 1461559270678...
    parseInt("Infinity", 37); // -> NaN
    

    parseInt null

    parseInt(null, 24); // -> 23
    

    上面的结果都是一样的解析过程,按字母表排序,每个字符对应数字是固定的。比如,I对应18,在18进制中只能解析0-17,所以parseInt("Infinity", 18); // -> NaN,在19进制中就能解析出结果:parseInt("Infinity", 19); // -> 18

    n对应23,在23进制中解析不了,只返回18,在24进制中就是18 * (24 ^ 5) + 23 * (24 ^ 4)+ 15 * (24 ^ 3)+ 18 * (24 ^ 2) + 23 * 24 + 18 = 151176378,其他依此类推。

    八进制

    parseInt("08"); // -> 8, 支持ES5
    parseInt("08"); // -> 0, 不支持ES5
    

    以0开头的数字可以被解析为10进制或8进制,ECMAScript 5规定为10进制,但不是所有浏览器都支持它。所以使用parseInt时指定进制是好习惯,有时可以避免不必要的bug。

    浮点数

    parseInt(0.000001); // -> 0
    parseInt(0.0000001); // -> 1
    parseInt(1/1999999); // -> 5
    

    parseInt 接受一个字符串参数并返回一个指定基数的整数。 parseInt 还会去除字符串参数中第一个非数字之后的任何内容。0.000001转换为字符串后是"0.000001",0.0000001转换后是"1e-7",所以返回1,1/1999999转换后是5.00000250000125e-7,返回结果是5。


  • 本地开发debug npm包

    使用pnpm包管理

    1. 在本地npm包目录下执行

    pnpm link --global

    2. 如果是cli,可直接在其他项目目录下调用

    3. 如果需要在其他项目中引入npm包,在其他项目目录下执行

    pnpm link --global npm-package-name

    使用npm包管理

    1. 在npm包目录下执行

    npm link

    2. 在其他目录使用

    npm link 本地npm包绝对路径

    官方文档:https://docs.npmjs.com/cli/v9/commands/npm-link


  • async/await class constructor

    背景:期望在新建类时调后台接口对类进行配置,配置成功后才可以执行其他操作。

    尝试封装类的构造函数为async/await,报错

    Class constructor may not be an async method

    原因:async函数返回值为promise,而构造函数返回值为object,同一个函数不可能返回值同时为promiseobject

    解决:参考 jQuery's ready()方法

    1. 类实现

        class myClass {
            constructor () {
    
            }
    
            async ready (callback) {
                await yourHttpRequest();
                // 回调函数绑定作用域
                callback.bind(this)();
            }
        }

    2. 调用

        const myObj = new myClass();
        myObj.ready(function() {
            // 保证配置完才能执行其他操作
        });
    

    参考:https://stackoverflow.com/questions/43431550/async-await-class-constructor


  • 创建 Docker Buildx 多架构构建节点

    前置条件

    1 台 linux/amd64 的机器 A,1 台 linux/arm64 的机器 B。A 可以通过密钥对直接 SSH 连接 B。

    实施

    在 A 执行命令以创建名为 multiarch 的构建实例,并将本机加入该实例:

    docker buildx create --name multiarch --driver docker-container --config /etc/buildkitd.toml --node amd64 --platform=linux/amd64

    在 A 执行命令以将 B 加入该构建实例:

    docker buildx create --append --name multiarch --driver docker-container --config /etc/buildkitd.toml --node aarch64 --platform=linux/arm64 ssh://<user>@<ip>:<port>

    启动该构建实例:

    docker buildx inspect --bootstrap --builder multiarch

    上述命令会在两个机器上都启动一个容器,并且输出构建节点的信息。

    可以随时通过下面的命令来查看本机上的构建实例:

    docker buildx ls

    如果上面创建的 multiarch 构建实例不是默认被使用的,可以通过该命令进行修改:

    docker buildx use --default --builder multiarch

    buildkitd 配置文件

    上述命令中提及的 /etc/buildkitd.toml 可用于指定 Registry Mirrors,例如:

    debug = true
    [registry."docker.io"]
      mirrors = ["mirror.gcr.io"]

    其它具体配置项请参阅官方文档,见引用。

    测试

    可以任意编写一个 Dockerfile,然后执行命令进行构建测试:

    docker buildx build -t <image-tag> --platform=linux/arm64 --load .

    引用

    How to Rapidly Build Multi-Architecture Images with Buildx | Docker

    Configure BuildKit

    docker buildx


  • 使用代理工具 Burp Suite 或 whistle 移除 HSTS 响应头

    在某些时候,例如出于某些环境调试目的,可能需要阻止服务端响应 HSTS 头(Strict-Transport-Security),此时可以使用代理工具将该响应头移除。请注意,不正确的配置可能会影响正常访问网站的安全性,请务必在必要时启用如下功能或特性,或使用独立的开发者版本浏览器。

    如果使用 Burp Suite,则可以直接使用内置规则:

    如果使用 whistle,则可以增加一条规则,这里以要匹配的站点为 xie.sh.cn 进行举例:

    xie.sh.cn delete://res.headers.strict-transport-security

    移除已经被浏览器记住的安全策略

    如果浏览器已经记住了服务端下发的 HSTS 响应头,则需要先将其删除。以 Chrome 浏览器为例,可以访问 chrome://net-internals/#hsts,然后进行查询或删除。部分 HSTS 响应头会使用 includeSubDomains 来包含子域,删除无效时可以留意一下。

    如果浏览器试图升级 HTTPS 连接

    某些情况下,即使后端没有发送 HSTS 响应头,浏览器也可能试图同时发送 HTTP 和 HTTPS 请求来升级连接,此时可以考虑访问 chrome://flags/#https-upgrades,然后将其禁用。

    引用

    delete · GitBook (wproxy.org)


  • Linux 不重启验证 /etc/fstab

    直接终端执行:

    sudo findmnt --verify --verbose

    这个工具应该是属于 util-linux,正常情况下都不需要额外进行安装操作。

    引用

    fedora – How do you validate fstab without rebooting? – Server Fault


  • Vue 3 TypeScript项目报错类型{}不存在属性

    搜了一下tsconfig.json文件需要配置"jsx": "preserve",但我的config文件原先就有这个配置。因为项目一开始是可以正常报错的,迁移到大仓后就有问题了。中间也考虑了是否是配置文件位置的问题,调整了位置也没有解决问题。

    最后看到tsconfig.json文件另一个报错“找不到node的类型定义文件”

    原因是我没有安装@types/node,装上后重新打开IDE”类型{}不存在属性“和“找不到node的类型定义文件”报错都没有了。

    // npm
    npm i @types/node --save-dev
    
    // pnpm
    pnpm add @types/node


  • 【Rust】Hello World

    创建main.rs文件来编写一个将文本打印到屏幕上的小程序Hello, world!

    fn main() {
        println!("Hello, world!");
    }

    Rust 文件总是以 .rs 扩展名结尾。如果在文件名中使用多个单词,惯例是使用下划线将它们分开。例如,使用hello_world.rs而不是helloworld.rs。

    编译和运行

    Linux或macOS

    rustc main.rs
    ./main
    编译
    编译成功后,Rust 输出二进制可执行文件
    运行

    Windows

    rustc main.rs

    .\main.exe

    编译后,使用 Windows 上的 PowerShell执行 ls 或者 使用 CMD 时执行

     dir /B %= the /B option says to only show the file names =%

    都可以看到三个文件:

    main.exe
    main.pdb
    main.rs

    扩展名为.rs的源代码文件、可执行文件(在 Windows 上为main.exe,但在所有其他平台上为main),以及使用 Windows 时包含调试信息且扩展名为.pdb的文件。

    程序剖析

    函数main始终是每个可执行 Rust 程序中运行的第一段代码。

    1. 函数体包裹在{}。Rust 要求所有函数体都用大括号括起来。
    2. Rust 风格是用四个空格缩进,而不是制表符。
    3. 使用 a!意味着您正在调用宏而不是普通函数,并且宏并不总是遵循与函数相同的规则。上面代码中println!调用 Rust 宏,如果它调用了一个函数,输入为println(不带!)
    4. 分号结束一行,表示表达式已结束

    编译和运行是分开的步骤

    Rust 是一种提前编译语言,这意味着可以编译一个程序并将可执行文件提供给其他人,他们可以在没有安装 Rust 的情况下运行它。

    如果给别人一个.rb.py.js文件,他们需要安装 Ruby、Python 或 JavaScript 实现(分别)。但是在这些语言中,只需要一个命令来编译和运行程序。一切都是语言设计的权衡。


  • OPPO K9 智能电视开启 HDMI 增强模式以使用 4K@60Hz

    问题描述

    最近把电脑接到电视(OPPO K9 55寸)上使用,发现设置 4K 分辨率会有显著卡顿。在 Windows 显示设置中发现,只有 1920*1080@60Hz、3840*2160@30Hz、4096*2160@24Hz 可选,显卡是 RTX3060,按理说不该有问题。OPPO官网也写了该电视支持 4K@60Hz。尝试更换 HDMI 线缆后问题依旧没有解决。

    解决方案

    看起来可能是协商成 HDMI 1.4 了,所以无法设置高分辨率和高刷新率。一番尝试后,在电视设置中找到了相关选项:在 HDMI 信号源显示的时候,按下遥控器菜单键,将信号格式变更为“增强”即可解决问题。修改后,就能使用 3840*2160@60Hz 了。如下图所示。

    信号格式选择“标准”,此时最高仅能选择 3840*2160@30Hz
    信号格式选择“增强”,此时最高可以选择 3840*2160@60Hz

    信号格式默认是“自动”,但我这里不清楚为什么自动模式却不能自动使用 4K@60Hz,需要手动设置为“增强”才可以正常使用。

    附:上面的截图通过 OPPO 电视助手 App 连接电视后截取。

    最后的碎碎念

    其实我本来都不想水这篇文章的,主要还是到处都搜不到详细的用户手册,官网只有制作精良的产品详情彩页和不那么详细的技术参数。客服这个点也下班了,只有机器人在那里回复:“亲,支持4K,支持60Hz的”。自己折腾半天发现那个“自动”并没有那么智能,实在是非常恼火。

    我还发现了什么

    NGA 上面也有一样遭遇的网友,可以自行移步观看。https://ngabbs.com/read.php?tid=33153215


  • Linksys MX4200 子节点手动升级固件

    本文假设两个 Linksys MX4200 组成局域网,主节点 IP 为 192.168.1.1,子节点 IP 为 192.168.1.2。

    问题

    发现组网之后,子节点在 App 或是网页版管理页面均无法升级固件,直接浏览器访问子节点 IP 试图请求管理页面会直接被重定向回主节点的管理页面。

    解决方案

    浏览器先访问主节点的管理页面,登录之后,点按右下角的“CA”进入高级设置,此时将浏览器地址栏中的 URL 的 IP(192.168.1.1)修改为子节点的 IP(192.168.1.2),此时可以正常登录子节点的管理页面。不过这个时候还不会显示本地上传固件升级,点按右下角的“CA”,再次点开连接选项卡即可手动上传固件升级。