关于阅读 ES6- Generator 整理的问题

1、简述Generator函数

答:① Generator函数是一种异步编程方案
② 从语法上,Generator是一个状态机,里面封存了多个内部状态
③ Generator函数是一个遍历器生成函数
④ 语法是, function* 函数名,函数内部使用yield表达式(yield只能用在Generator中,用在其他函数会报错),用来定义不同的内部状态
⑤ Generator函数调用后,并不执行和返回运行结果,而是一个指向内部状态的指针对象
⑥ 可以使用next()方法来依次访问Generator的状态

function* fun(){
  yield '1'
  yield '2'
  return '333' // 结束执行
}
var f = fun()
fun().next() // {value: '1', done: false}
f.next() // {value: '1', done: false}
for (let val of f){console.log(val)}
for (let val of fun()){console.log(val)}
/*上面两个循环结果 输出:
'1'
'2'
*/

2、Generator函数的星号(*)写在哪里呢?

答:写在function关键字和函数名之间。下面写法都行
function * foo(){}
function* foo(){}
funtion foo(){}
function
foo(){}

3、Generator函数和普通函数的区别

答:① 定义方式不一样,普通函数定义格式是 ,函数名(){},Generator函数定义格式是,函数名*(){}
② 普通函数和Generator函数都可以使用return来结束代码的执行,且只能有一个return来结束
③ Generator函数内部必须使用yield来定义不同的状态,普通函数只是逻辑代码的执行
④ Generator函数调用并不是真正的调用执行,返回也不是真的运行结果,二是一个直指向内部状态的指针对象
⑤ Generator函数可用于遍历器对象的生成,遍历器内部具有next方法。
⑥ Generator函数是分段执行的,遇到一个yield就停止,next方法返回一个对象,当对象中的done:false时,继续执行直到遇到return或者done:true停止

4、简述Generator函数中的yield表达式

答:① 它是Generator函数的暂停标志,当执行过程中遇到yield,就暂停它后面的代码,
并将yield后面的值作为对象value的值,并继续执行next方法,反复进行操作。
② 当遇到return语句,就把return后面的表达式值作为value的值
③ 如果函数执行最后没有return语句,就将undefined作为value的值
④ yield只能用在Generator函数中,用在其他函数中会报错
⑤ yield表达式如果用在另外的表达式中,必须使用圆括号括起来
⑥ yield表达式用作函数的参数或者放在赋值表达式的右边可以不加括号

function* fun(){
yield 12+13 // 不会立即求值,只会在next方法将指针移到这句的时候才会求值,惰性的。
'Hello' + (yeild 123) // 在另外的表达式中,yield需要用括号
let input  = yeild  // 赋值表达式等号右边,可不用括号
foo(yeild 'a', yeild 'b') // 作为函数的入参,可不用括号
}

5、当Generator函数中没有yield时,怎么处理

答:此时Generator函数变成了一个暂缓执行的函数,只有当调用next方法的时候,函数才会执行

function * fun(){
console.log(1111)
}
var g = fun()
setTimeout( () => {  g.next()  },  3000)// 3秒输出 1111

6、使用Generator函数,让对象具有iterator接口

答:直接将Generator赋值给对象的 Symbol.iterator属性

var obj = {}
obj[Symbol.iterator] = function*(){
yield 1;
yield 2;
}
[...obj] // [1, 2]

7、Generator函数中next方法

答:如果yield没有返回值挥着总返回undefined,可以使用next方法的入参作为上一个yield的返回值

function* fun(x){
var a = yield x;
var b = yield (a * 2);
return (b + 3)
}
var g = fun()
g.next() // {value: undefined, done: false}
g.next(12) // {value: 24, done: false} ----上一个yield返回值为 12,即a为12;那么当前yield返回值为 12*2
g.next(24) // {value: 27, done: true}----上一个yield返回值为 24,即b为24;那么当前yield返回值为 24+3

8、使用for…of遍历Generator函数运行时生成的iterator对象

