Learn JavaScript

lesson ৩ / ৯ · type, operator আর coercion: '5' + 2 কেন 7 না

Module ২ · type, operator আর coercion: '5' + 2 কেন 7 না

পুরো program: ইচ্ছে করে convert করা

Freeপড়া

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

  • ছয়টা পুরো program লিখতে পারবে, যেগুলো text-কে number বানায়, number-কে text বানায়, আর যেকোনো value-কে true বা false বানায়, প্রতিটা convert তুমি নিজে বেছে নিয়ে।
  • বুঝিয়ে বলতে পারবে isNaN("abc") কেন true অথচ Number.isNaN("abc") কেন false, আর parseInt("12px", 10) কেন 12 অথচ Number("12px") কেন NaN।
  • toFixed আর Intl.NumberFormat দিয়ে মানুষের পড়ার মতো করে number সাজাতে পারবে, আর জানবে দুটোই ফেরত দেয় একটা string।

Phone-এর calculator app-টার কথা ভাবো। ওর button-গুলোর নিচে থাকে ছোট্ট একটা core: টাইপ করা text-কে number বানায়, হিসাবটা করে, তারপর উত্তরটাকে আবার text বানায়। ওই core-এর প্রতিটা লাইনই একটা convert, যেটা কেউ একজন ভেবেচিন্তে বেছেছে। Lesson 01 আর 02-এ engine নিজে থেকে convert করেছে, অনেক সময় চমকে দিয়ে। এই lesson-এ convert হবে ইচ্ছে করে, ছয়টা program-এ: calculator-এর ওই core থেকে শুরু করে এমন একটা পর্যন্ত, যেটা একজন কাজের programmer সত্যিই ship করে।

সাতটা converter, এক table-এ

Lesson 01-এ তিনটা converter দেখেছ, যারা যেকোনো value নেয়: Number(), String() আর Boolean()। আসল program-এ লাগে আরও চারটা। Radix মানে সংখ্যা লেখার ভিত্তি (base): রোজকার সংখ্যার জন্য 10, binary-র জন্য 2, hexadecimal-এর জন্য 16।

Converterকী নেয়কী ফেরত দেয়উদাহরণফল
Number(x)যেকোনো valueএকটা number; পুরো text-টা number না হলে NaNNumber("12px")NaN
String(x)যেকোনো valueএকটা stringString(255)"255"
Boolean(x)যেকোনো valuefalsy value-গুলোর জন্য false, বাকি সবকিছুর জন্য trueBoolean("0")true
parseInt(text, radix)text (অন্য কিছু দিলে আগে text হয়ে যায়)সামনের দিকের পূর্ণসংখ্যাটা; সামনে কোনো digit না থাকলে NaNparseInt("12px", 10)12
parseFloat(text)textসামনের দিকের দশমিক সংখ্যাটা, সবসময় base 10-এparseFloat("3.5kg")3.5
n.toFixed(digits)একটা numberঠিক অতগুলো দশমিক ঘরসহ একটা string(1.005).toFixed(2)"1.00"
n.toString(radix)একটা numberওই base-এ লেখা একটা string(255).toString(16)"ff"

তিন নম্বর কলামটা আরেকবার পড়ো। toFixed আর toString ফেরত দেয় string, number না, আর নিচের তিনটা common mistake-এর দুটোই এটা ভুলে যাওয়া থেকে আসে। মানে converter-এর নাম বলে সে কী পড়ে, আর table বলে কোন type বের হয়।

পুরো string, নাকি শুধু সামনের অংশ

Number() আর parseInt() দুটোই text-কে number বানায়, তবু "12px" নিয়ে দুজনের মত মেলে না। কেন, ছবিটা দেখো।

