奇怪的知识点
为什么sort((a,b)=>a-b)就是升序?
这是js中基本语法,但我想了解它背后这么定义的原因。网上的很多解释都是a-b<0👉🏻所以a<b👉🏻所以是升序。这对于我来说非常牵强。我想弄懂的是为什么a-b就表示升序?
通过查找资料,我发现这不是a-b在数学上小于0的问题,而是JavaScript引擎如何解释比较函数返回值的约定。
当你在 sort() 中传入一个比较函数时:
javascript
array.sort(compareFunction)
引擎遵循的规则:
- 返回负数:a 应该排在 b 前面(a < b 的含义)
- 返回0:a 和 b 相等,相对位置不变
- 返回正数:a 应该排在 b 后面(a > b 的含义)
这不是数学上的“小于0”,而是引擎定义的语义约定。
关键理解:不是“a-b 小于0所以 a<b”,而是引擎看到负值,就按照约定把 a 放在 b 前面。
除此之外,这种设计源于其他编程语言(如C的qsort)的比较函数传统:
// C语言的qsort比较函数
int compare(const void* a, const void* b) {
return (*(int*)a - *(int*)b);
// 同样:负数表示a<b,正数表示a>b,0表示相等
}
Unicode & ASCII
在做有效的字母异位词时,进阶问题是“如果输入字符串包含 unicode 字符怎么办?”我之前常看到这个,但因为开发场景不常用都忽视了,今天我要弄懂它。
这道算法题其实有很多解法,但归类在哈希表解法中。给出的理由是:对于字母异位词问题,使用哈希表(Map)的通用解法可以很好地处理Unicode字符,因为Map的键可以是任意字符(包括Unicode字符)。而使用数组计数的方法只适用于字符范围有限的情况(如只有小写字母)。
Unicode出现的目的:
- 解决ASCII只能表示英文字符的局限性,使得计算机可以处理多语言文本。
- 统一之前各种互不兼容的字符编码(如中文的GB2312、GBK,日文的Shift-JIS等),避免乱码问题。
| 方面 | ASCII | Unicode |
|---|---|---|
| 出现时间 | 1963年 | 1991年 |
| 设计目标 | 标准化英语字符 | 0x0-0x10FFFF (21位) |
| 编码范围 | 0-127(7位) | 统一全球所有字符 |
| 存储效率 | 固定1字节 | 可变长度(1-4字节) |
| 使用场景 | 纯英文环境 | 国际化多语言 |
作为前端开发,需要知道:
- 永远使用UTF-8:
- 注意字符计数:JavaScript的length属性可能不准确
- 正确处理输入:使用normalize()规范化用户输入
- 设计字体栈:为不同内容提供合适的字体回退
- 测试国际化:在不同语言、不同平台上测试你的应用
算法题中的chartCodeAt()
在字符串相加的题中,通过chartCodeAt()方法,将字符串转化成ASCII,准确来说应该是Unicode(🚩这句话我会在下面解释),以便进行算术运算。算法题中一般不允许用parseInt、Number()转化,因为Number存在大数溢出、parseInt存在丢失精度的问题。
1986年,ASCII的最后一次更新
历史遗留原因,ASCII的设计初衷是实现计算机之间的英文信息交换,总共可以定义128个字符,最后一次更新已经非常成熟。随着计算机全球化,ASCII的局限性越来越明显,如无法表示中文、日文等非拉丁语系的文字。
因此,1991年推出的Unicode被推出,它作为容纳全球所有文字的统一编码标准迅速成为主流。
有趣的的是,🚩Unicode的前128个字符完全兼容ASCII,这意味着ASCII并没有消失,而是以另一种形式在现代计算机中永生了。
由于数字字符 '0' 到 '9' 的编码值是连续递增的('0' 的编码为 48,'1' 为 49,……,'9' 为 57),因此用任意数字字符的编码减去 '0' 的编码,就能得到该字符对应的真实数值('5' 的编码 53 - 48 = 5)
"1"<"2"为什么也可以比?
起因是我在做字符串解码这道题时,发现字符串也可以比较大小,平时工作中并不会这样写。我查了一下,这其实是JS中的字符串比较原理。
字符串比较是按照字典序(lexicographical order)进行比较的,也就是按照字符的Unicode编码逐个比较,而不是数值大小比较。
console.log("1" < "2"); // true
console.log("a" < "b"); // true
console.log("A" < "a"); // true(大写字母编码小于小写字母)
需要注意的陷阱:
// 这些结果可能违反直觉
console.log("10" < "2"); // true(字典序比较)
console.log("11" < "2"); // true
console.log("100" < "2"); // true
// 数字和字符串混合比较
console.log(10 < "2"); // false("2"被转换为数字2)
console.log("10" < 2); // false("10"被转换为数字10)
// 这是因为:当数字和字符串比较时,字符串会被转换为数字
// 但当两个字符串比较时,是按字典序比较
(注意上面提到算法题,不是按照大小比,而是按照编码表去比而已。)