答:for…of会依次输出 yield返回值,即done:true的对象的value;return语句返回值不包括在内。

function* fun(){
   yield 1;
   yield 2;
   return 6
}
for(let val of fun()){console.log(val)} // 依次输出 1和2

9、Generator函数的return

答:① return主要用来返回一个值并中止程序的运行,可用在Generator函数内部语句和外部方法。
② 如果return不提供返回值,那么返回值为undefined
③ 如果Generator函数有try…finally时,执行外部执行return方法,会导致直接进入finally代码块,finally代码块执行完,再返回return方法中指定的返回值。

function * fun(){
   yield 1
   yield 2
   yiled 3
}
var g = fun()
g.next() // {value: 1, done: false}
g.return(1111) // {value: 111, done: true}
g.next() // {value: undefined, done: true}

function* numbers () {
  yield 1;
  try {
    yield 2;
    yield 3;
  } finally {
    yield 4;
    yield 5;
  }
  yield 6;
}
var g = numbers();
g.next() // { value: 1, done: false }
g.next() // { value: 2, done: false }
g.return(7) // { value: 4, done: false }
g.next() // { value: 5, done: false }
g.next() // { value: 7, done: true }

10、简述Generator函数中的next() 、throw() 和return()方法共同点

答:它们的作用都是让Generator函数恢复执行,并且会使用不同的语句替代yield表达式。
next()将yield表达式替换成一个值
throw()将yield表达式替换成一个throw语句
return()将yield表达式替换成一个return语句

function* fun(){
  yield 1;
}
var g = fun()
g.next() // Object {value: 1, done: false}
g.next(222) // Object {value: 222, done: false}
// 相当于将 let result = yield 1
// 替换成 let result = 222

g.throw(new Error('出错了')) //  Uncaught Error: 出错了
// 相当于 let res = yield 1
// 替换成 let res = throw(new Error('出错了'));

g.return(2); // Object {value: 2, done: true}
// 相当于将 let res = yield x + y
// 替换成 let res = return 2;

11、简述 yield*

答:① 如果Generator函数内部想要调用另一个Generator函数,可以使用 yield或者for…of循环,
返回一个遍历器对象内部值。
② yield
Generator函数名 相当于用 for…of遍历这个Generator函数。
③ yield* 后面可以跟着一个具有iterator接口的遍历器,会依次遍历里面的成员
④ 如果yield*后面的Generator函数里有return值,这个return值可以用一个变量进行承接

function * fun1(){
  yield 1;
  yield 2;
}
function * fun2(){
  yield 4;
  yield 5;
  return 333
}
function * fun3(){
  yield 111
  yield* fun1() // 这个相当于  for( let val of fun1() ){ yield val; }
  let res = yield* fun1() // fun1中的return值赋给res,即res等于 333
  yield 222
}
var g = fun3()
[...g] // [111,  1,  2,  4, 5,222]

12、Generator函数作为对象的属性应该怎么写

答,有两种写法

var obj = {
  * fun(){.....}
}
或者
var obj = {
  fun: function*(){....}
}

13、Generator函数的prototype方法可以被它的实例继承吗?

答:可以

function * fun(){
  yield 1
}
fun.prototype.run = function(){console.log('run')}
var g = fun()
g.run() // 'run'
g instanceof fun // true

14、Generator函数内的this是它的实例吗?如果不是,怎么让this指向实例?

答:不是

function *fun(){
   this.a = 1
}
var g = fun()
g.a // undefined

// 实现 Generator内部的this指向其实例
function *F(){
  yield 2;
  this.a = 111
}
var g = {}
var f = F.call(F.propetype)
f.next() // {value: 2, done: false}
f.a // 111

15、Generator函数可以配合new使用吗?如果不行,怎么可以呢?

答:不行,会报错。

function * fun(){
   yield 111
}
var g = new fun() // 报错

// 让Generator可以配合new进行使用
function * fun(){
   yield 2
   this.a = 111
   console.log('F')
}
function F(){
  return fun.call(fun.prototype)
}
var f = new F()
f.next() // {value: 2, done: false}
f.a // 111

