جاوااسکریپت - باگ تایپاسکریپت؟ تفاوت `this` بین سینتکس `get` و `get` تابع `defineProperty`
من این کد را دارم:
var x = {
x1: 5,
x2: 7
};
var y = {
...x,
_originalX2: x.x2,
get x2() {
console.log(this.x1);
return 9;
}
};
console.log(y.x2);
var z = {
...x,
_originalX2: x.x2
};
Object.defineProperty(z, 'x2', {
get: function() {
console.log(this.x1);
return 9;
}
})
console.log(z.x2);وقتی این را به عنوان جاوااسکریپت در مرورگر یا در NodeJS اجرا میکنم، خروجی را دریافت میکنم:
5
9
5
9
وقتی همان کد را بهعنوان تایپاسکریپت اجرا میکنم (نگاه کنید به https://repl.it/repls/TornHomelyThing)، خروجی زیر را میگیرم:
undefined
9
5
9
من همچنین میبینم که JS و TS از آن چه تولید میکنند را در https://www.typescriptlang.org/play/?ssl=1&ssc=1&pln=22&pc=1#code/G4QwTgBAHhC8EG8oEYBcECsAaaAmdA7AL4DcAUGaJAJ5yJkQQB0LUODEA+gPZgCWAcz4A7EABsAGvihMoudowEBTAC54AFAEoEHRgGNuwgM7cxSpmO4D1KgBZ8js5JvKNGYVQFcwwiAE5XCCIyUjIDY1NzS2tqWVwXCioIAC86HUYWWQUuXkERcSlUGTkQ8gB5ACMAKyU9FSYAEyUAMxElAAUwbgAHJTAVanVknAByORGcBAhlFXRmz2E6vkMtejcIcJMzCysbe0cUBPWPFW9fAI4iIM0wwy2o3eS4hKA مشاهده میکنم.
سوال من دو بخش دارد:
- آیا باید این مسئله به عنوان یک باگ در تایپاسکریپت در نظر گرفته شود، با توجه به اینکه همان کد در جاوااسکریپت رفتار متفاوتی دارد؟
- آیا دلیل خوبی وجود دارد که
thisنتواند بهx1در JS تولید شده توسط TypeScript اشاره کند؟ یا اینکه این خود یک باگ در JS است؟
پاسخ شماره ۱
آیا باید این مسئله به عنوان یک باگ در تایپاسکریپت در نظر گرفته شود با توجه به اینکه همان کد در جاوااسکریپت رفتار متفاوتی دارد؟
بله، این قطعاً شبیه یک باگ مربوط به تبدیل سینتکس شیء اسپرد در تایپاسکریپت است. TS کامپایل شده همان کاری را که JS انجام میدهد انجام نمیدهد.
در اولی، شما یک شیء y با یک ویژگی x2 تعریف میکنید، که یک گیرنده است:
var y = {
...x,
_originalX2:x.x2,
get x2(){
پس ارجاع دادن به y.x2 بعداً باعث میشود getter فراخوانی شود. اما در تایپاسکریپت کامپایل شده، ما به این نتیجه میرسیم:
var x = { x1: 5, x2: 7 };
var y = Object.assign(
Object.assign({}, x),
{
_originalX2: x.x2,
get x2() {
console.log(this.x1);
}
}
);این منجر به فراخوانی فوری گتر خواهد شد - گترها زمانی فراخوانی میشوند که در یک شیء که به عنوان آرگومان دوم یا بیشتر در داخل Object.assign قرار داده شده است، باشند. و زمانی که گتر فراخوانی میشود، this به آرگومان دوم اشاره میکند، یعنی این شیء:
{
_originalX2: x.x2,
get x2() {
console.log(this.x1);
}
}
کسی که ویژگی x1 ندارد، بنابراین undefined را ثبت میکند.
مقدار undefined قبل از اینکه Object.assign به پایان برسد، ثبت شده است، قبل از اینکه به خط بعدی console.log(y.x2); برسید.
برای یک مثال حداقلیتر:
var y = {
...{},
get prop(){
console.log('should not be invoked immediately');
}
};
بهطور نادرست به
var y = Object.assign({}, { get prop() {
console.log('should not be invoked immediately');
} });
اگر طوری تنظیم کنید که تایپاسکریپت شیوه انتشار شیء را ترجمه نکند، با ارتقاء هدف به بالاتر از ES2017، کار خواهد کرد. به عنوان مثال، با ESNext، مورد بالا به این صورت ترجمه میشود:
var y = {
...{},
get prop() {
console.log('should not be invoked immediately');
}
};
