عملگرهای بیتی (Bitwise) آخرین گروه از عملگرهای جاوا اسکریپت هستند که در این مطلب مورد بررسی قرار خواهند گرفت. بررسی عملگرهای بیتی نیارمند آنست که با مفاهیم علوم کامپیوتر نیز آشنایی نسبی داشته باشید. اما چون توضیح آن مفاهیم خارج از حوصله این دوره آموزشی ابتدایی است از پرداختن به آن ها صرفنظر می کنیم. البته این را هم در نظر داشته باشید که این گروه از عملگرها به نسبت سایر عملگرها کاربردهای کمتری در برنامه های واقعی دارند و بیشتر جنبه تئوری دارند و چیزهایی نیستند که شما همیشه در برنامه هایتان با آن ها سر و کار داشته باشید ولی به هر حال کاربرد خودشان را دارند. در پایان نیز مختصری به موضوع تقدم عملگرها (Operator Precedence) در جاوا اسکریپت اشاره خواهم نمود.
ما انسان ها اعداد را در مبنای 10 (Decimal) به کار می بریم مثل اعداد 1، 2، 3، و ... . اما حتما می دانید که سیستم اعداد دهدهی برای کامپیوتر قابل فهم نیستند. کامپیوترها فقط قادر به درک و پردازش سیستم اعداد دودویی هستند. در این سیستم، همه چی به صورت ترکیبی از 0 و 1 ذخیره می شوند. برای ذخیره اعداد از بیت ها استفاده می کنیم هر 8 بیت داده تشکیل یک بایت (Byte) را می دهند. به عنوان مثال اگر بخواهیم برای ذخیره اعداد صحیح از یک بایت (هشت بیت) استفاده کنیم، 00000001 نمایش دودویی عدد 1، و 00000010 نمایش دودویی عدد 2 خواهد بود. اینکه چگونه می توانیم یک عدد دسیمال را به مبنای 2 و بالعکس ببریم را می توانید در گوگل جستجو کرده و مطالعه کنید.
عملگرهای بیتی نیز مشابه عملگرهای منطقی هستند با این تفاوت که عملگرها بیتی همانطور که از اسمشان پیداست بر روی بیت ها عمل می کنند. در این مطلب به دو عملگر بیتی که بیش از سایر عملگرهای بیتی در برنامه های واقعی کاربرد دارند می پردازیم و بررسی مابقی آن ها را به خودتان واگذار می کنیم. این عملگرهای بیتی عبارتند از:
نکته: هر وقت که یک عملگر بیتی بر روی دو عدد دسیمال اعمال شود، موتور جاوا اسکریپت ابتدا هر دو عدد را به اعداد باینری معادل تبدیل می کند، سپس عمل بیتی موردنظر را بر روی آن ها انجام می دهد و نهایتا نتیجه آن عمل بیتی را که یک عدد باینری است به عدد معادل دسیمال تبدیل کرده و بر می گرداند.
به عنوان مثال نتیجه عمل بیتی OR بر روی اعداد دسیمال زیر برابر با عدد دسیمال 3 خواهد بود:
console.log(1 | 2);
در مثال بالا موتور جاوا اسکریپت عدد دسیمال 1 را به عدد باینری 00000001، و عدد دسیمال 2 را به عدد باینری 00000010 تبدیل می کند سپس عمل بیتی OR را بر روی آن ها انجام می دهد. حاصل عدد باینری 00000011 خواهد بود. حالا اگر این عدد باینری را به مبنای 10 ببریم معادل عدد 3 خواهد شد. البته در نظر داشته باشید که در این مثال تنها برای سادگی مطلب از 8 بیت برای نمایش اعداد باینری استفاده کردیم وگرنه در عمل جاوا اسکریپت از تعداد بیت های بیشتری برای ذخیره و نمایش اعداد صحیح استفاده می کند.
حالا اگر همان مثال بالا را با عملگر بیتی AND تکرار کنیم نتیجه عملیات برابر با عدد دسیمال 0 خواهد شد:
console.log(1 & 2);
نوبت شماست تا بررسی کنید و ببینید که حاصل عملیات بیتی بالا چطور برابر با عدد دسیمال 0 شده است. حالا که نحوه کارکرد عملگرهای بیتی را به درستی درک نمودید نوبت آنست تا به سراغ یک مثال واقعی برویم.
یک سیستم کنترل سطح دسترسی کاربر در یک برنامه خاص را در نظر بگیرید. فرض کنید که سطوح دسترسی یک کاربر نوعی عبارت باشند از: Read، Write، و Execute
ما می توانیم برای نمایش این سطوح دسترسی خیلی راحت از سیستم اعداد باینری کمک بگیریم. چون سه سطح دسترسی مختلف داریم می توانیم فقط از 3 بیت آخر یک بایت داده استفاده کنیم مثلا بیت شماره شش را به سطح دسترسی Read، بیت شماره هفت را به سطح دسترسی Write، و بیت شماره هشت را به سطح دسترسی Execute اختصاص می دهیم. به این صورت که اگر آن سطح دسترسی وجود داشت بیت مربوطش 1 و در غیر اینصورت 0 می شود. بنابراین نمایش باینری سطح دسترسی Read عدد 00000100، نمایش باینری سطح دسترسی Write عدد 00000010، و نمایش باینری سطح دسترسی Execute عدد 00000001 خواهد شد.
حالا ببینیم پیاده سازی منطق بالا در کد به چه صورت خواهد شد. ابتدا ما به سه ثابت (Constant) مختلف برای نگهداری سه سطح دسترسی مذکور نیاز داریم:
const readPermission = 4; const writePermission = 2; const executePermission = 1;
اولین سوال اینجاست که اعداد 4 و 2 و 1 از کجا آمدند؟ جواب خیلی ساده است. عدد 4 معادل دهدهی عدد 00000100، عدد 2 معادل دهدهی عدد 00000010، و عدد 1 معادل دهدهی عدد 00000001 است که در بالا به آن ها اشاره نمودیم. همچنین به یک متغیر احتیاج داریم که سطوح دسترسی یک کاربر در حال حاضر را نشان دهد و به طور پیش فرض آن را با صفر مقدار دهی می کنیم به این معنی که کاربر در ابتدا هیچ سطح دسترسی ای ندارد:
let myPermission = 0;
حالا برای افزودن سطوح دسترسی مورد نظرمان به کاربر، کافیست تا مقدار سطح دسترسی مورد نظر را با مقدار سطح دسترسی حال حاضر کاربر OR بیتی کنیم مثل زیر که سطوح دسترسی خواندن و نوشتن را به کاربر اعطا می کند:
myPermission = myPermission | readPermission | writePermission;
بعد ازین هر جا نیاز بود تا بفهمیم که آیا کاربر فلان سطح دسترسی خاص را دارد یا خیر، کافیست تا مقدار متغیر myPermission را با مقدار سطح دسترسی مورد نظر AND بیتی کنیم. مثلا اگر می خواهیم ببینیم که کاربر بالا آیا سطح دسترسی خواندن دارد یا خیر باید به صورت زیر عمل کنیم:
let message = (myPermission & readPermission) ? 'yes' : 'no';
حالا اگر از متغیر message یک لاگ بگیریم، کلمه yes را در کنسول مشاهده خواهید نمود که نشان دهنده داشتن سطح دسترسی خواندن برای کاربر می باشد:
console.log(message); //yes
بنابراین برای افزودن سطح دسترسی از عملگر OR بیتی و برای بررسی اینکه آیا کاربر فلان سطح دسترسی خاص را دارد یا خیر از عملگر AND بیتی استفاده می کنیم.