比如我们有52张牌,现在的需求就是洗牌(俗名打乱顺序 - -!)
先构造一个数组:
const nums
= [
'
A
'
,
1
,
2
,
3
,
4
,
5
,
6
,
7
,
8
,
9
,
'
J
'
,
'
Q
'
,
'
K
']
const signs
= [
'
♥️
'
,
'
♦️
'
,
'
♣️
'
,
'
♠️
']
const cards
= []
signs
.
forEach(
sign
=>
{
nums
.
forEach(
num
=>
{
cards
.
push(
{
kind
: sign
,
num
: num
})
})
})
这样cards 就构造完成了,但是JS这样写很low,但是我觉得很快就想出来了,我们换一种其他优雅一点的方法(下面这段代码的作者是 月影):
function
*
getCards
()
{
const nums
= [
'
A
'
,
1
,
2
,
3
,
4
,
5
,
6
,
7
,
8
,
9
,
'
J
'
,
'
Q
'
,
'
K
']
yield
* nums
.
map(
num
=>(
{key
:
'
♥️
'
, num
: num
}))
yield
* nums
.
map(
num
=>(
{key
:
'
♠️
'
, num
: num
}))
yield
* nums
.
map(
num
=>(
{key
:
'
♦️
'
, num
: num
}))
yield
* nums
.
map(
num
=>(
{key
:
'
♣️
'
, num
: num
}))
}
const cards
= [
...
getCards()]
上面生成器的Key Point有两点:
// Key Point -01
...扩展运算符 内部调用的是数据结构的Iterator接口,生成器返回的就是一个Iterator对象,即遍历器对象
对这个遍历器对象执行扩展运算符 ... 就会将内部遍历到的值转为一个数组
// Key Point -02
任何数据结构只要有Iterator接口,就可以用yield * 来遍历
let readStr = (function* (){ yield* 'hello from other side' }())
readStr.next().value 这一句会输出 字符'h'
如果你写一个执行器把这个生成器执行完毕,你会发现会依次将这个字符串的单个字符给输出
好到现在为止,准备工作做完了,cards数组我们已经有了,现在我们来洗牌
// 洗牌
function
shuffle
(
cards
)
{
for(
let i
= cards
.length
-
1
; i
>=
0
; i
--)
{
var randomIndex
=
Math
.
floor(i
*
Math
.
random())
// 从 index 为 51 开始, 51 * Math.random() 的范围是 (0, 51)
// Math.floor 之后的整数范围是 [0, 50]
// 我们将 cards[51] 和 前面的随机索引位置的值交换
// 然后到 50个的时候,和 前面 [0, 49] 中索引取一个随机的 然后交换值
// 这样下去,交换位置之后 索引为51 和 50 的值就不会变动了
const temp
= cards[randomIndex]
cards[randomIndex]
= cards[i]
cards[i]
= temp
}
return cards
}
其实感觉在遍历数组的时候改变数组不太好,可以返回一个新的数组更好一点,当然也看实际的需求。
// 强制复习一下
const params
= (
function
*
(){
yield
1
;
yield
2
;
yield
* (
function
*
(){
yield
3
;
yield
4
;
})()
yield
* [
5
,
6
,
7]
yield
*
'
abc
'
// yield * { length: 9, name: 'Ariza' }
})()
console
.
log([
...params])