0%

总览

  • C++ 根据在捕获列表中标注的方式进行捕获。
  • Java 按照值捕获(而且 Java 在某些情况下还要求显式的 final 修饰符)。
  • JavaScript:见 JavaScript 捕获
    • 注意:捕获和传值是不同的!例如:JavaScript 在函数参数传递时仍然时按照值传递。
  • Python/Go 按照引用捕获,for 循环不会创造新的作用域。

JavaScript 捕获

看上去是引用捕获,但是 for 循环的 let 和 const 绑定会创造新的作用域。

function generateSquaringFunctions() {
    const funcList = [];
    const values = [1, 2, 3];
    for (var i of values) {
    //   ^^^
    // var:       [9, 9, 9]
    // let/const: [1, 4, 9]
        const square = function () {
            return i * i;
        };
        funcList.push(square);
    }
    return funcList;
}

const [square1, square2, square3] = generateSquaringFunctions();
console.log(square1(), square2(), square3());

可以参考 Javascript’s Hoisting(变量提升、函数提升、类提升)

其他测试:

首先检查 /etc/wsl.conf 配置,如果设置了不追加 Windows 的 PATH,则需要自己额外添加 VS Code 的命令目录到 WSL 中。

# /etc/wsl.conf
[boot]
systemd=true

[interop]
appendWindowsPath=false
# ~/.bashrc 或者其他配置文件
export PATH="/mnt/c/Users/xxx/AppData/Local/Programs/Microsoft VS Code/bin:$PATH"

如果报错:

/mnt/c/Users/xxx/AppData/Local/Programs/Microsoft VS Code/bin/code: 61: /mnt/c/Users/xxx/AppData/Local/Programs/Microsoft VS Code/Code.exe: Exec format error

{...a, ...b} 相当于 Object.assign({}, a, b)Object.assign 还能给已经存在的对象赋值,而且会触发 setter。Spread operator 是在创建对象,不会触发 setter。

[...a, ...b] 相当于 a.concat(b)

Spread operator 的结果是浅拷贝,如果要深拷贝可以用 structuredClone。它能作用于数组字面量却不能作用于对象字面量,必须通过一个额外的变量来完成。(毕竟支持字面量的 spread 没有意义。)

一个非原生数组的对象想要在数组中展开,必须实现 Iterable 接口。

Iterable

Symbol.iterator 是个特殊的键,属于 Iterator 规范的一部分。实现了 Iterable 接口的对象是可以用 spread operator 迭代的。

ArrayLike

length 属性,且在 [0, length) 范围内都可以访问的对象被称为 ArrayLike 的对象。ArrayLike 的对象可以使用诸如 Array.prototype.slice.call(obj, 2) 的方式来作为 Array 调用。

Array.from 既对 ArrayLike 有效,也对 Iterable 对象有效。

Array 系列方法,比如 map/filter/forEach

需要先转换成 Array。

  • Array.prototype.slice.call:适用于 ArrayLike,可行时效率最高。
  • Array.from:适用于 ArrayLike 和 Iterable。
  • [...obj]:适用于 Iterable。

删除重复行

可以用 awk '!x[$0]++'

$ cat text
aaaa
bb
bb
aaaa
c
$ awk '!x[$0]++' text
aaaa
bb
c

git-config

https://git-scm.com/docs/git-config#_configuration_file

git config --global --edit 能在命令行打开全局的配置文件,即 %userprofile%\.gitconfig~/.gitconfig 文件。

如果想要更换编辑器比如用 VS Code 编辑,可以用 EDITOR=code git config --global --edit

配置文件的格式:

  1. 空白字符都被忽略(无论是 \t 还是空格都可以)
  2. 注释的开头可以是 #;

内存不足时:

  1. 首先由 kswapd 尝试交换页面。
  2. 如果内存仍然不够,系统用 通知应用程序内存不足,希望应用主动减少内存使用。
  3. 如果内存仍然不够,使用 LMK 按照一定的优先级杀死应用。

交换

kswapd 负责在内存不足时交换内存页面。zram 和 swap file 都是交换区的实现。狭义的交换指的是 disk swap。

Android 一般厂商都是开 zram,但不开 swap file,原因是 swap file 在闪存上,读取慢,而且移动设备的闪存寿命比电脑硬盘少。在 MIUI 13 的小米 12s Pro(12G)上,zram 的大小是 6G。据说 MIUI 14 的 12G 小米机型用的 zram 是 8G。我还在酷安看到了很多 16G 小米机型使用 14G zram 的例子。

占用方式上,zram 是动态增长的,并不是一开机就占满设定的大小。swap file 虽然是要在开启前就固定大小,但由于其在文件系统上,也可以轻易地删除和重新创建。Android 厂商鼓吹的内存融合很可能就是 swap file

Function hoisting

const callerArrow = () => {
    return callee(); // 刚定义这个函数时,callee 的状态是:defined but uninitialized
                     // 只要 callee 在调用这个函数之前初始化了就没有问题
};

// callee(); // 见不到定义,调用会出错

const callee = () => {
    console.log("Hello from callee!")
};

callerArrow(); // callee 的定义出现了,可以调用

calleeRegular();
function calleeRegular() {
    console.log("Hello from calleeRegular!")
}

在同一个词法定义域中的所有声明都是能被看见的。但如果声明是函数,则还能支持直接(向后)调用,即函数提升规则。如果是箭头函数,则只能引用,不能调用。

为什么箭头函数和普通函数有这样的区别?因为箭头函数没有用到 function 关键字,是按照变量的方式来定义的,遵循的是变量提升规则。

Variable hoisting

console.log(a)
a = 1

尝试修改第二行:

写在前面

现在是 2024 年 4 月 17 日,Clash 源码(包括内核和 Clash for Windows,即 CFW)已经没了,clash.wiki 仍然能访问,并且里面有一些下载资源。虽然 Clash 现在不支持新协议了,也不继续维护了,但是它的一系列客户端实在是太好用了……

以下配置都是按照 Clash for Windows 说明,不讨论其他 Clash 变体。

使用 IPv6 上网

去年有一段时间和现在,实验室出现了一种非常诡异的现象:不打开 Clash 时能够正常上网(国内),打开 Clash 的系统代理之后不能正常上网,无论是国内国外都无法访问!最近发现是实验室无法使用 IPv4 访问校外网络。验证方法:ping IPv4 和 IPv6 的公共 DNS 服务器(Google 的可以,阿里云的也可以),发现 IPv4 不通,但是 IPv6 通。

附上 Google 的公共 DNS 服务器地址:

8.8.8.8
8.8.4.4
2001:4860:4860::8888
2001:4860:4860::8844

<a> 中加上 style="pointer-events: none;" 会使得标签本身不能点击,但是其子元素可以点击。而在 <div> 中加同样的样式,会使得标签本身和子元素都不能点击。

其他元素基本上都是只禁用本身,只有 <div> 元素会将子元素也禁用。

如果想要将子元素的鼠标事件开启,需要加上 style="pointer-events: auto;"