深入理解ES6 007【学习笔记】

Set集合与Map集合

在js中有g一个in运算符,其不需要读取对象的值就要以判断属性在对象中是否存在,如果存在就返回true。但是in运算符也会检索对象的原型,只有当对象原型为null时使用这个方法才比较稳妥。

Set集合

let set = new Set()
set.add(5)
set.add("5")
console.log(set.size) // 2
const key1={},key2={}
set.add(key1)
set.add(key1)
console.log(set.size) // 4
// 传入相同值实际上会被忽略
let set1 = new Set(1,2,3,4,5,5,5,5)
console.log(set.size) //5
set1.has(5) //true
set1.has(6) // false
set1.delete(5)
set1.has(5) //false

set1.clear() // 所有元素被清除

set集合中不会对所存值进行强制的类型转换,数字5和字符串“5”可以作为两个独立元素存在(引擎内部使用之前提到过的Object.is()来判断),如果向Set中添加多个对象则它们之前彼此保持独立。

Set集合的forEach方法

forEach()方法的回调函数接受以下3个参数

  • Set集合下一次索引位置
  • 与第一个参数一样的值
  • 被遍历的Set集合本身

Set集合的forEach()方法与数组中的forEach()方法有一个奇怪的差别:回调函数前两个参数的值竟然是一样的。实际上Map集合的forEach()的回调函数都接受3个参数,前两个分别是值和键名。

forEach函数的第二个参数与数组一样,如果需要回调函数中使用this使用,则可以将它作为第二参数传入

let set = new Set([1,2])
let processor = {
  output(value){
    console.log(value)
  },
  process(dataSet){
    // 这里使用箭头函数,就无须再将this作为第二个参数传入回调函数了
    dataSet.forEach(function(value){
      this.output(value)
    },this)
  }
}
processor.process(set)

尽管Set集合更适合用来跟踪多个值,而且又可以通过forEach()方法操作集合中的每一个元素,但是你不能像访问数组元素那样直接通过索引访问集合中的元素。如有需要,最好先将Set集合转换成一个数组

let set = new Set([1,2,3,3,3,4,5])
arrray = [...set]
console.log(array) // [1,2,3,4,5] 去重

function eliminateDuplicates(items){
  return [...new Set(items)]
}
let numbers = [1,2,3,3,3,4,5],
noDuplicates = eliminateDuplicates(numbers);
console.log(noDuplicates); // [1,2,3,4,5]

Weak Seb集合

将对象存储在Set的实例中与存储在变量中一样,只要Set实例中的引用存在,垃圾回收机制就不能释放该对象的内存空间,于是之前提到的Set类型可以被看作一个强引用的Set集合。如下

let set = new Set(),
key = {};
set.add(key);
console.log(set.size) // 1
// 移除原始引用
key = null;
console.log(set.size) // 1
// 重新取回原始引用
key = [...set][0]

比如我们使用这个set存储一个dom对象,当有脚本把这个dom元素删除掉,那么set中还保留着这份引用(引起内存泄露),所以ES6引入了一个WeakSet集合。WeakSet只能存储对象的弱引用,并且不可以存储原始值;集合中的弱引用如果是对象唯一引用,则会被回收并释放相应内存。

// 集合支持add()/has()/delete()
let set = new WeakSet(),key = {};
// 向集合添加对象
set.add(key);
console.log(set.has(key)); // true
set.delete(key);
console.log(set.has(key)); // false
let key1 = {}, key2 = {};
set = new WeakSet([key1,key2]) // 如果数组中包含其非对象值,程序会抛出错误
console.log(set.has(key1)) // true
console.log(set.has(key2)) // true

// #################
// 移除对象key的最后一个强引用(Weak Set中的引用也自动移除)
let set = new Set(),
key = {};
set.add(key);
console.log(set.has(key)) // true
// 移除对象key的最后个强引用(Weak Set中的引用也自动移除)
key = null;
// 这段代码执行过后,就无法访问WeakSet中的key的引用了,由于我们需要向has方法传递一个强引用才能验证这个弱引用是否已被移除了。
  • WeakSet
  • 如果向add/has/delete 3个方法传入非对象参数会导致程序报错
  • 不可迭代 不能使用for-of循环
  • 不暴露任何迭代器keysvalues所以无法通过程序本身来检测其中的内容
  • 不支持forEach
  • 不支持size

Map

  • set
  • get
  • has
  • delete
  • clear
  • size属性

初始化方法

let map = new Map([["name","Nicholas"],["age",23]])

