数据存储与垃圾回收机制

提示:牛客职导前端课程笔记

数据存储

1.JavaScript数据类型

1.1共8种基本数据类型

前7种为原始数据,最后一个称为引用数据类型

Boolean 只有true和false两个值

Null

Undefined 没被赋值变量的默认值,变量提升时的默认值

Number 数字类型

BigInt 类比Number,支持的整数范围更大

String 文本数据,不可更改

Symbol 通常作为对象标识符

Object 通常看做一组属性的集合

2.判断数据类型的几种方法

2.1 typeof

常用于判断基本数据类型,对于引用数据类型全部返回Object。

对于null,返回object。

对于function,返回function。

2.2 instanceof

最常用于数组和对象的检测。

  • 特点:

    • 可以区分复杂数据类型

    • 只要在当前实例的原型链上,我们用其检测出来的结果都是true

    • 基本类型值检测繁琐,且检测不全(undefined, null, symbol)

instanceof 遍历变量的原型链,直到找到右边变量的prototype(原型对象),找到返回true

手写instanceof

function mystanceof_(left,right){
        let proto = left.__proto__;
        let prototype = right.prototype;
        while(true){
                if(proto == null) return false;
                if(proto == prototype) return true;
                proto = proto.__proto__;
        }
}

left是实例,right是构造方法。

2.3 constructor

用于引用数据类型。原型链不会被干扰。

constructor属性指向构造函数自己,如果在实例上使用会指向构造函数。

2.4 Object.prototype.toString.call()

对象原型链的判断方法,可以判断所有类型。

但是返回的是字符串,需手动截取数据类型。

3.内存空间

3.1内存空间分配

代码空间主要是存储可执行代码

栈空间:简单数据类型压入栈中,复杂数据类型在堆中的存放地址

堆空间:存放复杂数据类型

3.2栈和堆空间

复杂数据类型放在堆中的原因:

JavaScript引擎需要用栈来维护程序执行期间上下文的状态。栈空间太大会影响上下文切换的效率

3.3数据赋值与引用数据类型的深浅拷贝

赋值:原始数据类型会完整复制变量值,引用数据类型会复制引用地址。

浅拷贝和深拷贝都是对于复杂数据类型来说的

浅拷贝:堆栈中各开辟一块新空间,栈中存放新开辟的堆空间的地址,堆中如果是基本数据类型会直接复制一份,如果是引用类型会指向源数据的存储地址。

方法:

①Object.assign(   , )

②_.clone

③…

④Array.prototype.concat()

⑤Array.prototype.slice()

深拷贝:拷贝之后两个数据占两块空间。改变其中一个,另一个不会随之改变。

方法:

①JSON.parse(JSON.stringify(   ))不能处理函数和正则

②_cloneDeep(  )

③jQuery.extend()

④手写递归方法

因为对应的属性值可能是复杂数据类型,所以要递归 。

解决循环引用问题,我们可以额外开辟一个存储空间,来存储当前对象和拷贝对象的对应关系,当需要拷贝当前对象时,先去存储空间中找,有没有拷贝过这个对象,如果有的话直接返回,如果没有的话继续拷贝 。

WeakMap 对象是一组键/值对的集合,其中的键是弱引用的。其键必须是对象,而值可以是任意的。

weakMap.get 返回与指定键相关联的值,如果 WeakMap 对象找不到这个键则返回 undefined

hasOwnProperty:用来检测一个对象是否含有特定的自身属性;

function deepClone(obj,hash=new WeakMap()){
    if(obj===null) return obj;
    if(obj instanceof Date) return new Date(obj);
    if(obj instanceof RegExp) return new RegExp(obj);
    if(typeof obj !=="object") return obj;
    if(hash.get(obj)) return hash.get(obj);
    let cloneobj=new obj.constructor();
    hash.set(obj,cloneobj);
    for(let key in obj){
        if(obj.hasOwnProperty(key)){
            cloneobj[key]=deepClone(obj[key],hash);
        }
    }
    return cloneobj;
}
let obj={name:1;address:{x:100}};
obj.obj=obj;
let d=deepClone(obj);
obj.address.x=200;
console.log(d);

垃圾回收机制

1.垃圾回收的方式

分为手动垃圾回收和自动垃圾回收。

c语言是手动垃圾回收,javaScript是自动垃圾回收。

2.JavaScript垃圾回收方式

调用栈中的垃圾数据回收方式。

堆中的垃圾数据回收方式。

3.调用栈中的垃圾数据回收方式。

一个函数执行结束后,JavaScript引擎会通过向下移动ESP来销毁该函数在栈中的执行上下文。

ESP:栈指针寄存器(extended stack pointer),其内存放着一个指针,该指针永远指向系统栈最上面一个栈帧的栈顶。

4.堆中的垃圾回收方式

4.1代际假说

大部分对象在内存中存在的时间很短,一部分会存在很长时间。

4.2分代收集

V8把堆分为

新生区:生存时间短,分为对象区域和空闲区域,副垃圾回收器。

老生区:生存时间长,主垃圾回收器。

4.3垃圾回收器的工作流程

一、标记 标记空间中的活动对象和非活动对象。

二、回收

三、做内存整理 不连续的内存空间称为内存碎片。 整理内存碎片 。

4.4新生区垃圾回收(副垃圾回收器)

小对象分配到新生区,垃圾回收较频繁,通常存储容量在1-8M 。

Scavenge算法:复制机制。标记、复制、角色翻转、回收。

对象晋升策略:两次垃圾回收依然存活会移到老生区。

4.5老生区垃圾回收(主垃圾回收器)

对象占空间大,存活时间长。

标记清除算法:遍历标记,清除。

标记整理算法:遍历标记,整理连续空间。

4.6全停顿

全停顿:一旦执行垃圾回收算法,都需要将正在执行的 JavaScript 脚本暂停下来,待垃圾回收完毕后再恢复脚本执行。

增量标记算法:V8将标记过程分为一个个子标记,并让垃圾回收标记和JavaScript应用逻辑交替进行,直到标记阶段完成。

5.避免内存泄漏的方式

内存溢出:系统内存不能满足需求。(死循环)

内存泄漏:产生了不可回收的垃圾数据。(例如全局变量)。

5.1 尽可能少地创建全局变量

5.2 手动清除定时器

手动清除:
var timer = window.setInterval(fun, 1000);
timer = null;

5.3 少用闭包

5.4 清除DOM引用

5.5 弱引用

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值