前端培训-中级阶段(32)-set、map、proxy、symbol、reflect、generator

简介: 前端最基础的就是 HTML+CSS+Javascript。掌握了这三门技术就算入门,但也仅仅是入门,现在前端开发的定义已经远远不止这些。前端小课堂(HTML/CSS/JS),本着提升技术水平,打牢基础知识的中心思想,我们开课啦(每周四)。

前言


这节标题超长了,难受箭头函数、set、map、proxy、symbol、reflect、generator


箭头函数


之前声明函数使用 function funName(arg1,...args){return args}

ES6 增加了新的声明函数方式 (arg1,...args)=>args


箭头函数的特点


  1. 匿名函数。通过上面例子可以看出,匿名函数没有名字。用法等价于之前的函数表达式。


  1. 简洁。[1,2,3,4,0,-1,-2,-3].map(v=>Math.sign(v))
  1. 入参的省略。如果只有一个入参,那么括号可以省略。没有入参、多个入参、rest 参数(...)、解构({status, response})都需要加括号。


bVbBSpF.webp.jpg


2.函数体的省略。如果没有花括号,那么只能传入一个表达式,表达式的结果会 return。如果有花括号,就需要显式的return,当然也可以不写默认 returnundefined


3.this 指向

  1. 箭头函数的 this 对象指向定义时所在的对象,而不是使用时所在的对象。
  2. 箭头函数的 this 对象是不可变的。bind、call、apply、赋值等操作都无法改变。


4.不可以当做构造函数。因为上面的 this 问题。


5.没有 arguments


6.不能用作 Generator 函数。不可以使用 yield 命令


箭头函数的一些错误用法


  1. 不应该在声明对象的时候使用。因为这个时候里面的 this 指向定义时的环境。
obj = {
  name: 'app',
  jumps: () => {
    console.log(this.app);
  }
}


Set、WeakSet


Set 特点是值唯一和有序。类似于数组,但是成员的值都是唯一的,没有重复的值,遍历的话是插入顺序。Array.from(new Set([1,2,3,1,1,2,3,1])) 依赖值唯一的特性实现去重。


1.png


Set 构造函数


new Set([iterable]); 使用可迭代的数组来创建。


  1. new Set([1,2,3,4,2,1,1,1,12,3])


  1. new Set('123123')


  1. new Set(['123123',1,2,3])


  1. new Set(document.querySelectorAll('a'))


5.

2.png


