Bug • باگ
Bug • باگ
خواندن ۵ دقیقه·۵ سال پیش

آشنایی با new Function و With


مدتی بود که اسم لایبرری Alpine رو میشنیدم ولی بهش توجهی نمیکردم تا این که بالاخره دیروز رفتم سراغش و دیدم لایبرری جالب و باحالیه. که اینجا alpine.js میتونید ببینیدش.

و در عین سادگی که مارو یاد TailwindCSS میندازه ولی دیدم تو پروژه های اصلیم نمیتونم ازش استفاده کنم مگر یه سری پروژه های کوچیک واسه همین تصمیم گرفتم حداقل چیزی ازش یاد بگیرم و واسه همین رفتم سراغ کداش تا ببینم چه خبره و چیکار میکنه.

اولین چیزی که منو کنجکاو کرد که ببینم چه جوری کار میکنه این بخشه :

<div x-data=&quot{ open: false }&quot> <button @click=&quotopen = true&quot>Open Dropdown</button> <ul x-show=&quotopen&quot @click.away=&quotopen = false&quot > Dropdown Body </ul> </div>

پیش خودم فکر کردم x-data رو چه جوری میگیره و ذخیره اش میکنه اولین چیزی که یادم افتاد فانکشن eval بود . خب eval کارش اینه که شما بهش یه استرینگ میدین و اون کد رو براتون اجرا میکنه. مثلا یه همچین کدی بعد از اجراش متغیر data رو داریم که مقدارش 4ه

var data = eval(`2 + 2`)

گفتم که حتما ازین استفاده میکنه ولی این فانکشنه خطرناکیه و ترجیحا نباید استفاده برم ببینم واقعا همینه یا نه که دیدم نه و توی فایل util.js داره از فانکشنی به اسم saferEval استفاده میکنه که اینجوریه :

export function saferEval(expression, dataContext, additionalHelperVariables = {}) { return (new Function(['$data', ...Object.keys(additionalHelperVariables)], `var result; with($data) { result = ${expression} }; return result`))( dataContext, ...Object.values(additionalHelperVariables) ) }

خب من تا الان new Function ندیده بودم و یه سرچی زدم ببینم چیه که فهمیدم new Function میتونه یه فانکشنی رو با کد داینامیک بسازه و اینشکلیه :

new Function ([arg1, arg2, ...argN], functionBody)

پس این میتونه به تعداد دلخواهی پارامتر بگیره و آخرین پارامترش بادی (بدنه) فانکشن هست.

خب جالب شد. یه چند تا نمونه ببینیم:

1)

new Function (`alert(&quotWow&quot)`)

خروجی این کد یه فانکشنه که وقتی ران شه alert میده و هیچ پارامتری نمیگیره

2)

new Function ('a', 'b', 'return a + b;') اینو میشه اینجوری هم نوشت: new Function (['a', 'b'], 'return a + b;')

این یکی بر خلاف قبلی پارامتر میگیره و موقع کال شدنش 2 تا پارامتر میگیره که اولی a و دومی b هستن و مجموع این 2 رو برمیگردونه در واقع با فانکشن زیر برابره

function sum (a,b) { return a + b; }

خب با new Function آشنا شدیم و فهمیدیمش و کارمون تو این قسمت تمومه فقط قبل از این که بریم دوباره سراغ saferEval و یه چیز جدید دیگه یاد بگیریم حواسمون باشه که new Function و از همون مشکل eval که امنیت و performance هست رنج میبره ولی به مقدار کمتری. پس ترجیحمون اینه که حد الامکان سراغش نریم و فقط جاهایی میریم سراغش که راه ای دیگری نداریم.

خب برگردیم سراغ saferEval و اگه یه مقدار سادش کنیم و تیکه هاییش که نکته ای ندارن رو حذف کنیم به یه همچین چیزی میرسیم:

new Function(['$data'], `var result; with($data) { result = ${expression} }; return result`)

خب این فانکشن یه پارامتر به اسم data$ میگیره و بادی اش هم اینه:

var result; with($data) { result = ${expression}; } return result;

خب دستور with یه دستور Deprecate شدست. و حتی تو حالت strict mode هم استفاده ازش ممنوعه در واقع و دلیلی که هنو کار میکنه هم برای ساپورت سایتای قدیمیه که ممکنه ازش استفاده کنن. ولی به هر حال ازش استفاده میشه تو این لایبرری که دلیلشو هم در ادامه میگم.

جاوااسکریپت اینجوری کار میکنه که وقتی به variable یی برسه به دنبال مقدارش تو scope chain میگرده تو execution context یی که داره ولی این دستور جاوااسکریپت رو مجبور میکنه که اول توی ابجکتی که بهش میدیم دتبالش بگرده بعد به شکل همیشگیش کارشو بکنه بزارین یه نمونه بگم :

var firstName = &quotAli&quot console.log(firstName); var data = {firstName : &quotHossein&quot}; with(data) { console.log(fistName); }

کنسول لاگ اولی علی رو چاپ میکنه و دومی حسین رو. دلیل دومی هم این که وقتی داخل with هستیم اول دنبال firstName تو data میگردیم اگه بود که اینجا هست اون مقدارو چاپ میکنیم اگه نه میریم تو اسکوپ بالا تر و علی رو چاپ میکردیم.

این دستور با این که به نظر جالب میاد ولی باعث مشکلات و باگ هایی میشه در نتیجه Deprecate شده.

در اخر در مورد دلیلی که ازین استفاده شده حدسی که میزنم اینه که در قسمت های دیگر که نیاز به مقداری که از x-data گرفتیم داریم میتونه کارمونو خیلی راحت کنه مثلا در مثالمون اینو داشتیم :

<ul x-show=&quotopen&quot @click.away=&quotopen = false&quot > Dropdown Body </ul>

برای x-show که بررسی میکنه که ایا المنت رو نمایش بده یا خیر میخواد با کمک with و قرار دادن مقداری که در x-data داشتیم در data$ میتونیم براحتی شرط رو بررسی کنیم یه همچین چیزی :

$data = { open : true }; expression = `open` var result; with($data) { result = ${expression}; // result = open = true } return result;


امیدوارم چیز جدیدی یاد گرفته باشین از این مطلب و در این روز های کرونایی سلامت باشین.

جاوااسکریپتبرنامه نویسی
یه توسعه دهنده که عاشق تولید محتوا و آموزشه
شاید از این پست‌ها خوشتان بیاید