16、Generator函数的应用

答:① 异步操作的同步化,例如可以将异步的ajax请求进行同步化
② 控制流管理,例如让多个嵌套的回调函数,按次序依次执行
③ 部署任意对象的iterator接口
④ 看作是数据结构,例如看作是一个数组结构

17、异步编程的方法有哪些

答:回调函数 、事件监听、发布/订阅 、Promise对象、Generator函数

18、什么叫做异步?

答:简单的说一个任务不是连续完成的,需要分成两段,先执行第一段,
然后转而执行其他任务,等做好准备后再回过头来做第二段。
举个例子:一个文件读取的任务,任务的第一段是向操作系统发出请求,
要求读取文件。然后程序执行其他任务,等操作系统返回文件后再接着执行任务的第二段(处理文件)

19、什么叫做同步?

答:就是一个任务是连续执行的,中间不能穿插其他任务,其他任务只能等待该任务完成后再执行。

365、简述对回调函数的理解

答:回调函数是早期异步编程的重要手段。一般异步编程任务切割为两段执行,而回调函数就是最后一段。
回调函数的第一个参数必须是错误对象或null,这是因为第一段执行完后,执行的上下文环境就没办法捕捉,
只能通过作为回调函数的参数传入第二段。
fs.readFile(‘/index.js’, ‘utf-8’, function(err, data){…})

20、简述Promise作为异步编程的个人理解

答:异步编程中的回调函数缺点就是如果有多个回调函数,很难管理,如果有一个操作需要修改,
那么上下回调函数可能都需要修改,陷入‘回调地狱’。
Promise的链式调用,很好的解决这种函数不断嵌套带来的问题。
Promise最大的问题就是什么操作都是一大堆的then,没有什么语义进行更好的解释区分
var fs = require(‘fs-readFile-promise’)
fs(file).then(data => {}).then(data => {}).then(data => {}).catch(err => {})

21、简述异步编程方案中Generator函数的 ‘协程’

答:协程是异步编程的一种解决方案,就是多个线程相互协作,完成异步任务。
协程遇到yield命令就暂停执行,等到执行权回归,再从暂停的地方继续往后执行。
协程有点像函数,有点像线程,执行过程一般如下:
第一步:协程A开始执行
第二步:协程A执行到一半,暂停,执行权转移到协程B
第三步:一段时间后协程B交还执行权给A,A恢复执行

function* gen(x) {
  var y = yield x + 2;
  return y;
}

var g = gen(1);
g.next() // { value: 3, done: false }
g.next() // { value: undefined, done: true }

22、为什么Generator函数可以封装异步任务

答:① 根本原因是它可以暂停执行和恢复执行
② 它可以通过 next() 、throw() 、return()方法实现函数体外的数据交换
④ 它有自己的错误处理机制,且不影响全局的错误处理机制
var fetch = require(‘node-fetch’);

function* gen(){
  var url = 'https://api.github.com/users/github';
  var result = yield fetch(url);
  console.log(result.bio);
}
var g = gen();
var result = g.next();
result.value.then(function(data){
  return data.json();
}).then(function(data){
  g.next(data);
});

23、什么是‘求值策略’及具体有些?

答:就是函数的参数到底应该什么时候求值。
‘求值策略’有两种。一种是 ‘传值调用’,即进入函数体内之前就计算;
另一种是‘传名调用’,即直接将表达式传入函数体,等用到它的时候再求值
var x = 1
function f(m){return m*2}
f(x+5) // 如果使用‘传值调用’那么等同于 f(6);’传名调用‘等同于 (x+5)*2

24、Generator函数中的Thunk函数

答:是自动执行 Generator函数的一种方法
采用‘求值策略’中的‘传值调用’

function f(m) {
  return m * 2;
}
f(x + 5);
// 等同于
var thunk = function () {
  return x + 5;
};
function f(thunk) {
  return thunk() * 2;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值