Learn JavaScript

lesson ১ / ৯ · Map, Set, WeakMap, iterator, generator আর regular expression

Module ১৬ · Map, Set, WeakMap, iterator, generator আর regular expression

ছবিটা: আসল key-এর table, আলাদা value-এর থলে, থেমে থাকা function, আর লেখার pattern

Freeপড়া

এই lesson-এ যা শিখবে

  • বুঝিয়ে বলো, object-কে key বানিয়ে গুনতে গেলে সাধারণ object কেন পারে না, আর Map কীভাবে ওই key-গুলো আলাদা রাখে।
  • Set দিয়ে প্রতিটা value একবার করে রাখো, আর তার size আর ভেতরে কী আছে সেটা পড়ো।
  • একটা generator লেখো যেটা একটা একটা করে value দেয়, আর প্রথম regular expression দিয়ে লেখা খুঁজে বের করো।

ঢাকা বিশ্ববিদ্যালয়ের কাছে Rafi-র একটা ছোট চায়ের দোকান। কোন নিয়মিত খদ্দের কতবার ফিরে আসে, সেটা গোনার জন্য ওর একটা ছোট program আছে। প্রত্যেক খদ্দের একটা object, যেমন { name: "Mitu" }। তাই Rafi সবচেয়ে সোজা জিনিসটাই লিখল: একটা object, খদ্দের key, আর সংখ্যা value।

Program চলল। কিন্তু সপ্তাহ শেষে দেখা গেল সবার সংখ্যা একই বিশাল একটা number, যেন একজন মানুষই সব চা খেয়ে ফেলেছে। কিছু crash করেনি, কোনো লাইন ভুলও দেখায় না। গোলমালটা লুকিয়ে আছে object ওর key নিয়ে কী করে, সেখানে।

এই module তোমাকে চারটা হাতিয়ার দেবে, যেগুলো এই ধরনের সমস্যা সারায়। Map এমন একটা table, যার key যেকোনো কিছু হতে পারে, object-ও। Set একটা থলে, যেটা প্রতিটা value একবারই রাখে। Generator এমন একটা function, যেটা মাঝপথে থামে আর একটা একটা করে value দেয়। Regular expression একটা pattern, যেটা লেখার ভেতর থেকে জিনিস খুঁজে বের করে। এই lesson প্রতিটাকে কাজ করতে দেখায়, আর module-এর বাকিটা এগুলোকে খুলে খুলে দেখে।

সাধারণ object প্রতিটা key-কে string বানিয়ে ফেলে

Module 8-এ দেখেছ, object-এর key হয় string। obj[42] লিখলে key হয় "42"। Key যখন একটা object, তখনও এই নিয়ম খাটে। JavaScript আগে object-টাকে string বানায়, আর প্রতিটা সাধারণ object একই string হয়ে যায়।

const rafi = { name: "Rafi" };
const mitu = { name: "Mitu" };
const visits = {};
for (const person of [rafi, mitu, rafi]) {
  visits[person] = (visits[person] ?? 0) + 1;
}
console.log(Object.keys(visits));
console.log(visits[rafi]);
[ '[object Object]' ]
3
Run in Compiler

Key মাত্র একটা, "[object Object]"। Rafi আর Mitu দুজনেই ওখানে গিয়ে পড়েছে, তাই Rafi-র সংখ্যা 3, মানে সবার যোগফল। চায়ের দোকানের bug এটাই। Key যখন শব্দ, তখন object ভালো table। কিন্তু দুটো object-কে ও আলাদা করতে পারে না।

Map: এমন table যার key যেকোনো কিছু

Map ঠিক এই কাজের জন্যই বানানো table। set(key, value) দিয়ে একটা জোড়া রাখো, get(key) দিয়ে আবার পড়ো। Key হতে পারে যেকোনো value: string, number, true, একটা function, বা একটা object। Object key মেলানো হয় identity দিয়ে, মানে "এটা কি হুবহু সেই object-টাই?", ভেতরে কী আছে তা দিয়ে না।