Number পুরো text পড়ে, parseInt পড়ে সামনের অংশ Number("12px"): পুরো text-টা একটা number, নইলে কিছুই না 1 2 p x চারটা একসাথে যাচাই: p আর x মানে না NaN বাতিল parseInt("12px", 10): বাঁ থেকে পড়ে, প্রথম non-digit-এ থামে 1 2 p x পড়া 1 পড়া 2 থামো পড়া হয়নি 12 সামনের অংশ Number জানতে চায়: পুরো text-টা কি number? parseInt জানতে চায়: text-টা কোন number দিয়ে শুরু?

তাই যে value-কে শুরু থেকে শেষ পর্যন্ত পুরোটাই number হতে হবে, যেমন form-এর একটা field, তার জন্য Number()। আর যে text একটা number দিয়ে শুরু হয়ে তারপর অন্য কিছু বলে, যেমন "12px" বা "3.5kg", তার জন্য parseInt() আর parseFloat()।

চারটা converter-এর গড়ন

parseInt(text, 10)
parseFloat(text)
value.toFixed(digits)
new Intl.NumberFormat(locale).format(value)
  • text হলো যে string পড়া হবে। অন্য কিছু দিলে আগে সেটা string হয়ে যায়।
  • 10 হলো radix, মানে কোন base-এ পড়বে। এই track সবসময় এটা লিখে দেয়।
  • digits বলে দশমিকের পরে কয়টা digit থাকবে, 0 থেকে 100। ফলটা একটা string।
  • locale একটা ভাষা আর একটা অঞ্চলের নাম, যেমন "en-US" বা "bn-BD"। new একটা formatter বানায়; new জিনিসটা বুঝিয়ে বলবে Module 9।
Example 1: calculator-এর core

নতুন যা: প্রতিটা token-কে নিজে হাতে Number() দিয়ে convert করা। Starter-এর nextInt() আসলে হুবহু Number(next()); এখানে দুই অংশই আলাদা করে দেখবে। Program-টা দুইটা সংখ্যা আর একটা operator পড়ে, তিনটাই text হিসেবে।

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 = [];

const left = next();
const op = next();
const right = next();

const a = Number(left);
const b = Number(right);
const result = op === "+" ? a + b : a * b;

out.push("text joined: " + (left + right));
out.push("converted:   " + a + " " + op + " " + b + " = " + result);

console.log(out.join("\n"));
text joined: 75
converted:   7 + 5 = 12

এই output-টা input 7 + 5-এর জন্য। প্রথম লাইনটা Bob-এর পুরনো bug, ইচ্ছে করেই রেখে দেওয়া: দুইটা string জোড়া লেগেছে। দ্বিতীয় লাইন আগে convert করে, তারপর number যোগ করে। Ternary শুধু + আর * সামলায়; - আর / যোগ হবে অনুশীলন 2-এ।

Run in Compiler

দুইটা isNaN function, আর যেটা মিথ্যা বলে

একটা validator-এর একটাই প্রশ্ন: এই text-টা কি ঠিকঠাক একটা number-এ convert হলো? সংকেতটা হলো NaN, আর ওটা খোঁজার জন্য JavaScript-এ function আছে দুইটা। দুজন কিন্তু আলাদা প্রশ্নের উত্তর দেয়।

console.log(isNaN("abc"), Number.isNaN("abc"));
console.log(isNaN(""), Number.isNaN(""));
console.log(isNaN(undefined), Number.isNaN(undefined));
console.log(isNaN(NaN), Number.isNaN(NaN));
console.log(Number.isNaN(Number("abc")));
true false
false false
true false
true true
true

Global isNaN(x) আগে Number(x) চালায়, তারপর দেখে। তাই isNaN("abc") এমন একটা value নিয়ে true বলে, যেটা আসলে string, NaN না। মিথ্যাটা এখানেই: নাম শুনে মনে হয় সে জিজ্ঞেস করছে "এটা কি NaN?", অথচ উত্তর দিচ্ছে "এটা কি NaN হয়ে যাবে?"। Number.isNaN(x) কিছুই convert করে না, শুধু আসল NaN value পেলেই true বলে।

