JavaScript中普通属性和排序属性详解

 更新时间:2023年09月18日 10:14:48   作者:LBruse  
JavaScript属性是对象中的特性,用于描述对象的状态,每个JavaScript对象都有一组属性,可以通过点号(.)或方括号([])访问和操作这些属性,本文将给大家讲讲JavaScript中你所不知道的普通属性和排序属性,需要的朋友可以参考下

普通属性

JavaScript中定义对象时,普通的以字符串为键定义的属性为普通属性,特点是在遍历对象属性时根据创建时的顺序排序

const obj = {
    'name': 'Bruse',
    'age': 16,
}
for (const key in obj) {
    console.log(key)
}

输出顺序为

name
age

排序属性

排序属性则是以数字为键定义的属性,特点是按照索引值的大小进行升序排序,优先级优于普通属性。

const obj = {
    'name': 'Bruse', // 普通属性
    'age': 16, // 普通属性
    2: 'obj2' // 排序属性
}
obj[1] = 'obj1' // 排序属性
obj[99] = 'obj99' // 排序属性
obj[10] = 'obj10' // 排序属性
for (const key in obj) {
    console.log(key)
}

输出

1
2
10
99
name
age

可以看到在使用for ... in 遍历obj的属性时,排序属性遍历顺序优先于普通属性,同时排序属性也是按照键值进行升序排序的,键值越小,遍历顺序越往前

字符串数字作为键

obj中新建一个键为'3',值为112的属性,遍历obj属性名并输出

const obj = {
    'name': 'Bruse', // 普通属性
    'age': 16, // 普通属性
    2: 'obj2', // 排序属性
    '3': 112 // 转换,也是排序属性
}
obj[1] = 'obj1' // 排序属性
obj[99] = 'obj99' // 排序属性
obj[10] = 'obj10' // 排序属性
for (const key in obj) {
    console.log(key)
}

输出

1
2
3
10
99
name
age

可以看到即便在定义属性键时,是字符串类型的数字3,也会做一下转换,将其转换为排序属性

排序属性 VS 普通属性

存储方式

首先排序属性普通属性在对象中的存储方式不一样

可以简单地理解为obj对象中,分别有着elementsproperties两个内置的属性,elements可以理解为是一个数组,而数字键则是属性在该数组中的下标,也就是内存偏移量。通过下标访问数组中的某个元素是很快的。当我们要访问obj.1时,会先从obj对象中内置的elements属性中通过1这个下标进行查询,最终找到obj[1]的值为obj1

properties可以理解为是一个Map,而字符串键则是该Map中的keyvalue则是对应的属性值。当访问obj.name时,会先从elements中进行查找,结果是找不到,然后再从properties中进行查找,但从properties中查找则没有elements中查找快,因为elements可以通过计算偏移量来进行访问,但是properties要hash计算访问。

对象内属性

其实上图还并不是全貌,因为即便有着elementsproperties分别存放排序属性和普通属性,但是无论访问排序属性和普通属性[排序属性访问速度优于普通属性],都是要先访问obj这个对象的elementsproperties内置属性,然后再通过属性键访问到具体的属性值,其实就相当于obj.name = obj.properties.name,还存在优化空间,这个时候对象内属性就出场了。

对象内属性其实就是被保存到对象自身的常规属性,也就是真正意义上的让obj.name不再等于obj.properties.name,而是真正的所见即所得obj.name

代码测试

为了方便理解,把之前的代码稍作修改

class People {
   constructor() {
       this.name = 'Bruse'
       this.age = 16
       this[2] = 'obj2'
   }
}
const obj = new People()
obj[1] = 'obj1' // 排序属性
obj[99] = 'obj99' // 排序属性
obj[10] = 'obj10' // 排序属性
debugger  // 避免执行过快,导致还来不及生成内存快照,obj对象就已被回收
for (const key in obj) {
   console.log(key)
}

F12打开浏览器开发者工具,当debugger阻塞住代码往下执行时,点击Memory,生成内存快照

可以看到obj这个对象中存在内置属性elements和一些内属性name[10][99][1][2],暂时并没有内置属性properties

首先因为obj属性并不多,此时对象内属性的数量还比较少,所以此时并不需要内置属性properties来存放普通属性,而是将name等普通属性当做是对象的内置属性存放即可,访问速度比访问elementsproperties更快。

Tips:不要看到elements中10、99排在1、2前面,就以为elements不是按照数字升序排列的,因为输出之后你会发现其实还是1、2、10、99这样的顺序,至于为什么在调试工具里看起来顺序有点不太一致,我也不知道...

添加更多的排序属性

接下来给obj塞入更多的排序属性

class People {
    constructor() {
        this.name = 'Bruse'
        this.age = 16
    }
}
const obj = new People()
for (let i = 0; i < 20; i++) {
    obj[i] = `obj${i}`
}
debugger
for (const key in obj) {
    console.log(key)
}

再看看看obj的变化,首先elements属性中的元素变多了