const rafi = { name: "Rafi" };
const mitu = { name: "Mitu" };
const visits = new Map();
for (const person of [rafi, mitu, rafi]) {
  visits.set(person, (visits.get(person) ?? 0) + 1);
}
console.log(visits.size);
console.log(visits.get(rafi), visits.get(mitu));
for (const [person, count] of visits) console.log(person.name, count);
2
2 1
Rafi 2
Mitu 1
Run in Compiler

এখন entry দুটো, প্রতি মানুষে একটা। size সেগুলো গোনে, Object.keys লাগে না। আর Map-এর ওপর for...of loop দিলে পাওয়া যায় [key, value] জোড়া, যেটা loop নিজেই দুটো নামে ভেঙে নেয়।

Map key-গুলো রাখে যে ক্রমে প্রথমবার বসানো হয়েছে, সেই ক্রমে। আগে থেকে থাকা key আবার বসালে value বদলায়, জায়গা বদলায় না।

const shelf = new Map();
shelf.set("tea", 15).set(7, "seven").set(true, "yes").set("coffee", 40);
shelf.set("tea", 20);
console.log([...shelf.keys()]);
console.log(shelf.get("tea"));
[ 'tea', 7, true, 'coffee' ]
20
Run in Compiler

প্রতিটা set Map-টাকেই ফেরত দেয়, তাই ডাকগুলো একটার পর একটা জোড়া যায়। Key-গুলো ফেরত আসে একটা string, একটা number, একটা boolean আর একটা string হিসেবে, যে ক্রমে এসেছিল। নতুন দাম দিয়ে আবার বসানো হলেও tea প্রথমেই থাকে।

নিচের widget প্রতিটা লাইনের পরে Map-টা এঁকে দেখায়। Object key আঁকা হয় তার identity দিয়ে, তাই দেখতে এক রকম দুটো object তবু দুটো আলাদা বাক্স।

একই ধাপগুলো table-এ, প্রতি ধাপে একটা row।

ধাপLineকী হলো
1const visits = new Map();একটা ফাঁকা Map: এখনো কোনো entry নেই।
2visits.set(rafi, 1);rafi object-টা নিজেই key, আঁকা হলো obj1 হিসেবে।
3visits.set(mitu, 1);mitu আলাদা একটা object, তাই নিজের entry পায়, obj2। Size এখন 2।
4visits.set(rafi, visits.get(rafi) + 1);একই object একই entry খুঁজে পায়, তাই সংখ্যা হয় 2, আর জায়গা থাকে প্রথমেই।
5visits.set({ name: "rafi" }, 1);ভেতরের লেখা এক, কিন্তু object নতুন: তৃতীয় একটা entry, obj3। Size এখন 3।
6visits.set("rafi", 5);String key আবার আরেকটা আলাদা key। Size এখন 4।

Step 5 দেখো। নতুন object-টায় rafi-র নামটাই আছে, তবু সে নিজের entry পায়। Map কখনো object key-এর ভেতরে উঁকি দেয় না। শুধু জিজ্ঞেস করে, এটা কি একই object?

Set: প্রতিটা value একবারই

Set হলো value ছাড়া একটা Map: এমন একটা থলে, যেটা প্রতিটা value বড়জোর একবার রাখে। add দিয়ে value দাও, has দিয়ে জিজ্ঞেস করো, size পড়ো। ভেতরে আগে থেকেই আছে এমন value আবার add করলে কিছুই হয় না। তাই "এটা কি আগে দেখেছি?" প্রশ্নে আর একই জিনিস বারবার থাকলে সেগুলো ছাঁটতে Set-ই স্বাভাবিক হাতিয়ার।

const scans = ["rafi", "mitu", "rafi", "nila", "mitu"];
const unique = new Set(scans);
console.log(unique.size);
console.log(unique.has("nila"), unique.has("tania"));
console.log([...unique]);
3
true false
[ 'rafi', 'mitu', 'nila' ]
Run in Compiler

new Set(scans) প্রতিটা নাম পালা করে যোগ করে, তাই বারবার আসা নামগুলো ঝরে যায়। Set-ও প্রথম দেখার ক্রম রাখে, তাই spread করলে নামগুলো আসে যে ক্রমে প্রথম এসেছিল। Set-এ পাঁচটা নাম থাকুক বা পঞ্চাশ লাখ, has প্রায় একই সময়ে উত্তর দেয়। Lesson 04 এটা array-র includes-এর সাথে মেপে দেখায়।