দুই নম্বর লাইনে দুজনেই ধোঁকা খায়। Number("") হলো 0, তাই খালি একটা field দিব্যি convert হয়ে যায়। তাই validator নিজে Number() দিয়ে convert করে, Number.isNaN() দিয়ে যাচাই করে, আর খালি input আসতে পারলে ""-টা আলাদা করে check করে।

Example 2: কোন input-গুলো number?

নতুন যা: নিজে convert করা value-র উপর Number.isNaN() দিয়ে যাচাই।

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 = [];

const n = nextInt();
for (let i = 0; i < n; i++) {
  const text = next();
  const value = Number(text);
  out.push(text + ": " + (Number.isNaN(value) ? "not a number" : "the number " + value));
}

console.log(out.join("\n"));
12: the number 12
-4.5: the number -4.5
abc: not a number
1e3: the number 1000
0x1f: the number 31
12px: not a number
Infinity: the number Infinity

এই output-টা input 7, তারপর 12 -4.5 abc 1e3 0x1f 12px Infinity-এর জন্য। 1e3 মানে 1 গুণ 10-এর ঘাত 3, আর 0x1f হলো 31-এর hexadecimal রূপ; Number() দুটোই পড়তে পারে। শেষ লাইনে একটা ফাঁক আছে: Infinity number হিসেবে পার পেয়ে যায়। ফাঁকটা বন্ধ হবে অনুশীলন 1-এ।

Run in Compiler

parseInt-এর radix, আগে আর এখন

ES5-এর আগে, মানে standard-এর 2009 সংস্করণের আগে, শুরুতে 0 থাকলে engine চাইলে সেটাকে octal (base 8) ধরে পড়তে পারত। কিছু পুরনো browser তাই করত, ফলে parseInt("08") দিত 0, কারণ 8 কোনো octal digit না। ES5 নিয়মটা তুলে দিয়েছে, আর Node 22 দেয় 8। যে ফাঁদটা আজও বেঁচে আছে, সেটা 0x। Radix না দিলে parseInt "0x1f"-কে hexadecimal ধরে পড়ে; radix 10 দিলে পড়ে "0", তারপর x-এ থেমে যায়।

Example 3: এলোমেলো মাপ পড়া

নতুন যা: radix-সহ আর radix ছাড়া parseInt, আর parseFloat, পাশাপাশি Number()-এর সাথে।

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 = [];

const n = nextInt();
for (let i = 0; i < n; i++) {
  const text = next();
  out.push(text + ": Number " + Number(text) + ", parseInt " + parseInt(text) + ", base 10 " + parseInt(text, 10) + ", parseFloat " + parseFloat(text));
}

console.log(out.join("\n"));
12px: Number NaN, parseInt 12, base 10 12, parseFloat 12
3.5kg: Number NaN, parseInt 3, base 10 3, parseFloat 3.5
08: Number 8, parseInt 8, base 10 8, parseFloat 8
0x1f: Number 31, parseInt 31, base 10 0, parseFloat 0
1e3: Number 1000, parseInt 1, base 10 1, parseFloat 1000
abc: Number NaN, parseInt NaN, base 10 NaN, parseFloat NaN

এই output-টা input 6, তারপর 12px 3.5kg 08 0x1f 1e3 abc-এর জন্য। এক সারি করে পড়ো। 3.5kg-এর দশমিক বিন্দুতে আর 1e3-এর e-তে parseInt থেমে যায়, কারণ কোনোটাই digit না। parseFloat দুটোই পড়ে, কিন্তু hexadecimal কখনো পড়ে না। সামনের অংশ পড়া converter আগেভাগে থেমে যায়, কোনো warning ছাড়াই।

Run in Compiler

toFixed ফেরত দেয় text

toFixed(2) একটা number-কে দুই দশমিক ঘরে গোল করে, মানুষের পড়ার জন্য। ফেরত দেয় একটা string, আর গোল করে computer যে value-টা store করেছে সেটাকে, যেটা সবসময় তোমার টাইপ করা value না। Module 1-এ 0.1 + 0.2 print হয়েছিল 0.30000000000000004, কারণ number store হয় binary ভগ্নাংশ হিসেবে, যেটা কাছাকাছি, হুবহু না। 1.005 store হয় 1.00499999999999989... হিসেবে, তাই নিচের দিকে গোল হয়।

