提示:牛客职导前端课程笔记
数据存储
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;