对象属性类型

1. 数据属性

  • [[Configurable]]:表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性,特性默认值为true
  • [[Enumberable]]:表示能否通过for-in循环返回属性,特性默认值为true
  • [[Wtiteable]]:表示能否修改属性的值,特性默认值为true
  • [[Value]]:包含这个属性的数据值,读取属性值/写入属性值,从这个位置读/把新值保存在这个位置,这个特性的默认值为undefined

2. 访问器属性

  • [[configurable]]: 表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性,特性默认值为true
  • [[Enumberable]]:表示能否通过for-in循环返回属性,特性默认值为true
  • [[Get]]:在读取属性时调用的函数,默认值为undefined
  • [[Set]]:在写入属性时调用的函数,默认值为undefined

3. 定义对象的访问器属性 - Object.defineProperty

var book = {
_year: 2004,
edition: 1
}; Object.defineProperty(book, "year", {
get: function(){
return 2018;
},
set: function(newValue){
if (newValue > 2004) {
this._year = newValue;
this.edition += newValue - 2004;
}
}
});
console.log(book.year);//2018
book.year = 2005;
console.log(book.year);//2018

对象创建底层分析

1. 对象创建

为什么下面第一种方式会报错而第二种不会?

//构造函数创建
var object=new Object();
object.x=1;
object.2=1; //Unexpected number
//字面量创建
var object = {
x: 1,
2: 2
};//不报错

分析如下:

window.2=2; //假设不会出错
2==2;//这个地方应该怎么处理?--没法处理

那么字面量为什么不会出错?往下看

当启用慢模式时以Hash作为底层存储结构,key为字符串,字面量方式会存在类型转换。

2. 对象属性详解 Chrome(V8)

2.1 V8中的快速属性

对象大多数时候表现为Dictionary:以字符串为key,任意object为值。但是...往下看

命名属性:

如:{a:'foo',b:'bar'}

  • 存储结构可以是数组也可以是HashMap
  • 具有额外的辅助信息(存储在描述符数组中)

数组索引属性(元素):

如:数组['foo','bar']有两个数组索引属性:0,值为'foo'; 1,值为'bar'。

  • 存储结构通常为简单的数组结构。但某些情况下也会切换到Hash结构以节省内存。
  • 可以使用键来推断它们在属性数组中的位置

数组索引属性和命名属性存储在两个单独的数据结构中:

2.2 隐藏类和描述符数组

每个JS对象都有一个隐藏类与之关联。

隐藏类存储有对象结构信息(属性数和对对象原型的引用),以及从属性名称到属性的索引映射。

隐藏类是动态创建的,并随着对象的变化而动态更新。

在V8中,位于堆内存并由GC管理的所有JS对象的第一个字段都指向隐藏类。

隐藏类存储中包含属性的数量,和一个指向描述符数组的指针。

在这个描述符数组中包含有命名属性的信息,例如命名属性的名称和存储属性值的位置。

注意:具有相同结构的JS对象(相同顺序和相同命名的属性),他们的隐藏类会指向同一个,以此达到复用的目的。对于不同结构的JS对象将使用不同的HiddenClass。

每次添加新属性时,都会更改对象的HiddenClass。V8维护了一个把HiddenClasses链接在一起的转换树。按相同属性添加顺序将得到一样的隐藏类。

如果我们创建一个添加了不同属性的新对象('d'),则会创建一个单独的隐藏类分支。

结论:

具有相同结构的对象(相同属性的相同顺序)具有相同的HiddenClass

默认情况下,每个添加的新命名属性都会导致创建一个新的HiddenClass。

添加数组索引属性不会创建新的HiddenClasses。

