اپراتور >>> در جاوااسکریپت چیست و چگونه از آن استفاده میکنید؟
من در حال نگاه کردن به کدهای موزیلا بودم که یک متد فیلتر به آرایه اضافه میکرد و خطی از کد داشت که من را سردرگم کرد.
var len = this.length >>> 0;
من هرگز قبل از این >>> را در جاوااسکریپت ندیدهام.
این چیست و چه کاری انجام میدهد؟
پاسخ شماره ۱
این فقط مقادیر غیرعددی را به عدد تبدیل نمیکند، بلکه آنها را به اعدادی تبدیل میکند که میتوان به صورت اعداد صحیح بدون علامت ۳۲ بیتی نمایش داد.
اگرچه اعداد در جاوااسکریپت به صورت عدد شناور با دقت دوگانه هستند (*), عملگرهای بیتی (<<، >>، &، | و ~) بر اساس عملیات بر روی اعداد صحیح ۳۲ بیتی تعریف شدهاند. انجام یک عملیات بیتی باعث میشود عدد به عدد صحیح ۳۲ بیتی علامتدار تبدیل شود، هر کسری و بیتهای بالاتر از ۳۲ از دست میروند، قبل از انجام محاسبه و سپس دوباره به Number تبدیل میشود.
بنابراین انجام یک عملیات بیتی که اثر واقعی ندارد، مانند شیفت به راست به اندازه ۰ بیت >>0، روشی سریع برای گرد کردن یک عدد و اطمینان از اینکه در محدوده عدد صحیح ۳۲ بیتی باشد، است. علاوه بر این، عملگر سهگانه >>>، پس از انجام عملیات بدون علامت خود، نتایج محاسباتش را به عنوان یک عدد صحیح بدون علامت به نوع Number تبدیل میکند، نه عدد صحیح با علامت که سایر عملگرها انجام میدهند، بنابراین میتوان از آن برای تبدیل اعداد منفی به نسخه مکمل دو ۳۲ بیتی به صورت یک عدد بزرگ استفاده کرد. استفاده از >>>0 تضمین میکند که یک عدد صحیح بین ۰ و 0xFFFFFFFF دارید.
در این حالت این مفید است زیرا ECMAScript شاخصهای آرایه را بر اساس اعداد صحیح بدون علامت ۳۲ بیتی تعریف میکند. بنابراین اگر شما سعی دارید array.filter را به گونهای پیادهسازی کنید که دقیقا همان چیزی باشد که استاندارد ECMAScript نسخه پنجم میگوید، عدد را به صورت عدد صحیح بدون علامت ۳۲ بیتی به این شکل تبدیل میکنید.
در حقیقت، نیاز عملی کمی به این وجود دارد زیرا امیدواریم مردم قرار نباشد array.length را روی 0.5، -1، 1e21 یا 'LEMONS' تنظیم کنند.
خلاصه :
1>>>0 === 1
-1>>>0 === 0xFFFFFFFF -1>>0 === -1
1.7>>>0 === 1
0x100000002>>>0 === 2
1e21>>>0 === 0xDEA00000 1e21>>0 === -0x21600000
Infinity>>>0 === 0
NaN>>>0 === 0
null>>>0 === 0
'1'>>>0 === 1
'x'>>>0 === 0
Object>>>0 === 0
(*: خوب، آنها به عنوان رفتارکننده مثل اعداد اعشاری تعریف شدهاند. اگر یک موتور جاوااسکریپت در واقع از اعداد صحیح وقتی میتواند استفاده میکرد، برای دلایل کارایی، تعجب نمیکنم. اما این یک جزئیات پیادهسازی خواهد بود که شما نمیتوانید از آن بهرهبرداری کنید.)
پاسخ شماره ۲
عملگر شیفت راست بدون علامت در تمام پیادهسازیهای متد array extra's در موزیلا استفاده میشود تا اطمینان حاصل شود که ویژگی length یک عدد صحیح ۳۲ بیتی بدون علامت است.
ویژگی length اشیاء آرایه در مشخصات به این صورت توصیف شده است:
هر شیء آرایه دارای یک خاصیت طول است که مقدار آن همیشه یک عدد صحیح غیرمنفی کمتر از 232 است.
این عملگر کوتاهترین راه برای دستیابی به آن است، متدهای داخلی آرایه از عملیات ToUint32 استفاده میکنند، اما آن متد قابل دسترسی نیست و در مشخصات صرفاً برای اهداف پیادهسازی وجود دارد.
پیادهسازیهای array extras موزیلا سعی میکنند با ECMAScript 5 سازگار باشند، به توضیحات روش Array.prototype.indexOf نگاه کنید (§ 15.4.4.14):
1. Let O be the result of calling ToObject passing the this value
as the argument.
2. Let lenValue be the result of calling the [[Get]] internal method of O with
the argument "length".
3. Let len be ToUint32(lenValue).
....
همانطور که میبینید، آنها فقط میخواهند رفتار متد ToUint32 را بازتولید کنند تا با مشخصات ES5 در یک پیادهسازی ES3 مطابقت داشته باشد، و همانطور که قبلاً گفتم، عملگر شیفت راست بدون علامت سادهترین راه است.
پاسخ شماره ۳
این عملگر شیفت راست بیتی بدون علامت است. تفاوت بین این و عملگر شیفت راست بیتی با علامت این است که عملگر شیفت راست بیتی بدون علامت (>>>) از سمت چپ با صفر پر میکند، و عملگر شیفت راست بیتی با علامت (>>) با بیت علامت پر میکند، بنابراین علامت مقدار عددی هنگام شیفت حفظ میشود.
پاسخ شماره ۴
درییس بهطور کافی توضیح داده است که اپراتور چیست و چه کاری انجام میدهد. در اینجا معنای پشت آن/چرا استفاده شده است:
جابجا کردن در هر جهت به اندازه 0 عدد اصلی را برمیگرداند و null را به 0 تبدیل میکند. به نظر میرسد که کد مثالی که شما نگاه میکنید از this.length >>> 0 استفاده میکند تا اطمینان حاصل شود که len عددی است حتی اگر this.length تعریف نشده باشد.
برای بسیاری از افراد، عملیات بیتبهبیت نامشخص است (و داگلاس کرکفورد/jslint استفاده از چنین چیزهایی را توصیه نمیکنند). این به این معنا نیست که انجام آن اشتباه است، اما روشهای مطلوبتر و آشناتری برای خواناتر کردن کد وجود دارد. یک راه واضحتر برای اطمینان از اینکه len برابر با 0 است، یکی از دو روش زیر است.
// Cast this.length to a number
var len = +this.length;
یا
// Cast this.length to a number, or use 0 if this.length is
// NaN/undefined (evaluates to false)
var len = +this.length || 0;
پاسخ شماره ۵
>>> عملگر شیفت به راست بدون علامت است (صفحه ۷۶ مشخصات JavaScript 1.5 را ببینید)، در مقابل >>، که عملگر شیفت به راست با علامت است.
>>> نتایج شیفت دادن اعداد منفی را تغییر میدهد زیرا بیت علامت را هنگام شیفت حفظ نمیکند. پیامدهای این موضوع را میتوان با یک مثال از یک مفسر فهمید:
1 >> 0
1
0 >> 0
0
-1 >> 0
-1
1 >>> 0
1
0 >>> 0
0
-1 >>> 0
4294967295
$(-1 >>> 0).toString(16)
"ffffffff"
"cabbage" >>> 0
0
بنابراین احتمالاً قصد این است که طول به دست آید، یا ۰ اگر طول تعریف نشده باشد یا یک عدد صحیح نباشد، طبق مثال "cabbage" که در بالا آمده است. فکر میکنم در این مورد میتوان به طور ایمن فرض کرد که this.length هرگز < 0 نخواهد بود. با این حال، من معتقدم که این مثال یک ترفند زشت است، به دو دلیل:
رفتار
<<<هنگام استفاده از اعداد منفی، یک اثر جانبی که احتمالاً ناخواسته است (یا به احتمال زیاد رخ میدهد) در مثال بالا.، همانطور که وجود این سؤال ثابت میکند.
بهترین روش احتمالاً استفاده از چیزی قابل خواندنتر است، مگر اینکه عملکرد کاملاً حیاتی باشد:
isNaN(parseInt(foo)) ? 0 : parseInt(foo)
پاسخ شماره ۶
دو دلیل:
نتیجه >>> یک «صحیح» است
undefined >>> 0=0 (چون JS تلاش خواهد کرد LFS را به زمینه عددی تبدیل کند، این برای "foo" >>> 0 و غیره نیز کار خواهد کرد)
به خاطر بسپارید که اعداد در JS دارای نمای داخلی از نوع double هستند. این فقط یک روش «سریع» برای بررسی پایهای اعتبار ورودی برای طول است.
با این حال، -1 >>> 0 (اوه، احتمالاً طول مورد نظر نیست!)