Generator একটা একটা করে value দেয়

এ পর্যন্ত তোমার লেখা প্রতিটা function ওপর থেকে নিচে এক টানে চলেছে। Generator এমন একটা function, যেটা মাঝখানে থেমে পরে আবার চলতে পারে। লেখো function* দিয়ে, আর ভেতরে yield একটা value বের করে দিয়ে ঠিক ওখানেই থেমে যায়।

Generator function ডাকলে ওর body চলে না। হাতে আসে একটা generator object। ওর next() method যতবার ডাকো, body চলে পরের yield পর্যন্ত। তারপর next() ফেরত দেয় { value, done }।

function* threeDays() {
  console.log("  (start)");
  yield "Saturday";
  console.log("  (resumed)");
  yield "Sunday";
  yield "Monday";
}
const days = threeDays();
console.log("made the generator");
console.log(days.next());
console.log(days.next());
console.log(days.next());
console.log(days.next());
made the generator
  (start)
{ value: 'Saturday', done: false }
  (resumed)
{ value: 'Sunday', done: false }
{ value: 'Monday', done: false }
{ value: undefined, done: true }
Run in Compiler

ক্রমটা ভালো করে পড়ো। "made the generator" print হয় "(start)"-এর আগে, কারণ generator বানাতে কিছুই চলেনি। প্রথম next() চলে প্রথম yield পর্যন্ত। দ্বিতীয়টা ঠিক তার পর থেকে আবার চলে, print করে "(resumed)"। চতুর্থটা দেখে body শেষ, তাই বলে done: true।

for...of loop তোমার হয়ে next() ডাকে, আর done true হলে থামে। Body যেহেতু শুধু চাইলেই চলে, generator অনন্তও হতে পারে। loop শুধু চাওয়া বন্ধ করে দেয়।

function* countFrom(n) {
  while (true) yield n++;
}
for (const k of countFrom(5)) {
  if (k > 8) break;
  console.log(k);
}
5
6
7
8
Run in Compiler

while (true) দেখে মনে হয় program আটকে যাবে, কিন্তু এখানে নিরাপদ। ওই loopের প্রতিটা পাক yield-এ থামে, আর break আর কিছু চায় না। Widget-এ দেখো একটা generator দুদিকেই কথা বলছে: next(value) একটা value ভেতরেও পাঠাতে পারে।

একই ধাপগুলো table-এ, প্রতি ধাপে একটা row।

