如何在内部生成器函数中访问 super class 方法?
How to access super class method inside of internal generator function?
看看这个 类,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' 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) {
...
}
});
});
}
有办法吗?为什么我不能将父方法的引用保存到变量中?
箭头函数来拯救!
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();
基本上,箭头函数维护 this
和 super
上下文,这与文字 function
关键字
不同
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 构造函数反模式。 co
已经 returns 一个承诺,没有必要用 new Promise
.
包装它
还有一点是为了无缝继承,将生成器方法和promisified方法分开是有好处的。 co
支持委派 yield
s,它使这更容易:
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
在 transpiled JS 项目中有效无用,上面的代码变为:
class Child extends Base {
async get(...) {
...
const accounts = await super.get(match, options);
...
}
}
显然您无论如何都为类型注释使用了一些编译器。在这种情况下,解决方案是只删除 co
库和生成器,并使用适当的现代 async
/await
语法代替,TypeScript、Babel 和本机 nodejs 支持:
async get(match: T, options: IQueryOptions|void): Promise<Array<Object>|Error> {
try {
const accounts = await super.get(match, options);
… // do something
return accounts;
}
catch(err) {
…
}
}
super
在这里开箱即用。
看看这个 类,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' 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) {
...
}
});
});
}
有办法吗?为什么我不能将父方法的引用保存到变量中?
箭头函数来拯救!
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();
基本上,箭头函数维护 this
和 super
上下文,这与文字 function
关键字
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 构造函数反模式。 co
已经 returns 一个承诺,没有必要用 new Promise
.
还有一点是为了无缝继承,将生成器方法和promisified方法分开是有好处的。 co
支持委派 yield
s,它使这更容易:
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
在 transpiled JS 项目中有效无用,上面的代码变为:
class Child extends Base {
async get(...) {
...
const accounts = await super.get(match, options);
...
}
}
显然您无论如何都为类型注释使用了一些编译器。在这种情况下,解决方案是只删除 co
库和生成器,并使用适当的现代 async
/await
语法代替,TypeScript、Babel 和本机 nodejs 支持:
async get(match: T, options: IQueryOptions|void): Promise<Array<Object>|Error> {
try {
const accounts = await super.get(match, options);
… // do something
return accounts;
}
catch(err) {
…
}
}
super
在这里开箱即用。