xxleyi / learning_list

聚集自己的学习笔记
10 stars 3 forks source link

String Interning in JS #264

Open xxleyi opened 3 years ago

xxleyi commented 3 years ago

JS 中对象无处不在,对象的取值是如何做到高效率的呢?如果按照正常的 hash 实现,在取某个 key 对象的 value 时,总免不了涉及到字符串的判等操作。常规意义上,字符串判等的复杂度是 o(min(m, n))。但对于异常频繁的对象取值来说,o(n) 的复杂度能容忍吗?换句话说:它还有没有优化空间?

答案是有的,就是使用 string interning 技术。

下面来演示一下:

let n = 1e7
let a = Array(n).fill('a').join('')
let b = Array(n).fill('a').join('')
let c = a.slice()

// 字符串判等 case 1
console.time('s1')
a == b
console.timeEnd('s1')

// 字符串判等 case 2
console.time('s2')
a == c
console.timeEnd('s2')
// s1: 6.43701171875 ms
// s2: 0.003173828125 ms

在我的 Mac 电脑上,s1 和 s2 耗时分别如上所示,可以看到,这差别不是一点半点。按照常规理解,字符串作为不可变数据类型,a 和 c 应该是不同的字符串,判等时的复杂度应该是 o(n) 才对,但怎么貌似是 o(1) 呢?

在这段代码中,a 和 c 其实是同一段内存。是不是很神奇?这就 string interning 技术。利用这个技术,绝大部分对象取值操作都可以在真正意义上的 o(1) 时间内完成。代价就是,写操作慢一些,因为要做 interning。但这个场景是典型的读多写少,所以问题就这么被解决啦!