JavaScript内存空间分为栈,堆,池,队列。其中栈存放变量,基本类型数据与指向复杂类型数据的引用指针;堆存放复杂类型数据;池又称为常量池,用于存放常量;而队列在任务队列也会使用。
1 基本类型和引用类型(栈和堆)
1】堆内存和栈内存
JS引擎中对变量的存储主要有两种位置:堆内存和栈内存
栈内存:主要用于存储各种基本类型的变量
堆内存:主要负责像对象Object这种变量类型的存储(或者说存储引用类型)
栈内存中的变量一般都是已知大小或者有范围上限的,算作一种简单存储。而堆内存存储的对象类型数据对于大小这方面,一般都是未知的,这也是为什么null作为一个object类型的变量却存储在栈内存中的原因
栈内存线性有序存储,容量小,系统分配效率高。而堆内存首先要在堆内存新分配存储区域,之后又要把指针存储到栈内存中,效率相对就要低一些了。
2】JavaScript数据类型
a、值类型(基本类型):
字符串(String)、数字(Number)、布尔(Boolean)、对空(Null)、未定义(Undefined)、Symbol 和 ES10的BigInt。
基本变量的值一般都是存在栈内存中。
b、引用数据类型(对象类型):
对象(Object)、数组(Array)、函数(Function)、ES6新增的Set、Map、WeakSet、WeakMap
对象类型的变量的值存储在堆内存中,堆内存专门存放大小为止,不可预测的数据。
2 浅拷贝和深拷贝
1】先看小例子,自己回味
(浅拷贝的对象属性,可以相互影响)
2】浅拷贝和深拷贝
Javascript 中的对象只是对内存地址的引用。
基本类型的数据存放在栈内存中,复制的时候是值传递。
引用类型的数据存放在堆内存中,栈内存中只存放具体的地址值,把object1赋值给object2的时候是把object1的地址值赋值给了object2,这个时候两个对象同时指向堆内存中的同一数据。
深拷贝在于引用类型的时候,浅拷贝只复制地址值,实际上还是指向同一堆内存中的数据,深拷贝则是重新创建了一个相同的数据,二者指向的堆内存的地址值是不同的。这个时候修改赋值前的变量数据不会影响赋值后的变量。
3】实现
浅拷贝:
a、直接用=拷贝
b、使用 Object.assign({},srcObj),前提是所拷贝对象的属性是属于引用类型。
深拷贝:
a、使用 Object.assign,前提是所拷贝对象的属性是属于基本类型。
b、利用 JSON 对象中的 parse 和 stringify
c、利用递归来实现每一层都重新创建对象并赋值
var obj1 = { //对象
name: “cat”,
show:function(){
console.log(this.name);
}
};
function deepClone(obj) { //参数为源对象
let objClone = Array.isArray(obj) ? [] : {}; //先判断源对象是普通对象还是数组
if(obj && typeof obj === “object”) {
for(key in obj) { //for…in遍历属性
if(obj.hasOwnProperty(key)) { //判断ojb子元素是否为对象,如果是,递归复制
if(obj[key] && typeof obj[key] === “object”) {
objClone[key] = deepClone(obj[key]);
} else { //如果不是对象,简单复制
objClone[key] = obj[key];
}
}
}
}
return objClone;
}
var obj3=deepClone(obj1);
obj3.show(); //输出cat
3 常量和常量池
(略)
4 执行环境和作用域
1)JS 执行上下文(函数调用栈)
1】定义
当代码运行时,会产生一个对应的执行环境,在这个环境中,所有变量会被事先提出来(变量提升),有的直接赋值,有的为默认值 undefined,代码从上往下开始执行,就叫做执行上下文
2】运行环境(注意