1.24学习笔记——JS数据存储

68 阅读4分钟

数据存储

1.JavaScript数据类型

js中共有8种数据类型。7种原始数据类型,1种引用数据类型。

标题属性
Boolean只有true或false
null空对象指针
undefined声明但未被赋值的变量默认为undefined,变量提升时的默认值也为undefined
number数字类型
bigint大数类型,在数字后加n即代表当前是大数类型,只能相同类型进行操作
string字符串类型
symbol唯一且不可修改的
object引用数据类型,对象,包含Date、function、array等

2.判断数据类型的方法

typeof——主要用于判断原始数据类型

  • typeof 数据 === ? |名称|返回值是否正确| |---|---| |基本数据类型(除null)|√| |null|×,返回object| |引用数据类型(除function)|×,均返回object| |function|√,function|

instanceof:检测某一个实例的原型链上是否有这个类的原型属性

  • [数据] instanceof [类名]//[] instanceof array 能够区分数组和常见的对象等,但是对于原始数据类型来说,过程更为复杂,不建议使用。

原理:左边这个数据的原型链上是否有右边这个类的原型属性。

function instanceMy(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__;
    }
}

constructor——用于引用数据

  • 数据.constructor === ? ※原型链不会对其进行干扰
[].constructor === Object//false

在我们的构造函数原型上,会有一个constructor是指向构造函数自身的,因此使用我们的实例.constructor会直接使用这个属性,并返回这个构造函数自身。

image.png

Object.prototype.toString.call()————适用于所有的数据类型

  • Object.prototype.toString.call(数据) 该方法可以检测出所有的数据类型。object.prototype.toString会返回一个对象类型的字符串,通过.call可以改变this的指向,使得其返回对应的数据的数据类型。

3.内存空间

内存空间分配

js中有3类空间,代码空间、栈空间、堆空间。

  • 代码空间中保存代码。
  • 栈空间:栈空间中存执行上下文,执行完后弹出,先进后出。
  • 堆空间:存储复杂数据类型。

栈和堆空间

对于我们的foo函数,此时有

function foo(){
    var a = "闷倒驴";
    var b = a;
    var c = {name:"王美丽"};
    var d = c;
}
foo();

image.png 可以发现在栈中,基本数据类型存储的是数据的值,而对于复杂数据类型,栈中存的是数据的地址。

不把栈中的数据放在堆中的原因:

js使用栈来维护程序执行期间上下文的的状态,若将所有的数据放在栈中,此时栈的数据变大,会影响上下文切换的效率,进而影响程序的执行效率。

赋值

在我们的赋值操作中,对于基本类型来说,赋值操作是直接将数据a在栈中的数据给了数据b。但是对于引用类型来说,赋值操作是将保存在栈中的数据a的地址赋值给了b,那么b中得到的其实是数据a的地址,因此一旦我修改了对应的地址中的数据,我们的数据a|b都会发生改变。

深浅拷贝

浅拷贝

对于拷贝的引用数据类型来说,如果我们要拷贝的对象,它既包含基本类型,又包含有对象。我们的浅拷贝则会开辟的新的堆栈,在我们的栈中,基本数据类型其数据被复制了过来。但是对于对象,我们浅拷贝拷贝过来的这个对象的地址。他们指向的仍然是同一块堆。

var user = {
    userName:"闷倒驴",
    sex:"女",
    body:{
        weight:"50kg",
        height:"160"
    }
};
userCopy = Object.assign({},user);
浅拷贝方法
  • object.assign()
  • lodash的.clone方法
  • 展开运算符...
  • concat()
  • slice

image.png

深拷贝

深拷贝就是在我的拷贝之后,我新建了所有的空间地址等,我只是将你的数据拷过来了,但是之后再也没有了联系。

深拷贝方法
  • Json.parse(Json.stringfy()),可以用来实现数组或对象的深拷贝,但是不能用来处理函数和正则。
  • lodash的._deepClone
  • jQuery的extend
  • 手写深克隆 递归一直找,直到为基本数据类型,使用WeakMap来处理循环引用。
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.o = obj; // 对象存在循环引用的情况
let d = deepClone(obj);
obj.address.x = 200;
console.log(d);

垃圾回收机制

垃圾回收的方式

垃圾回收分为手动垃圾回收(C语言)和自动垃圾回收(JS)两种方式。

js中垃圾回收的方式

  • 调用栈中的垃圾回收
  • 堆中的垃圾数据回收

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

function foo(){ 
	var a = 1;
	var b = {name:"王美丽"};
    function showName(){ 
    	var c = 2;
        var d = {name:"闷倒驴"};
    };
    showName()
};
foo()

当一个函数执行结束后,js引擎通过移动我们的esp指针来销毁函数在栈中的执行上下文。

堆中垃圾回收方式

避免内存泄露的方式