Symbol در جاوا اسکریپت نوعی داده اولیه محسوب میشود که در «ECMAScript 6 (ES6)» معرفی شده است. نمادها یا سیمبلها مقادیر منحصربهفرد و تغییرناپذیری هستند که میتوانند بهعنوان کلید ویژگی برای ویژگیهای «شی» (Object) مورد استفاده قرار گیرند. سیمبلها اغلب برای ایجاد خصوصیات خصوصی یا پنهان در اشیا استفاده میشوند. این اشیا از نظر عملکردی با اشیای معمولی متفاوت هستند. با استفاده از Symbol، میتوان از ویژگیهای منحصربهفردی برای شی یا متغیر استفاده کرده و از تداخل با دیگر اجزای کد جلوگیری به عمل آورد. در مطلب پیش رو از «مجله فرادرس»، به بررسی جزئیات مختلف مفهوم سیمبل در جاوا اسکریپت پرداخته خواهد شد تا خواننده با کاربردها و نحوه استفاده از این ابزار قدرتمند زبان برنامه نویسی جاوا اسکریپت آشنا شود.
Symbol در جاوا اسکریپت چیست؟
«جاوا اسکریپت ES6» نوعی داده بدوی جدید به نام «Symbol» به معنی نماد را معرفی کرد. سیمبلها در جاوا اسکریپت تغییرناپذیر هستند، به این معنی که نمیتوان آنها را تغییر داد و هر سیمبلی منحصربهفرد است.
توجه به مثال زیر در رابطه با درک مفهوم Symbol در زبان برنامه نویسی جاوا اسکریپت بسیار اهمیت دارد:
1// Two symbols with the same description
2const value1 = Symbol('hello');
3const value2 = Symbol('hello');
4
5console.log(value1 === value2); // false
در مثال فوق با وجود اینکه « value1
» و « value2
» توصیف یکسانی دارند، اما متمایز هستند.
سیمبل در اصل نوعی داده بدوی جدید است که از آن در ES6 پردهبرداری شده است و به عنوان شناسههای کاملاً منحصربهفرد عمل میکند. مشابه دیگر انواع داده ابتدایی مانند «اعداد | Number» ،«استرینگ یا رشته | String» و «داده دودویی | Boolean»، میتوان با استفاده از تابع « Symbol()
» سیمبلهایی ایجاد کرد که منحصربهفرد هستند. سینتکس زیر برای بیان این هدف است:
1const symbol = Symbol('description');
هر فراخوانی از تابع Symbol()
نوعی سیمبل جدید و متمایز تولید میکند. پارامتر رشته اختیاری در سینتکس فوق به عنوان نوعی برچسب توصیفی عمل میکند که هنگام بررسی سیمبل نمایش داده میشود.
1> symbol
2Symbol(description)
از آنجا که هر شناسه از Symbol در جاوا اسکریپت از دیگری متمایز است، مقایسه Symbol() === Symbol()
به false
ارزیابی میشود.
1> Symbol() === Symbol()
2false
زمانی که عملگر « Typeof
» اعمال میشود، سیمبل ماهیت ابتدایی خود را نشان داده و نتیجه خاصی را به دست میدهد:
1> typeof symbol
2'symbol'
به طور خلاصه، سیمبل در جاوا اسکریپت، شناسههای غیرقابل تغییر و منحصربهفردی هستند که در ES6 معرفی شدهاند و روشی متمایز برای ایجاد و مدیریت شناسهها در کد کاربر ارائه میدهند.
نوع داده سیمبل در جاوا اسکریپت
طبق مشخصات جاوا اسکریپت، تنها دو نوع اولیه داده میتوانند به عنوان کلیدهای ویژگی شی ارائه شوند: رشتهها و سیمبلها. هنگام استفاده از هر نوع دیگری مانند اعداد، به صورت خودکار به رشته تبدیل میشود. در نتیجه، دسترسی به ویژگی شی با کلید عددی، مانند obj[1]
، معادل استفاده از کلید رشتهای obj[“1”]
است. همین امر برای کلیدهای بولی نیز صدق میکند. برای مثال، obj[true]
معادل obj[“true”]
است.
نحوه ایجاد Symbol در جاوا اسکریپت چگونه است
سیمبلها در جاوا اسکریپت با استفاده از تابع «Symbol» ساخته میشوند و در صورت ارائه توضیحات، میتوان از طریق ویژگی «Description» با استفاده از عملگر نقطه به آن دسترسی داشت. این قابلیت راهی مختصر برای ایجاد و تشخیص سیمبلهای منحصربهفرد در کد کاربر فراهم میکند. برای تولید Symbol در جاوا اسکریپت، از تابع Symbol()
به صورت زیر استفاده میشود:
1// Creating a symbol
2const x = Symbol();
3
4typeof x; // symbol
کاربر این امکان را دارد که نوعی رشته اختیاری به عنوان توضیحات به سیمبل به صورت زیر ارائه دهد:
1const x = Symbol('hey');
2console.log(x); // Symbol(hey)
همچنین برای بازیابی توضیحات مربوط به سیمبل، میتوان از عملگر نقطه به صورت زیر استفاده کرد:
1const x = Symbol('hey');
2console.log(x.description); // hey
مثالی از ایجاد سیمبل در جاوا اسکریپت
همانطور که بیان شد، سیمبل یا همان نماد در جاوا اسکریپت به عنوان نوعی شناسه متمایز عمل میکند که مقدار منحصربهفردی را نشان میدهد. مثال زیر در رابطه با نحوه ایجاد سیمبل اهمیت زیادی دارد:
سیمبلها را میتوان در حین ایجاد توصیفی که اغلب به عنوان نام سیمبل از آن یاد میشود، عمدتاً برای اهداف اشکالزدایی اختصاص داد:
1// Creating a symbol with the description "id"
2let id = Symbol("id");
توجه به این نکته حائز اهمیت است که سیمبلها منحصربهفرد هستند. حتی اگر چندین Symbol در جاوا اسکریپت توصیف یکسانی داشته باشند، از لحاظ مقادیر متمایز هستند. همچنین توضیحاتی که برای هر سیمبل ارائه میشود که به عنوان نوعی برچسب عمل میکند و بر منحصربهفرد بودن نماد تأثیر نمیگذارد:
1let id1 = Symbol("id");
2let id2 = Symbol("id");
3alert(id1 == id2); // Outputs: false
سیمبلهای جاوا اسکریپت ماهیت متفاوتی از سیمبلها در زبانهای برنامه نویسی دیگر مانند زبان روبی دارند.
اهداف Symbol در جاوا اسکریپت
سیمبلها در جاوا اسکریپت دو هدف اساسی را دنبال میکنند که اولی ایجاد خواص پنهان شی و دومی سیمبلهای سیستم هستند. در ادامه در رابطه با این دو هدف توضیحاتی ارائه شده است.
خواص پنهان شی
سیمبلها برای معرفی ویژگیهای پنهان به اشیا، بهویژه آنهایی که به اسکریپتها یا کتابخانههای خارجی تعلق دارند، بسیار مفید هستند. با استفاده از سیمبلها بهعنوان کلیدهای ویژگی، این ویژگیهای سیمبل در طول پیمایش با حلقه « for..in
» پنهان میمانند و از دسترسی مستقیم سایر اسکریپتها محافظت میشوند و سطحی از کپسولهسازی و محافظت در برابر استفاده تصادفی یا بازنویسی را ارائه میدهند.
سیمبل های سیستم
جاوا اسکریپت از سیمبلهای سیستمی مختلفی استفاده میکند که به وسیله « Symbol.*
» قابل دسترسی هستند و امکان اصلاح رفتارهای داخلی را فراهم میکنند. به عنوان مثال میتوان به کاربرد « Symbol.iterator
» برای قابلیت پیمایش و « Symbol.toPrimitive
» برای پیکربندی تبدیل شی به اولیه اشاره کرد. در حالی که سیمبلها کاملاً پنهان نیستند (متدهایی مانند « Object.getOwnPropertySymbols(obj)
» و « Reflect.ownKeys(obj)
» میتوانند آنها را آشکار کنند. اکثر کتابخانهها، توابع داخلی و ساختارهای نحوی از استفاده از این متدها خودداری میکنند.
استفاده از سیمبل به عنوان کلید برای ویژگی های خصوصی
در سناریوهای مربوط به سلسلهمراتب وراثت در جاوا اسکریپت، دو نوع ویژگی ظاهر میشود: ویژگیهای عمومی، قابل مشاهده برای همه افراد و ویژگیهای خصوصی که به صورت داخلی در اجزای سلسلهمراتب (مانند کلاسها، اشیا) استفاده میشوند. ویژگیهای عمومی اغلب از کلیدهای رشتهای برای قابلیت استفاده بهره میبرند، استفاده از کلیدهای رشتهای برای ویژگیهای خصوصی ممکن است منجر به تداخل و ایجاد نام تصادفی شود. اینجاست که سیمبلها سودمند واقع میشوند و از تداخل جلوگیری خواهند کرد. به عنوان مثال، کد زیر را در نظر بگیرید که در آن سیمبلها برای ویژگیهای خصوصی _counter
و _action
به کار میروند:
1const _counter = Symbol('counter');
2const _action = Symbol('action');
3
4class Countdown {
5 constructor(counter, action) {
6 this[_counter] = counter;
7 this[_action] = action;
8 }
9
10 dec() {
11 let counter = this[_counter];
12 if (counter < 1) return;
13 counter--;
14 this[_counter] = counter;
15 if (counter === 0) {
16 this[_action]();
17 }
18 }
19}
توجه به این نکته ضروری است که Symbol در جاوا اسکریپت در درجه اول از تضاد نام محافظت میکند، نه دسترسی غیرمجاز. میتوان تمام کلیدهای ویژگی، از جمله سیمبلها را از شی بازیابی کرد، مانند مثال زیر:
1const obj = {
2 [Symbol('my_key')]: 1,
3 enum: 2,
4 nonEnum: 3
5};
6
7Object.defineProperty(obj, 'nonEnum', { enumerable: false });
8
9// Ignores symbol-valued property keys:
10> Object.getOwnPropertyNames(obj)
11['enum', 'nonEnum']
12
13// Ignores string-valued property keys:
14> Object.getOwnPropertySymbols(obj)
15[Symbol(my_key)]
16
17// Considers all kinds of keys:
18> Reflect.ownKeys(obj)
19[Symbol(my_key), 'enum', 'nonEnum']
20
21// Only considers enumerable property keys that are strings:
22> Object.keys(obj)
23['enum']
استفاده از سیمبلها بهعنوان کلید برای ویژگیهای خصوصی به کاهش تداخل نامهای تصادفی کمک میکند و راهی تمیز و متمایز برای مدیریت عناصر داخلی در سلسله مراتب وراثت ارائه میدهد. با این حال، تشخیص این نکته ضروری است که سیمبلها از دسترسی غیرمجاز به این ویژگیها جلوگیری نمیکنند.
مثالی از اضافه کردن سیمبل به عنوان کلید شی
با استفاده از براکت []
میتوان سیمبل را به عنوان کلید در شی گنجاند، مانند مثال زیر:
1let id = Symbol("id");
2
3let person = {
4 name: "Jack",
5
6 // Adding symbol as a key
7 [id]: 123 // Not "id": 123
8};
9
10console.log(person); // {name: "Jack", Symbol(id): 123}
نمادها میتوانند بهطور یکپارچه بهعنوان کلید در اشیا استفاده شوند.
آیا واقعا به سیمبل در جاوا اسکریپت نیاز داریم؟
سیمبل در جاوا اسکریپت برای موارد استفاده خاص ارزشمند هستند و به نوعی وجود آنها ضروری است. در زیر موارد استفاده ضروری از سیمبل در جاوا اسکریپت آورده شده است.
- «Enum»: وقتی کاربری بخواهد ثابتها را با نامهای معنایی تعریف و از مقادیر منحصربهفرد اطمینان حاصل کند، نمادها یا همان سیمبلها مفید هستند. مثال زیر برای بیان این هدف است:
1const directions = {
2 UP: Symbol('UP'),
3 DOWN: Symbol('DOWN'),
4 LEFT: Symbol('LEFT'),
5 RIGHT: Symbol('RIGHT')
6};
- تداخل نامها: Symbol در جاوا اسکریپت به جلوگیری از برخورد با کلیدها در اشیا کمک میکند. با استفاده از سیمبلها به عنوان کلید، خطر تداخل نامی ناخواسته کاهش مییابد.
- حریم خصوصی: وقتی کاربری بخواهد مطمئن شود که ویژگیهای شی قابل شمارش نیست، سیمبلها راهحل مناسبی را ارائه میدهند.
پروتکلها: سیمبلها برای بررسی پایبند بودن اشیا به پرتوکلها مفید هستند. به عنوان مثال، کتابخانهای مانند «Dragula» ممکن است نوعی پروتکل را به وسیله « Symbol.for(dragula.moves)» تعریف کند. با افزودن متدی به این سیمبل در هر عنصر «DOM»، کتابخانه میتواند el[Symbol.for(‘dragula.moves’)]()
را فراخوانی کرده تا مشخص کند آیا عنصر به پروتکل پایبند است یا خیر. مثال زیر برای این هدف است:
1// Example of defining a protocol
2const movesSymbol = Symbol.for('dragula.moves');
3
4// Adding a method to the symbol on a DOM element
5someDOMElement[movesSymbol] = function() {
6 // Implementation for checking if the element can be moved
7};
- سیمبلهای شناخته شده: جدا از سیمبلهای تعریف شده به وسیله کاربر، جاوا اسکریپت شامل سیمبلهای داخلی است که رفتارهای زبان را نشان میدهد که در نسخههای قبل از «ES5» در دسترس توسعهدهندگان قرار نگرفته است.
سیمبلها در جاوا اسکریپت در سناریوهایی که نیاز به شناسههای منحصربهفرد دارند، جلوگیری از برخورد نام، حفظ حریم خصوصی، تعریف پروتکلها و تعامل با نمادهای شناختهشده که رفتارهای زبان داخلی را نشان میدهند، ضروری هستند. آنها به عنوان ابزاری قدرتمند برای افزایش وضوح کد و جلوگیری از اثرات جانبی ناخواسته عمل میکنند.
سیمبل ها و حلقه for…in
سیمبلها در حلقه for…in
نمیتوانند به کار گرفته شوند که مثال زیر برای بیان این هدف است:
1let id = Symbol("id");
2
3let person = {
4 name: "Jack",
5 age: 25,
6 [id]: 12
7};
8
9// Utilizing for...in
10for (let key in person) {
11 console.log(key);
12}
خروجی مثال فوق به صورت زیر است:
name age
ویژگیهای سیمبل در جاوا اسکریپت از پیمایش با حلقه for…in
مستثنی هستند. عدم استفاده از سیمبلها در حلقه For in در جاوا اسکریپت جنبه عمدی از اصل پنهان کردن ویژگیهای سیمبل است که برای جلوگیری از دسترسی سهوی به ویژگیهای سیمبل در طول پیمایش به وسیله اسکریپتها یا کتابخانههای دیگر طراحی شده است.
1let id = Symbol("id");
2let user = {
3 name: "John",
4 age: 30,
5 [id]: 123
6};
7
8// Properties from for...in loop or Object.keys() exclude symbols
9for (let key in user) {
10 alert(key); // Outputs: name, age (no symbols)
11}
12
13// Direct access by the symbol works
14alert("Direct: " + user[id]); // Outputs: Direct: 123
در کد بالا، حلقه « for…in
» و « Object.keys()
» عمداً ویژگیهای تعریف شده با سیمبلها را نادیده میگیرند و به اصل پنهان نگهداشتن این ویژگیهای سیمبل در طول پیمایش شی پایبند هستند. با این حال، توجه به این نکته مهم است که « Object.assign()
» رفتار متفاوتی دارد. هنگام استفاده از Object.assign()
برای شبیهسازی نوعی شی یا ادغام اشیا، هر دو ویژگی رشته و نماد کپی میشوند:
1let id = Symbol("id");
2let user = {
3 [id]: 123
4};
5
6let clone = Object.assign({}, user);
7
8alert(clone[id]); // Outputs: 123
در این مورد، رفتار عمدی کپی کردن تمام ویژگیها، از جمله سیمبلها، در طول عملیات شبیهسازی یا ادغام است. این انتخاب طراحی، سازگاری را هنگام کار با شبیهسازی شی یا سناریوهای ادغام تضمین میکند.
مزایای Symbol در جاوا اسکریپت چیست؟
استفاده از سیمبل در جاوا اسکریپت به عنوان کلید در اشیا مزیتهای مشخصی را ارائه میدهد، بهویژه در سناریوهایی که در آن قطعه کد یکسانی در برنامههای مختلف به کار میرود. این عمل با فعال کردن استفاده از نامهای کلیدی یکسان در زمینههای مختلف، مشکلات تداخل نام را کاهش میدهد.
مثال زیر در این رابطه اهمیتی فراوانی دارد:
1let person = {
2 name: "Jack"
3};
4
5// Creating Symbol
6let id = Symbol("id");
7
8// Adding symbol as a key
9person[id] = 12;
در مثال بالا، امکان دارد شی person
به وسیله برنامه دیگری مورد استفاده قرار گیرد. حال با استفاده از سیمبل هدف این است که از افزودن یا اصلاح ناخواسته خاصیتی که میتواند به وسیله آن برنامه قابلدسترسی یا تغییر باشد، جلوگیری شود. با استفاده از سیمبل در اصل نوعی خاصیت یا ویژگی ایجاد میشود که ایزوله و منحصربهفرد باقی میماند. فرض کنید برنامه دیگر نیز به خاصیتی به نام id
نیاز دارد. در این صورت، افزودن سیمبلی به نام id
تضمین میکند که مشکل نامهای تکراری وجود نخواهد داشت، مانند مثال زیر:
1let person = {
2 name: "Jack"
3};
4
5let id = Symbol("id");
6
7person[id] = "Another value";
در برنامه فوق، حتی اگر از همان نام برای ذخیره مقادیر ( id
) استفاده شود، نوع داده Symbol در جاوا اسکریپت، نوعی مقدار منحصربهفرد را تضمین میکند. در مقابل، اگر کلیدی رشتهای استفاده شود، برنامه بعدی ممکن است به طور ناخواسته مقدار ویژگی را تغییر دهد:
1let person = {
2 name: "Jack"
3};
4
5// Using string as a key
6person.id = 12;
7console.log(person.id); // 12
8
9// Another program overwrites the value
10person.id = 'Another value';
11console.log(person.id); // Another value
در مثال بالا، استفاده از کلید رشتهای ( id
) به برنامه دوم اجازه میدهد تا مقدار قبلی را بازنویسی کند که به طور بالقوه منجر به پیامدهای ناخواسته میشود. استفاده از Symbol در Javascript با ارائه مکانیزمی برای ایجاد کلیدهای منحصربهفرد و ایزوله در اشیا، در برابر چنین سناریوهایی محافظت میکند.
متدهای Symbol در جاوا اسکریپت
Symbol در جاوا اسکریپت حاوی متدهایی کاربردی و جذاب است که در موارد خاص از این متدها میتوان استفاده کرد. این متدها به برنامه نویس امکان انجام عملیات مختلفی را میدهند. در زیر فهرستی از مهمترین متدهای سیمبل در زبان برنامه نویسی جاوا اسکریپت ارائه شده است.
- for()
: این متد برای جستجوی سیمبلهای موجود استفاده میشود. این متد در اصل به کاربر امکان میدهد اگر سیمبلی از قبل وجود داشته باشد از رجیستری سیمبل جهانی بازیابی آن صورت بگیرد یا اگر وجود ندارد سیمبلی جدیدی ایجاد شود.
- keyFor()
: متد keyFor()
نوعی کلید سیمبل مشترک را از رجیستری سیمبل جهانی برمیگرداند. اگر سیمبل در رجیستری باشد، این متد کلید خود را ارائه میدهد. در غیر این صورت، تعریفنشده را بازمیگرداند.
- toSource()
: متد toSource()
رشتهای حاوی کد منبع نمایش شی Symbol در جاوا اسکریپت را برمیگرداند. این متد میتواند برای اهداف اشکالزدایی و سریالسازی مفید باشد.
- toString()
: متد toString()
رشتهای حاوی توضیحات Symbol را برمیگرداند. این متد در اصل حاوی نوعی توضیحات اختیاری است و هنگام ایجاد سیمبل قابل ارائه است. اگر هیچ توضیحی ارائه نشود، رشته Symbol
به عنوان پیشفرض استفاده میشود.
- valueOf()
: متد valueOf()
مقدار اولیه شی Symbol را برمیگرداند.
در زیر مثالی برای نشان دادن استفاده از این متدها آورده شده است:
1// get symbol by name
2let sym = Symbol.for('hello');
3let sym1 = Symbol.for('id');
4
5// get name by symbol
6console.log( Symbol.keyFor(sym) ); // hello
7console.log( Symbol.keyFor(sym1) ); // id
در مثال فوق سیمبلها با استفاده از Symbol.for()
ایجاد و نام آنها با استفاده از Symbol.keyFor()
بازیابی شده است.
ویژگی های سیمبل در جاوا اسکریپت
سیمبلها در جاوا اسکریپت دارای ویژگیهای خاصی هستند که میتوان از آنها برای تعریف رفتار یا ویژگیهای اشیا استفاده کرد.
در این بخش از مطلب مجله فرادرس، توضیحی در مورد این ویژگیهای Symbol در جاوا اسکریپت آورده شده است:
- asyncIterator
: این ویژگی AsyncIterator پیشفرض را برای شیئی برمیگرداند و برای پیمایش ناهمزمان بر روی شی استفاده میشود.
- hasInstance
: این ویژگی تعیین میکند که آیا شی سازنده شیئی را به عنوان نمونه خود تشخیص میدهد یا خیر. این ویژگی اغلب در زمینه کلاسهای سفارشی استفاده میشود.
- isConcatSpreadable
: این ویژگی نشان میدهد که آیا هنگام استفاده از متد concat
، شی باید به عناصر آرایه خود گسترش یابد. ویژگی نام برده هنگام برخورد با آرایهها مفید است.
- iterator
: این ویژگی پیمایش کننده پیشفرض شیئی را برمیگرداند و برای پیمایش روی عناصر شی استفاده میشود.
- match
: این ویژگی با عبارات منظم برای یافتن موارد منطبق در رشتهها استفاده میشود.
- matchAll
: این ویژگی پیمایش کنندهای را برمیگرداند که مطابق با عبارت منظم در برابر رشتهای است. ویژگی نام برده در اصل برای یافتن تمام موارد منطبق در رشته مفید است.
- replace
: این ویژگی جایگزین رشتههای فرعی همسان رشته و اغلب با عبارات منظم برای دستکاری رشته مورداستفاده قرار میگیرد.
- search
: این ویژگی اندیسی را در رشته که با عبارت منظم مطابقت دارد برمیگرداند و در واقع برای یافتن موقعیت الگویی خاص در رشته استفاده میشود.
- split
: این ویژگی رشته را در اندیسهایی که با عبارت منظم مطابقت دارند تقسیم میکند و در اصل برای تقسیم رشته به آرایهای از رشتههای فرعی استفاده میشود.
- species
: این ویژگی اشیا مشتق شده را ایجاد میکند و در زمینه وراثت برای ایجاد اشیاء از همان نوع استفاده میشود.
- toPrimitive
: ویژگی toPrimitive
شی را به نوعی مقدار اولیه تبدیل میکند. این ویژگی به وسیله جاوا اسکریپت برای تبدیل شی به نوع اولیه مانند رشته یا عدد فراخوانی میشود.
- toStringTag
: ویژگی toStringTag
توضیحات پیشفرض شی را میدهد و اغلب برای سفارشی کردن خروجی Object.prototype.toString()
مورداستفاده قرار میگیرد.
- description
: این ویژگی رشتهای حاوی توضیحات سیمبل در جاوا اسکریپت را برمیگرداند. description
در واقع نوعی ویژگی خاص برای سیمبلها است که توضیحاتی را ارائه میدهد که در طول ایجاد سیمبل ارائه میشود.
در اینجا مثالی برای نشان دادن استفاده از ویژگی description
و ویژگی isConcatSpreadable
آورده شده است:
1const x = Symbol('hey');
2
3// description property
4console.log(x.description); // hey
5
6const stringArray = ['a', 'b', 'c'];
7const numberArray = [1, 2, 3];
8
9// isConcatSpreadable property
10numberArray[Symbol.isConcatSpreadable] = false;
11
12let result = stringArray.concat(numberArray);
13console.log(result); // ["a", "b", "c", [1, 2, 3]]
در مثال بالا، ویژگی description
برای بازیابی توضیحات سیمبل و ویژگی isConcatSpreadable
برای کنترل رفتار الحاق آرایه استفاده میشود.
عدم تبدیل سیمبل به صورت خودکار به رشته
برخلاف بسیاری از مقادیر در جاوا اسکریپت که به راحتی از تبدیل ضمنی به رشته پشتیبانی میکنند، سیمبلها به طور خودکار تحت این تبدیل قرار نمیگیرند. تلاش برای نمایش نوعی Symbol در جاوا اسکریپت در قالب رشته به طور مستقیم، مانند استفاده از alert(id)
منجر به خطا میشود که مثال زیر این موضوع را نشان میدهد:
1let id = Symbol("id");
2alert(id); // TypeError: Cannot convert a Symbol value to a string
رفتار فوق به عنوان نوعی اقدام محافظتی برای جلوگیری از سو استفاده ناخواسته عمل میکند زیرا رشتهها و سیمبلها اساساً متمایز هستند و نباید به طور تصادفی به یکدیگر تبدیل شوند. اگر نیاز واقعی به نمایش سیمبل وجود دارد، باید به صراحت از متد «.toString()»
به صورت زیر استفاده شود:
1let id = Symbol("id");
2alert(id.toString()); // Outputs: Symbol(id), now it works
همچنین، میتوان به ویژگی description
سیمبل دسترسی داشت تا فقط توضیحات را نمایش دهد ، مانند مثال زیر:
1let id = Symbol("id");
2alert(id.description); // Outputs: id
نوع مدیریت صریح بالا تضمین میکند که با سیمبلها به دقت رفتار میشود، طبیعت منحصربهفرد آنها تائید و از تبدیلهای ناخواسته جلوگیری خواهد شد.
ویژگی مخفی در سیمبل های جاوا اسکریپت چیست؟
سیمبلهای جاوا اسکریپت مکانیزمی را برای ایجاد ویژگیهای پنهان برای اشیا فراهم میکنند و اطمینان میدهند که سایر بخشهای کد نمیتوانند به طور سهوی به آنها دسترسی پیدا کرده یا آنها را بازنویسی کنند. این قابلیت بهویژه هنگام کار با اشیا از کد شخص ثالث مفید واقع خواهد شد. مثال زیر برای بیان این هدف مهم است:
1let user = { // Object from another code
2 name: "John"
3};
4
5let id = Symbol("id");
6
7// Assigning a hidden property to the user object using a symbol key
8user[id] = 1;
9
10// Accessing the data using the symbol as the key
11alert(user[id]); // Outputs: 1
در سناریوی بالا، کلید نماد ( id
) برای ایجاد ویژگی مخفی برای شی user
استفاده میشود. این قابلیت تضمین میکند که شناسه جدا باقی میماند و بهطور تصادفی به وسیله قسمتهای دیگر کد به آن دسترسی یا اصلاح نمیشود، سطحی از کپسولهسازی را فراهم میکند و از تداخل ناخواسته با ویژگیهای شی جلوگیری خواهد کرد.
مزیت استفاده از Symbol(“id”) بر روی رشته id چیست؟
استفاده از Symbol(“id”)
روی رشته id
مزایای قابلتوجهی را در سناریوهایی که اشیا کاربر به پایگاه کد دیگری تعلق دارند، ارائه میدهد. مزیت کلیدی در جلوگیری از تداخل ناخواسته با رفتار از پیش تعریف شده در پایگاه کد خارجی نهفته است. توجه به کد زیر در این رابطه خالی از لطف نیست:
1// ...
2let id = Symbol("id");
3
4user[id] = "Their id value";
هنگام استفاده از سیمبلها، کد شخص ثالث از سیمبلهای جدید تعریف شده بیاطلاع است و افزودن آنها به اشیا کاربر را ایمن میکند. این محافظت در برابر دسترسی یا اصلاح تصادفی توسط پایگاه کد خارجی، تضمین میکند که افزودههای کاربر، مانند Symbol(“id”)
محصور میشوند و عملکرد مورد نظر شی کاربر را مختل نمیکنند. علاوه بر این، زمانی که چندین اسکریپت به طور مستقل بخواهند شناسههای خود را در داخل شی کاربر معرفی کنند، سیمبل در جاوا اسکریپت مزیت مهم دیگری را ارائه میدهد که مثال زیر برای بیان این هدف است:
1let user = { name: "John" };
2
3// Our script uses Symbol("id") property
4let id = Symbol("id");
5user[id] = "Our id value";
6
7// Another script wants its own identifier inside user
8let theirId = Symbol("id");
9user[theirId] = "Their id value";
در مثال بالا، استفاده از سیمبل (Symbol(“id”)` و “Symbol(“id”))
تضمین میکند که هیچ تضادی بین شناسههای اسکریپتهای مختلف وجود ندارد. سیمبلها، حتی اگر یکسان نامگذاری شوند، ذاتاً متفاوت هستند و شناسایی منحصربهفرد را تضمین میکنند. از سوی دیگر، اگر رشته id
به جای سیمبلها استفاده شود، زمانی که اسکریپتها سعی میکنند ویژگی id
را به اشتراک بگذارند یا تغییر دهند، تضادها به راحتی ایجاد میشود که به طور بالقوه منجر به بازنویسی ناخواسته و اختلال در عملکرد نهایی کد میشود.
سیمبل های سراسری
در جاوا اسکریپت، سیمبلها معمولاً موجودیتهای متمایز هستند، حتی اگر نام یکسانی داشته باشند. با این حال، سناریوهایی وجود دارد که در آن قسمتهای مختلف برنامه باید دقیقاً به سیمبلی خاص اشاره کنند، مانند زمانی که چندین مؤلفه میخواهند به سیمبلی به نام id
با معنای ثابت دسترسی پیدا کنند. برای رفع این نیاز، جاوا اسکریپت نوعی ریجستری سیمبل جهانی ارائه میدهد. سیمبلهای ایجاد شده در این رجیستری به عنوان سیمبلهای جهانی شناخته میشوند.
میتوان این سیمبلها را با استفاده از متد Symbol.for(key)
ایجاد یا بازیابی کرد. این تابع رجیستری جهانی را بررسی میکند و اگر نمادی با کلید مشخص شده وجود داشته باشد، آن سیمبل را برمیگرداند. در غیر این صورت، نوعی سیمبل جدید (`Symbol(key)`)
ایجاد میکند و آن را در رجیستری در زیر کلید داده شده ذخیره میکند. در زیر مثالی برای نشان دادن استفاده از سیمبلهای جهانی آورده شده است:
1// Read from the global registry
2let id = Symbol.for("id"); // Creates a new symbol if it doesn't exist
3
4// Read it again (perhaps from another part of the code)
5let idAgain = Symbol.for("id");
6
7// The same symbol
8alert(id === idAgain); // Outputs: true
در مثال بالا، id
و idAgain
هر دو به سیمبل سراسری اشاره دارند زیرا از ریجستری جهانی بازیابی شدهاند. این مکانیسم مخصوصاً زمانی مفید است که ما به Symbol در جاوا اسکریپت در سطح برنامه نیاز داریم که بتوان به طور مداوم در بخشهای مختلف کد به آن دسترسی داشت.
Symbol.keyFor
در جاوا اسکریپت، هنگام کار با سیمبلهای سراسری، متد Symbol.for(key)
به کاربر اجازه میدهد تا نوعی سیمبل را با نام آن بازیابی کرد. برعکس، برای بازیابی نام مرتبط با نماد سراسری، میتوان از Symbol.keyFor(sym)
استفاده کرد. در زیر مثالی برای نشان دادن استفاده از Symbol.keyFor
آورده شده است:
1// Get symbols by name from the global registry
2let sym = Symbol.for("name");
3let sym2 = Symbol.for("id");
4
5// Get name by symbol using Symbol.keyFor
6alert(Symbol.keyFor(sym)); // Outputs: name
7alert(Symbol.keyFor(sym2)); // Outputs: id
توجه به این نکته مهم است که Symbol.keyFor
به صورت داخلی به ریجیستری سیمبل سراسری متکی است. در نتیجه، منحصراً برای سیمبلهای سراسری کار میکند. اگر سیمبل سراسری نباشد، متد نمیتواند آن را پیدا کند و «تعریفنشده | Undefined» بازمیگردد. از سوی دیگر، هم برای سیمبلهای سراسری و هم برای سیمبلهای محلی، هر سیمبلی دارای نوعی ویژگی «توضیح» است که میتوان به آن دسترسی داشت. مانند مثال زیر:
1let globalSymbol = Symbol.for("name");
2let localSymbol = Symbol("name");
3
4// Accessing the key for a global symbol
5alert(Symbol.keyFor(globalSymbol)); // Outputs: name (global symbol)
6
7// Unable to retrieve key for a local symbol
8alert(Symbol.keyFor(localSymbol)); // Outputs: undefined (not global)
9
10// Accessing the description property for any symbol
11alert(localSymbol.description); // Outputs: name
در مثال بالا، localSymbol.description
توضیحات مرتبط با سیمبل را ارائه میکند و در هنگام برخورد با نمادهای غیر سراسری، جایگزینی ارائه میدهد.
سیستم سیمبل در جاوا اسکریپت چیست؟
جاوا اسکریپت شامل انواع سیستمهای سیمبل است که به صورت داخلی مورد استفاده قرار میگیرند و میتوان از آنها برای تنظیم دقیق جنبههای مختلف اشیا استفاده کرد. این سیمبلها در جدول سیمبلهای شناخته شده در مشخصات زبان مستند شدهاند. چند نمونه از این سیمبلهای سیستم به صورت موارد زیر هستند:
- «Symbol.hasInstance»
- «Symbol.isConcatSpreadable»
- «Symbol.iterator»
- «Symbol.toPrimitive»
این سیمبلها اهداف خاصی را در داخل زبان انجام میدهند و با بررسی ویژگیهای زبان مربوطه، کاربرد آنها آشکارتر میشود. به عنوان مثال، سیمبل «Symbol.toPrimitive» به کاربر اجازه میدهد تا تبدیل شی به نوع اولیه را تعریف کند. کاربران با پیشرفت و مطالعه ویژگیهای مختلف زبان، با این سیمبلهای سیستم و نقش آنها در تنظیم و بهینهسازی رفتار اشیا در جاوا اسکریپت بیشتر آشنا میشوند.
سخن پایانی
Symbol در جاوا اسکریپت نوعی داده ابتدایی بوده که به طور خاص برای ایجاد شناسههای منحصر به فرد طراحی شده است. سیمبلها با استفاده از تابع Symbol()
تولید میشوند و میتوانند شامل توضیحی اختیاری باشند. مهمتر از همه، سیمبلها همیشه مقادیر متمایز هستند، حتی زمانی که نام یکسانی داشته باشند. برای ایجاد برابری برای سیمبلهای همنام، ریجیستری جهانی سیمبلها وارد عمل میشود.
در مطلب فوق از مجله فرادرس مفهوم Symbol در جاوا اسکریپت به زبان ساده مورد بررسی قرار گرفت و در کنار تعریف مفهوم Symbol، اهداف و مزایای سیمبلها، ویژگی و متدهای آنها، سیمبلهای سراسری و سیستم سیمبل در جاوا اسکریپت نیز مورد بررسی واقع شد. درک مفهموم سیمبل در جاوا اسکریپت و ابعاد مختلف آن به کاربر کمک میکند که کدهای واضحتر و بهتری بنویسد و در کنار آن کدهای کاربر باگ و تداخل کمتری داشته باشند.
source