Example 4: tip-এর হিসাব

নতুন যা: toFixed, তার ফেরত দেওয়া string, আর store করা value-কে গোল করার ব্যাপারটা।

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 = [];

const bill = Number(next());
const percent = Number(next());

const tip = bill * percent / 100;
const tipText = tip.toFixed(2);

out.push("tip:   " + tipText);
out.push("total: " + (bill + tip).toFixed(2));
out.push("typeof tipText: " + typeof tipText);
out.push("(1.005).toFixed(2): " + (1.005).toFixed(2));

console.log(out.join("\n"));
tip:   6.00
total: 46.00
typeof tipText: string
(1.005).toFixed(2): 1.00

এই output-টা input 40 15-এর জন্য: 40-এর bill, 15 শতাংশ tip। Total-এ আগে দুইটা number যোগ হয়, bill + tip, তারপরেই কেবল toFixed call হয়। আগে হিসাব, শেষে text: নিয়ম এটাই। নিয়মটা ভাঙলে কোন bill-এ এক cent খোয়া যায়, সেটা দেখাবে lesson 04।

Run in Compiler
Example 5: truthy-falsy ছাঁকনি

নতুন যা: filter(Boolean), যেটা starter Module 1 থেকেই ব্যবহার করছে। Falsy value-গুলোর নাম lesson 01 বলে দিয়েছে: false, 0, "", null, undefined আর NaN, সাথে শূন্যের আরও দুই রূপ -0 আর 0n। এই program প্রতিটা print করে, তারপর এমন পাঁচটা value, যেগুলো শুধু দেখতেই খালি। check এক লাইনের একটা arrow function, starter-এর next-এর মতোই গড়ন।

const out = [];
const check = (label, value) => out.push(label + ": " + (Boolean(value) ? "truthy" : "falsy"));

check("false", false);
check("0", 0);
check("-0", -0);
check("0n", 0n);
check("empty string", "");
check("null", null);
check("undefined", undefined);
check("NaN", NaN);
check("the text 0", "0");
check("the text false", "false");
check("one space", " ");
check("empty array", []);
check("empty object", {});

const mixed = [0, "0", "", " ", null, "12", NaN, []];
const kept = mixed.filter(Boolean);
out.push("kept " + kept.length + " of " + mixed.length);

console.log(out.join("\n"));
console.log(kept);
false: falsy
0: falsy
-0: falsy
0n: falsy
empty string: falsy
null: falsy
undefined: falsy
NaN: falsy
the text 0: truthy
the text false: truthy
one space: truthy
empty array: truthy
empty object: truthy
kept 4 of 8
[ '0', ' ', '12', [] ]

String falsy হয় শুধু খালি হলে, তাই "0" আর "false" দুটোই truthy। Array বা object খালি হলেও truthy। শেষ লাইনটা Node যেভাবে array দেখায় সেভাবে, string-গুলো single quote-এ। তাই starter-এর filter(Boolean) input-এর দুই কিনারার খালি string-গুলো ফেলে দেয়, কিন্তু "0" token-টা রেখে দেয়।

Run in Compiler

Intl.NumberFormat, তোমার প্রথম built-in API

API (application programming interface) মানে একটা system তোমার code-কে যে তৈরি করা যন্ত্রপাতিগুলো দেয়। Intl browser আর Node দুই জায়গাতেই built-in একটা API, যার নিজের আলাদা standard আছে, ECMA-402। Intl.NumberFormat জানে প্রতিটা অঞ্চলের digit, ভাগ করে লেখা (grouping) আর মুদ্রার নিয়ম। Playground-এর Node 22-এ সব অঞ্চলের পুরো data আছে, তাই "bn-BD" বাংলা digit print করে।

