• ES6 入门教程 19 Generator 函数的语法 19.8 作为对象属性的 Generator 函数 & 19.9 Generator 函数的this


    ES6 入门教程

    ECMAScript 6 入门

    作者:阮一峰

    本文仅用于学习记录,不存在任何商业用途,如侵删

    19 Generator 函数的语法

    19.8 作为对象属性的 Generator 函数

    如果一个对象的属性是 Generator 函数,可以简写成下面的形式。

    let obj = {
      * myGeneratorMethod() {
        ···
      }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5

    上面代码中,myGeneratorMethod属性前面有一个星号,表示这个属性是一个 Generator 函数。

    它的完整形式如下,与上面的写法是等价的。

    let obj = {
      myGeneratorMethod: function* () {
        // ···
      }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    19.9 Generator 函数的this

    Generator 函数总是返回一个遍历器,ES6 规定这个遍历器是 Generator 函数的实例,也继承了 Generator 函数的prototype对象上的方法。

    function* g() {}
    
    g.prototype.hello = function () {
      return 'hi!';
    };
    
    let obj = g();
    
    obj instanceof g // true
    obj.hello() // 'hi!'
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    在这里插入图片描述

    上面代码表明,Generator 函数g返回的遍历器obj,是g的实例,而且继承了g.prototype

    但是,如果把g当作普通的构造函数,并不会生效,因为g返回的总是遍历器对象,而不是this对象。

    function* g() {
      this.a = 11;
    }
    
    let obj = g();
    obj.next();
    obj.a // undefined
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    上面代码中,Generator 函数gthis对象上面添加了一个属性a,但是obj对象拿不到这个属性。

    Generator 函数也不能跟new命令一起用,会报错。

    function* F() {
      yield this.x = 2;
      yield this.y = 3;
    }
    
    new F()
    // TypeError: F is not a constructor
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    上面代码中,new命令跟构造函数F一起使用,结果报错,因为F不是构造函数。

    那么,有没有办法让 Generator 函数返回一个正常的对象实例,既可以用next方法,又可以获得正常的this

    下面是一个变通方法。首先,生成一个空对象,使用call方法绑定 Generator 函数内部的this。这样,构造函数调用以后,这个空对象就是 Generator 函数的实例对象了。

    function* F() {
      this.a = 1;
      yield this.b = 2;
      yield this.c = 3;
    }
    var obj = {};
    var f = F.call(obj);
    
    f.next();  // Object {value: 2, done: false}
    f.next();  // Object {value: 3, done: false}
    f.next();  // Object {value: undefined, done: true}
    
    obj.a // 1
    obj.b // 2
    obj.c // 3
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    上面代码中,首先是F内部的this对象绑定obj对象,然后调用它,返回一个 Iterator 对象。这个对象执行三次next方法(因为F内部有两个yield表达式),完成 F 内部所有代码的运行。这时,所有内部属性都绑定在obj对象上了,因此obj对象也就成了F的实例。

    上面代码中,执行的是遍历器对象f,但是生成的对象实例是obj,有没有办法将这两个对象统一呢?

    一个办法就是将obj换成F.prototype

    function* F() {
      this.a = 1;
      yield this.b = 2;
      yield this.c = 3;
    }
    var f = F.call(F.prototype);
    
    f.next();  // Object {value: 2, done: false}
    f.next();  // Object {value: 3, done: false}
    f.next();  // Object {value: undefined, done: true}
    
    f.a // 1
    f.b // 2
    f.c // 3
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    再将F改成构造函数,就可以对它执行new命令了。

    function* gen() {
      this.a = 1;
      yield this.b = 2;
      yield this.c = 3;
    }
    
    function F() {
      return gen.call(gen.prototype);
    }
    
    var f = new F();
    
    f.next();  // Object {value: 2, done: false}
    f.next();  // Object {value: 3, done: false}
    f.next();  // Object {value: undefined, done: true}
    
    f.a // 1
    f.b // 2
    f.c // 3
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
  • 相关阅读:
    TP5 封装通用的微信服务类
    Mysql取数据怎么取?
    OSError: [Errno 22] Invalid argument: ‘D:\test\x07‘
    Plotjuggler之ulog格式分析
    Linux UDP编程流程
    不同版本Ubuntu安装Docker及Docker desktop
    C++ 之LeetCode刷题记录(三十六)
    挑战一周完成Vue3项目Day2:路由配置+登录模块+layout组件+路由鉴权
    每日练习------使用Java实现输出如下图形。(三角形,空心菱形等)
    基于APB与I2C的多主多从架构设计 - Function Description
  • 原文地址:https://blog.csdn.net/weixin_44226181/article/details/127975622