javascript - 如何访问内部生成器函数内部的父类(super class)方法?

标签 javascript node.js ecmascript-6 co

看看这个类,Base 和 Derived,它们只是具有“名称”作为属性的简单类:

class Base {
    constructor(name) {
        this.name = name;
    }
    printName() {
        console.log("Base: " + this.name);
    }
}

class Derieved extends Base {
    constructor(name) {
        super(name);
    }
    // Override
    printName() {
        // IIFE.
        (function() {
            super.printName();  // Can't use super here
        })();

        console.log("Derived: " + this.name);
    }
}

var obj = new Derieved('John');
obj.printName();

我想从 Derieved::printName 调用 Base::printName。但出于某种原因,我必须调用 Derieved::printName 的内部函数内部。

但是运行上面的代码,它失败了:

SyntaxError: 'super' keyword unexpected here

如果我将父方法的引用保存到变量中,看起来它可以调用但无法访问任何属性,它说未定义。

TypeError: Cannot read property 'name' of undefined

我刚刚写了内部函数只是普通函数,但实际上它是生成器函数,所以我不能使用箭头函数:

get(match: T, options: IQueryOptions|void): Promise<Array<Object>|Error> {
    const superGet = super.get;

    return new Promise((resolve, reject) => {
        co(function*() {
            try {
                    // I need to invoke parent's get method here!!
                const accounts = yield superGet(match, options);

                ... // do something with accounts

                resolve(accounts);
            }
            catch(err) {
                ...
            }
        });
    });
}

有办法做到这一点吗?为什么我无法将父方法的引用保存到变量中?

最佳答案

super 只能从子方法访问,而不能从该方法内部调用的函数范围访问。

生成器函数仍然是函数并且支持绑定(bind)。这将导致绑定(bind)函数无法通过其签名识别为生成器函数,但只要协程库支持通用迭代器( co ),那就没问题。

所以基本上是这样的

get(...) {
    const superGet = super.get;

    return new Promise((resolve, reject) => {
        co(function*() {
              ...
              const accounts = yield superGet.call(this, match, options);
              ...
        }.bind(this));
    });
}

或者更好:

get(...) {
    const superGet = super.get.bind(this);

    return new Promise((resolve, reject) => {
        co(function*() {
              ...
              const accounts = yield superGet(match, options);
              ...
        });
    });
}

这里有几件事可以改进。第一个是它使用 Promise 构造函数反模式。 co 已经返回了一个 Promise,无需用 new Promise 包装它。

另一件事是,为了无缝继承,将生成器方法和 promise 方法分开是有益的。 co 支持委托(delegate)yield,它使这变得更加容易:

class Base {
  get(...args) {
    return co(this._get.bind(this, ...args));
  }

  * _get(...) { ... }
}

class Child extends Base {
  * _get(...) {
    ...
    const accounts = yield* super._get(match, options);
    ...
  }
}

TypeScript 和 Babel 都支持 ES2017 async..await,并且能够在 ES6 目标输出中回退到类似 co 的生成器协程。这使得 co 在转译的 JS 项目中毫无用处,上面的代码变成:

class Child extends Base {
  async get(...) {
    ...
    const accounts = await super.get(match, options);
    ...
  }
}

关于javascript - 如何访问内部生成器函数内部的父类(super class)方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46683552/

相关文章:

javascript - Vue.js 从服务发出事件

npm - Webpack/ES6 : how to import stylesheets

javascript - 如何使用 lodash 从数组中获取多个键值?

javascript - 使用任何编程语言或脚本或通过工具更改 JSON 内容以获取 excel 格式的数据?

javascript - 计算两个日期之间的差异

javascript - gulp-live-server 不刷新页面

javascript - 图像未使用本地主机加载到 NodeJS 服务器上

Node.JS + 和尚。 "ORDER BY"在 "find"

javascript - 如何将文本插入多个带有 id 的文本区域中的一个?

javascript 将数组与对象数组进行比较