是否可以将缓存的 hashCode 方法添加到原始字符串?
问题描述
我有一些依赖于哈希码的方法,比如JS
中的自定义唯一和哈希集合。
由于JS
中的字符串是不可变的,并且哈希码是昂贵的操作,因此缓存它是有意义的,但不幸的是,无法在字符串上设置属性,因此下面的代码将不起作用。
我想知道是否有某种方法可以使其工作,也许是一些隐藏的内置foo.builtInHashCode()
函数?
function calculateStringHashCode(s) {
console.log("Calculating hash code for", s)
return s.length
}
String.prototype.hashCode = function() {
return this.cachedHashCode ??= calculateStringHashCode(this)
}
const s = "foo"
console.log(s.hashCode())
console.log(s.hashCode())
更新,或者可能使用外部缓存,类似于下面的非工作代码,但不幸的是WeakMap
不接受原语作为键。
declare global {
interface String {
hashCode(): number
}
}
const hashes = new WeakMap<string, number>() // <= Error primitives can't be keys
String.prototype.hashCode = function (this: string): number {
let hash = hashes.get(this)
if (hash == undefined) {
console.log('calculating hash')
hash = this.length // complex calculation of hash
hashes.set(this, hash)
}
return hash
}
console.log('hi'.hashCode())
console.log('hi'.hashCode())
解决方案
问题不在于字符串的不可变性,而在于原型的工作方式。我建议使用这种变体:
function calculateStringHashCode(s) {
console.log("Calculating hash code for", s)
return s.length
}
String.prototype.cachedHashCodes = { }
String.prototype.hashCode = function() {
return this.cachedHashCodes[this] ??=calculateStringHashCode(this)
}
const s = "foo"
const t = "bar"
console.log(s.hashCode())
console.log(s.hashCode())
console.log(t.hashCode())
console.log(s.hashCode())
console.log(t.hashCode())
这个想法是在原型中存储一个对哈希对象的不可变引用,并为每个字符串添加值。