# JS数据类型
- 最新的 ECMAScript 标准定义了 8 种数据类型:
- 7 种原始类型:
- Null, Undefined, Number,Boolean, String, BigInt, Symbol(符号类型)
- 所有基本类型的值都是不可改变的。但需要注意的是,基本类型本身和一个赋值为基本类型的变量的区别。变量会被赋予一个新值,而原值不能像数组、对象以及函数那样被改变
- 基本类型值可以被替换,但不能被改变
- 第8种 Object 类型又具体包含了 function、array等
# js内存管理
- https://blog.csdn.net/sinat_23515817/article/details/86550612
- 基本类型的值存储在栈中,栈结构的特点是后进先出,入栈、出栈都在栈顶进行,栈一般用于保存固定大小的值,通过访问保存值的变量直接可以操作值,所以说基本类型是按值访问的,
- 引用类型的值存储在堆中,堆是没有结构的,用于为一些数据大小不确定的复杂类型(引用类型)数据分配空间,例如对象、数组,JS不允许直接访问堆内存中的位置,因此我们不能直接操作对象的堆内存空间。JS提供了一种间接的方式,将对象在堆中的引用(地址)保存到变量中,使用变量时,就间接地通过引用(地址)访问对象属性。因此,引用类型的值都是按引用访问的。
- 原始值。存储在栈(stack),即它们的值直接存储在变量访问的位置
- 引用值。 存储在堆(heap)中的对象,存储在变量处的值是一个指针,指向存储对象的内存处,
- 原始类型占据的空间固定,将它们存储在较小的内存区域,栈,便于迅速查寻变量的值
- 引用类型的值,它的存储空间从堆中分配,因为引用值的大小会改变,故不能存放在栈中,这样会降低变量查寻的速度,而将该对象存储在堆中地址存放于变量的栈空间,地址大小固定,这样对变量性能无任何影响
# 内存生命周期
- 分配内存
- 当我们声明变量、函数,并初始化时(未初始化,默认值undefined),JS引擎在内存中自动为它们开辟空间
- 使用内存
- 复制变量值,在从一个变量向另一个变量复制值的时候,基本类型复制的是值,而引用类型复制的是引用地址。
- 应用——函数参数传递,JavaScript函数参数的传递,其实就是复制变量值的应用。向参数传递基本类型的值,被传递的值会复制给一个局部变量;向参数传递引用类型的值时,会把这个值在内存中的地址复制给一个局部变量,因此这个局部变量的变化会反应在函数的外部。
- 参数为基本类型时,函数体内复制了一份参数值,对于任何操作不会影响参数实际值
- 函数参数是一个引用类型时,当在函数体内修改这个值的某个属性值时,将会对参数进行修改
- 函数参数是一个引用类型时,如果我们直接修改了这个值的引用地址,则相当于函数体内新创建了一份引用,对于任何操作不会影响原参数实际值
- 释放内存,垃圾回收算法
- 引用计数
- 在内存管理的环境中,一个对象如果有访问另一个对象的权限(隐式或者显式),叫做一个对象引用另一个对象。例如,一个Javascript对象具有对它原型的引用(隐式引用)和对它属性的引用(显式引用)
- 此算法把“对象是否不再需要”简化定义为“对象有没有其他对象引用到它”。如果没有引用指向该对象(零引用),对象将被垃圾回收机制回收
- 限制:无法处理循环引用的事例
- 标记清除
- 这个算法把“对象是否不再需要”简化定义为“对象是否可以获得
- 垃圾回收器将定期从全局对象开始,找所有从全局对象开始引用的对象,然后找这些对象引用的对象……从根开始,垃圾回收器将找到所有可以获得的对象和收集所有不能获得的对象
- 因为“有零引用的对象”总是不可获得的,但是相反却不一定,循环引用不再是问题了
- 限制: 那些无法从根对象查询到的对象都将被清除,但实践中我们很少会碰到类似的情况
- 引用计数
# 内存泄露
- 内存泄漏(memory leak)是指程序不再使用的内存,由于某些原因,无法被释放到内存中。虽然JavaScript有自动垃圾收集,但是如果我们的代码写法不当,会让变量一直处于“进入环境”的状态,无法被回收,造成内存泄漏
# 常见的四种内存泄露
- 全局变量
- 被遗忘的计时器和回调
- 闭包
- DOM 之外的引用
# JS类型判断
- typeof
- typeof 可以准确判断出除 null 以外的基本类型,以及 function 类型,object类型, null 会被 typeof 判断为 object
- instanceof
- Object.prototype.toString.call(o).slice(8,-1)
object →