Example 6: দুই রকম পাঠকের জন্য দূরত্বের হিসাব

নতুন যা: Intl.NumberFormat দিয়ে একই number তিন ভাবে সাজানো। Zara-র delivery app trip-গুলো মিটারে লেখে। ওর report দেখায় ইংরেজিতে আর বাংলায় কিলোমিটার, মাইল, আর US dollar-এ তেলের খরচ।

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 = [];

const n = nextInt();
const en = new Intl.NumberFormat("en-US");
const bn = new Intl.NumberFormat("bn-BD");
const usd = new Intl.NumberFormat("en-US", { style: "currency", currency: "USD" });

let totalKm = 0;
for (let i = 0; i < n; i++) {
  const metres = Number(next());
  const km = metres / 1000;
  totalKm += km;
  out.push(en.format(km) + " km | " + bn.format(km) + " km | " + en.format(km * 0.621371) + " mi");
}
out.push("total: " + en.format(totalKm) + " km");
out.push("fuel at $0.12 a km: " + usd.format(totalKm * 0.12));

console.log(out.join("\n"));
2.5 km | ২.৫ km | 1.553 mi
42.195 km | ৪২.১৯৫ km | 26.219 mi
1,234,567.891 km | ১২,৩৪,৫৬৭.৮৯১ km | 767,124.685 mi
total: 1,234,612.586 km
fuel at $0.12 a km: $148,153.51

এই output-টা input 3, তারপর 2500 42195 1234567891-এর জন্য; শেষ trip-টা আসলে একটা truck-এর সারা জীবনের odometer। একই number en-US-এ পড়া যায় 1,234,567.891, আর bn-BD-তে ১২,৩৪,৫৬৭.৮৯১, লাখের হিসাবে ভাগ করা। Currency formatter dollar চিহ্ন বসায় আর cent পর্যন্ত গোল করে। প্রতিটা format call একটা string ফেরত দেয়, তাই সাজানোটা সবার শেষের কাজ।

Run in Compiler

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

  • React Hook Form। Form field-এর value সবসময় string। Library-টার register-এর option valueAsNumber: true তোমার code-এর হাতে একটা number তুলে দেয়, আর ওদের documentation বলে convert না হলে ফেরত আসে NaN।
  • Express। Node-এর এই web framework একটা URL-এর query string রাখে req.query-তে, তাই ?page=2 এসে পৌঁছায় string "2" হিসেবে। ওদের documentation সাবধান করে দেয়: এই value-গুলো user-এর input, ব্যবহারের আগে যাচাই করে নিতে হবে।
  • Next.js Commerce। Vercel-এর open-source দোকান template প্রতিটা দাম পায় string হিসেবে। ওর Price component সেটাকে parseFloat দিয়ে convert করে, তারপর currency style-এ Intl.NumberFormat দিয়ে সাজায়।

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

১. toFixed-এর text-এর সাথে number যোগ করা।

const tip = 6;
const bill = 40;
const total = tip.toFixed(2) + bill;
console.log(total);
6.0040

কোনো error নেই, শুধু উত্তরটা ভুল। tip.toFixed(2) হলো string "6.00", তাই + text জোড়া লাগায়। লেখো (tip + bill).toFixed(2): আগে number, একদম শেষে একবার text। ভুলটা তুমি করবে, কারণ "6.00" দেখতে হুবহু একটা number-এর মতো।

২. Token-এর উপর toFixed call করা।

const price = "3.14159";
console.log(price.toFixed(2));
TypeError: price.toFixed is not a function

Playground-এর রায় Runtime error। price একটা string, next() থেকে আসা প্রতিটা token-ই তাই, আর string-এর কোনো toFixed নেই। লেখো Number(price).toFixed(2)। ভুলে যাবে, কারণ টাইপ করার সময় input-টা number-ই মনে হয়েছিল।

৩. হাজারের comma-ওয়ালা দামের উপর parseInt।

const price = "1,299";
console.log(parseInt(price, 10));
1

