بررسی کاربرد Map و Set در جاوااسکریپت (پیشرفته)

سلام در این قسمت از آموزش می خواهیم درباره دو ساختار داده پیچیده بنام های Map و Set به صورت پیشرفته تر صحبت کنیم. با ما باشید…تا الان با دو نوع ساختار داده پیچیده آشنا شدیم:آبجکت ها (Objects): برای ذخیره مجموعه های کلید-آیتمآرایه ها (Arrays): برای ذخیره مجموعه های مرتباما این دو نوع پاسخگوی تمام نیازهای یک برنامه نویس نمی باشند. به همین منظور Map و Set معرفی شدند.نوع داده ای Map:Map هم مثل آبجکت ها بصورت “کلید-آیتم” است. با این تفاوت که کلید (key) می تواند هر نوع داده ای داشته باشد.لیست متدها و property های MAP:متدها و property های Map به شرح زیر است:new Map: برای ایجاد یک مپmap.set(key, value) : برای ذخیره مقدار با کلیدmap.get(key) : برای دریافت مقدار توسط کلید. اگر کلید در map وجود نداشته باشد undefined برمی گردد.map.has(key) : اگر کلید موجود باشد true بر می گردد وگرنه false .map.delete(key) : مقدار را با کلید مذکور بر می گرداند.()map.clear : تمام المان ها را از map پاک می کند.map.size : تعداد المان های جاری را بر می گرداند.بعنوان مثال:let map = new Map(); map.set('1', 'str1'); // a string key map.set(1, 'num1'); // a numeric key map.set(true, 'bool1'); // a boolean key // remember the regular Object? it would convert keys to string // Map keeps the type, so these two are different: alert( map.get(1) ); // 'num1' alert( map.get('1') ); // 'str1' alert( map.size ); // 3همانطور که مشاهده می کنید، کلیدها به رشته تبدیل نشده اند و می توانند از هر نوعی باشند.نکته: استفاده از map با براکت یعنی map[key] روش مناسبی نمی باشد. زیرا در اینصورت جاوا اسکریپت با Map بعنوان یک آبجکت ساده رفتار خواهد کرد و کلید آن نمی تواند از هر نوعی باشد (فقط رشته می تواند باشد). روش صحیح کار با map استفاده از set و get است.نکته جالب اینجاست که Map می تواند از object بعنوان کلید خود استفاده کند.بعنوان مثال:let john = { name: &quotJohn&quot }; // for every user, let's store their visits count let visitsCountMap = new Map(); // john is the key for the map visitsCountMap.set(john, 123); alert( visitsCountMap.get(john) ); // 123این قابلیت Map (یعنی امکان تعریف یک آبجکت بعنوان کلید) بسیار اهمیت دارد و کاربردی است. مثال:let john = { name: &quotJohn&quot }; let visitsCountObj = {}; // try to use an object visitsCountObj[john] = 123; // try to use john object as the key // That's what got written! alert( visitsCountObj[&quot[object Object]&quot] ); // 123از آنجا که متغیر visitsCountObj یک آبجکت است، تمام کلیدهای تعریف شده برای آن (مانند John) بطور اتوماتیک به رشته تبدیل خواهند شد. بنابراین کلید آبجکت مذکور بصورت “[object Object]” تعریف می شود.تعریف زنجیره ای متد set در Map:map.set('1', 'str1') .set(1, 'num1') .set(true, 'bool1');در کد بالا، مشاهده می شود که می توانید متدهای set را بصورت زنجیروار تعریف کنید. زیرا هر یک از دستورات set یک map را برمیگرداند.پیمایش و اجرای حلقه در Map:برای اجرای حلقه روی آیتم های یک map می توان به یکی از سه روش زیر اقدام کرد:()map.keys: امکان لوپ زدن روی کلیدهای Map را فراهم می کند.()map.values: امکان لوپ زدن روی مقادیر Map را فراهم می کند.()map.entries: جفت کلید-آیتم را بر می گرداند. یعنی [key, item] . معمولا در حلقه for..of استفاده می شود.مثالی از 3 متد فوق:let recipeMap = new Map([ ['cucumber', 500], ['tomatoes', 350], ['onion', 50] ]); // iterate over keys (vegetables) for (let vegetable of recipeMap.keys()) { alert(vegetable); // cucumber, tomatoes, onion } // iterate over values (amounts) for (let amount of recipeMap.values()) { alert(amount); // 500, 350, 50 } // iterate over [key, value] entries for (let entry of recipeMap) { // the same as of recipeMap.entries() alert(entry); // cucumber,500 (and so on) }علاوه بر موارد ذکر شده، Map بطور پیش فرض یک متد forEach درون خود دارد (مانند آرایه ها):// runs the function for each (key, value) pair recipeMap.forEach( (value, key, map) => { alert(`${key}: ${value}`); // cucumber: 500 etc });تبدیل Object به Map توسط متد Object.entries:وقتی Map را ایجاد کردیم می توان یک آرایه (یا هر نوع داده iterable دیگر) به آن پاس داد.// array of [key, value] pairs let map = new Map([ ['1', 'str1'], [1, 'num1'], [true, 'bool1'] ]); alert( map.get('1') ); // str1اگر یک آبجکت ساده داشته باشیم و بخواهیم آنرا به Map تبدیل کنیم می توان از متد Object.entries(obj) استفاده کرد.مثالی از تبدیل object به Map:let obj = { name: &quotJohn&quot, age: 30 }; let map = new Map(Object.entries(obj)); alert( map.get('name') ); // Johnدر این مثال Object.entries یک آرایه ای از جفت key/value بر می گرداند که بصورت زیر خواهد بود:[ [&quotname&quot,&quotJohn&quot], [&quotage&quot, 30] ]تبدیل Map به Object توسط متد Object.fromEntries:اگر بخواهیم آرایه ای از [key, value] را به یک آبجکت ساده یا plain object تبدیل کنیم باید از متد Object.fromEntries استفاده کنیم:let prices = Object.fromEntries([ ['banana', 1], ['orange', 2], ['meat', 4] ]); // now prices = { banana: 1, orange: 2, meat: 4 } alert(prices.orange); // 2بعنوان مثال فرض کنید ما مقادیر موردنظر خود را در یک Map ذخیره کرده ایم و برای تعامل با یک اپلیکیشن 3rd-party نیاز است که این Map به آبجکت ساده تبدیل شود. داریم:let map = new Map(); map.set('banana', 1); map.set('orange', 2); map.set('meat', 4); let obj = Object.fromEntries(map.entries()); // make a plain object (*) // done! // obj = { banana: 1, orange: 2, meat: 4 } alert(obj.orange); // 2برای آرگومان ورودی Object.fromEntries عبارت map.entries تعریف شده که مناسب است. همچنین می توان آن را بصورت خلاصه تری تعریف کرد (حذف entries)let obj = Object.fromEntries(map); // omit .entries()مثالی دیگر از تعریف ساختار داده ای Map:در کد زیر، داده Map بطور اشتباه مقداردهی شده است:let wrongMap = new Map(); wrongMap['bla'] = 'blaa'; wrongMap['bla2'] = 'blaaa2'; console.log(wrongMap) // Map { bla: 'blaa', bla2: 'blaaa2' }و مسلما در هنگام اجرا، نتیجه مورد انتظار را نخواهیم گرفت:wrongMap.has('bla'); // false wrongMap.delete('bla'); // false console.log(wrongMap); // Map { bla: 'blaa', bla2: 'blaaa2' }و اما روش صحیح استفاده از Map (همانطور که قبلا گفتیم) بصورت زیر است:let myMap = new Map(); myMap.set('bla','blaa'); myMap.set('bla2','blaa2'); console.log(myMap); // Map { 'bla' => 'blaa', 'bla2' => 'blaa2' }و خروجی مورد نظر را خواهیم داشت:myMap.has('bla'); // true myMap.delete('bla'); // true console.log(myMap); // Map { 'bla2' => 'blaa2' }نوع داده ای Set:Set نوعی داده است که فقط شامل مقادیر است و کلید ندارد. هر مقدار نیز باید یکتا و منحصر بفرد باشد و نمی تواند تکراری باشد.لیست متدهای Set:متدهای اصلی Set عبارتند از:new Set(iterable): یک Set ایجاد می کند و اگر یک داده iterable مثل آرایه به آن پاس داده شده باشد آیتم های آن را برای Set در نظر می گیرد.set.add(value): یک مقدار جدید به set می افزاید و خود set را بر می گرداند.set.delete(value): آیتم value را از set حذف می کند. اگر value وجود داشته باشد true بر می گرداند وگرنه falseset.has(value): اگر value در set وجود داشته باشد true وگرنه false بر می گردد.()set.clear: تمام مقادیر داخل set را پاک می کند.set.size: تعداد آیتم های داخل set را بر می گرداند.نکته: اجرای مکرر set.add(value) هیچکاری انجام نمی دهد. به این دلیل که نمی توان یک مقدار ثابت را چندین بار در Set درج کرد (Set آیتم تکراری ندارد)بعنوان مثال فرض کنید می خواهیم اسامی بازدیدکنندگان یک وب سایت را در طول روز ذخیره کنیم و نمی خواهیم نام تکراری در لیست ما درج شود. داریم:let set = new Set(); let john = { name: &quotJohn&quot }; let pete = { name: &quotPete&quot }; let mary = { name: &quotMary&quot }; // visits, some users come multiple times set.add(john); set.add(pete); set.add(mary); set.add(john); set.add(mary); // set keeps only unique values alert( set.size ); // 3 for (let user of set) { alert(user.name); // John (then Pete and Mary) }آرایه می تواند جایگزین Set باشد به شرطی که در هر بار Add کردن یک آیتم جدید توسط متد find بررسی کنیم که آن آیتم از قبل در آرایه وجود نداشته باشد و آیتم تکراری ایجاد نکند. در صورت استفاده از آرایه بدین شکل، کارایی (performance) اسکریپت کاهش می یابد و سرعت اجرای برنامه نیز کند می شود.لوپ زدن روی Set:توسط دستورات for..of و forEach می توان روی مقادیر داخل Set حلقه اجرا کرد.بعنوان مثال:let set = new Set([&quotoranges&quot, &quotapples&quot, &quotbananas&quot]); for (let value of set) alert(value); // the same with forEach: set.forEach((value, valueAgain, set) => { alert(value); });متدهای Set:Set هم مانند Map متدهای زیر را برای کار با آیتم ها دارد:()set.keys: یک شیء iterable از مقادیر را بر می گرداند.()set.values: یک شیء iterable از مقادیر را بر می گرداند. (مانند متد keys)()set.entries: یک شیء iterable از مقادیر را بر می گرداند. بصورت [value, value]همچنین بخوانید:اسکوپ (scope) در جاوااسکریپت چیست؟هویستینگ (Hoisting) در جاوااسکریپت چیست؟بررسی (let - var - const) در جاوااسکریپتتفاوت دو مساوی (==) و سه مساوی (===) در جاوااسکریپتبررسی متدهای تعامل با کاربر در جاوااسکریپت : alert , prompt, confirmاستفاده از عبارت &amp;amp;#x27;use strict&amp;amp;#x27; در جاوااسکریپتکار با توابع یا Functions در جاوااسکریپتمقایسه توابع Declarations و Expressions در جاوااسکریپتبررسی Callback Function در جاوااسکریپتتفاوت عملگرهای Spread و Rest در جاوااسکریپتپارامتر پیشفرض(Default Parameter) در جاوااسکریپتبررسی arguments در توابع جاوااسکریپتبررسی پروتوتایپ (Prototype) در جاوااسکریپتبررسی Arrow Functions در جاوااسکریپتبررسی Functions Calling Other Functions در جاوااسکریپتبررسی آرایه (Array) در جاوااسکریپتبررسی اشیاء یا آبجکت (objects) در جاوااسکریپتبررسی حلقه‌ها (Loops) در جاوااسکریپتبررسی انتخابگرها (Selectors) در جاوااسکریپتبررسی innerHTML در جاوااسکریپتبررسی DOM در جاوااسکریپت، آموزش متد querySelectorبررسی نحوه عملکرد جاوا اسکریپت در پشت صحنهبررسی مفهوم Execution Context در جاوااسکریپت - پشت‌ پرده جاوااسکریپت (بخش اول)بررسی مفهوم Execution Context در جاوااسکریپت - پشت‌ پرده جاوااسکریپت (بخش دوم)تعریف API (Application Programming Interface) به زبان ساده!دِستراکچرینگ (Destructuring) در جاوااسکریپت یعنی چه؟بررسی عملگر (...) Spread در جاوااسکریپتبررسی پارامترهای Rest در جاوااسکریپتاتصال کوتاه (Short Circuiting) با عملگرهای منطقی AND (&amp;amp;amp;&amp;amp;amp;) و OR (||) در جاوااسکریپتاتصال کوتاه (Short Circuiting) با عملگر منطقی Nullish coalescing (??) در جاوااسکریپتحلقه for ... of در جاوااسکریپتبررسی Enhanced Object literals در جاوااسکریپبررسی Optional Chaining (_.) در جاوااسکریپتبررسی کاربرد Map و Set در جاوااسکریپت (مقدماتی)