如何访问内部生成器函数内的超类方法?

时间:2017-10-11 08:36:28

标签: javascript node.js ecmascript-6 co

看看这个类,Base和Derived,它只是将“name”作为属性的简单类:

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'关键字在这里意外

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

  

TypeError:无法读取未定义的属性“name”

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

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) {
                ...
            }
        });
    });
}

有没有办法解决这个问题?为什么我不能将父方法的引用保存到变量中?

3 个答案:

答案 0 :(得分:2)

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

生成器功能仍然是功能并支持绑定。这将导致绑定函数无法通过其签名识别为生成器函数,但只要协程库支持泛型迭代器(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构造函数antipattern。 co已经返回一个承诺,没有必要用new Promise包装它。

另一方面,为了无缝继承,分离生成器方法和promisified方法是有益的。 co支持委派的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,并且能够回退到co - 就像ES6目标输出中的生成器协同程序一样。这使co在已编译的JS项目中无效,上面的代码变为:

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

答案 1 :(得分:1)

显然,无论如何你都会为类型注释使用一些编译器。在这种情况下,解决方案是删除href="javascript:void(0)" 库和生成器,并使用适当的现代d[order(as.Date(d$V3, format="%d/%m/%Y)),] / co语法,TypeScript,Babel和native nodejs支持:< / p>

async

await将在此处开箱即用。

答案 2 :(得分:0)

箭头有助于救援!

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

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

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

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

基本上,箭头函数维护thissuper上下文,与文字function关键字

不同