ধাপLineStateYieldedReceivedকী হলো
1const it = order();suspendedorder() ডাকলে body-র কিছুই চলে না। শুধু একটা থামানো generator তৈরি হয়।
2function* order() {runningপ্রথম next() body-টা একদম ওপর থেকে চালু করে।
3it.next();suspendedsize?একটা yield-এ থেমে যায়, আর বের করে দেয় "size?"।
4 const size = yield "size?";runninglargeএকই yield-এর ভেতর থেকে আবার চলে, আর yield এখন ফেরত দেয় "large"।
5it.next("large");suspendeddrink for a large meal?largeএকটা yield-এ থেমে যায়, আর বের করে দেয় "drink for a large meal?"।
6 const drink = yield "drink for a " + size + " meal?";runninglassiআবার চলে: drink এখন "lassi", আর size এখনো ধরে আছে "large"।
7it.next("lassi");donelassiBody ফেরত দেয় "large meal with lassi", তাই next() বলে done: true।
8it.next();doneশেষ হওয়া generator শুধু done: true বলে, কোনো value ছাড়া।

চমকটা step 4 আর 6-এ। next("large")-এ যে value পাঠানো হলো, সেটা বের হয় আগে থেমে থাকা yield থেকে। তাই yield একটা দুদিকের দরজা: একটা value বাইরে যায়, পরে একটা value ভেতরে আসে।

Regular expression হলো লেখার একটা pattern

শেষ হাতিয়ারটা লেখা নিয়ে কাজ করে। Regular expression, ছোট করে regex, একটা ছোট pattern যেটা তুমি যে লেখা খুঁজছ তার বর্ণনা দেয়। লেখো দুটো slash-এর মাঝে। /#\w+/-এ # মানে আসল একটা hash চিহ্ন, \w মানে একটা অক্ষর, অঙ্ক বা underscore, আর + মানে "ওটার এক বা একাধিক"।

const post = "Fuchka at #Dhanmondi, then tea at #TSC!";
console.log(/#\w+/.test(post));
console.log(post.match(/#\w+/g));
console.log("call 01712-345678".replace(/\d/g, "#"));
true
[ '#Dhanmondi', '#TSC' ]
call #####-######
Run in Compiler

test উত্তর দেয় হ্যাঁ বা না: pattern-টা কোথাও আছে কি? g flag, মানে "global", দিলে match প্রতিটা match একটা array-তে ফেরত দেয়। /\d/g দিয়ে replace প্রতিটা অঙ্ক বদলে দেয়, যেটা কোনো সাধারণ string method এক ডাকে পারে না। Lesson 02 পুরো pattern-ভাষাটা টুকরো টুকরো করে দেখাবে।

এক নজরে Map, Set, generator আর regex

const m = new Map();             // a table; keys of any type, by identity
m.set(key, value)  m.get(key)    // put and read; set returns m, so calls chain
m.has(key)  m.delete(key)  m.size
for (const [k, v] of m) { }      // pairs, in the order keys were first set
const s = new Set(list);         // each value once; s.add(v), s.has(v), s.size
function* gen() { yield v; }     // gen() makes a paused generator
g.next()                         // runs to the next yield: { value, done }
/#\w+/g                          // a regex: # then one or more word characters, every match
text.match(re)  re.test(text)  text.replace(re, "new")
Example 1: প্রথম দেখার ক্রমে শব্দ গোনা

Mitu জানতে চায় খদ্দেররা review-তে কোন শব্দ সবচেয়ে বেশি লেখে। Map সেগুলো গোনে, আর ওর ক্রম শব্দগুলো দেয় যেভাবে প্রথম এসেছিল।

const reviews = "good tea good price slow service good tea";
const counts = new Map();
for (const word of reviews.split(" ")) {
  counts.set(word, (counts.get(word) ?? 0) + 1);
}
for (const [word, count] of counts) console.log(word, count);
const top = [...counts].sort((a, b) => b[1] - a[1])[0];
console.log("most used:", top[0]);
good 3
tea 2
price 1
slow 1
service 1
most used: good

(counts.get(word) ?? 0) + 1 এই module-এর গোনার কৌশল। না থাকা key পড়লে আসে undefined, যেটাকে ?? বানায় 0। Map spread করলে জোড়ার একটা array হয়, আর Module 7-এর sort সেগুলো সংখ্যা ধরে সাজায়।

Run in Compiler
Example 2: অনন্ত Fibonacci, অলসভাবে নেওয়া

Generator এমন একটা ধারার বর্ণনা দিতে পারে যেটা কখনো শেষ হয় না, আর ছোট একটা helper যতগুলো দরকার ততগুলো value নেয়। না চাওয়া পর্যন্ত কিছুই হিসাব হয় না।

function* fibonacci() {
  let [a, b] = [0, 1];
  while (true) {
    yield a;
    [a, b] = [b, a + b];
  }
}
function* take(n, items) {
  for (const item of items) {
    if (n-- <= 0) return;
    yield item;
  }
}
console.log([...take(10, fibonacci())]);
[
  0, 1,  1,  2,  3,
  5, 8, 13, 21, 34
]

take নিজেও একটা generator, যেটা আরেকটাকে মুড়ে রাখে। Value-গুলো পার করে দেয়, আর n টার পরে থামে। take(10, ...) spread করলে take শেষ না হওয়া পর্যন্ত value চাওয়া হয়। তাই অনন্ত generator-টা মোটে দশ ধাপ চলে।

Run in Compiler

এটা কোথায় কাজে লাগে

  • Redux-Saga: React app-এর এই library প্রতিটা side effect লেখে একটা generator function হিসেবে, যেটা library-কে চালানোর নির্দেশ yield করে।
  • Node.js readline: একটা file-এর ওপর তৈরি interface for await দিয়ে লাইন ধরে ধরে পড়া যায়, কারণ এটা একটা async iterable, Lesson 02 যেটা দেখায়।
  • VS Code: search box-এ একটা regex বোতাম আছে, ওটা চালু রেখে \d{4} লিখলে পুরো project-এর প্রতিটা চার অঙ্কের সংখ্যা খুঁজে পায়।
  • lodash _.memoize: আগের ফলাফলগুলো প্রথম argument-কে key করে Map-এর মতো একটা cache-এ রাখে, তাই object argument-ও key হিসেবে চলে।

যে ভুলগুলো সবাই করে

১. Bracket দিয়ে Map পড়া

const prices = new Map([["tea", 15]]);
console.log(prices["tea"]);
prices["coffee"] = 40;
console.log(prices.size, prices.get("coffee"));
undefined
1 undefined

Square bracket পড়ে আর লেখে সাধারণ object-এর property, Map-এর entry না। তাই Map-এ tea থাকলেও prices["tea"] হলো undefined। আর prices["coffee"] = 40 Map object-টার গায়ে একটা property লাগিয়ে দেয়, যেটা size বা get কখনো দেখে না। সবসময় get আর set ব্যবহার করো।

২. Generator function ডেকে ভাবা যে সেটা চলবে

function* greet() {
  console.log("hello from the generator");
  yield 1;
}
greet();
console.log("done");
done

শুধু "done" print হয়। greet() ডাকলে একটা থামানো generator object তৈরি হয়ে ফেলে দেওয়া হয়, body-র একটা লাইনও না চালিয়ে। Body চলে শুধু তখন, যখন কেউ next() ডাকে, সরাসরি বা for...of loop বা spread-এর মাধ্যমে।

৩. g flag ভুলে যাওয়া

const order = "2 tea, 3 singara, 10 samosa";
console.log(order.match(/\d+/));
console.log(order.match(/\d+/g));
[
  '2',
  index: 0,
  input: '2 tea, 3 singara, 10 samosa',
  groups: undefined
]
[ '2', '3', '10' ]

g ছাড়া match প্রথম match-এ থেমে যায়, আর সেটা ফেরত দেয় বাড়তি খবর-সহ: কোথায় পাওয়া গেছে, আর পুরো input। শুধু g দিলেই প্রতিটা সংখ্যা পাও। ফলাফলে একটাই জিনিস আর একটা index দেখলে আগে flag-গুলো দেখো।

মাথা খাটাও

এই Set কত বড়?

Nadia সাতটা value দিয়ে একটা Set বানায়। ওর দাবি উত্তর 7-ই হবে, কারণ Set শুধু হুবহু একইভাবে লেখা value বাদ দেয়।

const s = new Set([1, "1", 1.0, NaN, NaN, 0, -0]);
console.log(s.size);

ও কি ঠিক? সাতটার মধ্যে কোনগুলো আসলে একই value, ভেবে দেখো।

Exercise 1সহজ

বইমেলার একটা stall-এ visitor খাতা রাখে Nadia। যে-ই ঢোকে, খাতায় নিজের নাম লেখে। Nadia চায় প্রথমবার আসা মানুষকে এক রকম আর আগে আসা মানুষকে আরেক রকম করে স্বাগত জানাতে। দিন শেষে ও জানতে চায় মোট কতজন আলাদা মানুষ এসেছিল।

Input. প্রথম token-টা n। তারপর n টা নাম, visitor-রা যে ক্রমে এসেছে সেই ক্রমে।

Output. প্রতিটা নামের জন্য এক লাইন: আজ এই নাম আগে না এলে new NAME, নয়তো again NAME। তারপর এক লাইনে distinct D, মোট কটা আলাদা নাম।

Constraints. 1 <= n <= 60000. Every name is 1 to 11 lowercase English letters..

Sample.

6
rafi
mitu
rafi
constructor
mitu
rafi
new rafi
new mitu
again rafi
new constructor
again mitu
again rafi
distinct 3
const input = require("fs").readFileSync(0, "utf8");
const tokens = input.split(/\s+/).filter(Boolean);
let at = 0;
const next = () => tokens[at++];
const nextInt = () => Number(next());
const out = [];

// your code: read with next() and nextInt(), push every line of output to out

console.log(out.join("\n"));
Run in Compiler

first-visits নামে grade হয়।

Exercise 2সহজ

মিরপুরের এক clinic-এ কয়েকটা counter: একটা ডাক্তারের, একটা test-এর, একটা ওষুধের। প্রতিটা counter নিজের serial token দেয়, নিজের প্রথম নম্বর থেকে শুরু করে। Token print করার machine-টা লেখে Shuvo। প্রত্যেক রোগী একটা counter-এর নাম বলে, আর ওই counter-এর পরের token পায়।

Input. প্রথম token-টা m। তারপর m জোড়া, প্রতিটায় একটা counter-এর নাম আর সে প্রথম যে নম্বর দেয়। তারপর n, তারপর n টা counter-এর নাম, প্রতি রোগীর জন্য একটা।

Output. প্রতিটা রোগীর জন্য এক লাইন NAME-K: counter-এর নাম, একটা hyphen, আর token-এর নম্বর। একটা counter-এর token প্রতিবার এক করে বাড়ে।

Constraints. 1 <= m <= 100. 1 <= n <= 60000. Every first number is 1 to 1000. Every name is 1 to 8 lowercase letters, the m names are different, and every patient names one of them..

Sample.

2
doc 1
lab 50
5
doc
lab
doc
doc
lab
doc-1
lab-50
doc-2
doc-3
lab-51
const input = require("fs").readFileSync(0, "utf8");
const tokens = input.split(/\s+/).filter(Boolean);
let at = 0;
const next = () => tokens[at++];
const nextInt = () => Number(next());
const out = [];

// your code: read with next() and nextInt(), push every line of output to out

console.log(out.join("\n"));
Run in Compiler

token-counters নামে grade হয়।

Exercise 3সহজ

একটা ছোট cafe-র page চালায় Mitu, ও জানতে চায় লোকে post-এ কোন কোন hashtag ব্যবহার করে। Hashtag মানে একটা #, তার পরে এক বা একাধিক অক্ষর, অঙ্ক বা underscore। বড় হাত ছোট হাতের তফাত নেই, তাই #Fuchka আর #fuchka একই tag। ও প্রতিটা tag একবার করে চায়, সাথে কতবার ব্যবহার হয়েছে।

Input. প্রথম লাইনে n। পরের n টা লাইনের প্রতিটা একটা post, space-সহ এক লাইন লেখা। একটা post-এ কোনো hashtag না-ও থাকতে পারে, আবার কয়েকটাও থাকতে পারে, এমনকি পাশাপাশি দুটো, যেমন #a#b।

Output. প্রতিটা আলাদা tag-এর জন্য এক লাইন: ছোট হাতের অক্ষরে #-সহ tag, একটা space, তারপর তার সংখ্যা। Tag-গুলো লেখো যে ক্রমে প্রথম দেখা দিয়েছে সেই ক্রমে। কোনো post-এ কোনো tag না থাকলে এক লাইনে লেখো none।

Constraints. 1 <= n <= 5000. Every post is 1 to 150 characters: printable ASCII and spaces. The last line of the input is never empty..

Sample.

3
Best #fuchka in #Dhaka! #fuchka
no tags here, just 100% love
#dhaka#rain and #FUCHKA_time
#fuchka 2
#dhaka 2
#rain 1
#fuchka_time 1
const input = require("fs").readFileSync(0, "utf8");
const lines = input.split("\n");
let at = 0;
const next = () => lines[at++];
const nextInt = () => Number(next());
const out = [];

// your code: read with next() and nextInt(), push every line of output to out

console.log(out.join("\n"));
Run in Compiler

hashtag-count নামে grade হয়।

Exercise 4কঠিন

Arif-এর radio station একটা গান খুব তাড়াতাড়ি আবার বাজাতে পারে না। আজকের playlist দেখে বের করো, টানা বাজানো গানের সবচেয়ে লম্বা অংশটা কত, যার ভেতরে কোনো গান দুবার নেই।

Input. n, তারপর n টা গানের নাম, যে ক্রমে বাজানো হয়েছে।

Output. একটা সংখ্যা, কোনো গান না ফেরা সবচেয়ে লম্বা অংশের দৈর্ঘ্য।

Constraints. 1 <= n <= 100000। প্রতিটা নাম 1 থেকে 10টা ছোট হাতের অক্ষর।

Sample. নিচের input।

7
dhaka nodi rain dhaka hawa nodi sky
const input = require("fs").readFileSync(0, "utf8");
const tokens = input.split(/\s+/).filter(Boolean);
let at = 0;
const next = () => tokens[at++];
const nextInt = () => Number(next());
const out = [];

// your code: read with next() and nextInt(), push every line of output to out

console.log(out.join("\n"));

Sample-এর output.

5
Run in Compiler

সচরাচর যে প্রশ্নগুলো আসে

  • তাহলে কি object-কে table হিসেবে ব্যবহার করা বাদ দেব?

    না। Key যখন নির্দিষ্ট কয়েকটা শব্দ, যেমন একজন user-এর field-গুলো, তখন object-ই ঠিক হাতিয়ার, আর JSON-ও ওকে পছন্দ করে। Map ধরো যখন key-গুলো object, যখন সেগুলো বাইরে থেকে আসে, বা যখন অনেক key যোগ আর মোছা হয়। পুরো নিয়মটা Lesson 04 দেবে।

  • Set কি শুধু বারবার-আসা-ছাড়া একটা array?

    for...of loopে ও array-র মতোই আচরণ করে, কিন্তু ভেতরে অন্যভাবে বানানো। Set নিজের value-গুলোর ওপর দিয়ে না হেঁটেই has-এর উত্তর দেয়, তাই বড় হলেও ভেতরে আছে কি না দেখা দ্রুত থাকে। তবে ওর কোনো index নেই: s[0] বলে কিছু নেই। জায়গা ধরে কাজ করতে হলে array-তে spread করে নাও।

  • থেমে থাকা function আমার কেন লাগবে?

    কারণ কিছু ধারা এত লম্বা, বা অনন্ত, যে পুরোটা বানানো যায় না। Generator চাইলে তবেই পরের value বানায়। আর ডাকের মাঝে নিজের জায়গা মনে রাখে, যেটা page-এ ভাগ করা feed বা একটা counter-এর ঠিক দরকার।

  • Regular expression কি শুধু বিশেষজ্ঞদের জন্য?

    পুরো ভাষাটা বড়, কিন্তু তুমি প্রতি সপ্তাহে এর ছোট একটা অংশই ব্যবহার করবে। সংখ্যা খোঁজা, একটা format ঠিক আছে কি না দেখা, বা কয়েক রকম চিহ্নে ভাগ করা, প্রতিটায় লাগে একটা ছোট pattern। Lesson 02 এটা এক টুকরো করে গড়ে তুলবে।

মূল কথা

  • সাধারণ object প্রতিটা key-কে string বানায়, তাই দুটো object key "[object Object]" হয়ে ধাক্কা খায়।
  • Map যেকোনো ধরনের key রাখে, object মেলায় identity দিয়ে, size দিয়ে গোনে, আর বসানোর ক্রম মনে রাখে।
  • Set প্রতিটা value একবার রাখে; "আগে দেখেছি?" আর বারবার আসা ছাঁটার হাতিয়ার has আর add।
  • function* দিয়ে লেখা generator চলে শুধু next() চাইলে, প্রতিটা yield-এ থামে, আর অনন্তও হতে পারে।
  • /#\w+/g-এর মতো regex লেখার বর্ণনা দেয়; test, match আর replace সেটা ব্যবহার করে।
  • আরও গভীরে যেতে চাইলে: ভেতরের কলকবজা, V8-এর Map, WeakMap কখন ছাড়ে, থেমে থাকা generator আর regex-এর backtracking (Pro)।

এরপর: Map, Set, WeakMap, iterator, generator আর regular expression-এর প্রতিটা method, একটা একটা করে।

lesson ১ শেষ

শেষ হলে চিহ্ন দিন, অগ্রগতি আপনার সাথে থাকবে।

পরেরটা: প্রতিটা method: Map, Set, WeakMap, iterator, generator আর regex-এর ভাষা, একটা একটা করে