属性和方法


  1. Set.prototype.size:返回总数,等价于(Array.prototype.length


  1. Set.prototype.add(value):添加,返回当前对象可链式操作。


  1. Set.prototype.delete(value):删除,返回一个布尔值,表示删除是否成功。


  1. Set.prototype.has(value):返回一个布尔值,表示该值是否为Set的成员。


  1. Set.prototype.clear():清除所有成员,没有返回值。


  1. Set.prototype.keys():返回键(key)的遍历器 Iterator。


  1. Set.prototype.values():返回值(value)的遍历器 Iterator。


  1. Set.prototype.entries():返回键值对([key, value])的遍历器 Iterator。


  1. Set.prototype.forEach():使用回调函数(value, key, this)=>遍历每个成员


WeakSet


  1. 只能存放对象的集合


  1. 以弱引用方式保存。弱引用就是可以被垃圾回收(如果放入数组,那么你不知道什么实际是可以被回收的,因为数组是强引用),


  1. 没有总数


  1. 不可枚举。


bVbCSVO.webp.jpg

Map、WeakMap


Map 其实 和 JavaScript 的对象(Object)一样,本质上是键值对的集合(Hash 结构)。


但是传统上 Object 只能用字符串当作键,在使用上有很大的局限性。


Map 的数据结构也可以理解为对象,是键值对的集合。


但是 key 的范围不限于字符串,可以是其他类型(包括对象)都可以当作键。是一种更完善的 Hash 结构实现。


userinfo = {name: 'lilnong.top'}
map = new Map()
map.set(userinfo, {age: 123})
map.has(userinfo)
map.get(userinfo)

bVbGum9.webp.jpg


构造函数


map = new Map([
  ['key1', 'value1'],
  ['key2', 'value2']
]);
map.forEach(
  (key, value) => console.log(key, value)
);


bVbGun0.webp.jpg


属性和方法


  1. size 返回记录总数。(Object 可是没有这个属性的哟)


  1. set(key, value) 赋值操作


  1. get(key) 取值操作


  1. has(key) 判断当前 key 是否存在于集合中。


  1. delete(key) 删除操作。返回 true,表明删除成功。返回 false 表明删除失败,比如你删除了一个不存在的 key


  1. clear() 清空所有。


  1. 遍历方法。(插入顺序)
  • Map.prototype.keys():返回键名的遍历器。
  • Map.prototype.values():返回键值的遍历器。
  • Map.prototype.entries():返回所有成员的遍历器。
  • Map.prototype.forEach():遍历 Map 的所有成员。


weakMap


WeakMap 只接受对象作为键名(null除外),不接受其他类型的值作为键名。


WeakMap 的键名所指向的对象,不计入垃圾回收机制。


因为是弱引用,所以没有遍历方法、没有 size,不支持 clear()。


proxy


Proxy 用于修改操作(getset)的默认行为。


说到这里是不是想到了 Object.defineProperty ?其实也和 JavaBean 那种操作 getter、setter 差不多。


等同于在语言层面做出修改,对编程语言进行编程,属于一种“元编程”(meta programming )。


Proxy 可以理解成,在目标对象之前架设个代理,对该对象的访问,都必须先通过代理,这样可以对外界的访问进行过滤和改写。


vue 2.x 基于 Object.defineProperty 来实现的,但是会有一些场景监测不到(array.lenth、$set)。


vue 3.x 使用了 Proxy 来做了,可以监测到更多的场景。当然,基于兼容性考虑还是可以回退到 Object.defineProperty


var obj = new Proxy({}, {
  get: function (target, propKey, receiver) {
    console.log(`getting ${propKey}!`);
    return Reflect.get(target, propKey, receiver);
  },
  set: function (target, propKey, value, receiver) {
    console.log(`setting ${propKey}!`);
    return Reflect.set(target, propKey, value, receiver);
  }
});


从下面这个例子我们可以看到,我们可以只设置读的代理,不管读取什么都返回 www.lilnong.top。然后我们没有设置写的代理,值已经被真正的写入了。


bVbGuZR.webp.jpg


构造函数


var proxy = new Proxy(target, handler);


支持代理的操作


key arguments 触发时机 demo
get (target, propKey, receiver) 读取属性时触发 proxy.titleproxy['title']
set (target, propKey, value, receiver) 设置属性时触发 proxy.title = 'lilnong.top'proxy['title'] = 'lilnong.top'
has (target, propKey) in 时触发 title in proxy
deleteProperty (target, propKey) delete时触发 delete proxy.title
ownKeys (target) 获取 key 合集时触发 Object.getOwnPropertyNames(proxy)Object.getOwnPropertySymbols(proxy)Object.keys(proxy)for...in
getOwnPropertyDescriptor (target, propKey) 读取属性时触发 Object.getOwnPropertyDescriptor(proxy, propKey)
defineProperty (target, propKey, propDesc) 读取属性时触发 Object.defineProperty(proxy, propKey, propDesc)Object.defineProperties(proxy, propDescs)
preventExtensions (target) 读取属性时触发 Object.preventExtensions(proxy)
getPrototypeOf (target) 读取属性时触发 Object.getPrototypeOf(proxy)
isExtensible (target) 读取属性时触发 Object.isExtensible(proxy)
setPrototypeOf (target, proto) 读取属性时触发 Object.setPrototypeOf(proxy, proto)
apply (target, object, args) proxy 为函数被调用时触发 proxy(...args)proxy.call(object, ...args)proxy.apply(...)
construct (target, object, args) proxy 为实例被New 时触发 new proxy(...args))


注意事项


  1. 严格模式下,set 代理执行完毕应该返回 true,否则会报错。


symbol


ES5 的对象属性名都是字符串 ,这容易造成属性名的冲突。比如,你使用了一个他人提供的对象,但又想为这个对象添加新的方法(mixin 模式),新方法的名字就有可能与现有方法产生冲突。如果有一种 机制,保证每个属性的名字都是独一无二的就好了,这样就从根本上防止属性名的冲突。这就是 ES6 引入 Symbol 的原因。

ES6 引入了一种新的原始数据类型Symbol,表示独一无二的值。它是 JavaScript 语言的第七种数据类型,前六种是:undefinednull、布尔值(Boolean)、字符串(String)、数值(Number)、对象(Object)。


Symbol 值通过 Symbol 函数生成。这就是说,对象的属性名现在可以有两种类型,一种是原来就有的字符串,另一种就是新增的 Symbol 类型。凡是属性名属于 Symbol 类型,就都是独一无二的,可以保证不会与其他属性名产生冲突。


s = Symbol();
typeof s // "symbol"
s1 = Symbol('foo');
s1 // Symbol(foo)
s1.toString() // "Symbol(foo)"
s2 = Symbol('bar');
s2 // Symbol(bar)
s2.toString() // "Symbol(bar)"


reflect


Reflect对象与Proxy对象一样,也是 ES6 为了操作对象而提供的新 API。


Reflect 对象的设计目的有这样几个。

(1) 将Object对象的一些明显属于语言内部的方法(比如Object.defineProperty),放到Reflect对象上。现阶段,某些方法同时在ObjectReflect对象上部署,未来的新方法将只部署在Reflect对象上。也就是说,从Reflect对象上可以拿到语言内部的方法。