2.3 三种不同的命名属性

  1. 内嵌属性与普通属性:

    • V8支持对象内属性,存储在对象本身,可以直接访问,速度最快。
    • 内嵌属性的数量由对象的初始大小预先确定。
    • 如果添加的属性多于对象中的空间,则它们将存储在隐藏类链上,由隐藏类指向的一个属性数组。

  1. (普通属性中的)快属性与慢属性:

    • 直接存储在属性数组(如上图中的Properties结构)中的属性为'快属性'。可通过属性数组中的索引访问,若要从属性名称获取属性数组中的实际位置,必须查看HiddenClass上的描述符数组才能知道(如上)。
    • 慢属性使用HashMap作为属性存储,所有属性元信息不再存储在HiddenClass上的描述符数组中,而是直接存储在属性Hash中(没有缓存,所以叫慢属性)。

注意:过多的添加或删除属性,会从快属性模式切换为慢属性模式。

结论:

三种不同的命名属性类型:in-object,fast和slow(dictionary)。

内嵌属性直接存储在对象本身上,并提供最快的访问。

快速属性存在于属性存储中,所有元信息都存储在HiddenClass上的描述符数组中。

慢属性存在于自包含的属性字典中,不再通过HiddenClass共享元信息。

慢属性提供有效的属性删除和添加,但访问速度比其他两种类型慢。

2.4 数组索引属性

  1. 连续和有缺口的数组索引属性:

    如果删除索引元素,或者例如没有定义它,则会在连续存储中出现漏洞。一个简单的例子是[1,,3],其中第二个项是一个缺口。
const o = ["a", "b", "c"];
console.log(o[1]); // Prints "b". delete o[1]; // Introduces a hole in the elements store.
console.log(o[1]); // Prints "undefined"; property 1 does not exist.
o.\_\_proto\_\_ = {1: "B"}; // Define property 1 on the prototype. console.log(o[0]); // Prints "a".
console.log(o[1]); // Prints "B".
console.log(o[2]); // Prints "c".
console.log(o[3]); // Prints undefined

当有缺口的时候会在该位置打上the_hole标记表示不存在的属性,可以大大提高数组操作效率。

  1. 快速数组索引属性或Hash数组索引属性:

    快速数组索引属性是简单的VM内部数组,其中属性索引映射到数组索引属性存储中的索引。但是,该结构对于较大的数组但占用元素较少的情况相当浪费内存,这种情况会使用HashMap来节省内存,但代价是访问速度稍慢。
const sparseArray = [];
sparseArray [9999] ='foo'; //创建一个包含字典元素的数组。

注意:只要使用自定义描述符定义索引属性,V8就会转向慢数组索引属性:

const array = [];
Object.defineProperty(array, 0, {value: "fixed", configurable: false});
console.log(array[0]); // Prints "fixed".
array[0] = "other value"; // Cannot override index 0.
console.log(array[0]); // Still prints "fixed".

refs:

https://www.cnblogs.com/renlong0602/p/4235533.html

https://v8project.blogspot.com/2017/08/fast-properties.html

