JavaScript中的对象概念非常不同,要把它当作其它语言的关联数组(如PHP)或者Map(如Java)来理解的话,还是有很大的不一样——由于原型链和属性描述符(主要是[[Enumerable]]
)的存在。
一个对象字面量{}
有Object
作为原型,它有继承自原型链的不可枚举的toString
方法。下面将以对象字面量为例。
-
下标操作符、点操作符可以访问到自身属性或继承自原型链的任何属性,除非出现了属性覆盖
var a ={}; a.toString
返回toString方法
var a ={toString:"a"}; a.toString
返回字符串"a" -
for in
循环将枚举的自身属性和继承自原型链的所有[[Enumerable]]
的属性 -
"key" in obj
的判断中,判断自身属性或继承自原型链的属性的存在性
"toString" in {}
返回true -
obj.hasOwnProperty()
的判断中,只判断自身属性的存在性
({}).hasOwnProperty("toString")
返回false
({toString:"a"}).hasOwnProperty("toString")
返回true -
Object.keys()
可返回自身[[Enumerable]]
的属性组成的数组,不包括原型链上继承的属性
Object.keys({a:1})
返回["a"]
,不包含原型链上的toString等内容 -
Object.getOwnPropertyNames()
可以返回自身任何属性组成的数组,不包括原型链上继承的属性
类目 | 语句 | 自身属性 | 原型链上继承的属性 | ||
可枚举属性 | 不可枚举属性 | 可枚举属性 | 不可枚举属性 | ||
访问 | obj.prop | √ | √ | √ | √ |
obj["prop"] | √ | √ | √ | √ | |
循环 | for key in obj | √ | √ | ||
判断 | key in obj | TRUE | TRUE | TRUE | TRUE |
obj.hasOwnProperty(key) | TRUE | TRUE | FALSE | FALSE | |
列举 | Object.keys(obj) | √ | |||
Object.getOwnPropertyNames(obj) | √ | √ |
可以通过以下方式避免遍历过程中的原型链干扰:
- 在get/set方法中为每一个键加上前缀
Object.create(null)
来创建一个没有原型的对象
这些都可以在StringMap的解决方案里找到。