آیا می دانستید که عناصر DOM با شناسه در جاوا اسکریپت به عنوان متغیرهای سراسری قابل دسترسی هستند؟ این یکی از آن چیزهایی است که همیشه وجود داشته است، اما من واقعاً برای اولین بار است که به آن می پردازم.
اگر این اولین بار است که در مورد آن می شنوید، خود را آماده کنید! ما می توانیم آن را به سادگی با افزودن یک شناسه به یک عنصر در HTML در عمل مشاهده کنیم:
به طور معمول، ما با استفاده از یک متغیر جدید تعریف می کنیم querySelector("#cool")
or getElementById("cool")
برای انتخاب آن عنصر:
var el = querySelector("#cool");
اما ما در واقع از قبل به آن دسترسی داریم #cool
بدون آن ریگامورال:
بنابراین، هر id
- یا name
ویژگی، برای آن موضوع - در HTML می توان با استفاده از جاوا اسکریپت به آن دسترسی پیدا کرد window[ELEMENT_ID]
. باز هم، این دقیقاً «جدید» نیست، اما دیدن آن واقعاً غیرمعمول است.
همانطور که ممکن است حدس بزنید، دسترسی به دامنه جهانی با مراجع نامگذاری شده بهترین ایده نیست. برخی از مردم این را "آلوده کننده گستره جهانی" نامیده اند. ما به دلیل این امر خواهیم پرداخت، اما ابتدا…
برخی زمینه ها
این رویکرد است در مشخصات HTML مشخص شده است، جایی که به عنوان "دسترسی نامگذاری شده در Window
هدف - شی."
اینترنت اکسپلورر اولین کسی بود که این ویژگی را پیاده سازی کرد. همه مرورگرهای دیگر نیز آن را اضافه کردند. Gecko تنها مرورگری در آن زمان بود که مستقیماً از آن در حالت استاندارد پشتیبانی نمی کرد و در عوض آن را به یک ویژگی آزمایشی تبدیل کرد. اصلاً برای اجرای آن تردید وجود داشت، اما این بود به نام سازگاری مرورگر پیش رفت (Gecko حتی سعی کرد WebKit را متقاعد کنید تا آن را از حالت استاندارد خارج کنید) و در نهایت آن را به حالت استاندارد در فایرفاکس 14 رساند.
یکی از مواردی که ممکن است به خوبی شناخته نشده باشد این است که مرورگرها مجبور بودند اقدامات احتیاطی - با درجات مختلف موفقیت - انجام دهند تا اطمینان حاصل شود که جهانی های تولید شده صفحه وب را شکسته نمی کنند. یکی از این اقدامات…
سایه متغیر
احتمالاً جالب ترین بخش این ویژگی این است که ارجاعات عناصر نامگذاری شده این کار را انجام نمی دهند متغیرهای جهانی موجود را تحت الشعاع قرار دهید. بنابراین، اگر یک عنصر DOM دارای یک باشد id
که قبلاً به عنوان یک جهانی تعریف شده است، آن موجود را لغو نمی کند. مثلا:
window.foo = "bar";
I won't override window.foo
console.log(window.foo); // Prints "bar"
و برعکس آن نیز صادق است:
I will be overridden :(
window.foo = "bar";
console.log(window.foo); // Prints "bar"
این رفتار ضروری است زیرا نادیده گرفتن موارد خطرناکی مانند
، که در غیر این صورت با باطل کردن آن، تضاد ایجاد می کند alert
API. این تکنیک حفاظتی ممکن است دلیلی باشد که شما - اگر مثل من هستید - برای اولین بار در مورد این موضوع یاد می گیرید.
پرونده علیه جهانیان نام برده
قبلاً گفتم که استفاده از عناصر با نام جهانی به عنوان مرجع ممکن است بهترین ایده نباشد. دلایل زیادی برای آن وجود دارد که TJ VanToll به خوبی در وبلاگ خود پوشش داده است و من در اینجا خلاصه می کنم:
- اگر DOM تغییر کند، مرجع نیز تغییر می کند. این باعث می شود برخی واقعا "شکننده" (مدت مشخصات برای آن) کدی که در آن جداسازی نگرانیها بین HTML و جاوا اسکریپت ممکن است بیش از حد باشد.
- ارجاعات تصادفی بسیار آسان است. یک اشتباه تایپی ساده ممکن است با ارجاع به یک جهانی با نام به پایان برسد و نتایج غیرمنتظره ای به شما بدهد.
- در مرورگرها به صورت متفاوتی اجرا می شود. به عنوان مثال، ما باید بتوانیم به یک لنگر با یک دسترسی داشته باشیم
id
- به عنوان مثال— اما برخی از مرورگرها (یعنی سافاری و فایرفاکس) a را برمیگردانند
ReferenceError
در کنسول - ممکن است چیزی را که شما فکر می کنید برنگرداند. با توجه به مشخصات، زمانی که چندین نمونه از یک عنصر با نام مشابه در DOM وجود دارد - مثلاً، دو نمونه از
- مرورگر باید an را برگرداند
HTMLCollection
با آرایه ای از نمونه ها با این حال، فایرفاکس فقط اولین نمونه را برمی گرداند. سپس دوباره، مشخصات می گوید ما باید از یک نمونه از an استفاده کنیمid
به هر حال در درخت یک عنصر اما انجام این کار مانع از کار کردن یک صفحه یا هر چیز دیگری نمی شود. - شاید هزینه عملکردی داشته باشد؟ منظورم این است که مرورگر باید آن فهرست منابع را تهیه کند و آن را حفظ کند. چند نفر تست زدند در این رشته StackOverflow، جایی که جهانی های نام برده در واقع در آنجا بودند عملکرد بیشتر در یک آزمون و در یک آزمایش اخیر عملکرد کمتری دارد.
ملاحظات اضافی
بیایید بگوییم که انتقادات علیه استفاده از جهانی های نامگذاری شده را کنار می گذاریم و به هر حال از آنها استفاده می کنیم. همه چیز خوبه. اما مواردی وجود دارد که ممکن است بخواهید در حین انجام آن در نظر بگیرید.
پلی پر
همانطور که ممکن است به نظر برسد، این نوع چک های سراسری یک نیاز راه اندازی معمولی برای polyfills هستند. مثال زیر را بررسی کنید که در آن یک کوکی با استفاده از جدید تنظیم کردیم CookieStore
API، آن را در مرورگرهایی که هنوز از آن پشتیبانی نمی کنند، پر کنید:
// Polyfill the CookieStore API if not yet implemented.
// https://developer.mozilla.org/en-US/docs/Web/API/CookieStore
if (!window.cookieStore) {
window.cookieStore = myCookieStorePolyfill;
}
cookieStore.set("foo", "bar");
این کد در کروم کاملاً خوب کار می کند، اما خطای زیر را در سافاری ایجاد می کند.
TypeError: cookieStore.set is not a function
سافاری فاقد پشتیبانی از CookieStore
API از زمان نوشتن. در نتیجه پلی فیل اعمال نمی شود زیرا img
شناسه عنصر یک متغیر جهانی ایجاد می کند که با آن در تضاد است cookieStore
جهانی
به روز رسانی جاوا اسکریپت API
میتوانیم وضعیت را تغییر دهیم و مشکل دیگری را پیدا کنیم که در آن بهروزرسانیهای موتور جاوا اسکریپت مرورگر میتواند ارجاعات جهانی عنصر نامگذاری شده را بشکند.
مثلا:
window.BarcodeDetector.focus();
آن اسکریپت ارجاعی به عنصر ورودی می گیرد و فراخوانی می کند focus()
بر روی آن. درست کار می کند. با این حال، ما نمی دانیم چگونه طولانی به کار خود ادامه خواهد داد.
می بینید، متغیر جهانی که ما برای ارجاع به عنصر ورودی استفاده می کنیم، به محض اینکه مرورگرها شروع به پشتیبانی از BarcodeDetector
API. در آن نقطه، window.BarcodeDetector
global دیگر مرجعی به عنصر ورودی و .focus()
پرتاب خواهد کردwindow.BarcodeDetector.focus
خطای تابع نیست.
پاداش: همه عناصر نامگذاری شده ارجاعات جهانی ایجاد نمی کنند
می خواهید چیزی خنده دار بشنوید؟ برای اضافه کردن توهین به آسیب، عناصر نامگذاری شده به عنوان متغیرهای سراسری تنها در صورتی قابل دسترسی هستند که نامها چیزی جز حرف نداشته باشند. مرورگرها برای عنصری با شناسه ای که شامل نویسه ها و اعداد خاصی است، مرجع جهانی ایجاد نمی کنند hello-world
و item1
.
نتیجه
بیایید خلاصه کنیم که چگونه به اینجا رسیدیم:
- همه مرورگرهای اصلی به طور خودکار به هر عنصر DOM با یک ارجاع جهانی ایجاد می کنند
id
(یا در برخی موارد الفname
صفت). - دسترسی به این عناصر از طریق مراجع جهانی آنها غیر قابل اعتماد و بالقوه خطرناک است. استفاده کنید
querySelector
orgetElementById
به جای آن. - از آنجایی که مراجع جهانی به صورت خودکار تولید می شوند، ممکن است عوارض جانبی بر روی کد شما داشته باشند. این دلیل خوبی برای اجتناب از استفاده است
id
ویژگی مگر اینکه واقعاً به آن نیاز داشته باشید.
در پایان، احتمالاً ایده خوبی است که از استفاده از جهانی های نامگذاری شده در جاوا اسکریپت خودداری کنید. من این مشخصات را قبلاً در مورد اینکه چگونه به کد "شکننده" منجر می شود نقل کردم، اما در اینجا متن کامل برای هدایت موضوع به خانه آمده است:
به عنوان یک قاعده کلی، تکیه بر این به کد شکننده منجر می شود. اینکه کدام شناسهها در نهایت به این API نگاشت میشوند میتواند در طول زمان متفاوت باشد، مثلاً ویژگیهای جدیدی به پلتفرم وب اضافه میشود. به جای این، استفاده کنید
document.getElementById()
ordocument.querySelector()
.
من فکر میکنم این واقعیت که خود مشخصات HTML توصیه میکند از این ویژگی دور بمانید، خودش صحبت میکند.