جاوااسکریپت - مراجع به خود در آبجکت لیترالها/مقداردهی اولیهها
آیا راهی وجود دارد که بتوان چیزی شبیه به مورد زیر را در جاوااسکریپت اجرا کرد؟
var foo = {
a: 5,
b: 6,
c: this.a + this.b // Doesn't work
};
در شکل فعلی، این کد به وضوح یک خطای ارجاع ایجاد میکند زیرا this به foo اشاره نمیکند. اما آیا به هر نحوی میتوان مقادیر ویژگیهای یک شیء لفظی را به دیگر ویژگیهایی که قبلاً اعلام شدهاند، وابسته کرد؟
پاسخ شماره ۱
خب، تنها چیزی که میتوانم درباره آن به شما بگویم گترها است:
var foo = {
a: 5,
b: 6,
get c() {
return this.a + this.b;
}
}
console.log(foo.c) // 11این یک توسعه نحوی است که توسط مشخصات ویرایش پنجم ECMAScript معرفی شده است، نحوهی نوشتن آن توسط اکثر مرورگرهای مدرن (شامل IE9) پشتیبانی میشود.
پاسخ شماره ۲
میتوانید چیزی شبیه این انجام دهید:
var foo = {
a: 5,
b: 6,
init: function() {
this.c = this.a + this.b;
return this;
}
}.init();
این نوعی مقداردهی اولیه یکباره برای شیء خواهد بود.
توجه داشته باشید که شما در واقع مقدار بازگشتی init() را به foo اختصاص میدهید، بنابراین باید return this کنید.
پاسخ شماره ۳
پاسخ واضح و ساده مفقود است، بنابراین برای کامل بودن:
اما آیا راهی وجود دارد که مقادیر در ویژگیهای یک شیء به ویژگیهای دیگری که قبلاً اعلام شدهاند وابسته باشند؟
خیر. همهٔ راهحلهای اینجا آن را تا بعد از ایجاد شیء به تأخیر میاندازند (به روشهای مختلف) و سپس ویژگی سوم را اختصاص میدهند. سادهترین راه این است که فقط این کار را انجام دهید:
var foo = {
a: 5,
b: 6
};
foo.c = foo.a + foo.b;
همهٔ روشهای دیگر فقط راههای غیرمستقیم بیشتری برای انجام همان کار هستند. (روش فلیکس بهخصوص هوشمندانه است، اما نیاز به ایجاد و حذف یک تابع موقت دارد که پیچیدگی اضافه میکند؛ و یا یک ویژگی اضافه روی شیء باقی میگذارد یا [اگر آن ویژگی را حذف کنید] بر عملکرد دسترسیهای بعدی به ویژگیهای آن شیء تأثیر میگذارد.)
اگر نیاز دارید همه در یک عبارت باشد، میتوانید این کار را بدون استفاده از ویژگی موقت انجام دهید:
var foo = function(o) {
o.c = o.a + o.b;
return o;
}({a: 5, b: 6});
یا البته، اگر شما نیاز دارید این کار را بیش از یک بار انجام دهید:
function buildFoo(a, b) {
var o = {a: a, b: b};
o.c = o.a + o.b;
return o;
}
پس جایی که نیاز به استفاده از آن دارید:
var foo = buildFoo(5, 6);
پاسخ شماره ۴
به سادگی یک تابع ناشناس ایجاد کنید:
var foo = new function () {
this.a = 5;
this.b = 6;
this.c = this.a + this.b;
};
پاسخ شماره ۵
حالا در ES6 شما میتوانید ویژگیهای تنبل و کش شده ایجاد کنید. در اولین استفاده، ویژگی فقط یک بار ارزیابی میشود تا به یک ویژگی ثابت عادی تبدیل شود. نتیجه: دفعه دوم، سربار تابع ریاضی نادیده گرفته میشود.
جادو در گتر است.
const foo = {
a: 5,
b: 6,
get c() {
delete this.c;
return this.c = this.a + this.b
}
};
در تابع پیکانی this دامنه لغوی اطراف خود را دریافت میکند.
foo // {a: 5, b: 6}
foo.c // 11
foo // {a: 5, b: 6 , c: 11}
پاسخ شماره ۶
برخی از بستهها باید با این مسئله برخورد کنند؛
var foo = function() {
var a = 5;
var b = 6;
var c = a + b;
return {
a: a,
b: b,
c: c
}
}();
تمام متغیرهایی که درون foo اعلام شدهاند، خصوصی برای foo هستند، همانطور که انتظار دارید با هر اعلام تابعی، و چون همه در محدوده هستند، همه به یکدیگر دسترسی دارند بدون اینکه نیاز به اشاره به this داشته باشند، همانطور که با یک تابع انتظار دارید. تفاوت این است که این تابع یک شیء برمیگرداند که متغیرهای خصوصی را در معرض قرار میدهد و آن شیء را به foo تخصیص میدهد. در نهایت، تنها رابطی را که میخواهید به صورت یک شیء با عبارت return {} در معرض قرار دهید، برمیگردانید.
سپس تابع در پایان با () اجرا میشود که باعث میشود کل شیء foo ارزیابی شود، تمام متغیرهای داخل آن نمونهسازی شوند و شیء بازگشتی به عنوان ویژگیهای foo() اضافه شود.
پاسخ شماره ۷
تو میتوانی این کار را اینطور انجام دهی
var a, b
var foo = {
a: a = 5,
b: b = 6,
c: a + b
}
این روش برای من مفید بوده است زمانی که مجبور بودم به شیئی که یک تابع در ابتدا بر روی آن اعلام شده بود، مراجعه کنم. مثال زیر یک نمونه حداقلی از نحوه استفاده من از آن است:
function createMyObject() {
var count = 0, self
return {
a: self = {
log: function() {
console.log(count++)
return self
}
}
}
}
با تعریف خود به عنوان شیئی که تابع print را در بر دارد، شما اجازه میدهید که تابع به آن شیء ارجاع دهد. این بدان معنی است که شما نیازی نخواهید داشت که تابع print را به یک شیء 'متصل' کنید اگر بخواهید آن را به جای دیگری منتقل کنید.
اگر شما به جای آن، از این همانطور که در زیر نشان داده شده است استفاده کنید
function createMyObject() {
var count = 0
return {
a: {
log: function() {
console.log(count++)
return this
}
}
}
}
سپس کد زیر عددهای 0، 1، 2 را ثبت خواهد کرد و سپس یک خطا ایجاد میکند
var o = createMyObject()
var log = o.a.log
o.a.log().log() // this refers to the o.a object so the chaining works
log().log() // this refers to the window object so the chaining fails!
با استفاده از روش خود، شما تضمین میکنید که print همیشه همان شیء را برگرداند، صرفنظر از زمینهای که تابع در آن اجرا میشود. کد بالا بهخوبی اجرا خواهد شد و هنگام استفاده از نسخه خود createMyObject()، 0، 1، 2 و 3 را ثبت میکند.
پاسخ شماره ۸
برای تکمیل، در ES6 ما کلاسها داریم (در زمان نوشتن این فقط توسط مرورگرهای جدید پشتیبانی میشد، اما در Babel، TypeScript و سایر ترنسپایلرها در دسترس است)
class Foo {
constructor(){
this.a = 5;
this.b = 6;
this.c = this.a + this.b;
}
}
const foo = new Foo();
