|
8 U7 B, o. x& l1 Y+ I% S
<p><span style="background-color: rgba(194, 224, 244, 1)"><span style="background-color: rgba(52, 73, 94, 1)"><span style="color: rgba(255, 255, 255, 1)">我认为前端生态很大,犹如一片汪洋大海,很难短时间内窥其全貌,在这里我们不谈其他,只聊聊</span> <span style="color: rgba(255, 255, 255, 1)">Set</span></span></span></p>8 @: T$ t4 m: m! u% D( g D
<p><span style="background-color: rgba(52, 73, 94, 1)"><span style="color: rgba(255, 255, 255, 1)">Set</span></span>是 es6 新提出的一个对象,也是一种数据结构,为什么es6要提出这样一个新对象呢,无非就是丰富js的对象类型,在遇到具体的业务场景需要一个比较适合的恰当的数据结构来保存和操作数据,接下来就让我们更深刻的认识下<span style="background-color: rgba(52, 73, 94, 1)"><span style="color: rgba(255, 255, 255, 1)">Set</span></span>的一些常用的方法和应用场景</p>
0 h! \: p5 ~0 E1 x* n. X; F<p>首先 <span style="background-color: rgba(52, 73, 94, 1)"><span style="color: rgba(255, 255, 255, 1)">Set</span></span>的一个重要特性就是集合中是不允许添加重复元素的,如何判断重复,如果是基本类型的话根据===操作符,如果是引用类型的话是根据对象的指针是否指向同一个引用对象,特别有意思的是NaN,<span style="background-color: rgba(52, 73, 94, 1)"><span style="color: rgba(255, 255, 255, 1)">Set</span></span>是把它作为相同对待的,尽管NaN本身是不相等的,所以<span style="background-color: rgba(52, 73, 94, 1)"><span style="color: rgba(255, 255, 255, 1)">Set</span></span>中的值都是唯一的</p>+ Q' i& S; c& z2 {# X2 @
<p><span style="background-color: rgba(52, 73, 94, 1)"><span style="color: rgba(255, 255, 255, 1)">Set</span></span>是一个构造函数,所以我们使用<span style="background-color: rgba(52, 73, 94, 1)"><span style="color: rgba(255, 255, 255, 1)">Set</span></span>必须使用new关键字</p>
3 Z+ x6 V F# d1 C9 y<p>两种方法创建</p>
5 c9 b) ?' l3 @<ul>
# ]! t$ [. |6 N6 U8 g/ m<li> 直接创建一个空的集合
& _; L3 v6 i8 z/ ~ a/ b3 H5 u<pre class="language-javascript"><code>const set = new Set()</code></pre>) o. s' k# D0 n( |$ i5 y9 A
</li>9 D. l- V2 A) J# y) Q `) T
<li>传入一个数组或者具有iterable接口的其他数据结构 5 `. s) o5 m+ U
<pre class="language-javascript"><code>const set = new Set([1,2,3,4,5])
& x% E0 l. M* _% H9 i- tconst set = new Set('我是字符串,我具有iterable接口哦')</code></pre>
9 b! n8 K. H- k$ {( |</li>
/ ?: g0 `- r% Y3 A$ x. M+ m- U</ul>
3 I: o0 d+ t; M0 Q# l0 B9 m& q<p><strong>Set 的实例属性和方法</strong></p>
2 e6 m7 d6 P0 W/ c<ol style="list-style-type: upper-roman">, l# u6 u4 u" Y# F: ]5 c
<li>操作方法- ?2 Q5 o9 [0 B6 p4 F
<ol>
* r! o5 u5 v) n- P) V( n* p' D. M<li>添加
" ^- U+ v+ n: J" a5 n- j<pre class="language-javascript"><code>const s = new Set()" c5 A: N; c& h2 v z! X
// add 方法返回Set实例本身,所以可以执行链式操作
* c4 q0 L+ g& a. l4 \) F5 nconst ret = s.add(1).add('one').add({1:'one'})</code></pre>
2 X6 N4 q! W1 n' ` I( i4 ^, C5 \</li>8 V2 d% d/ {3 M1 Y; Q) [
<li>删除
" p2 a0 k( o; F0 z<pre class="language-javascript"><code>const s = new Set([1,2,3,4,5])
* X0 `2 T( {- J' d9 b% a6 d// delete 方法返回被删除元素是否删除成功
* ]5 A1 \& v, _) t9 q& V9 n5 g3 ~const flag = s.delete(1) // true
6 u! |" \( e3 s, u- m' T+ v8 Qconst flag = s.delete('2') // false</code></pre>
6 v/ [9 [$ N4 |+ K l( q</li>; e+ C8 q& H; F2 n8 ^' u
<li>查找
) K6 p# c' Y1 q: j% U8 G) L' y<pre class="language-javascript"><code>const s = new Set([1,2,4,5,6,7])
: U w* J& K7 ^( _& t/ _const flag = s.has(2)</code></pre>
% N2 C# y2 ]) z6 v" s- n/ A</li>4 j$ n3 ~5 ]" O/ g, R; c
<li>清空, B0 j2 J) o( ]( h7 J! X \
<pre class="language-javascript"><code>const s = new Set([12,324,1])
; D1 Q4 M% M/ J' B1 q T( i! }8 B//clear 方法没有返回值,返回undefined
9 e: s! K1 n" U: N" ?s.clear()</code></pre>
: p# g$ m7 i) t0 b: v3 [: L</li>
. B8 D1 l. L8 L) R+ A<li>两个实例属性<br>, a9 s! }5 e$ \5 `( T
<pre class="language-javascript"><code>const s = new Set(): M4 o, H% Y. h6 B" X
// 实例还有两个属性% w2 k5 U+ m8 V0 r$ C
s.size //返回当前集合中元素个数$ A, l. I- p) h
s.constructor // 返回实例构造器,也就是Set</code></pre>) p+ u6 ~& m. [0 W5 |; K
<p> </p>7 C; Z5 E9 _* U0 F" y$ t
</li>
/ d1 n7 H* Z: k/ n</ol>
3 @1 ]6 E8 B1 ]</li>
! O; k- J) D( d) b e0 U<li>遍历方法</li>; S, I: y3 p3 \2 g i
</ol>
' O3 {) D$ W" `: [* C2 T% @1 w- g/ g<ol>- V5 R G+ d5 c: O6 U3 g* s9 z: k! Z! |
<li style="list-style-type: none">
" w- o& t, w3 L0 [# o1 \* u<ol>
. j4 b1 k$ R; v# P* w x- f, i# ^2 G<li>遍历键名
3 M. j9 o' S) u/ r$ |3 X! T( E<pre class="language-javascript"><code>const s = new Set(['javascript','html','css'])
# R, P6 F' i; F+ I8 a1 T
- g: }1 K0 ^ ]& ? X) g. c5 b+ e' mfor(let key of s.keys()){; K. @- T! k( _! S+ j V5 x8 k
console.log(key)
8 g2 _( y4 b& m6 a* o}/ B t9 f: S |, l, o1 x. A
//javascript% `. ? s- n+ e( c7 _- \6 Q5 l
//html
; \( i1 L, ^7 {" O a% }5 O//css8 a8 d$ R7 P) J! c% y
//遍历顺序就是插入顺序,利用这个特性可以储存一些需要按顺序调用的函数</code></pre>6 d* B2 W. w: n; \! I& w4 l$ H+ T
</li>/ W" V" b# k, S* O( K# p
<li>遍历键值
9 d: \ c3 T; a5 H- J9 O. }<pre class="language-javascript"><code>const s = new Set(['javascript','html','css'])
2 ?# S! l! H7 C3 c9 x4 O5 q! A4 Y& \% ^0 Q; ^* S
for(let value of s.values()){
! s( }* j: |. i$ E, E' D console.log(value)
3 v( G- M- A# g) g}
) M3 c A# B) n/ i U//Set不存在键名,只有键值,也可以认为键名和键值是同一个,所以keys和values返回的值是一样的</code></pre>( ]! T- y- k9 n- x. `
</li>7 J2 B/ `- g% B: s/ q, a* R
<li>遍历键值对$ h3 J4 d1 C3 {. C" x( F- A5 |0 s
<pre class="language-javascript"><code>const s = new Set(['javascript','html','css'])' l/ s, a/ T4 f8 _5 {; q
$ L9 P1 V, p5 }) |( ffor(let entry of s.entries()){
1 I" j2 K3 s( E7 N. K4 I! S console.log(entry)% q5 G/ x4 q' o0 \ X& f' _
}9 |6 Y3 |' x5 D1 b0 I1 i7 Q- q- q' \
//['javascript', 'javascript']- E7 E1 F) D. e- `2 k
//['html', 'html']
* d+ F5 v& w) ]+ a* U$ }//['css', 'css']/ u. D" v5 C% \- Y3 C
//遍历的每一对都是一个包括键名和键值的数组</code></pre>
4 Z1 p: N3 w' ]/ N2 ^! z</li>
( ?/ e- i- V& O6 V<li>forEach 使用回调函数遍历每一个元素
+ `% P; r! K5 a0 }- {2 R/ k<pre class="language-javascript"><code>const s = new Set(['javascript','html','css'])+ v Q4 H* y7 X- \* ]' c8 q
s.forEach(function(value,key,s) {
) g. V' J- Y* i% H$ F( L1 ` // 回调函数接受三个参数,键值,键名,set本身
- [# Z+ ~# Q* J! x6 y1 m console.log(`键值:${value};键名${key};集合大小${s.size};${this.thisName}`)
' L8 B4 Q0 D/ L/ m: L' k: i! b},{thisName:'改变回调函数this'})
( r/ `# I7 ^7 ] c @// forEach函数还接受第二个参数,可以绑定处理函数的this</code></pre>
" A$ e" [$ s1 G% T8 q</li>
; ^( o ~$ J) C' l<li>Set实例默认是可以迭代的,因为它的遍历器生成函数其实调用的就是values方法,这意味着我们可以直接省略values()方法直接遍历- w4 }: x% P( ], v1 u
<pre class="language-javascript"><code>const s = new Set(['javascript','html','css'])
' B ?6 }; E9 V% a# B8 @$ F5 R/ L k7 S- s
for(let value of s){8 G1 \- `" x) R" F
console.log(value)% b& x, V+ X% Z# R
}</code></pre>
. v6 g4 \$ n& e$ J5 t: R<p> </p>
+ h/ |/ F# q u/ v9 ^8 Z</li>
6 Y0 C8 a* O3 w. A! F* \6 t</ol>& v& [/ z% i& q9 {' b
</li># R# X0 Z4 c8 l, z, r
</ol>5 |. k. h# u, Q
<p><strong>应用</strong></p>
- K! m+ {7 @) \4 _) M<p>1、我们首先可以结合扩展操作符(...)给数组去重</p>
' p" i8 Z7 ~, C2 F+ k/ w<pre class="language-javascript"><code>const unique = [...new Set([1,2,3,4,5,1,21,23,5])]
3 n& R1 d: ~. ~- ]4 ~//[1, 2, 3, 4, 5, 21, 23]</code></pre>
; o& r0 s& s# H6 ?6 t/ i<p>2、实现并集,交集,差集</p>) X/ b% \1 V: p7 E! m$ @/ u
<pre class="language-javascript"><code>const s1 = new Set([1,2,3,4])
/ Z# `6 a1 \2 D# D1 ?const s2 = new Set([2,3,4,5])
3 e9 j; d, _" \. M; n: B2 g
( Z! M& K- ^/ f! K( ^; X6 q//并集 Set(5) {1, 2, 3, 4, 5}
) |7 f0 F: n# ], h: J" Gconst union = new Set([...s1,...s2])
9 j. k3 |3 }! i9 k( I& \9 r& C3 i" m' g* }' m
//交集 Set(3) {2, 3, 4}
, M" i8 Y% U _! ]const intersect = new Set([...s1].filter(v => s2.has(v))): R+ g7 _. f! `+ x7 r4 `
f3 q4 M0 n0 Z* s
//差集1 y0 `9 w6 F7 L
const difference = new Set([...new Set([...s1].filter(v => !s2.has(v))),...new Set([...s2].filter(v => !s1.has(v)))])</code></pre>; x2 a/ Y. N; @+ e! c1 v
<p> </p>
# \9 ~3 v9 n$ f5 A0 |9 d<p>Set 基本的用法就先讲到这里,有不对的地方欢迎大家指正</p># {" M% r: T0 j
|
|