JavaScript 对象属性底层原理的更多相关文章

  1. 删除要被替换的元素的所有事件处理 程序和 JavaScript 对象属性

    使用本节介绍的方法替换子节点可能会导致浏览器的内存占用问题,尤其是在 IE 中,问题更加明显.在删除带有事件处理程序或引用了其他 JavaScript 对象子树时,就有可能导致内存占用问题.假设 某个 ...

  2. Javascript对象属性与方法汇总

    Javascript对象属性与方法汇总 发布时间:2015-03-06 编辑:www.jquerycn.cn 详细介绍下,javascript对象属性与对象方法的相关知识,包括javascript字符 ...

  3. JavaScript对象属性的基础教程指南

    JavaScript是使用“对象化编程”的,或者叫“面向对象编程”的.所谓“对象化编程”,意思是把JavaScript能涉及的范围划分成大大小小的对象,对象下面还继续划分对象直至非常详细为止,所有的编 ...

  4. JavaScript对象属性访问的两种方式

    JavaScript对象属性访问的两种方式 object.attribute object["attribute"] 例如: var employees = [ { "f ...

  5. JavaScript 对象属性

    JavaScript 对象属性 属性中的 . 和 [ ](点 和 方括号)的区别 .  :取对象自身的属性值: [ ]:括号内容可以是变量: var obj = {}; obj.name = 'Twx ...

  6. EL表达式获取对象属性的原理

    EL表达式获取对象属性的原理是这样的: 以表达式${user.name}为例 EL表达式会根据name去User类里寻找这个name的get方法,此时会自动把name首字母大写并加上get前缀,一旦找 ...

  7. js 技巧 (六)JavaScript[对象.属性]集锦

    JavaScript[对象.属性]集锦 SCRIPT 标记 用于包含javascript代码. 语法 属性 LANGUAGE 定义脚本语言 SRC 定义一个URL用以指定以.JS结尾的文件 windo ...

  8. javascript对象属性和数组的访问

    javascript对象属性的访问 假如有对象test:var test = {  "a":1,  "b":2};直接访问对象test的属性a的值,有两种方法: ...

  9. 了解JavaScript 对象属性的标签

    对象属性的标签 value(属性值), writable(属性可写), enumerable(属性可枚举), configurable(属性可配置), 这些属性标签使对象所持有的属性体现出不同的特性, ...

随机推荐

  1. IIC时序和24C02读写字节时序

    一年前刚学51单片机时,接触到了IIC时序和用IIC通信读写AT24C02的学习历程.那时刚刚大一,对数据线时钟线等概念不是很清楚,也没有分清IIC通信的底层时序和写24c02的时序为什么不同. 借着 ...

  2. VMSTAT监控CPU使用率,内存使用,虚拟内存交换情况

    Linux性能监控分析命令(一)—vmstat命令详解 一.vmstat介绍 语法格式: vmstat [-V] [-n] [-S unit] [delay [count]] -V prints ve ...

  3. 服务器配置+wordpress建站(小白)

    一. 安装好centos7.2系统后,登录centos系统输入如下命令: yum install -y wget && wget -O install.sh http://downlo ...

  4. Element-ui 更新tableData 中 row的某一个属性时,没有更新视图的问题

    在一个报警音管理的页面中,每次点击试听的时候,需要把‘试听’ 更新为 ‘停止’, 起初我们给row.play=0时,显示为 试听,row.play=1时显示为停止, 但是在代码中每次为row.play ...

  5. day 15递归 匿名函数

    三元表达式 目的是简化书写 局限性:三元表达式智能简化仅有两个分支的if判断,而且这个判断无论是否成立都必须要返回值 res = True if age >=18 else False 递归: ...

  6. WEB学习笔记3-开发环境和工具

    WEB前端集成开发环境:Aptana Studio和WebStormWEB前端代码调试:IE浏览器自带的IE Dev Toolbar,Chrome浏览器自带的Developer Tools,Firef ...

  7. 小程序视频播放组件video

    最近在做一个视频播放的功能,要求如下: 1.实现视频的全屏播放: 2.实现视频相关信息的展示: 3.实现视频滑动上下切换效果: 肯定选择用原生组件video了,真是不用不知道,一用都是坑: 首先,组件 ...

  8. python学习1---列表、矩阵、数组

    1.列表与数组区别 numpy数组的所有元素类型是相同的,而列表的元素类型是任意的. 2.numpy数组与矩阵区别 矩阵必须是二维的,数组可以是多维的,matrix是array的一个分支. matri ...

  9. Redis须知重点

    一.为什么使用 Redis? 我觉得在项目中使用 Redis,主要是从两个角度去考虑:性能和并发. 当然,Redis 还具备可以做分布式锁等其他功能,但是如果只是为了分布式锁这些其他功能,完全还有其他 ...

  10. Django_ORM相关操作

    一般的操作 1.all():查询所有的结果 2.filter():包含与所有筛选条件匹配的对象 3.get():返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果对象没有或者超过一个会报错 4 ...