Module ১ · প্রথম program: console, let আর const, type, typeof
সাতটা primitive আর একটা object
এই lesson-এ যা শিখবে
- JavaScript-এর সাতটা primitive type আর object type-এর নাম বলতে পারবে, প্রতিটার একটা করে value সহ।
- বুঝিয়ে বলতে পারবে 5 আর 5.0 কেন একই সংখ্যা, আর
0.1 + 0.2কেন 0.30000000000000004 ছাপে। undefinedআরnull-এর পার্থক্য ধরতে পারবে, আর বলতে পারবে পূর্ণসংখ্যা কোথায় গিয়ে আর হুবহু থাকে না।
Maria আগে একটু C শিখেছে। সে জানতে চায়, 5-এর type কী, আর 5.0-এর type কী। C-তে উত্তর দুইটা, int আর double, আর দুইটার আচরণও আলাদা। JavaScript-এ উত্তর একই শব্দ, দুইবার: number। এই lesson দেখাবে JavaScript-এ value কয় রকমের হয়, আর যেটা তুমি সবচেয়ে বেশি ব্যবহার করবে, তার কিনারাগুলো কোথায়।
প্রতিটা value-র একটা type আছে
একটা value-র type মানে সে কোন জাতের জিনিস: একটা সংখ্যা, একটুকরো লেখা, নাকি হ্যাঁ বা না। Operator একটা value নিয়ে কী করবে, সেটা ঠিক করে দেয় type। 2 * 3 গুণ করে, কিন্তু "two" * 3 নিয়ে ঠিকঠাক কিছু করার উপায়ই নেই।
JavaScript-এ type আটটা। এর সাতটা primitive: সাদামাটা value, যেগুলো ভেঙে টুকরো করা যায় না। অষ্টমটা, object, বাকি সবকিছু ধরে রাখে।
| Type | এর একটা value | কী কাজে লাগে | কত ঘনঘন দেখা হবে |
|---|---|---|---|
number | 42, 4.5, -3 | সব সংখ্যা, পূর্ণ হোক বা না হোক | প্রতিদিন |
string | "Zara" | যেকোনো দৈর্ঘ্যের লেখা | প্রতিদিন |
boolean | true, false | হ্যাঁ বা না | প্রতিদিন |
undefined | undefined | এখনো কোনো value নেই | প্রায়ই, সাধারণত হঠাৎ করে |
null | null | কোনো value নেই, ইচ্ছা করেই | প্রায়ই |
bigint | 10n | এমন পূর্ণসংখ্যা, যেটা number-এর জন্য বেশি বড় | কালেভদ্রে |
symbol | Symbol("id") | এমন একটা লেবেল, যার জোড়া নেই; library-র ভেতরে ব্যবহার হয় | কালেভদ্রে |
object | { name: "Zara" } | বাকি সবকিছু: তালিকা, record, function | Module 7 থেকে |
কোনো value-র type জানতে চাইলে typeof দিয়ে জিজ্ঞেস করো। উত্তর আসে type-এর নাম, একটা string হিসেবে। Lesson 04 পুরোটাই এটা নিয়ে; এখানে শুধু এক লাইন।
console.log(typeof 42);
console.log(typeof "Zara");
console.log(typeof true);
console.log(typeof 10n);
number
string
boolean
bigint
Type থাকে value-র সঙ্গে, নামের সঙ্গে না। যে let এখন একটা সংখ্যা ধরে আছে, পরের assignment-এর পরে সে একটা string ধরতে পারে, নিচের বাক্সগুলো সেটাই দেখায়। তাই প্রতিটা value আটটা type-এর একটা সঙ্গে নিয়ে ঘোরে, আর তার তিনটা, number, string আর boolean, বেশিরভাগ কাজ করে দেয়।
number: 5 আর 5.0-এর জন্য একটাই type
JavaScript-এ পূর্ণসংখ্যা আর দশমিক, দুইটার জন্য number type একটাই। 5 আর 5.0 একই value, আর console.log দুইটাকেই ছাপে 5।
console.log(typeof 5);
console.log(typeof 5.0);
console.log(5.0);
console.log(5.50);
console.log(7 / 2);
number
number
5
5.5
3.5
Engine-এর ভেতরে প্রতিটা number রাখা হয় 64 bit-এ, IEEE 754 double precision নামের একটা format-এ। ওই একটা সিদ্ধান্তই তিনটা জিনিসের কারণ, যেগুলোর সঙ্গে তোমার দেখা হবে। ভাগ করলে ভগ্নাংশ থেকে যায়, দশমিক সব সময় হুবহু থাকে না, আর খুব বড় পূর্ণসংখ্যার শেষের অঙ্কগুলো হারিয়ে যায়।
C জানা থাকলে
JavaScript-এর number হলো C-র double, সব সংখ্যার জন্য, পূর্ণসংখ্যাও বাদ নেই। int, long বা float বলে কিছু নেই। তাই C-তে double নিয়ে যা শিখেছ, এখানেও সব খাটে, তার rounding-সহ।
তাই 5 আর 5.0 একই সংখ্যা, আর পরের তিনটা অংশ হলো সব সংখ্যাকে double হিসেবে রাখার ফল।
0.1 + 0.2 কেন 0.3 না
Double একটা সংখ্যা রাখে binary-তে, অর্ধেক, সিকি, আট ভাগের এক ভাগ, এরকম টুকরোর যোগফল হিসেবে। বেশিরভাগ দশমিক ভগ্নাংশ, যেমন 0.1, binary-তে হুবহু লেখা যায় না, ঠিক যেমন 1/3 দশমিকে হুবহু লেখা যায় না। তাই engine সবচেয়ে কাছের double-টা রাখে। বেশিরভাগ সময় এই ছোট্ট পার্থক্যটা লুকিয়ে থাকে, আর মাঝে মাঝে বেরিয়ে পড়ে।
console.log(0.1 + 0.2);
console.log(0.1 + 0.2 === 0.3);
console.log(0.5 + 0.25 === 0.75);
console.log(Math.abs(0.1 + 0.2 - 0.3) < 1e-9);
0.30000000000000004
false
true
true
=== জিজ্ঞেস করে দুইটা value হুবহু এক কি না, আর উত্তর দেয় true বা false; পুরোটা দেখাবে Module 2। 0.5 আর 0.25 হলো অর্ধেক আর সিকি, binary-তে হুবহু, তাই ওদের যোগফলও হুবহু। 0.1 আর 0.2 তা না, আর ওদের যোগফল 0.3 থেকে প্রায় 0.00000000000000006 দূরে থেকে যায়।
শেষ লাইনটাই দশমিক মেলানোর উপায়। Math.abs শূন্য থেকে দূরত্ব দেয়, তাই এটা মাপে দুইটা value একটা আরেকটা থেকে কত দূরে। 1e-9 মানে 0.000000001, দশের power লেখার ছোট কায়দায়। দূরত্বটা এর চেয়ে কম হলে value দুইটাকে সমান ধরো। তাই দুইটা দশমিক কখনো === দিয়ে মিলিয়ো না; দেখো ওরা কাছাকাছি কি না।
NaN আর Infinity
Number type-এর দুইটা value আছে, যেগুলো সাধারণ সংখ্যা না। দুইটারই type number।
console.log(0 / 0);
console.log("abc" * 2);
console.log(1 / 0);
console.log(-1 / 0);
console.log(typeof NaN);
console.log(NaN + 1);
NaN
NaN
Infinity
-Infinity
number
NaN
NaN মানে "not a number", অর্থাৎ সংখ্যা না। যে হিসাবের কোনো ঠিকঠাক উত্তর হয় না, যেমন লেখাকে দুই দিয়ে গুণ, সেখান থেকে এটা আসে। হ্যাঁ, ঠিকই পড়েছ: "not a number"-এর type হলো number; এটা এমন একটা number value, যেটা জানিয়ে দেয় হিসাবটা গোলমাল হয়ে গেছে। NaN দিয়ে যা-ই করো, ফল NaN, তাই একটা খারাপ value পরের প্রতিটা হিসাবে ছড়িয়ে পড়ে।
Infinity আসে একটা positive সংখ্যাকে শূন্য দিয়ে ভাগ করলে, আর negative সংখ্যাকে ভাগ করলে আসে -Infinity। শূন্য দিয়ে ভাগের জন্য JavaScript কখনো program থামায় না, অথচ পূর্ণসংখ্যার ভাগ হলে C থামিয়ে দেয়। তাই NaN আর Infinity দিয়েই number type জানায় যে একটা হিসাব ভুল পথে গেছে, আর program চলতেই থাকে।
পূর্ণসংখ্যা কোথায় গিয়ে আর হুবহু থাকে না
একটা double-এ জায়গা আছে মোটামুটি 15 থেকে 17টা significant অঙ্কের। 253 - 1, মানে 9007199254740991 পর্যন্ত প্রতিটা পূর্ণসংখ্যা হুবহু রাখা যায়। JavaScript ওই কিনারার নাম দিয়েছে Number.MAX_SAFE_INTEGER।
console.log(Number.MAX_SAFE_INTEGER);
console.log(Number.MAX_SAFE_INTEGER + 1);
console.log(Number.isSafeInteger(9007199254740991));
console.log(Number.isSafeInteger(9007199254740992));
console.log(1234567890123456789);
9007199254740991
9007199254740992
true
false
1234567890123456800
শেষ লাইনটা আবার পড়ো। Program-এ লেখা ছিল 1234567890123456789, অথচ ছাপা হলো এমন একটা সংখ্যা, যার শেষে 800। নিরাপদ কিনারা পেরোলে engine শুধু সবচেয়ে কাছের সেই double-টা রাখে, যেটা সে ধরতে পারে, তাই শেষের অঙ্কগুলো কোনো message ছাড়াই বদলে যায়। নিচের সংখ্যারেখা দেখায়, পূর্ণসংখ্যা কোথা পর্যন্ত নিরাপদ, আর কিনারার পরে কেন ফাঁক তৈরি হয়।
কিনারা পেরিয়েও হুবহু পূর্ণসংখ্যা লাগলে JavaScript-এর আছে bigint। অঙ্কগুলোর পরে একটা n লেখো। Bigint আলাদা একটা type, আর যেকোনো মাপে হুবহু থাকে।
console.log(2 ** 64);
console.log(2n ** 64n);
console.log(9007199254740993n + 1n);
18446744073709552000
18446744073709551616n
9007199254740994n
প্রথম লাইনটা double, round করা। দ্বিতীয়টা হুবহু, আর console.log সঙ্গে n-টাও দেখায়, যাতে দুইটাকে আলাদা করে চেনা যায়। তাই Number.MAX_SAFE_INTEGER পর্যন্ত পূর্ণসংখ্যা হুবহু, আর তার পরে হয় rounding মেনে নাও, নয়তো bigint-এ চলে যাও।
string আর boolean
string হলো যেকোনো দৈর্ঘ্যের লেখা, খালি string "" থেকে শুরু করে আস্ত একটা বই পর্যন্ত। প্রতিটা string জানে তাতে কয়টা character আছে, .length দিয়ে। Module 3 পুরোটাই string নিয়ে।
console.log("Zara".length);
console.log("".length);
console.log(typeof "42");
console.log(5 > 3);
console.log(2 > 7);
console.log(typeof (5 > 3));
4
0
string
true
false
boolean
"42"-এ অঙ্ক দেখা গেলেও এটা string, quote-এর কারণে। boolean হলো দুইটা value-র একটা, true বা false। এগুলো তুমি খুব কমই নিজে টাইপ করবে; 5 > 3-এর মতো তুলনা এগুলো বানায়, আর Module 4 এগুলো দিয়ে সিদ্ধান্ত নেবে। তাই string হলো quote-এর ভেতরের লেখা, আর boolean হলো হ্যাঁ-না প্রশ্নের উত্তর।
undefined আর null: দুই রকমের ফাঁকা
JavaScript-এ দুইটা value আছে, যেগুলোর মানে "এখানে কিছু নেই", আর দুইটার মানে এক না।
undefined | null | |
|---|---|---|
| মানে | এখনো কোনো value নেই | কোনো value নেই, ইচ্ছা করেই |
| কে বসায় | engine, নিজে থেকেই | তুমি, যে code লিখছ |
| উদাহরণ | let nickname; | const middleName = null; |
| যেভাবে পড়বে | "কেউ এটায় value দেয়নি" | "কেউ দেখেছে, আর কিছু নেই" |
let nickname;
const middleName = null;
console.log(nickname);
console.log(middleName);
undefined
null
Amara-র কোনো মাঝের নাম নেই, তাই ওর form-এ রাখা হয় null: প্রশ্নটা করা হয়েছিল, আর উত্তর "নেই"। যে নাম declare করা হয়েছে কিন্তু কখনো value পায়নি, তাতে থাকে undefined। তাই "নেই" যখন আসল উত্তর, তখন null নিজে লেখো, আর হঠাৎ চোখে পড়া undefined-কে ধরো একটা সংকেত হিসেবে: কিছু একটা কখনো value পায়নি। ওটা কোথা থেকে আসে, খুঁজে বের করবে lesson 04।
bigint, symbol আর object, অল্প কথায়
bigint এসেছে ES2020-এ, নিরাপদ কিনারার পরের হুবহু পূর্ণসংখ্যার জন্য: database-এর id, cryptography, contest-এর যোগফল। এই track-এর Module 2-এর problem-এ তুমি এটা একবার ব্যবহার করবে, তারপর কালেভদ্রে।
symbol এসেছে ES2015-এ। Symbol হলো এমন একটা লেবেল, যেটা সব সময় আলাদা, এমনকি একই description-এর আরেকটা symbol থেকেও। Library-গুলো আর ভাষাটা নিজেও এগুলো ব্যবহার করে। একটাও না বানিয়ে বছরের পর বছর code লেখা যায়, আর এই track-এ ওটার দেখা পাবে Module 16-এ, iterator-এর পাশে।
object হলো primitive না, এমন সবকিছুর type: [1, 2, 3]-এর মতো একটা তালিকা, { name: "Zara", age: 14 }-এর মতো একটা record, এমনকি একটা function-ও। Module 7 আর 8 এটা খুলে দেখাবে। তাই আটটা type-এর মধ্যে যে পাঁচটা তুমি এই সপ্তাহ থেকেই ব্যবহার করবে, সেগুলো এখন তোমার চেনা।
সবচেয়ে ছোট চক্কর: পাঁচটা value, পাঁচটা typeof উত্তর।
console.log(typeof 2026);
console.log(typeof 19.99);
console.log(typeof "2026");
console.log(typeof false);
console.log(typeof undefined);
number
number
string
boolean
undefined
2026 আর 19.99-এর type একই। "2026"-এর তা না, ওর quote-এর কারণে।
Run in CompilerZara প্রথমে দাম হিসাব করে তিনটা পেন্সিলের, প্রতিটা 2.99 টাকা, তারপর একটা পেন্সিল আর 1.99 টাকার একটা ইরেজারের। প্রতিটা হিসাব সে দুইভাবে করে: টাকায়, দশমিক দিয়ে, আর পুরো পয়সায়, মানে টাকার একশো ভাগের এক ভাগে।
console.log(2.99 * 3);
console.log(299 * 3);
console.log(299 * 3 / 100);
console.log(1.99 + 2.99);
console.log((199 + 299) / 100);
8.97
897
8.97
4.98
4.98
এখানে দশমিকগুলো কপালগুণে ঠিক এসেছে। প্রায়ই আসে, আর ফাঁদটা ওখানেই: 0.1 + 0.2 দেখিয়েছে যে সব সময় আসে না। নিরাপদ কিনারা পর্যন্ত পুরো পয়সা হুবহু থাকে, তাই দোকান দাম রাখে পূর্ণসংখ্যায়, আর 100 দিয়ে ভাগ করে শুধু ছাপার সময়।
Kenji এমন একটা লাইন চায়, যেটা বলে দেবে কাজের হিসাবে দুইটা দশমিক সমান কি না।
const a = 0.1 + 0.2;
const b = 0.3;
console.log("exact:", a === b);
console.log("close:", Math.abs(a - b) < 1e-9);
console.log("gap:", Math.abs(a - b));
exact: false
close: true
gap: 5.551115123125783e-17
দূরত্বটা 5.55 গুণ 10-17, 1e-9-এর চেয়ে অনেক অনেক কম। Grade হওয়া problem close-enough হুবহু এই test-টাই ব্যবহার করে।
Bob একটা let দুইটা কাজে ব্যবহার করে। এই মুহূর্তে ওতে যা আছে, type হয় তারই।
let reading = 36.6;
console.log(reading, typeof reading);
reading = "not taken";
console.log(reading, typeof reading);
reading = null;
console.log(reading);
36.6 number
not taken string
null
JavaScript এটা করতে দেয়, আর এতে program বোঝা কঠিন হয়ে যায়। এক নামে এক রকমের value, এই অভ্যাসটা ধরে রাখার মতো। TypeScript, JavaScript-এর উপর বানানো একটা ভাষা, মূলত এই অভ্যাসটা মানতে বাধ্য করার জন্যই আছে।
Run in Compilerএটা কোথায় কাজে লাগে
- Stripe. এর payments API প্রতিটা amount নেয় পূর্ণসংখ্যা হিসেবে, currency-র সবচেয়ে ছোট এককে: 1099 মানে 10.99 dollar। পুরো cent একটা double-এ হুবহু থাকে, তাই কোনো charge-এ rounding চুপিচুপি ঢুকে পড়ে না।
- X, আগের নাম Twitter. Post-এর id হলো 64-bit পূর্ণসংখ্যা, নিরাপদ কিনারার বাইরে। পুরোনো v1.1 API প্রতিটা id দুইবার পাঠাত, একবার number হিসেবে, আরেকবার
id_str-এ string হিসেবে, কারণ JavaScript-এর number শেষের অঙ্কগুলো বদলে দিত। v2 API id পাঠায় শুধু string হিসেবে। - decimal.js. যে program-কে দশমিকের হিসাব হুবহু করতেই হবে, যেমন tax-সহ invoice, সেগুলো সাধারণ number-এর বদলে এরকম একটা decimal library ব্যবহার করে।
যে ভুলগুলো সবাই করে
১. দশমিক === দিয়ে মেলানো।
const total = 0.1 + 0.2;
console.log(total === 0.3);
কোনো message-ই নেই: এটা ছাপে false। Value দুইটা আলাদা হয় 17 নম্বর অঙ্কে গিয়ে। এর বদলে দেখো কাছাকাছি কি না: Math.abs(total - 0.3) < 1e-9। তুমি ===-ই লিখবে, কারণ কাগজে-কলমে যোগফলটা হুবহু 0.3।
২. bigint আর number মেশানো।
console.log(10n + 1);
TypeError: Cannot mix BigInt and other types, use explicit conversions। তুমি কোন type চেয়েছিলে, engine সেটা আন্দাজ করবে না। দুইটাকেই bigint লেখো, 10n + 1n। দ্বিতীয় n-টা তুমি ভুলবে, কারণ 1-টা দেখতে এত ছোট যে মনে হয় ওতে কিছু যায় আসে না।
৩. লম্বা একটা id number হিসেবে রাখা।
const orderId = 1234567890123456789;
console.log(orderId);
কোনো message নেই: এটা ছাপে 1234567890123456800, যেটা অন্য একটা order। Id রাখো string হিসেবে, "1234567890123456789", নয়তো bigint হিসেবে। তুমি এটা number হিসেবে রাখবে, কারণ এটা তো অঙ্ক দিয়েই বানানো।
৪. Quote, যেটা সংখ্যাকে লেখা বানিয়ে দেয়।
const age = "14";
console.log(typeof age);
এটা ছাপে string। Quote থাকলে 14 হলো লেখা, আর + এটা নিয়ে কী করে, দেখাবে Module 2। লেখো const age = 14;। Quote তুমি বসাবে তখন, যখন value-টা এসেছে কোনো form বা file থেকে, যেখানে সবকিছু আসে লেখা হিসেবে।
Alice একটা form save হওয়ার আগে সেটা check করছে। এর পাঁচটা value হলো 2026, "2026", false, 9.99 আর 10n। প্রতিটার type ছাপো, এক লাইনে একটা, এই ক্রমেই।
Output. পাঁচ লাইন।
number
string
boolean
number
bigint
const year = 2026;
const yearText = "2026";
const agreed = false;
const price = 9.99;
const bigCount = 10n;
// Print typeof each one, in the order above.
Grade হয় না। Grade হওয়া version-টা, type-of-each, value-গুলো input থেকে পড়ে, আর সেটা আসবে lesson 04 আর 05-এর পরে।
Zara 0.1 + 0.2-কে বিশ্বাস করে না। ছাপো এটা হুবহু 0.3 কি না, তারপর ছাপো এটা 0.3 থেকে 1e-9-এর মধ্যে আছে কি না।
Output. দুই লাইন।
false
true
const sum = 0.1 + 0.2;
// Line 1: is sum exactly 0.3? Use ===.
// Line 2: is the distance between sum and 0.3 less than 1e-9?
Grade হয় না। Grade হওয়া version-টা, close-enough, input থেকে তিনটা সংখ্যা পড়ে।
সচরাচর যে প্রশ্নগুলো আসে
JavaScript-এ number type মাত্র একটা কেন?
ভাষাটা বানানো হয়েছিল 1995-এ, web page-এর ছোট ছোট script-এর জন্য, যেখানে একটা সহজ number type-ই যথেষ্ট ছিল। তার দাম হলো এই lesson-এর rounding। যেখানে হুবহু পূর্ণসংখ্যা জরুরি, সেই case-গুলোর জন্য ES2020 যোগ করেছে
bigint।একটা character-এর জন্য কি আলাদা type আছে, C-র
char-এর মতো?না।
"a"হলো এমন একটা string, যার length 1। এক character-এর string আর হাজার character-এর string, দুইটার type একই।কখন
nullলিখব, আর কখনundefined?nullনিজে লেখো, যখন "নেই"-টাই আসল উত্তর।undefinedছেড়ে দাও engine-এর হাতে, যাতে ওটা দেখলেই বোঝা যায় "এটায় কখনো value দেওয়া হয়নি"। অনেক team এই ভাগটা মানে, আর এটা কেন কাজে দেয়, দেখাবে lesson 04।Rounding আছে মানে কি JavaScript অঙ্কে কাঁচা?
Double ব্যবহার করে এমন যেকোনো ভাষার চেয়ে বেশি না। Python আর Java-ও এই যোগফলের জন্য একই 0.30000000000000004 ছাপে, আর C-ও একই double রাখে। পার্থক্য হলো, JavaScript প্রতিটা সংখ্যার জন্যই double ব্যবহার করে, তাই এর সঙ্গে তোমার দেখা হয় আগেভাগে।
মূল কথা
- JavaScript-এ primitive type সাতটা (number, string, boolean, undefined, null, bigint, symbol), আর আছে object।
numberপূর্ণসংখ্যা আর দশমিক, দুইটার জন্যই একটা type, রাখা হয় 64-bit double হিসেবে।- দশমিক সব সময় হুবহু থাকে না, তাই
0.1 + 0.2হলো 0.30000000000000004; দশমিক মেলাও কাছাকাছি কি না দেখে। NaNআরInfinityজানায় যে হিসাবটা গোলমাল হয়েছে বা অসীমে গেছে, আর program চলতেই থাকে।Number.MAX_SAFE_INTEGERপর্যন্ত পূর্ণসংখ্যা হুবহু; তার পরেbigintবা string ব্যবহার করো।undefinedমানে এখনো কোনো value নেই;nullমানে কোনো value নেই, ইচ্ছা করেই।
এরপর lesson 04 typeof দিয়ে value-দের জিজ্ঞেস করবে তারা কী, আর দেখা পাবে সেই উত্তরের, যেটা 1995 থেকে ভুল।
lesson ৩ শেষ
শেষ হলে চিহ্ন দিন, অগ্রগতি আপনার সাথে থাকবে।
পরেরটা: typeof, undefined আর null: একটা value-কে জিজ্ঞেস করা সে কী