কোনো error নেই, আর দাম এখন 1। parseInt comma-তে থেমে সামনের অংশটা ফেরত দেয়। Number("1,299") হলো NaN, অন্তত জোরে আওয়াজ করে ব্যর্থ হয়। আগে comma-গুলো সরাও (কীভাবে, দেখাবে Module 3), নয়তো comma ছাড়া input চাও। চুপচাপ ভুল 1-এর চেয়ে জোরালো একটা NaN ভালো।

মাথা খাটাও

console.log(parseInt(0.0000005));
console.log(parseInt(0.000005));

Node 22-এ এটা print করে 5, তারপর 0। ছোট সংখ্যাটা দিচ্ছে বড় উত্তর। কেন?

Table বলছে parseInt নেয় text, আর অন্য কিছু দিলে আগে সেটা text হয়ে যায়। কোন converter কাজটা করে, আর খুব ছোট একটা সংখ্যাকে সে কী বানায়?

অনুশীলন ১সহজ

Zara Example 2-কে token 1e400 খাওয়ায়, যেটা একটা number-এর জন্য অনেক বড়, আর program বলে "the number Infinity"। ও এমন একটা validator চায়, যে অসীম value-গুলোকে আলাদা করে চেনে।

Input. এক লাইনে n, তারপর n-টা token, কোনোটার ভিতরে space নেই।

Output. প্রতিটা token-এর জন্য এক লাইন: value-টা সসীম number হলে yes আর String(Number(t)), Infinity বা -Infinity হলে infinite, আর NaN হলে no।

Constraints. n অন্তত 1। Token মানে space ছাড়া যেকোনো text।

Sample. Input 5, তারপর 12 abc Infinity -0 1e400 দিলে পাঁচ লাইনে yes 12, no, infinite, yes 0 আর infinite।

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"));

আলাদা করে grade হয় না। মূল validator-টা grade করে clean-numbers। Number.isFinite(x) true হয় শুধু এমন number-এর জন্য, যেটা NaN-ও না, অসীমও না, আর Number.isNaN-এর মতো এটাও কিছু convert করে না।

Run in Compiler
অনুশীলন ২মাঝারি

Example 1-কে বড় করে Alice-এর পুরো calculator বানাও। এটা একসাথে অনেকগুলো হিসাব পড়ে, আর প্রতিটার উত্তর দেয় ঠিক JavaScript যেভাবে দিত।

Input. এক লাইনে n, তারপর n-টা লাইনে a op b: তিনটা token, যেখানে op হলো +, -, * বা /।

Output. প্রতিটা লাইনের জন্য Number(a) op Number(b)-এর ফল, JavaScript যেভাবে print করে সেভাবে। Infinity, -Infinity আর NaN-ও উত্তর।

Constraints. 1 <= n <= 10000। a আর b প্রতিটা 1 থেকে 20 অক্ষরের একটা দশমিক সংখ্যা, negative হতে পারে, দশমিক বিন্দুও থাকতে পারে।

Sample. Input 5, তারপর পাঁচ লাইনে 7 + 5, 7 - 10, 0.1 * 3, 1 / 0 আর 0 / 0 দিলে পাঁচ লাইনে 12, -3, 0.30000000000000004, Infinity আর NaN।

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"));

calculator নামে grade হয়। Hidden test-এ শূন্য দিয়ে ভাগ আছে, আর convert না করে দুইটা token যোগ করে ফেলা program-কে সেগুলো ধরে ফেলে।

Run in Compiler
অনুশীলন ৩কঠিন

Kenji বলে, একটা সংখ্যার পূর্ণ অংশ যেভাবেই নাও, একই আসবে। তিনটা উপায়ে ওকে যাচাই করো: Math.trunc(Number(t)), যেটা দশমিকের পরের অংশ কেটে ফেলে; parseInt(t, 10); আর Math.floor(Number(t)), যেটা নিচের দিকে গোল করে।

Input. এক লাইনে n, তারপর n-টা token, প্রতিটা text-এ লেখা একটা সংখ্যা।