(2) 修改某些Object方法的返回结果,让其变得更合理。比如,Object.defineProperty(obj, name, desc)在无法定义属性时,会抛出一个错误,而Reflect.defineProperty(obj, name, desc)则会返回false

....

....https://es6.ruanyifeng.com/#d...


generator


Generator 函数也是 ES6 提供的一种异步编程解决方案。现在一般都是 Promise 或者 await/async,就不展开说了。

Generator 函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同。本章详细介绍 Generator 函数的语法和 API,它的异步编程应用请看《Generator 函数的异步应用》一章。

Generator 函数有多种理解角度。语法上,首先可以把它理解成,Generator 函数是一个状态机,封装了多个内部状态。

执行 Generator 函数会返回一个遍历器对象,也就是说,Generator 函数除了状态机,还是一个遍历器对象生成函数。返回的遍历器对象,可以依次遍历 Generator 函数内部的每一个状态。

形式上,Generator 函数是一个普通函数,但是有两个特征。一是,function关键字与函数名之间有一个星号;二是,函数体内部使用yield表达式,定义不同的内部状态(yield在英语里的意思就是“产出”)。

....

.... https://es6.ruanyifeng.com/#d...


相关文章
|
1月前
|
算法
你对Collection中Set、List、Map理解?
你对Collection中Set、List、Map理解?
73 18
你对Collection中Set、List、Map理解?
|
1月前
|
存储 缓存 安全
只会“有序无序”?面试官嫌弃的List、Set、Map回答!
小米,一位热衷于技术分享的程序员,通过与朋友小林的对话,详细解析了Java面试中常见的List、Set、Map三者之间的区别,不仅涵盖了它们的基本特性,还深入探讨了各自的实现原理及应用场景,帮助面试者更好地准备相关问题。
65 20
|
2月前
|
存储 C++ 容器
【C++】map、set基本用法
本文介绍了C++ STL中的`map`和`set`两种关联容器。`map`用于存储键值对,每个键唯一;而`set`存储唯一元素,不包含值。两者均基于红黑树实现,支持高效的查找、插入和删除操作。文中详细列举了它们的构造方法、迭代器、容量检查、元素修改等常用接口,并简要对比了`map`与`set`的主要差异。此外,还介绍了允许重复元素的`multiset`和`multimap`。
45 3
【C++】map、set基本用法
|
2月前
|
存储 算法 C++
【C++】unordered_map(set)
C++中的`unordered`容器(如`std::unordered_set`、`std::unordered_map`)基于哈希表实现,提供高效的查找、插入和删除操作。哈希表通过哈希函数将元素映射到特定的“桶”中,每个桶可存储一个或多个元素,以处理哈希冲突。主要组成部分包括哈希表、哈希函数、冲突处理机制、负载因子和再散列,以及迭代器。哈希函数用于计算元素的哈希值,冲突通过开链法解决,负载因子控制哈希表的扩展。迭代器支持遍历容器中的元素。`unordered_map`和`unordered_set`的插入、查找和删除操作在理想情况下时间复杂度为O(1),但在冲突较多时可能退化为O(n)。
32 5
|
4月前
|
存储 Java API
【数据结构】map&set详解
本文详细介绍了Java集合框架中的Set系列和Map系列集合。Set系列包括HashSet(哈希表实现,无序且元素唯一)、LinkedHashSet(保持插入顺序的HashSet)、TreeSet(红黑树实现,自动排序)。Map系列为双列集合,键值一一对应,键不可重复,值可重复。文章还介绍了HashMap、LinkedHashMap、TreeMap的具体实现与应用场景,并提供了面试题示例,如随机链表复制、宝石与石头、前K个高频单词等问题的解决方案。
56 6
【数据结构】map&set详解
|
3月前
|
存储 JavaScript 前端开发
Set、Map、WeakSet 和 WeakMap 的区别
在 JavaScript 中,Set 和 Map 用于存储唯一值和键值对,支持多种操作方法,如添加、删除和检查元素。WeakSet 和 WeakMap 则存储弱引用的对象,有助于防止内存泄漏,适合特定场景使用。
|
3月前
|
存储 缓存 Java
【用Java学习数据结构系列】HashMap与TreeMap的区别,以及Map与Set的关系
【用Java学习数据结构系列】HashMap与TreeMap的区别,以及Map与Set的关系
52 1
|
4月前
|
算法
你对Collection中Set、List、Map理解?
你对Collection中Set、List、Map理解?
48 5
|
4月前
|
存储 JavaScript 前端开发
js的map和set |21
js的map和set |21
|
4月前
|
存储 前端开发 API
ES6的Set和Map你都知道吗?一文了解集合和字典在前端中的应用
该文章详细介绍了ES6中Set和Map数据结构的特性和使用方法,并探讨了它们在前端开发中的具体应用,包括如何利用这些数据结构来解决常见的编程问题。
ES6的Set和Map你都知道吗?一文了解集合和字典在前端中的应用