یک Object در جاوااسکریپت، ویژگیها یا همان Properties متناظر با خود را دارد. Propertyهای یک Object اساساً عملکردی شبیه به متغیرها (Variables) دارند، با این تفاوت که به یک Object متصل هستند، نه به یک Scope (حوزه دسترسی). این Propertyها مشخصات و رفتارهای آن Object را تعریف میکنند.
برای مثال، کد زیر شیئی به نام myCar ایجاد میکند که دارای ویژگیهایی به نامهای make ،model و year است و مقادیر آنها به ترتیب روی "Ford"، "Mustang" و 1969 تنظیم شده است:
const myCar = {
make: "Ford",
model: "Mustang",
year: 1969,
};
نامِ ویژگیها (Property names) درست مثل متغیرها در جاوااسکریپت، به حروف کوچک و بزرگ حساس هستند (Case-sensitive). نام ویژگیها فقط میتوانند از نوع String یا Symbol باشند؛ یعنی تمام کلیدها (Keys) به رشته تبدیل میشوند مگر اینکه از نوع Symbol باشند. جالب است بدانید ایندکسهای یک آرایه (Array indices) در واقع همان Propertyهایی با کلیدهای رشتهای (String keys) هستند که حاوی اعداد صحیح میباشند.
شما میتوانید با استفاده از نام یک Property، به مقدار آن دسترسی داشته باشید. دسترسیدهندههای ویژگی (Property accessors) دو نحوِ (Syntax) متفاوت دارند: Dot notation (دسترسی با نقطه) و Bracket notation (دسترسی با کروشه).
برای مثال، به هر دو روش زیر میتوان به ویژگیهای شیء myCar دسترسی داشت:
// روش Dot notation
myCar.make = "Ford";
myCar.model = "Mustang";
myCar.year = 1969;
// روش Bracket notation
myCar["make"] = "Ford";
myCar["model"] = "Mustang";
myCar["year"] = 1969;
نام یک Property میتواند هر نوع رشته یا سمبول دلخواهی در جاوااسکریپت باشد، حتی یک رشتهی خالی (""). اما فراموش نکنید که نمیتوانید از Dot notation برای دسترسی به ویژگیهایی استفاده کنید که نام آنها یک شناسه (Identifier) معتبر در جاوااسکریپت نیست.
به عنوان مثال، اگر نام یک ویژگی دارای «فاصله» یا «خط تیره» باشد، با «عدد» شروع شود یا داخل یک «متغیر» قرار گرفته باشد، فقط و فقط از طریق Bracket notation قابل دسترسی است. این روش همچنین زمانی که نام ویژگیها قرار است به صورت داینامیک در زمان اجرا (Runtime) مشخص شوند، بسیار کاربردی است:
const myObj = {};
const str = "myString";
const rand = Math.random();
const anotherObj = {};
// ایجاد ویژگیهای مختلف روی myObj
myObj.type = "Dot syntax for a key named type";
myObj["date created"] = "This key has a space";
myObj[str] = "This key is in variable str";
myObj[rand] = "A random number is the key here";
myObj[anotherObj] = "This key is object anotherObj";
myObj[""] = "This key is an empty string";
console.log(myObj);
/* خروجی در کنسول:
{
type: 'Dot syntax for a key named type',
'date created': 'This key has a space',
myString: 'This key is in variable str',
'0.6398914448618778': 'A random number is the key here',
'[object Object]': 'This key is object anotherObj',
'': 'This key is an empty string'
}
*/
console.log(myObj.myString); // 'This key is in variable str'
در کد بالا، متغیر anotherObj خودش یک Object است (نه String است و نه Symbol). وقتی این شیء را به عنوان کلید به myObj اضافه میکنیم، جاوااسکریپت به صورت خودکار متد ()toString آن را صدا میزند و از رشتهی حاصل از آن ('[object Object]') به عنوان کلید جدید استفاده میکند.
همچنین شما میتوانید با متغیری که مقدار آن یک رشته است، به یک ویژگی دسترسی داشته باشید؛ اما این متغیر حتماً باید داخل کروشه پاس داده شود. در مثال بالا، متغیر str حاوی رشتهی "myString" بود، پس نام اصلی ویژگی همان "myString" است. به همین دلیل، نوشتن myObj.str مقدار undefined برمیگرداند:
str = "myString";
myObj[str] = "This key is in variable str";
console.log(myObj.str); // undefined
console.log(myObj[str]); // 'This key is in variable str'
console.log(myObj.myString); // 'This key is in variable str'
این قابلیت به شما اجازه میدهد در Runtime به هر ویژگی که محتوای آن تغییر میکند دسترسی داشته باشید:
let propertyName = "make";
myCar[propertyName] = "Ford";
// با تغییر محتوای متغیر، به ویژگیهای متفاوتی دسترسی پیدا میکنیم
propertyName = "model";
myCar[propertyName] = "Mustang";
console.log(myCar); // { make: 'Ford', model: 'Mustang' }
هشدار امنیتی: مراقب باشید که از ساختار کروشه
[ ]برای دسترسی به ویژگیهایی که نام آنها مستقیماً از طریق ورودیهای خارجی (کاربر) تامین میشود استفاده نکنید؛ زیرا این کار میتواند کد شما را در برابر حملات تزریق شیء (Object injection attacks) آسیبپذیر کند.
نکتهی آخر اینکه ویژگیهای موجودنشده (Nonexistent properties) در یک Object، مقدار undefined را برمیگردانند (نه null).
myCar.nonexistentProperty; // undefined
سه راه بومی (Native) در جاوااسکریپت برای لیست کردن یا پیمایش (Traverse) ویژگیهای یک Object وجود دارد:
حلقههای for...in: این متد تمام ویژگیهای رشتهایِ شمارشپذیر (Enumerable) یک Object و همچنین ویژگیهای موجود در زنجیره نمونه اولیه (Prototype chain) آن را پیمایش میکند.
متد Object.keys(): این متد آرایهای شامل نام ویژگیهای رشتهای، شمارشپذیر و متعلق به خودِ شیء ("keys") را برمیگرداند، اما ویژگیهای زنجیره پروتیپ را شامل نمیشود.
متد Object.getOwnPropertyNames(): این متد آرایهای حاوی تمام ویژگیهای رشتهای متعلق به خودِ شیء را برمیگرداند، چه شمارشپذیر (Enumerable) باشند و چه نباشند.
شما میتوانید از Bracket notation به همراه حلقه for...in برای تکرار روی تمام ویژگیهای شمارشپذیر یک شیء استفاده کنید. تابع زیر نمونهای از نحوه نمایش ویژگیهای یک شیء است که خودِ شیء و نام آن را به عنوان آرگومان دریافت میکند:
function showProps(obj, objName) {
let result = "";
for (const i in obj) {
// از Object.hasOwn برای فیلتر کردن ویژگیهای زنجیره پروتیپ
// و صرفاً نمایش ویژگیهای اختصاصی خودِ شیء (Own properties) استفاده میشود
if (Object.hasOwn(obj, i)) {
result += `${objName}.${i} = ${obj[i]}\n`;
}
}
console.log(result);
}
اصطلاح Own property به ویژگیهایی اشاره دارد که مستقیماً روی خودِ آن Object تعریف شدهاند و ویژگیهای به ارث رسیده از Prototype chain را شامل نمیشوند. بنابراین فراخوانی تابع ('showProps(myCar, 'myCar خروجی زیر را چاپ میکند:
myCar.make = Ford
myCar.model = Mustang
myCar.year = 1969
کد بالا کاملاً معادل است با این روش که از Object.keys() استفاده کنیم:
function showProps(obj, objName) {
let result = "";
Object.keys(obj).forEach((i) => {
result += `${objName}.${i} = ${obj[i]}\n`;
});
console.log(result);
}
هیچ راه پیشفرض و بومی برای لیست کردن «تمام ویژگیهای ارثبردهشده» (Inherited properties) که غیرقابل شمارش (Non-enumerable) هم هستند وجود ندارد. با این حال، با نوشتن تابع سفارشی زیر میتوانید به این هدف برسید:
function listAllProperties(myObj) {
let objectToInspect = myObj;
let result = [];
while (objectToInspect !== null) {
result = result.concat(Object.getOwnPropertyNames(objectToInspect));
objectToInspect = Object.getPrototypeOf(objectToInspect);
}
return result;
}
شما میتوانید یک Property غیرِ ارثبردهشده (Non-inherited) را با استفاده از عملگر delete به طور کامل حذف کنید. کد زیر نحوه حذف یک ویژگی را نشان میدهد:
// ساخت یک شیء جدید به نام myObj با دو ویژگی a و b
const myObj = { a: 5, b: 12 };
// حذف ویژگی a؛ در نتیجه فقط ویژگی b روی شیء باقی میماند
delete myObj.a;
console.log("a" in myObj); // false -> ویژگی دیگر وجود ندارد
این محتوا کاملا رایگان توسط تیم کدلپر ترجمه شده و در اختیار شما کاربران عزیز قرار گرفته است، هر گونه کپی برداری برای مقاصد غیر رایگان و بدون ذکر منبع، مورد پیگیری قانونی قرار میگیرد.
ترجمه شده از منبع: https://developer.mozilla.org/en-US/docs/Web/JavaScript