同时也并没有出现内置属性properties

因为只是增加了更多的排序属性,并没有突破内置属性(内置常规属性)的数量限制

添加更多的普通属性

接下来再塞入更多的普通属性

class People {
    constructor() {
        this.name = 'Bruse'
        this.age = 16
        for (let i = 0; i < 20; i++) {
            this[`obj${i}`] = i
        }
    }
}
const obj = new People()
debugger
for (const key in obj) {
    console.log(key)
}

可以看到在这个时候obj的内置属性properties终于出现了

只不过貌似并不像elements那样方便预览其中的属性...后来经过一番查找和尝试,终于是找到了解决办法... 也很简单,就是生成内存快照时多做一步操作,勾上“在快照中添加数字值”

再次内存分析,好吧...因为生成20个常规变量的缘故,貌似也还没达到内置属性的限制...

将数量调整到50个,可以看到elementsproperties都有了相应存放的变量

for (let i = 0; i < 50; i++) {
    this[i] = `obj${i}`
    this[`obj${i}`] = i
}

困惑

单纯在Chrome上进行内存分析的话,貌似即便超出了内属性数量限制,那多出来的一部分普通属性,也非常直白地展示在properties之外,这个暂时不太清楚...

总结

把上述排序属性``普通属性``内属性结合到一块来看,那么JavaScript中的对象属性存放结构应该如下图所示

首先是为了提高访问速度,对象obj本身就会有一定空间存放内属性,在访问内属性时,可以直接跳过访问elementsproperties这一步,直接访问到该属性的值。

但是内属性是有一定数量限制的,所以当超出了限制后,剩下的普通属性会被存放到properties中,而properties有点像Map,在进行属性访问的时候,需要计算出键的hash值,然后才能访问到具体的属性值。

elements则是存放排序属性用的,有点像Array,数字键即数组中的下标,所有元素按数字升序进行排序,访问属性值时则是通过下标进行访问,访问速度会比properties要快一些。

propertieselements两种存储方式之间的VS,本质上就像是数据结构中的MapArray之间的VS。

以上就是JavaScript中普通属性和排序属性详解的详细内容,更多关于JavaScript属性的资料请关注脚本之家其它相关文章!

相关文章

  • JavaScript+CSS实现唯美蝴蝶动画

    JavaScript+CSS实现唯美蝴蝶动画

    这篇文章主要介绍了JavaScript+CSS实现唯美蝴蝶动画,文章围绕主题展开详细的内容介绍,具有一定的参考价值,需要的小伙伴可以参考一下
    2022-07-07
  • JS如何实现form表单登录验证并使用MD5加密详解

    JS如何实现form表单登录验证并使用MD5加密详解

    表单验证为终端用户检测无效的数据并标记这些错误,是一种用户体验的优化,下面这篇文章主要给大家介绍了关于JS如何实现form表单登录验证并使用MD5加密的相关资料,需要的朋友可以参考下
    2023-06-06
  • JS实现的简洁二级导航菜单雏形效果

    JS实现的简洁二级导航菜单雏形效果

    这篇文章主要介绍了JS实现的简洁二级导航菜单雏形效果,通过简单的JavaScript响应鼠标事件遍历页面元素实现二级导航菜单切换的效果,非常简单实用,需要的朋友可以参考下
    2015-10-10
  • JS瀑布流实现方法实例分析

    JS瀑布流实现方法实例分析

    这篇文章主要介绍了JS瀑布流实现方法,结合实例形式分析了javascript瀑布流加载图片效果的实现原理、步骤与相关操作技巧,需要的朋友可以参考下
    2016-12-12
  • Javascript动画效果(4)

    Javascript动画效果(4)

    这篇文章主要为大家详细介绍了第四篇Javascript动画效果,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-10-10
  • 前端获取excel表格数据并在浏览器展示方法实例

    前端获取excel表格数据并在浏览器展示方法实例

    在开发过程中,难免会碰到用前端来处理excel文件的需求,这篇文章主要给大家介绍了关于前端获取excel表格数据并在浏览器展示方的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2024-08-08
  • 20行代码实现的一个CSS覆盖率测试脚本

    20行代码实现的一个CSS覆盖率测试脚本

    这里我们只求CSS规则的覆盖率,所以访问 querySelectorAll().length 即可。通过排序就可看出各个CSS使用情况
    2013-07-07
  • javascript的BOM汇总

    javascript的BOM汇总

    本文给大家汇总了一些javascript的BOM相关方法,有需要的小伙伴可以参考下。
    2015-07-07
  • 深入理解ES6中let和闭包

    深入理解ES6中let和闭包

    本篇文章主要介绍了深入理解ES6中let和闭包,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-02-02
  • JS+CSS实现的蓝色table选项卡效果

    JS+CSS实现的蓝色table选项卡效果

    这篇文章主要介绍了JS+CSS实现的蓝色table选项卡效果,通过鼠标事件调用自定义函数实现页面元素样式的遍历与动态切换效果,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-10-10

最新评论