Output. প্রতিটা token-এর জন্য এক লাইন: token, একটা colon, তারপর ওই ক্রমে তিনটা ফল। শেষে === দিয়ে তিনটাই সমান হলে same, নইলে differ।

Constraints. n অন্তত 1। প্রতিটা token Number() দিয়ে একটা সসীম number-এ convert হয়।

Sample. Input 3, তারপর 7.9 -7.9 1e21 দিলে তিন লাইনে 7.9: 7 7 7 same, -7.9: -7 -7 -8 differ আর 1e21: 1e+21 1 1e+21 differ।

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"));

আলাদা করে grade হয় না। Sample-এর বাইরে নিজে একটা token খুঁজে বের করো, যেটায় তিনটার উত্তর আলাদা আসে। দামের জন্য তিনটার কোনটাকে ভরসা করবে, আর page নম্বরের জন্য কোনটাকে?

Run in Compiler

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

  • +text আর Number(text) কি একই জিনিস?

    হ্যাঁ। Unary plus একই convert চালায়, তাই +"42" হলো 42। এই track লেখে Number(text), কারণ নাম দেখেই বোঝা যায় কাজটা কী। একলা একটা + পড়ার সময় চোখ এড়িয়ে যেতে পারে।

  • Number("") কেন 0, NaN না?

    Standard বলে, খালি text বা শুধু space-ওয়ালা text convert হয় 0-তে। নিয়মটা পুরনো, এখন বদলালে অসংখ্য website ভেঙে যাবে। তাই validator convert-এর উপর ভরসা করার আগে "" আলাদা করে check করে।

  • টাকা গোল করতে কি toFixed চলবে?

    শুধু দেখানোর জন্য। এটা text ফেরত দেয়, আর store করা binary value-টাকে গোল করে, তাই (1.005).toFixed(2) হয় "1.00"। Lesson 04 টাকা গোনে পুরো cent-এ।

  • bn-BD কেন digit-গুলো 12,34,567 এভাবে ভাগ করে?

    এটা দক্ষিণ এশিয়ার লাখ-কোটির হিসাব: প্রথমে তিনটা digit, তারপর দুইটা দুইটা করে। প্রতিটা অঞ্চলের নিয়ম Intl নেয় locale data-র একটা সবার-ব্যবহারের database থেকে, যার নাম CLDR, মানে Unicode Common Locale Data Repository। "en-IN"-ও একইভাবে ভাগ করে, শুধু digit-গুলো Latin।

মূল কথা

  • Number() চায় পুরো text-টাই number হোক; parseInt আর parseFloat সামনের অংশ পড়ে চুপচাপ থেমে যায়।
  • parseInt-কে সবসময় radix দাও: parseInt(text, 10)। পুরনো "08"-এর ফাঁদ আর নেই, কিন্তু "0x1f" এখনো hexadecimal হিসেবে পড়া হয়।
  • যাচাই করো Number.isNaN আর Number.isFinite দিয়ে, যারা কিছু convert করে না; global isNaN আগে convert করে, তারপর অন্য একটা প্রশ্নের উত্তর দেয়।
  • toFixed, toString আর Intl.NumberFormat সবাই string ফেরত দেয়: আগে হিসাব, একদম শেষে একবার সাজাও।
  • Falsy value হলো false, 0, "", null, undefined আর NaN, সাথে -0 আর 0n; "0", " ", [] আর {} truthy।
  • আরও গভীরে: Interview Pack, output puzzle, প্রশ্ন আর bug gallery (Pro)।

এরপর Kenji একটা review comment-এ লেখে "never use ==", ঠিক সেই লাইনে যেখানে ==-ই ঠিক ছিল, আর lesson 04 ব্যাপারটার মীমাংসা করে।

lesson ৩ শেষ

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

পরেরটা: == কখন, কখন না, আর বাকি judgement call-গুলো

পুরো program: ইচ্ছে করে convert করা | Learn JavaScript | Progsity