写作不易,未经作者允许禁止以任何形式转载!
WeakMap是key / value的组合,key只接受对象,不接受基本类型,value可以为任意类型。
在WeakMap中设置一组关联对象,返回WeakMap对象
返回key的关联对象,不存在时返回undefined
根据是否有key关联对象,放回一个Boolean值
移除key的关联对象,之后执行has(key)方法返回false
const name = "LeBron";
const person = {
name: "LeBron",
age: 21,
};
let wk = new WeakMap();
wk.set(person, "nice");
console.log(wk.get(person)); // nice
wk.set(name, 1); // TypeError: Invalid value used as weak map key
let map = new Map();
map.set(name, "JS");
map.set(person, "nice");
console.log(map.get(name)); // JS
console.log(map.get(person)); // nice
const name = "LeBron";
const person = {
name: "LeBron",
age: 21,
};
let wk = new WeakMap();
wk.set(name, "JS");
wk.set(person, "nice");
console.log(wk.keys()); // TypeError: wk.keys is not a function
console.log(wk.values()); // TypeError: wk.values is not a function
console.log(wk.entries()); // TypeError: wk.entries is not a function
let map = new Map();
map.set(person, "nice");
console.log(map.keys()); // [Map Iterator] { 'LeBron', { name: 'LeBron', age: 21 } }
console.log(map.values()); // [Map Iterator] { 'JS', 'nice' }
console.log(map.entries()); // [Map Entries] {
// [ 'LeBron', 'JS' ],
// [ { name: 'LeBron', age: 21 }, 'nice' ]
// }
node --expose-gc xxx
Map
function memmorySizeLogger() {
global.gc();
const used = process.memoryUsage().heapUsed;
console.log((used / 1024 / 1024).toFixed(2) + "M");
}
memmorySizeLogger(); // 1.79M
let person = {
name: "LeBron",
age: 21,
tmp: new Array(5 * 1024 * 1024),
};
memmorySizeLogger(); // 41.96M
let map = new Map();
memmorySizeLogger(); // 41.96M
map.set(person, "nice");
memmorySizeLogger(); // 41.96M
person = null;
memmorySizeLogger(); // 41.96M person的内存没有被回收
如果想在这种情况下正常GC,标记为null前需先执行map.delete(person)
WeakMap
function memmorySizeLogger() {
global.gc();
const used = process.memoryUsage().heapUsed;
console.log((used / 1024 / 1024).toFixed(2) + "M");
}
memmorySizeLogger(); // 1.79M
let person = {
name: "LeBron",
age: 21,
tmp: new Array(5 * 1024 * 1024),
};
memmorySizeLogger(); // 41.96M
let wk = new WeakMap();
memmorySizeLogger(); // 41.96M
wk.set(person, "nice");
memmorySizeLogger(); // 41.96M
person = null;
memmorySizeLogger(); // 1.96M person的内存被回收
let domData = new WeakMap();
let dom = document.getElementById("xxx");
const anyDomData = getDomData(dom);
domData.set(dom, anyDomData);
console.log(domData.get(dom));
dom.parentNode.removeChild(dom);
dom = null;
let cache = new WeakMap();
class HandleCache {
get(key) {
if (cache.has(key)) {
return cache.get(key);
} else {
return undefined;
}
}
set(key, value) {
cache.set(key, value)
}
delete(key){
cache.delete(key)
}
}
let privateData = new WeakMap();
class Person{
constructor(name, age){
privateData.set(this,{name, age});
}
getData(){
return privateData.get(this);
}
}
WeakSet对象是一些对象值的集合,并且其中的每个对象只能出现一次,在WeakSet集合中是唯一的
在该WeakSet对象中添加一个新的元素value
在该WeakSet对象中删除value这个元素后,has方法会返回false。
返回一个Boolean值,表示给定的value值是否存在这个WeakSet中
const name = "LeBron";
const age = 21;
const person = {
name: "LeBron",
age: 21,
};
const ws = new WeakSet();
const set = new Set();
set.add(name);
set.add(age);
set.add(person);
ws.add(person);
ws.add(name); // TypeError: Invalid value used in weak set
ws.add(age); // TypeError: Invalid value used in weak set
const name = "LeBron";
const age = 21;
const person = {
name: "LeBron",
age: 21,
};
const ws = new WeakSet();
const set = new Set();
set.add(name);
set.add(age);
set.add(person);
console.log(set.values()); // { 'LeBron', 21, { name: 'LeBron', age: 21 } }
ws.add(person);
ws.add(name);
ws.add(age);
console.log(set.values()); // TypeError: ws.values is not a function
node --expose-gc xxx
Set存在values数组,在原value指向null后,values数组仍对value的值存在强引用,影响正常GC
function memmorySizeLogger() {
global.gc();
const used = process.memoryUsage().heapUsed;
console.log((used / 1024 / 1024).toFixed(2) + "M");
}
memmorySizeLogger(); // 1.79M
let person = {
name: "LeBron",
age: 21,
tmp: new Array(5 * 1024 * 1024),
};
memmorySizeLogger(); // 41.96M
const set = new Set();
set.add(person);
memmorySizeLogger(); // 41.96M
person = null;
memmorySizeLogger(); // 41.96M
WeakSet不存在这样的数组,故不影响正常GC
function memmorySizeLogger() {
global.gc();
const used = process.memoryUsage().heapUsed;
console.log((used / 1024 / 1024).toFixed(2) + "M");
}
memmorySizeLogger(); // 1.79M
let person = {
name: "LeBron",
age: 21,
tmp: new Array(5 * 1024 * 1024),
};
memmorySizeLogger(); // 41.96M
const ws = new WeakSet();
ws.add(person);
memmorySizeLogger(); // 41.96M
person = null;
memmorySizeLogger(); // 1.96M
递归调用自身的函数需要一种通过跟踪哪些对象已被处理,来应对循环数据结构的方法
// 对 传入的subject对象 内部存储的所有内容执行回调
function execRecursively(fn, subject, _refs = null){
if(!_refs)
_refs = new WeakSet();
// 避免无限递归
if(_refs.has(subject))
return;
fn(subject);
if("object" === typeof subject){
_refs.add(subject);
for(let key in subject)
execRecursively(fn, subject[key], _refs);
}
}
const foo = {
foo: "Foo",
bar: {
bar: "Bar"
}
};
foo.bar.baz = foo; // 循环引用!
execRecursively(obj => console.log(obj), foo);
Reflect译为反射,是一个内置的新的全局对象,它提供拦截JavaScript操作的方法。这些方法与Proxy handler的方法相同。Reflect不是一个函数对象,是静态的类似工具函数,类似Math,因此它是不可构造的
具体用法参考:Reflect MDN文档
Reflect.apply()
Reflect.construct()
Reflect.defineProperty()
Reflect.deleteProperty()
Reflect.get()
Reflect.getOwnPropertyDescriptor()
Reflect.getPrototypeOf()
Reflect.has()
Reflect.isExtensible()
Reflect.ownKeys()
Reflect.preventExtensions()
Reflect.set()
Reflect.setPrototypeOf()
这些方法与Proxy handler的方法的命名相同,其中的一些方法与Object的方法相同,尽管二者之间存在着某些细微的差别
你会发现JS的内置反射方法散落在各处,Reflect将他们很好地组织了起来。
使用Reflect进行操作不容易抛出异常、线程阻塞,使代码更健壮地运行。