node.js - 'این' در تایپاسکریپت تعریف نشده است حتی با استفاده از تابع آررو در یک پرامیس
وقتی کالبک 'catch' را دریافت میکنم، 'this' تعریف نشده است، حتی با استفاده از توابع فلش. پیشنهادی دارید؟
private all(req: Request, res: Response): void {
EntityRepository.getRepositoty(req.params.etName).then(repo => {
...
}).catch((err) => {
this.handleError(res, err); // here I get undefined.
});
}
چگونه تابع all فراخوانی میشود.
این نامگذاری شده بر اساس یک مسیر اکسپرس است.
متد bind اضافه شد، همانطور که @jfriend00 پیشنهاد داد.
constructor() {
// Connect to database.
DataAccess.connect();
// Starts configuring routes for api
this.router = Router();
// Bad request due to absence of entity type.
this.router.get("/", (req, res) => {
res.statusCode = 400;
res.statusMessage = SysMsgs.error.noEntityTypeSpecified.message;
res.send();
});
// Added method 'bind'.
this.router.get(this.routeBase, this.all.bind(this));
this.router.get(this.routeBase + "/:id", this.findOne.bind(this));
}
پاسخ شماره ۱
با توابع فلشی، this مقداری را که در دامنه قبل از فراخوانی تابع فلشی داشته است، حفظ خواهد کرد. در مورد شما، این بدان معناست که مقدار this هر مقداری که در ابتدای تابع all بود، خواهد بود. بنابراین، آن مقدار this به نحوه فراخوانی تابع all بستگی دارد.
و، بر اساس this.router.get() شما که this.all را به عنوان callback مشخص کردهاید، این بدان معناست که this داخل all به چیزی که Express هنگام فراخوانی آن callback برایش تعیین میکند، تنظیم خواهد شد. و آن undefined است.
میتوانید مشکل خود را با استفاده از .bind() برطرف کنید.
this.router.get(this.routeBase, this.all.bind(this));
این اطمینان خواهد داد که this مناسب هنگام اجرای .all() تنظیم شده است. و سپس تابع arrow شما در داخل all() از آن مقدار this استفاده خواهد کرد.
توجه: شما نیاز خواهید داشت از .bind() برای هر متدی که به عنوان یک callback میفرستید و انتظار دارید this در داخل callback به شیء اشاره کند، استفاده کنید. وقتی چیزی مثل this.all را میفرستید، مقدار this از بین میرود و تنها یک ارجاع به متد فرستاده میشود. سپس فراخواننده آن متد را به عنوان یک تابع معمولی بدون اتصال به شیء فراخوانی میکند. شما از .bind() استفاده میکنید تا کنترل آن را خودتان بر عهده بگیرید. .bind() در واقع یک تابع کوچک ایجاد میکند که با استفاده از آن، اشارهگر مناسبی به this را دوباره متصل میکند و متد شما را با آن فراخوانی میکند.
شما همچنین میتوانید خودتان یک تابع فلش پوششی برای آن بسازید:
this.router.get(this.routeBase, (req, res) => this.all(req, res));
که همانطور که ساروانا اشاره میکند، بررسی نوع TypeScript را حفظ خواهد کرد.
پاسخ شماره ۲
در حالی که پاسخ @jfriend00 مشکل کد شما را پوشش میدهد و هیچ مشکلی در استفاده از bind در جاوااسکریپت وجود ندارد، یک مشکل کوچک هنگام استفاده از bind در تایپاسکریپت وجود دارد. امضای نوع برای bind به شکل زیر است:
bind(this: Function, thisArg: any, ...argArray: any[]): any;
توجه کنید که bind مقدار any را برمیگرداند، به این معنی که هرگونه بررسی نوع روی تابع بازگشتی غیرفعال میشود، که میتواند به باگهای ظریف منجر شود. به عنوان مثال زیر را در نظر بگیرید:
// Assume the definition for `router.get` is something similar to this:
get(routeBase: string, callback: (req: Request, resp: Response) => void)
// ... and in the place you are calling it
private all(param: number): void {
}
this.route.get(this.routeBase, this.all.bind(this));
// No compiler error, but `all` and the callback parameter expected by `route.get` don't match!
اگر میخواهید بررسی نوع را حفظ کنید، میتوانید از چیزی مانند موارد زیر به جای bind استفاده کنید:
this.route.get((req, resp) => this.all(req, resp));
ببینید: https://github.com/Microsoft/TypeScript/issues/212
