Set和Map

Set

const set = new Set([1, 2, 3, 4, 4]);
[...set]
// [1, 2, 3, 4]
let set = new Set();
set.add({});
set.size // 1
set.add({});
set.size // 2
//两个对象总是不相等的。
//转化:
const items = new Set([1, 2, 3, 4, 5]);
const array = Array.from(items);

基本可以使用数组的功能:

let a = new Set([1, 2, 3]);
let b = new Set([4, 3, 2]);
// 并集
let union = new Set([...a, ...b]);
// Set {1, 2, 3, 4}
// 交集
let intersect = new Set([...a].filter(x => b.has(x)));
// set {2, 3}
// (a 相对于 b 的)差集
let difference = new Set([...a].filter(x => !b.has(x)));
// Set {1}

WeakSet

WeakSet()参数只能为对象,而不能是其它类型,优点是存储dom节点而不用担心在节点从文档移除时,会引发内存泄漏问题。

Map

const m = new Map();
const o = {p: 'Hello World'};
m.set(o, 'content')
m.get(o) // "content"
m.has(o) // true
m.delete(o) // true
m.has(o) // false
//对于不同对象实例,无法获取对应的值,键实际上和内存地址绑定
const map = new Map();
map.set(['a'], 555);
map.get(['a']) // undefined
//链式
let map = new Map()
  .set(1, 'a')
  .set(2, 'b')
  .set(3, 'c');

其它情况下,严格相等的(0和-0)都会被当作一个键,NaN也会被当作相等。

//也可以使用拓展
const map0 = new Map()
  .set(1, 'a')
  .set(2, 'b')
  .set(3, 'c');
const map1 = new Map(
  [...map0].filter(([k, v]) => k < 3)
);

WeakMap

只接受对象作为键名,且不计入垃圾回收,为了防止内存泄漏,所引用的键的对象会可能在未来消失,即消除外部多余引用,而不清除内部的

const wm = new WeakMap();
let key = {};
let obj = {foo: 1};
wm.set(key, obj);
obj = null;
wm.get(key)
// Object {foo: 1}

Proxy

使用Proxy设置访问拦截,相当于重载操作符

//第一个是被代理的目标,而handler是定义的拦截器
var proxy = new Proxy(target, handler);
var proxy = new Proxy({}, {
  get: function(target, propKey) {
    return 35;
  }
});
proxy.time // 35
proxy.name // 35
proxy.title // 35

返回的结果指向原对象:

const proxy = new Proxy({}, {
  get: function(target, key, receiver) {
    return receiver;
  }
});
const d = Object.create(proxy);
d.a === d // true
//禁止写操作
const handler = {
  set: function(obj, prop, value, receiver) {
    obj[prop] = receiver;
  }
};
const proxy = new Proxy({}, handler);
const myObj = {};
Object.setPrototypeOf(myObj, proxy);
myObj.foo = 'bar';
myObj.foo === myObj // true

apply

拦截调用,三个参数是目标对象,目标对象上下文(this),目标对象的参数数组,一但出现函数调用,不论使用的是什么方法,都会被拦截。

has

拦截in运算符

var handler = {
  has (target, key) {
    if (key[0] === '_') {
      return false;
    }
    return key in target;
  }
};
var target = { _prop: 'foo', prop: 'foo' };
var proxy = new Proxy(target, handler);
'_prop' in proxy // false

construct

对于new命令拦截,参数是目标对象,构造函数参数对象,返回对象
此外还有:

  • deleteProperty()拦截delete操作
  • defineProperty()拦截对应的定义属性操作。
  • ...其它同理.

Proxy.revocable()

返回一个可取消的Proxy实例。

let target = {};
let handler = {};
let {proxy, revoke} = Proxy.revocable(target, handler);
proxy.foo = 123;
proxy.foo // 123
revoke();//取消代理
//对于Proxy代理,this指向的是Proxy对象。

使用Proxy可以定义出拦截器,作为代理对象

function createWebService(baseUrl) {
  return new Proxy({}, {
    get(target, propKey, receiver) {
      return () => httpGet(baseUrl + '/' + propKey);
    }
  });
}
const service = createWebService('http://example.com/data');
service.employees().then(json => {
  const employees = JSON.parse(json);
  // ···
});

Reflect

将部分Object中明显属于语言内部的方法放到Reflect对象上,一般用于对应的读取获取操作,反向获取属性和方法。

var myObject = {
  foo: 4,
  set bar(value) {
    return this.foo = value;
  },
};
var myReceiverObject = {
  foo: 0,
};
Reflect.set(myObject, 'bar', 1, myReceiverObject);
myObject.foo // 4
myReceiverObject.foo // 1
posted @ 2022-10-19 10:09  梦呓qwq  阅读(16)  评论(0编辑  收藏  举报