假设我们有个 Bar
类并创建了一个 bar
实例
function Bar() {
this[2] = 2
this[3] = 1
this['b'] = 'b'
this[1] = 1
this['a'] = 'a'
}
const bar = new Bar()
// 打印属性
for (key in bar) {
console.log(`index:${key} value:${bar[key]}`)
}
// 打印的属性顺序
// index:1 value:1
// index:2 value:2
// index:3 value:3
// index:b value:b
// index:a value:a
可以发现属性的打印顺序和我们赋值顺序是不一样的,这是因为属性和属性间也是有区别的。
bar
拥有两个隐藏属性 elements
和 properties
。
数字属性 2、3、1 会放到 elements 属性中,被称为排序属性。elements
属性指向一个 elements 对象,在 elements 对象中,会按照属性数字的大小(从小到大)存放排序属性 —— 以 2、3、1 的顺序输入的属性会以 1、2、3 的顺序输出。
字符串属性 b、a 称为常规属性,会放到 properties 属性中。properties
属性指向一个 properties 对象,在 properties 对象中,会按照属性创建的先后顺序保存了常规属性 —— 以 b、a 的顺序输入的属性会以 b、a 的顺序输出。
elements 对象和 properties 对象都是用线性结构存储属性的,但这样存在效率问题,因为在查某个属性的时候,要先去查 elements 对象或 properties 对象,增加了查找步骤。为了减轻这个问题,引擎会将部分常规属性(默认是 10 个)直接存到对象下面,称为对象内属性。
将保存在线性结构里的属性称为快属性,快属性查找快,增删慢;当对象属性很多的时候,就会放大线性结构增删属性的缺点,因此引擎会利用非线性结构(字典)来保存属性,这时候被存储的属性称为慢属性。