بیشتر تعامل شما با ویژگیهای شی احتمالاً در سطح سطح خواهد بود، از جمله ایجاد حروف الفبای شی و تنظیم و دسترسی به مقادیر ویژگی با استفاده از کلیدها. با این حال، میتوانید هر ویژگی یک شی را برای کنترل دقیق نحوه دسترسی، تغییر و تعریف آن ویژگیها پیکربندی کنید. هر ویژگی شی دارای مجموعهای از ویژگیهای نامرئی است که حاوی ابردادههای مرتبط با آن ویژگی است که «توصیفگرهای ویژگی» نامیده میشوند.
دو نوع توصیفگر مرتبط با هر ویژگی وجود دارد: توصیفگرهای داده و توصیفگرهای دسترسی . توصیفگر داده شامل جفتهای کلید و مقدار است که حاوی مقدار یک ویژگی هستند، صرف نظر از اینکه آن مقدار قابل نوشتن، تنظیم یا شمارشپذیر است. توصیفگرهای دسترسی شامل توابعی هستند که هنگام تنظیم، تغییر یا دسترسی به یک ویژگی اجرا می شوند.
اموال | نوع توصیفگر | مقدار پیش فرض ازObject.defineProperty() | توضیحات |
---|---|---|---|
[[Value]] | داده ها | undefined | حاوی ارزش یک ملک است. |
[[Writable]] | داده ها | false | تعیین می کند که آیا می توانید ارزش دارایی را تغییر دهید یا خیر. |
[[Get]] | دسترسی | undefined | تابع گیرنده ویژگی که با دسترسی به ویژگی اجرا می شود. |
[[Set]] | دسترسی | undefined | تابع تنظیم کننده ویژگی، که با تنظیم یا تغییر ویژگی اجرا می شود. |
[[Configurable]] | هر دو | false | اگر این false باشد، ویژگی را نمی توان حذف کرد و ویژگی های آن را نمی توان تغییر داد. اگر این false باشد و [[Writable]] true باشد، مقدار ویژگی همچنان قابل تغییر است. |
[[Enumerable]] | هر دو | false | اگر این true است، میتوانید با استفاده از حلقههای for...in یا متد استاتیک Object.keys() روی ویژگی تکرار کنید. |
هر یک از این ویژگیها از کوتاهنویسی مشابه [[Prototype]]
استفاده میکنند، که نشان میدهد این ویژگیها قرار نیست مستقیماً قابل دسترسی باشند. در عوض، از متد استاتیک Object.defineProperty()
برای تعریف یا تغییر خصوصیات یک شی استفاده کنید. Object.defineProperty()
سه آرگومان را می پذیرد: شی مورد نظر برای عمل، کلید ویژگی که باید ایجاد یا اصلاح شود، و یک شی حاوی توصیفگر(های) مرتبط با ویژگی در حال ایجاد یا اصلاح.
به طور پیش فرض، ویژگی های ایجاد شده با استفاده از Object.defineProperty()
قابل نوشتن، شمارش یا تنظیم نیستند. با این حال، هر ویژگی که به عنوان بخشی از شیء واقعی یا با استفاده از علامت نقطه یا براکت ایجاد می کنید، قابل نوشتن، شمارش و تنظیم است.
const myObj = {};
Object.defineProperty(myObj, 'myProperty', {
value: true,
writable: false
});
myObj.myProperty;
> true
myObj.myProperty = false;
myObj.myProperty;
> true
به عنوان مثال، زمانی که [[Writable]]
مقدار false
دارد، تلاش برای تنظیم یک مقدار جدید برای ویژگی مرتبط بهطور بیصدا در خارج از حالت سخت با شکست مواجه میشود و یک خطا در حالت سختگیر ایجاد میکند:
{
const myObj = {};
Object.defineProperty(myObj, 'myProperty', {
value: true,
writable: false
});
myObj.myProperty = false;
myObj.myProperty;
}
> true
(function () {
"use strict";
const myObj = {};
Object.defineProperty(myObj, 'myProperty', {
value: true,
writable: false
});
myObj.myProperty = false;
myObj.myProperty;
}());\
> Uncaught TypeError: "myProperty" is read-only
استفاده مؤثر از توصیفگرها یک مفهوم نسبتاً پیشرفته است، اما درک ساختار داخلی یک شی برای درک نحوی که در کار با اشیا به روشهای رایجتر کار میکند ضروری است. به عنوان مثال، این مفاهیم هنگام استفاده از متد استاتیک Object.create()
که به شما کنترل دقیقی بر هر نمونه اولیه متصل به شی جدید می دهد، وارد عمل می شوند.
Object.create()
یک شی جدید با استفاده از یک شی موجود به عنوان نمونه اولیه خود ایجاد می کند. این به شی جدید اجازه میدهد تا ویژگیها و روشها را از یک شی تعریفشده توسط کاربر دیگر به ارث ببرد، همانطور که اشیاء ویژگیها را از نمونه اولیه Object
داخلی جاوا اسکریپت به ارث میبرند. هنگامی که Object.create()
را با یک شی به عنوان آرگومان فراخوانی می کنید، یک شی خالی با شی ارسال شده به عنوان نمونه اولیه آن ایجاد می کند.
const myCustomPrototype = {
'myInheritedProp': 10
};
const newObject = Object.create( myCustomPrototype );
newObject;
> Object { }
<prototype>: Object { myInheritedProp: 10 }
myInheritedProp: 10
<prototype>: Object { … }
Object.create
میتواند آرگومان دومی را که ویژگیهای خود را برای شی جدید ایجاد شده با استفاده از نحوی شبیه به Object.defineProperty()
تعیین میکند - یعنی یک شی نگاشت کلیدهای مجموعهای از ویژگیهای توصیفگر:
const myCustomPrototype = {
'myInheritedProp': 10
};
const myObj = Object.create( myCustomPrototype, {
myProperty: {
value: "The new property value.",
writable: true,
configurable: true
}
});
myObj;
> Object { … }
myProperty: "The new property value."
<prototype>: Object { myInheritedProp: 10 }
در این مثال، شی جدید ( myObj
) از یک شی تحت اللفظی ( myCustomPrototype
) به عنوان نمونه اولیه خود استفاده می کند که خود حاوی Object.prototype
به ارث رسیده است که در نتیجه یک سری از نمونه های اولیه به ارث برده شده به نام زنجیره اولیه می شود. هر شیء دارای یک نمونه اولیه است، اعم از اختصاص داده شده یا ارثی، که نمونه اولیه اختصاص یافته یا ارثی خود را دارد. این زنجیره به یک نمونه اولیه null
ختم می شود که نمونه اولیه خود را ندارد.
const myPrototype = {
'protoProp': 10
};
const newObject = Object.setPrototypeOf( { 'objProp' : true }, myPrototype );
newObject;
> Object { objProp: true }
objProp: true
<prototype>: Object { protoProp: 10 }
protoProp: 10
<prototype>: Object { … }
ویژگی های موجود در نمونه اولیه یک مقدار در "سطح بالای" یک شی در دسترس هستند، بدون نیاز به دسترسی مستقیم به ویژگی نمونه اولیه:
const objectLiteral = {
"value" : true
};
objectLiteral;
> Object { value: true }
value: true
<prototype>: Object { … }
objectLiteral.toString();
"[object Object]"
این الگو برای کل زنجیره نمونه اولیه مرتبط با یک شی صادق است: زمانی که مفسر تلاش می کند به یک ویژگی دسترسی پیدا کند، مفسر آن ویژگی را در هر "سطح" زنجیره نمونه اولیه، از بالا به پایین جستجو می کند تا زمانی که ویژگی یا زنجیره را پیدا کند. به پایان می رسد:
const myCustomPrototype = {
'protoProp': "Prototype property value."
};
const myObj = Object.create( myCustomPrototype, {
myProperty: {
value: "Top-level property value.",
writable: true,
configurable: true
}
});
myObj.protoProp;
> "Prototype property value."
درک خود را بررسی کنید
کدام توصیفگرها دستیاب هستند؟
[[Get]]
[[Set]]
[[Writable]]