在 JavaScript 中,对象是很方便的。它们允许我们轻松地将多个数据块组合在一起。 在ES6之后,又出了一个新的语言补充– Map。在很多方面,它看起来像是一个功能更强的对象,但接口却有些笨拙。
然而,大多数开发者在需要 hash map 的时候还是会使用对象,蓝狮注册登陆只有当他们意识到键值不能只是字符串的时候才会转而使用 Map。因此,Map 在当今的 JavaScript 社区中仍然没有得到充分的使用。
在本文本中,我会列举一些应该更多考虑使用 Map 的一些原因。
为什么对象不符合 Hash Map 的使用情况
在 Hash Map 中使用对象最明显的缺点是,对象只允许键是字符串和 symbol。任何其他类型的键都会通过 toString 方法被隐含地转换为字符串。
const foo = []
const bar = {}
const obj = {[foo]: ‘foo’, [bar]: ‘bar’}
console.log(obj) // {“”: ‘foo’, [object Object]: ‘bar’}
更重要的是,使用对象做 Hash Map 会造成混乱和安全隐患。
不必要的继承
在ES6之前,获得 hash map 的唯一方法是创建一个空对象:
const hashMap = {}
然而,在创建时,这个对象不再是空的。尽管 hashMap 是用一个空的对象字面量创建的,但它自动继承了 Object.prototype。这就是为什么我们可以在 hashMap 上调用hasOwnProperty、toString、constructor 等方法,尽管我们从未在该对象上明确定义这些方法。
由于原型继承,我们现在有两种类型的属性被混淆了:存在于对象本身的属性,即它自己的属性,以及存在于原型链的属性,即继承的属性。
因此,我们需要一个额外的检查(例如hasOwnProperty)来确保一个给定的属性确实是用户提供的,而不是从原型继承的。
除此之外,由于属性解析机制在 JavaScrip t中的工作方式,在运行时对 Object.prototype 的任何改变都会在所有对象中引起连锁反应。这就为原型污染攻击打开了大门,这对大型的JavaScript 应用程序来说是一个严重的安全问题。
不过,我们可以通过使用 Object.create(null) 来解决这个问题,它可以生成一个不继承Object.prototype的对象。
名称冲突
当一个对象自己的属性与它的原型上的属性有名称冲突时,蓝狮官网它就会打破预期,从而使程序崩溃。
例如,我们有一个函数 foo,它接受一个对象。
function foo(obj) {
//…
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
}
}
}
obj.hasOwnProperty(key)有一个可靠性风险:考虑到属性解析机制在JavaScript中的工作方式,如果 obj 包含一个开发者提供的具有相同名称的 hasOwnProperty 属性,那就会对Object.prototype.hasOwnProperty产生影响。因此,我们不知道哪个方法会在运行时被准确调用。
可以做一些防御性编程来防止这种情况。例如,我们可以从 Object.prototype 中 “借用””真正的 hasOwnProperty 来代替:
function foo(obj) {
//…
for (const key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
// …
}
}
}
还有一个更简短的方法就是在一个对象的字面量上调用该方法,如{}.hasOwnProperty.call(key),不过这也挺麻烦的。这就是为什么还会新出一个静态方法Object.hasOwn 的原因了。
0 Comments