JavaScript ES语法学习笔记(六)

Generator(如何让遍历“停”下来)

通俗的讲,Generators是可以用来控制迭代器的函数。
ES6支持这功能,应用场景:一个个抽奖

1
2
3
4
5
6
7
8
9
10
loop()
function * loop ({ //*号之间有空格
  for (let i = 0; i < 5; i++) {
    yield console.log(i) //遇到yield来暂停函数的执行
  }
}
const l=loop()
l.next() //执行一步
l.next()
l.next()

语法
1、比普通函数多一个 *
2、函数内部用yield来控制程序的执行的“暂停”
3、函数的返回值通过调用next来恢复程序的执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function * gen () {
let val
val = yield 1 //yield后面可以加常数,*,数组
console.log(val)
}
const l = gen()
l.next()
l.next()

function * gen ({
  let val
  val = yield * [123] //yield *后可加实例
  console.log(val)
}
const l = gen()
l.next() //next会返回一个对象,包含两个属性:value-运行结果 done-遍历是否结束
l.next()

循环中间传参

1
2
3
4
5
6
7
8
9
10
function * gen ({
  let val
  val = yield  [123]
  console.log(val)
}
const l = gen()
l.next(10) //找到yield后暂停,没进行赋值
l.return //控制循环结束,类似for循环中的break
console.log(l.return (100)) //控制最后的返回值
l.next(20) //用20代替yield后表达式的返回值

throw()
通过throw方法在Generator外部控制内部执行的“终断”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function * gen ({
  while (true) {
    try {
      yield 1
    } catch (e) {
      console.log(e.message)
    }
  }
}
const g = gen()
console.log(g.next()) //value:1 ,done:false
console.log(g.next()) //value:1 ,done:false
console.log(g.next()) //value:1 ,done:false
g.throw(new Error('break')) //中断操作
console.log(g.next()) //value:undefined,done:true

Scene Practice 抽奖(举个例子)
ES5写法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
function draw (first = 1, second = 3, third = 5{
  let firstPrize = ['1A''1B''1C''1D''1E']
  let secondPrize = ['2A''2B''2C''2D''2E''2F''2G''2H''2I']
  let thirdPrize = ['3A''3B''3C''3D''3E''3F''3G''3K''3O''3P']
  let result = []
  let random
  // 抽一等奖
  for (let i = 0; i < first; i++) {
    random = Math.floor(Math.random() * firstPrize.length)
    result = result.concat(firstPrize.splice(random, 1))
  }
  // 抽二等奖
  for (let i = 0; i < second; i++) {
    random = Math.floor(Math.random() * secondPrize.length)
    result = result.concat(secondPrize.splice(random, 1))
  }
  // 抽三等奖
  for (let i = 0; i < third; i++) {
    random = Math.floor(Math.random() * thirdPrize.length)
    result = result.concat(thirdPrize.splice(random, 1))
  }
  return result
}
let t = draw()
for (let value of t) {
  console.log(value)
}

ES6写法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
function * draw (first = 1, second = 3, third = 5{
  let firstPrize = ['1A''1B''1C''1D''1E']
  let secondPrize = ['2A''2B''2C''2D''2E''2F''2G''2H''2I']
  let thirdPrize = ['3A''3B''3C''3D''3E''3F''3G''3K''3O''3P']
  let count = 0
  let random
  while (1) {
    if (count < first) {
      random = Math.floor(Math.random() * firstPrize.length)
      yield firstPrize[random]
      count++
      firstPrize.splice(random, 1) //避免重复,删除抽中的
    } else if (count < first + second) {
      random = Math.floor(Math.random() * secondPrize.length)
      yield secondPrize[random]
      count++
      secondPrize.splice(random, 1)
    } else if (count < first + second + third) {
      random = Math.floor(Math.random() * thirdPrize.length)
      yield thirdPrize[random]
      count++
      thirdPrize.splice(random, 1)
    } else {
      return false
    }
  }
}
let d = draw()
console.log(d.next().value)
console.log(d.next().value)
console.log(d.next().value)
console.log(d.next().value)
console.log(d.next().value)
console.log(d.next().value)

另一个例子:找到3的倍数的数字

1
2
3
4
5
6
7
8
9
10
11
function * count (x = 1{
  while (1) {
    if (x % 3 === 0) {
      yield x
    }
    x++
  }
}
let num = count()
console.log(num.next().value)
console.log(num.next().value)

Iterator(如何让不支持遍历的数据结构“可遍历”)

lterator就是ES6中用来实现自定义遍历的接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
let authors = {
  allAuthors: {
    fiction: ['Agla''Skks''LP'],
    scienceFiction: ['Neal''Arthru''Ribert'],
    fantasy: ['J.R.Tole''J.M.R''Terry P.K']
  },
  Addres: []
}
//对以上数据结构部署lterator接口
authors[Symbol.iterator] = function ({
  let allAuthors = this.allAuthors
  let keys = Reflect.ownKeys(allAuthors)
  let values = []
  return {
    next () {
      if (!values.length) {
        if (keys.length) {
          values = allAuthors[keys[0]]
          keys.shift()
        }
      }
      return {
        done: !values.length,
        value: values.shift()
      }
    }
  }
}

let r = []
for (let v of authors) {
  r.push(v)
}
console.log(r)

第二种写法:Generator(天然满足可迭代协议)
用gen写,省去写done,value

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
authors[Symbol.iterator] = function * ({
  let allAuthors = this.allAuthors
  let keys = Reflect.ownKeys(allAuthors)
  let values = []
  while (1) {
    if (!values.length) {
      if (keys.length) {
        values = allAuthors[keys[0]]
        keys.shift()
        yield values.shift()
      } else {
        return false
      }
    } else {
      yield values.shift()
    }
  }
}

两个概念:
迭代器协议
1、首先,他是一个对象
2、其次,这个对象包含一个无参函数next
3、最后,next返回一个对象,包含done和value属性
可迭代协议
可迭代协议允许JavaScript对象去定义或定制他们的迭代行为。
一般object不可遍历
如果让一个对象是可遍历的,就要遵守可迭代协议,要求对象要部署一个以Symbol.iterator为key的键值对,而value就是一个无参函数,这个函数返回的对象要遵守迭代器协议。

Export Import(如何把代码进行模块化设计)

模块,通过import、export来实现原生JavaScript的导入导出

1
2
3
4
5
6
7
8
9
10
11
12
//导出变量
const name = 'hello3'
let addr = 'Beijing'
let list = [124]
export default name //default 导出时,允许自己取名字
export {
  addr,
  list
}
//模块的导入
impott names ,{addr as addrs} from './lessons-14-mod'
console.log(name2, addr2)
1
2
3
4
5
6
7
8
9
10
11
//导出函数
export function say (content){
console.log(content)
}
export function run (content){
console.log('running')
}
//导进函数
import say,{run} from './lessons-14-mod'
say('hello world')
run()

多个对象导出(应用解构赋值)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
 //导出
const data = {
  code: 1,
  message: 'success'
}
const des = {
  age: 20,
  addr: 'Beijing'
}
export default {
  data,
  des
}

//导入
import obj from './lessons-14-mod'
let {data,des}=obj
console.log(data,des)

1
2
3
4
5
6
7
8
9
10
 //导出
export class Test {
  constructor () {
    this.id = 6
  }
}
//导入
import {Test} from './lessons-14-mod'
let test =new Test()
console.log(text.id)

多模块导入

1
2
3
4
5
6
7
import * as Mod from './lesson2-14-mod'   //*表示全部
let test = new Mod.Test()
console.log(test.id)
let animal = new Mod.Animal()
console.log(animal.name)
let people = new Mod.default()
console.log(people.id)
0%