垃圾回收
什么是垃圾
简单来说就是不被别人需要的,垃圾可能是单独的,也可能是抱团的,比如有个对象user = {name:'garbage'}
,后面将user置为null,user = null
,这样一来对象{name:'garbage'}
不被其他引用,无法访问到,所以成了垃圾(单独),又比如,a1 = {a1:'1',a2:a2}, a2 = {a2:'2',a3:a3}, a3 = {a3:'3'}
,再将a1置为null,此时{a1:'1',a2:a2}
和a2
,a3
也无法访问到了,于是都成了垃圾(抱团)
如何找到垃圾
垃圾回收的基本算法被称为mark-and-sweep,定期执行以下“垃圾回收”步骤
- 标记根
- 从根出发标记所有引用
- 遍历引用,若到了对象再重复以上步骤,直到最后
- 这样一来所有能访问的都能被标记
- 没有被标记的就会被回收
内部算法
- 分代收集:简单来说就是分组,分为“新的”和“旧的”,旧的降低检查频次
- 增量收集:将整个对象集拆成多个部分,逐一清除
- 闲时收集:垃圾收集器只会在 CPU 空闲时尝试运行,以减少可能对代码执行的影响
构造函数和操作符new
构造函数有两个约定:
- 命名以大写字母开头
- 只能由
"new"
操作符来执行
当一个函数被new操作符执行时,会按照以下步骤:
- 创建一个新的空对象,并分配给
this
- 执行函数体(通常会修改this,添加新属性)
- 返回
this
的值
function Animal(name) {
// 1、this = {} 隐式创建
//执行函数体
this.name = name;
// 3、return this; 隐式返回
}
const cat = new Animal('cat');
构造函数的主要目的就是实现可重用的对象创建代码,像上述想创建其他动物,直接调用new Animal('dog')
等
构造函数一般没有return
,它们的任务是将所有必要的东西写入this
,并自动转换为结果,如果出现return
,则按照以下规则
- 如果
return
返回的是一个对象,则返回这个对象,而不是this
- 如果
return
返回的是一个原始类型,则忽略
Symbol数据类型
对象属性键只有两种数据类型,字符串和Symbol,若用了其他数据类型,会自动转换为字符串,比如obj[1]
与obj['1']
相同,obj[true]和obj['true']
相同
Symbol
表示唯一的标识符,symbol
保证是唯一的。即使我们创建了许多具有相同描述的symbol
,它们的值也是不同
symbol属性不参与循环,所以for..in
,Objecct.keys
会忽略symbol,但Object.assign
会同时复制字符串和 symbol 属性
let sym1 = Symbol('sym');
let sym2 = Symbol('sym');
alert(sym1 === sym2); //false
let user = {
[sym1]: 'test',
age: 18
}
alert(user[sym1]);
for(let key in user) {
console.log(key); //age
}
console.log(Object.keys(user))//['age']
let user_ = Object({},user)
console.log(user_); //{age: 18, Symbol(sym): 'test'}
全局symbol
有时想要一个应用程序范围内的 symbol,可以在代码中随处访问,这时需要全局Symbol,介绍一下两个api
Symbol.for(key)
:根据给定的key,来从运行时的 symbol 注册表中找到对应的 symbol,如果找到了,则返回它,否则,新建一个与该键关联的 symbol,并放入全局 symbol 注册表中Symbol.keyFor(sym)
:获取全局 symbol 注册表中与某个 symbol 关联的键
const sym1 = Symbol.for('sym');
const sym2 = Symbol.for('sym');
console.log(sym1 === sym2); // true
const symDes = Symbol.keyFor(sym1);
console.log(symDes); // 'sym'
Symbol使用场景
如果我们想要向“属于”另一个脚本或者库的对象添加一个属性,我们可以创建一个 symbol 并使用它作为属性的键,这样,该属性将受到保护,防止被意外使用或重写
总结
- symbol 是唯一标识符的基本类型
- 使用Symbol(name)创建,name可选
- 如果我们希望同名的 symbol 相等,那么我们应该使用全局注册表
- 当有诉求希望对象的属性不被重写收到保护,应使用Symbol