forEach((value,key,ownerMap)=>{},绑定上下文)

let map = new Map([["name","Nicholas"],["age",23]])
map.forEach(function(value,key,ownerMap){
   console.log(key+" "+value);
   console.log(ownerMap === map)
})

WeakMap

原理跟WeakSet一致的,键是对对象的弱引用,而且key只能是存对象

let map = new WeakMap(),
element = document.querySelector('.element');
map.set(element,"Original")
let value = map.get(element)
console.log(value) // Original
// 移除element元素
element.parentNode.removeChild(element);
element = null;
// 此时Weak Map集合为空

私有对象数据

function Person(name){
  this._name = name;
}
Person.prototype.getName = function(){
  return this._name;
}
// 约定前缀为下划线的属性为私有属性,不允许在对象实例外改变这个属性。例如,只能通过getName()方法读取this._name,所以它也有可能在无意间被覆写

ES5可以通过以下这种模式创建一个对象接近真正的私有数据

var Person = (function(){
  var privateData = {},
  privateId = 0;
  function Person(name){
    Object.defineProperty(this,"_id",{value:privateId++})
    privateData[this._id] = {
      name:name
    }
  }
  Person.prototype.getName = function(){
    return privateData[this._id].name
  }
  return Person
}())

调用Person构造函数时,属性_id的值被加1,这个属性不可枚举,不可配置且不可写,上面的代码最大的问题不能主动管理,由于无法获取对象实例何时被销毁,因此privateData中的数据就永远不会消失。而且使用WeakMap集合可以解决这个问题

let Person = (function(){
  let privateData = new WeakMap();
  function Person(name){
    privateData.set(this,{name:name})
  }
  Person.prototype.getName = function(){
    return privateData.get(this).name
  }
  return Person
}())
// 只要对象实例被销毁,相关信息也会被销毁,从而保证了信息的私有性

主题测试文章,只做测试使用。发布者:Walker,转转请注明出处:https://joyjs.cn/archives/4333

(0)
Walker的头像Walker
上一篇 2025年3月8日 12:51
下一篇 2025年3月8日 12:51

相关推荐

  • TS珠峰 002【学习笔记】

    泛型 /* * @Author: error: error: git config user.name & please set dead value or install git && error: git config user.email & please set dead value or install git &a…

    个人 2025年3月27日
    1.2K00
  • Nuxt3_扫盲 入门与原理介绍【学习笔记】

    Nuxt 3 入门与原理介绍 💡 什么是 Nuxt 3? Nuxt 3 是基于 Vue 3 和 Vite 打造的全栈前端框架,支持: 服务端渲染(SSR) 静态站点生成(SSG) 单页应用(SPA) 构建全栈应用(支持 API) Nuxt 3 是 Vue 的“加强版”,帮你简化项目结构和开发流程。 🔧 核心原理 功能 Nuxt 如何处理 ✅ 页面路由 自动根…

    个人 2025年4月6日
    1.7K00
  • 深入理解ES6 001【学习笔记】

    块级作用域绑定 之前的变量声明var无论在哪里声明的都被认为是作域顶部声明的,由于函数是一等公民,所以顺序一般是function 函数名()、var 变量。 块级声明 块级声明用于声明在指定块的作用域之外无法访问的变量。块级作用域存在于: 函数内部 块中(字符和{和}之间的区域) 临时死区 javascript引擎在扫描代码发现变量声明时,要么将它们提升至作…

    个人 2025年3月8日
    1.4K00
  • TS珠峰 001【学习笔记】

    课程大纲 搭建 TypeScript 开发环境。 掌握 TypeScript 的基础类型,联合类型和交叉类型。 详细类型断言的作用和用法。 掌握 TypeScript 中函数、类的类型声明方式。 掌握类型别名、接口的作用和定义。 掌握泛型的应用场景,熟练应用泛型。 灵活运用条件类型、映射类型与内置类型。 创建和使用自定义类型。 理解命名空间、模块的概念已经使…

    个人 2025年3月27日
    1.2K00
  • TS珠峰 003【学习笔记】

    装饰器 // 装饰器 // 只能在类中使用(类本身,类成员使用) // 装饰器,类的装饰器,属性装饰器,访问装饰器 参数装饰器 // 1. 类型装饰器 给类进行扩展,也可以返回一个子类 // 先要在tsconfig.json中开启experimentalDecorators const classDecorator1 = <T extends new …

    个人 2025年3月27日
    1.2K00

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信
欢迎🌹 Coding never stops, keep learning! 💡💻 光临🌹