Learn JavaScript

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

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

দুটো value একটা operator-এর সামনে: পুরো ছবিটা

Freeপড়া

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

  • +-এর যেকোনো পাশে string থাকলে কী হয়, আর একই দুটো value পেলে -, * আর / কী করে, আগে থেকেই বলে দিতে পারবে।
  • Coercion কী, বুঝিয়ে বলতে পারবে, Number(), String() আর Boolean() দিয়ে ইচ্ছে করে convert করতে পারবে, আর সবগুলো falsy value-র নাম বলতে পারবে।
  • Default হিসেবে === দিয়ে তুলনা করতে পারবে, == কোথায় আলাদা সেটা বলতে পারবে, আর NaN ধরার একমাত্র কাজের উপায়টা লিখতে পারবে।

Bob-এর প্রথম judged problem-এ দুটো সংখ্যার যোগফল চাওয়া হয়েছে। ও starter paste করে, সংখ্যা দুটো পড়ে, যোগ করে, submit দেয়। Sample input 5 2, আর ওর program print করে 52। Judge বলে Wrong Answer, Bob বলে judge-ই ভুল। Judge ঠিক আছে। এই lesson-এ আমরা engine-এর পেছন পেছন এক ধাপ এক ধাপ করে ওই 52 পর্যন্ত যাব।

Bob-এর 52

এটা Bob-এর program। Module 1-এর lesson 05-এর সেই fixed starter, আর comment-এর জায়গায় ওর নিজের তিনটা লাইন।

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 a = next();
const b = next();
out.push(a + b);

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

এই output input 5 2-এর জন্য। Starter input-টাকে space ধরে টুকরো টুকরো করে, প্রতিটা টুকরোকে বলে token। next() পরের token-টা ঠিক যেভাবে টাইপ করা হয়েছিল সেভাবেই ফেরত দেয়, তাই a হলো string "5", সংখ্যা 5 না। Module 1 সোজাসুজি বলে দিয়েছিল: input থেকে যা পড়ো সব text, যতক্ষণ না তুমি নিজে convert করছ।

তাহলে a + b আসলে "5" + "2", আর দুটো string পেলে + ওদের জোড়া লাগায়। Fix হলো প্রতি লাইনে একটা শব্দ বদলানো। nextInt() মানে Number(next()): token পড়ে, তারপর সেটাকে 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 a = nextInt();
const b = nextInt();
out.push(a + b);

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

মানে একই + দুটো string পেয়ে দিল 52, আর দুটো number পেয়ে দিল 7। একটা operator কী করবে, সেটা ঠিক হয় ওর দুই পাশের value-র type দেখে। Lesson-এর বাকিটা হলো প্রতিটা ক্ষেত্রের নিয়ম।

Coercion জিনিসটা কী

Operator হলো এমন একটা চিহ্ন, যেটা কয়েকটা value নিয়ে নতুন একটা value বানায়: +, -, ===। যে value-গুলো ও নেয়, সেগুলো ওর operand। প্রতিটা operator নির্দিষ্ট type-এর operand আশা করে। - সংখ্যা বিয়োগ করে, তাই ওর চাই দুটো number।

--কে একটা string দাও, JavaScript error দিয়ে থেমে যাবে না। আগে string-টাকে number বানাবে, তারপর বিয়োগ করবে। Operator যেন কাজ করতে পারে, সেজন্য engine নিজে থেকে যে conversion করে, তার নাম coercion (অনেকে "implicit conversion"-ও বলে)। আর তুমি নিজে হাতে যে conversion লেখো, যেমন Number("5"), সেটা explicit conversion।

Engine-কে কাজটা করতে দেখো। নিচের table সাত জোড়া operand নেয়, একটা একটা করে, আর উত্তর বের হওয়ার আগে engine কোন কোন ধাপ পার হয়, সেটা দেখায়।

Operator কাজ শুরু করার আগে engine এক বা দুটো operand-কেই convert করে। কোনো পাশে string থাকলে + text জোড়া লাগায়, আর বাকি arithmetic operator দুই পাশকেই number বানায়। == convert করে, === করে না।

ExpressionEngine আগে যা করেফলType
"5" + 2এক পাশে string আছে, তাই 2 হয় "2""52"string
"5" - 2--এর চাই number, তাই "5" হয় 53number
"5" * "2"দুটোই number হয়, 5 আর 210number
5 + truestring নেই, তাই true হয় 16number
"a" * 1"a" কোনো সংখ্যা না, তাই হয় NaNNaNnumber
1 == "1""1" হয় 1, তারপর তুলনাtrueboolean
1 === "1"কিছুই না: আলাদা type কখনো strictly equal নাfalseboolean

প্রতিটা সারি সত্যি। চালিয়ে দেখো, ঠিক এই value আর এই type-ই পাবে।

console.log("5" + 2, typeof ("5" + 2));
console.log("5" - 2, typeof ("5" - 2));
console.log("5" * "2", typeof ("5" * "2"));
console.log(5 + true, typeof (5 + true));
console.log("a" * 1, typeof ("a" * 1));
console.log(1 == "1", 1 === "1");
52 string
3 number
10 number
6 number
NaN number
true false

তাহলে coercion এলোমেলো কিছু না। প্রতিটা operator-এর জন্য engine একটা নিয়ম মানে, আর নিয়মগুলো ছোট।

+-এর নিয়ম, আর বাকিদের নিয়ম

+-এর কাজ দুটো: সংখ্যা যোগ করা, আর string জোড়া লাগানো। Text জোড়া লাগানোর নাম concatenation। দুটো কাজ আছে বলেই +-এর নিয়মটা আলাদা।

  • +-এর নিয়ম। যেকোনো একটা operand string হলে অন্যটাও string হয়ে যায়, আর + দুটো জোড়া লাগায়। না হলে দুটোই number হয়, আর + যোগ করে।
  • বাকিদের নিয়ম। -, *, /, % আর **-এর কাজ একটাই, হিসাব। এরা সবসময় দুটো operand-কেই number বানায়।
একই দুটো operand, প্রথমে + আর তারপর - একই দুটো value, দুটো operator, দুই রকম conversion operand conversion-এর ধাপ ফল "5" string 2 number + এক পাশ string, তাই 2 হয়ে যায় "2" "52" string "5" string 2 number - - শুধু number নিয়ে কাজ করে, তাই "5" হয়ে যায় 5 3 number যে operand-এর type বদলায় না, তার চারপাশে টানা দাগ। ডট-দেওয়া বাক্সটাই coercion। + number-কে text বানাল; - text-কে number বানাল।

String না হলে বাকি সবাই number-এর নিয়মে চলে। true হয় 1, false হয় 0। null হয় 0, আর undefined হয় NaN।

console.log(10 - "4");
console.log("10" / "4");
console.log("2" ** 3);
console.log(true + 1);
console.log(null + 1);
console.log(undefined + 1);
console.log("Tk " + 250);
6
2.5
8
2
1
NaN
Tk 250

শুধু শেষ লাইনে +-এর পাশে string ছিল, তাই শুধু ওখানেই text জোড়া লেগেছে। মানে + দেখলে আগে খোঁজো, কোনো পাশে string আছে কি না। না থাকলে ওটা যোগ।

প্রতিটা operator পরিবারের জন্য lesson 02-তে আলাদা অংশ আছে। এখানে সবগুলো এক card-এ রাখা হলো, যাতে একটা একটা করে শেখার আগেই পুরো সেটটা চোখে পড়ে।

Operator-এর চারটা পরিবার

arithmetic   a + b   a - b   a * b   a / b   a % b   a ** b
comparison   a === b   a !== b   a < b   a > b   a <= b   a >= b   (and a == b, a != b)
logical      a && b   a || b   !a   a ?? b
assignment   x = v   x += v   x -= v   x *= v   x /= v   ...
  • Arithmetic সংখ্যা থেকে সংখ্যা বানায়। শুধু + string-ও জোড়া লাগায়।
  • Comparison দুটো value নিয়ে একটা হ্যাঁ-না প্রশ্ন করে, আর উত্তর দেয় true বা false।
  • Logical হ্যাঁ-না উত্তরগুলোকে মেলায়, আর প্রতিটা value truthy না falsy সেটা দেখে কাজ করে, নিচে যার সংজ্ঞা আছে।
  • Assignment একটা variable-এ value রাখে; += আর এর ভাইবোনেরা হলো x = x + v জাতীয় লাইনের ছোট রূপ।

ইচ্ছে করে convert করা: Number, String, Boolean

Coercion হয় তোমার অগোচরে। যে program-এর ওপর ভরসা করা যায়, সেটা ইচ্ছে করে convert করে, built-in তিনটা converter দিয়ে। প্রতিটা যেকোনো type-এর value নেয়, আর ফেরত দেয় একটা নির্দিষ্ট type।

console.log(Number("42"), Number("3.5"), Number("12px"), Number(""));
console.log(String(42), String(true), String(null));
console.log(Boolean(1), Boolean(0), Boolean("hi"), Boolean(""));
42 3.5 NaN 0
42 true null
true false true false

Number(x) পুরো string-টাকে একটা সংখ্যা হিসেবে পড়ে, দুই মাথায় space থাকলে সমস্যা নেই। কিন্তু মাঝখানে অন্য কোনো অক্ষর ঢুকলে, যেমন "12px"-এ, উত্তর হয় NaN। Number("") খেয়াল করো: খালি string হয় 0, NaN না। String-এর শুধু সামনের অংশ পড়ে এমন converter আছে, lesson 03-এ দেখবে।

String(x) value-টাকে text হিসেবে লেখে, console.log যে text print করে ঠিক সেটাই। Boolean(x) একটাই প্রশ্নের উত্তর দেয়: এই value-টা কি true হিসেবে গোনা হয়?

যে value false হিসেবে গোনা হয়, সেটা falsy। বাকি সব value truthy। Falsy-র তালিকাটা এত ছোট যে মুখস্থ রাখা যায়: ছয়টা value, সাথে শূন্যের আরও দুটো রূপ।

Falsy valueএটা কী
falseboolean নিজেই
0শূন্য সংখ্যা, আর এর আরও দুটো রূপ: -0 আর bigint 0n
""খালি string, একটাও character নেই
null"ইচ্ছে করে কোনো value নেই" (Module 1)
undefined"এখনো কোনো value দেওয়া হয়নি" (Module 1)
NaNব্যর্থ সংখ্যা, এর কথা ঠিক পরেই

বাকি সব truthy, এমনকি কিছু value যেগুলো দেখতে খালি লাগে, সেগুলোও। "0" আর " " হলো একটা করে character-ওয়ালা string, তাই এরা truthy। পুরো তালিকা, চমকসহ, lesson 03 print করে দেখাবে।

তাহলে Number, String আর Boolean প্রত্যেকে ঠিক বলে দেয় কোন type ফেরত পাবে। Operator-এর ভরসায় ছেড়ে দেওয়ার চেয়ে এগুলো এ কারণেই ভালো।

NaN, যে সংখ্যা আসলে সংখ্যা না

NaN মানে "Not a Number"। Number-এ convert করা ব্যর্থ হলে, অথবা কোনো হিসাবের সংখ্যায় কোনো উত্তর না থাকলে, যেমন 0 / 0, এটা পাওয়া যায়। তবু এর type "number", কারণ এটা number type-এরই একটা বিশেষ value।

NaN ছড়িয়ে পড়ে। যে হিসাবে NaN ঢোকে, তার উত্তরও NaN, তাই একটা খারাপ value পুরো যোগফলকে NaN বানিয়ে দেয়। আর এর আরও একটা অদ্ভুত স্বভাব আছে, যেটা Zara সবার আগে test করে বের করেছে।

const price = Number("abc");
console.log(price);
console.log(typeof price);
console.log(price === NaN);
console.log(NaN === NaN);
console.log(Number.isNaN(price));
NaN
number
false
false
true

NaN কোনো কিছুর সমান না, নিজের সমানও না। তাই যেকোনো x-এর জন্য x === NaN হলো false, এটা দিয়ে কখনো NaN ধরা যায় না। যেটা কাজ করে, সেটা Number.isNaN(x)। মানে কোনো conversion ব্যর্থ হতে পারলে ফলটা Number.isNaN দিয়ে check করো, === দিয়ে কখনো না।

=== type আর value দুটোই দেখে; == আগে convert করে

JavaScript-এ equality operator দুটো। === হলো strict equality। দুটো operand-এর type এক আর value এক হলেই শুধু এটা true বলে, আর কোনো কিছু convert করে না।

== হলো loose equality। Type আলাদা হলে এটা আগে এক বা দুটো operand-কে convert করে, widget-এ 1 == "1"-এর বেলায় যেমন দেখলে, তারপর তুলনা করে। এর conversion-গুলো একটা লম্বা নিয়ম মানে, যার কয়েকটা চমক বেশ বিখ্যাত।

console.log(7 === 7, 7 === "7");
console.log(7 == 7, 7 == "7");
console.log(0 == "", 0 === "");
console.log(null == undefined, null === undefined);
true false
true true
true false
true false

এই track default হিসেবে === আর !== লেখে, বেশিরভাগ team-ও তাই করে। == একটা জায়গায় বেশি পরিষ্কার, আর lesson 04 ঠিক সেই জায়গাটা দেখায়। তাই তুলনা করো === দিয়ে, আর type আলাদা হতে পারলে আগে নিজে convert করে নাও।

Example 1: প্রতিটা উত্তরের type

এই lesson-এর সবচেয়ে ছোট program। প্রতিটা ফলের পাশে তার type print করে, যাতে type বদলানোটা চোখে পড়ে।

console.log(4 + 4, typeof (4 + 4));
console.log("4" + 4, typeof ("4" + 4));
console.log("4" - 4, typeof ("4" - 4));
console.log("4" * "4", typeof ("4" * "4"));
console.log(4 / "four", typeof (4 / "four"));
8 number
44 string
0 number
16 number
NaN number

শুধু দ্বিতীয় লাইনে +-এর পাশে string আছে, তাই শুধু ওই উত্তরটাই string। শেষ লাইনে "four" convert হতে পারেনি, তবু type number, কারণ NaN একটা number।

Run in Compiler
Example 2: Amara-র PIN check

Amara-র দরজার তালা PIN রাখে number 4721 হিসেবে। Guess আসে input থেকে, তাই আসে text হয়ে। ওর প্রথম check token-টাকেই সরাসরি তুলনা করে; দ্বিতীয়টা আগে convert করে নেয়।

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 PIN = 4721;
const guess = next();
out.push("as typed:  " + (guess === PIN));
out.push("converted: " + (Number(guess) === PIN));

console.log(out.join("\n"));
as typed:  false
converted: true

এই output input 4721-এর জন্য, মানে ঠিক PIN দিলে। প্রথম check string "4721"-কে number 4721-এর সাথে তুলনা করে, আর type আলাদা বলে === বলে না। দ্বিতীয়টা ইচ্ছে করে convert করে, আর একই === বলে হ্যাঁ।

প্রতিটা তুলনার চারপাশের bracket জরুরি। ওগুলো না থাকলে === চলার আগেই + label আর guess জোড়া লাগিয়ে ফেলত, কেন সেটা lesson 02 বলবে।

Run in Compiler
Example 3: Zara নষ্ট reading-গুলো বাদ দেয়

Zara-র আবহাওয়া station n-টা reading পাঠায়। কোনো sensor বিগড়ে গেলে সংখ্যার বদলে পাঠায় err। ও প্রতিটা reading convert করে, যেগুলো NaN হয়ে আসে সেগুলো বাদ দেয়, আর বাকিগুলোর গড় করে। for loop আর if সেই দুটোই, যা Module 1-এর lesson 05-এ দেখেছ; ঠিকমতো শেখাবে Module 4।

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();
let sum = 0;
let good = 0;
for (let i = 0; i < n; i++) {
  const reading = nextInt();
  if (!Number.isNaN(reading)) {
    sum += reading;
    good += 1;
  }
}
out.push("good readings: " + good + " of " + n);
out.push("average: " + sum / good);

console.log(out.join("\n"));
good readings: 3 of 5
average: 21.333333333333332

এই output input 5, তারপর 21.5 err 23 err 19.5-এর জন্য। Number.isNaN check না থাকলে একটা err-ই sum-কে NaN বানিয়ে দিত, আর গড় print হতো NaN।

শেষ লাইনে number type-এর লম্বা দশমিকটা দেখা যাচ্ছে। দেখানোর জন্য lesson 03 এটাকে toFixed দিয়ে গোল করবে। Zara-র প্রথম test ছিল সব err: তখন good হয় 0, আর গড় দাঁড়ায় 0 / 0, মানে NaN।

Run in Compiler

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

  • Web form। যেকোনো browser-এ <input> element-এর value সবসময় string, field-টা type="number" হলেও। Code নিজে convert না করা পর্যন্ত form-এর যোগফল মানেই Bob-এর 52-এর অপেক্ষা (Module 15)।
  • Web address। Browser আর Node দুই জায়গাতেই built-in URLSearchParams URL-এর query অংশ পড়ে। new URLSearchParams("page=2").get("page") ফেরত দেয় string "2", তাই page নিয়ে হিসাব করার আগে Number() লাগে।
  • Command-line tool। Node-এর process.argv-এ থাকে node script.js-এর পরে টাইপ করা শব্দগুলো, আর প্রতিটাই string। node add.js 5 2 চালালে script হাতে পায় "5" আর "2"।
  • Server থেকে আসা JSON। JSON.parse('{"price": 250}') দেয় একটা number, কিন্তু '{"price": "250"}' দেয় string। Type ঠিক করে পাঠানো পক্ষ, তাই JSON পড়া code type check করে নেয় (Module 8)।

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

১. next() দিয়ে সংখ্যা পড়া।

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

out.push(next() + next());

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

কোনো error নেই, কোনো warning নেই: program চলে, input 5 2 পেয়ে print করে 52, আর judge বলে Wrong Answer। প্রতিটা সংখ্যা পড়ো nextInt() দিয়ে। তুমি next() লিখবে, কারণ screen-এ token-টাকে সংখ্যার মতোই দেখায়, আর screen type দেখায় না।

২. Input-এর token-কে === দিয়ে number-এর সাথে তুলনা করা।

const typed = "10";
console.log(typed === 10);
console.log(Number(typed) === 10);
false
true

প্রথম লাইন চুপচাপ false, আর যে branch এই ফলের ওপর নির্ভর করে, সেটা কখনো চলে না। আগে token convert করো, তারপর তুলনা। === শেখার ঠিক পরেই তুমি এই ভুলটা করবে, কারণ operator ঠিক, type ভুল।

৩. === দিয়ে NaN খোঁজা।

const value = Number("twelve");
console.log(value === NaN);
console.log(Number.isNaN(value));
false
true

value আসলেই NaN, তবু value === NaN বলে false, কারণ NaN কারো সমান না। লেখো Number.isNaN(value)। তুমি === NaN লিখবে, কারণ পড়তে একদম সাধারণ ইংরেজি বাক্যের মতো লাগে।

৪. ভাবা যে Number() খালি string ফিরিয়ে দেবে।

const field = "";
console.log(Number(field));
console.log(Number.isNaN(Number(field)));
0
false

খালি field convert হয়ে হয় 0, দেখতে একদম আসল সংখ্যা, আর Number.isNaN সেটা আটকায় না। খালি value মানে যদি "নেই" হয়, তাহলে convert করার আগে "" check করো। তুমি NaN আশা করবে, কারণ text-এ কোনো সংখ্যাই নেই, কিন্তু নিয়ম বলে খালি string মানে 0।

মাথা খাটাও

Bob নিশ্চিত, এই দুই লাইন একই জিনিস print করবে। দুটোতেই একই তিনটা value, একই operator।

console.log("3" + 4 + 5);
console.log(3 + 4 + "5");

কোন লাইন কী print করে, আর দুটো আলাদা কেন?

+ একবারে দুটো operand নিয়ে কাজ করে, বাঁ থেকে ডানে। প্রথম জোড়ায় +-এর নিয়ম খাটাও, তারপর সেই ফল আর তৃতীয় value-তে।

অনুশীলন ১সহজ

Bob নিজের দুটো উত্তরই পাশাপাশি দেখতে চায়, ভুলটা আর ঠিকটা, যাতে আর কখনো গুলিয়ে না ফেলে।

Input. দুটো token, a আর b, প্রতিটা দশমিক পদ্ধতিতে লেখা একটা সংখ্যা। Token-এ minus চিহ্ন, দশমিক বিন্দু বা শুরুতে বাড়তি শূন্য থাকতে পারে।

Output. দুই লাইন। লাইন 1-এ a আর b-কে number হিসেবে যোগ করে JavaScript যা print করে। লাইন 2-এ token দুটো text হিসেবে জোড়া লাগিয়ে।

Constraints. প্রতিটা token-এ 1 থেকে 25টা অক্ষর।

Sample. Input 5 2 দিলে দুই লাইনে আসে 7 আর 52।

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 হবে sum-and-join হিসেবে। Hidden test-এ শুরুর বাড়তি শূন্য, negative সংখ্যা আর 0.1 0.2-এর মতো দশমিক আছে, তাই প্রতিটা token একবার পড়ে রেখে দাও।

Run in Compiler
অনুশীলন ২সহজ

Zara একটা sensor log থেকে কিছু token পেয়েছে, আর জানতে চায় কোনগুলো পরিষ্কার সংখ্যা। Number(token) NaN না হলে token-টা পরিষ্কার।

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

Output. প্রতি token-এর জন্য এক লাইন: পরিষ্কার হলে yes, একটা space, আর JavaScript সংখ্যাটা যেভাবে print করে; না হলে no।

Constraints. 1 <= n <= 30000। প্রতিটা token-এ 1 থেকে 20টা অক্ষর।

Sample. Input 5 আর 12 3.50 abc 007 12px দিলে পাঁচ লাইনে আসে yes 12, yes 3.5, no, yes 7 আর no।

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 হবে clean-numbers হিসেবে। Hidden test-এ এমন token আছে যেগুলো সবাইকে চমকে দেয়, যেমন NaN, Infinity আর 0x1f। চালানোর আগে প্রতিটার উত্তর আন্দাজ করে নাও।

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

Example 3-এর Zara-র আবহাওয়া station এখনো একটা test-এ ফেল করে: সব reading err হলে গড় print হয় NaN। Report-টা যেন কথায় সেটা বলে, সেই ব্যবস্থা করো।

Input. n, তারপর n-টা token। একটা token হলো 21.5-এর মতো একটা reading, অথবা sensor বিগড়ে গেলে যে শব্দটা পাঠায়।

Output. দুই লাইন। লাইন 1-এ good: আর যতগুলো token number-এ convert হয়, তার সংখ্যা। লাইন 2-এ average: আর ওদের গড়, JavaScript যেভাবে print করে; একটা token-ও convert না হলে average: none।

Constraints. 1 <= n <= 1000। প্রতিটা token-এ 1 থেকে 20টা অক্ষর।

Sample. Input 4 আর 20 err 22 err দিলে আসে good: 2 আর average: 21। Input 2 আর err err দিলে আসে good: 0 আর average: none।

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 হয় না। Example 3 থেকে শুরু করো, আর ভাগ করার আগে good check করো। তারপর Infinity reading-টা দিয়ে চালাও, আর ঠিক করো তোমার station এটাকে গুনবে কি না।

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

Example 2-এর Amara-র দরজার তালা এখন PIN রাখে text হিসেবে, 0472, কারণ PIN 0 দিয়েও শুরু হতে পারে। প্রতিটা guess-এর জন্য ও জানতে চায়: সেটা টাইপ করা PIN-এর সাথে হুবহু মেলে, নাকি শুধু দুটোকে number বানানোর পরে মেলে, নাকি একদমই মেলে না।

Input. PIN, তারপর n, তারপর n-টা guess। কোনো token-এ space নেই।

Output. প্রতিটা guess-এর জন্য এক লাইন: guess আর PIN হুবহু একই text হলে text, তা না হয়ে Number(guess) === Number(pin) হলে number, আর বাকি সব ক্ষেত্রে no।

Constraints. PIN-এ 4 থেকে 8টা digit। 1 <= n <= 1000। প্রতিটা guess-এ 1 থেকে 20টা অক্ষর।

Sample. Input 0472, 5 আর 0472 472 +472 4.72e2 4720 দিলে পাঁচ লাইনে আসে text, number, number, number আর no।

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 হয় না। কঠিন অংশটা হলো দেখা, Number() কত রকম লেখাকে একই সংখ্যা হিসেবে পড়ে: একটা চিহ্ন, একটা দশমিক বিন্দু, একটা exponent। তিনটা উত্তরের কোনটা দিয়ে আসলে দরজা খোলা উচিত?

Run in Compiler

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

  • JavaScript convert করতেই বা যায় কেন? Python তো error দিয়ে থেমে যায়।

    হ্যাঁ, Python 3-এ "5" + 2 দিলে আসে TypeError: can only concatenate str (not "int") to str। JavaScript বানানো হয়েছিল 1995-এ, web page-এর ভিতরের ছোট ছোট script-এর জন্য, আর এটাকে বানানো হয়েছিল থেমে না গিয়ে চলতে থাকার জন্য। পুরনো page না ভেঙে সেই সিদ্ধান্ত এখন আর ফেরানো যায় না। তাই তুমি ইচ্ছে করে convert করো, engine-এর আর কিছু আন্দাজ করার থাকে না।

  • typeof NaN কেন "number"?

    কারণ NaN number type-এরই একটা value, আলাদা করে রাখা হয়েছে "এই হিসাবের কোনো সংখ্যায় উত্তর নেই" বোঝাতে। এটা এসেছে IEEE 754 থেকে, floating-point সংখ্যার যে standard প্রায় সব processor মানে, তাই C আর Python-এও এটা আছে। Lesson 05 ওই standard-টা খুলে দেখায়।

  • অনেককে convert করতে +x লিখতে দেখেছি। এটা কি Number(x)-এর মতোই?

    হ্যাঁ। শুধু একটা operand-ওয়ালা +, value-র আগে লেখা, সেটাকে number বানায়, ঠিক Number(x)-এর মতো। +"42" হলো 42। এই track Number(x) লেখে, কারণ পড়তে গিয়ে কেউ এটা মিস করে না।

  • Coercion কি ভাষাটার একটা bug?

    না, এটা একটা নিয়ম, আর নিয়মটা ভাষার standard, ECMAScript-এ লেখা আছে। এর কিছু ফল মানুষকে চমকে দেয়, আর interview-তে ঠিক ওগুলোই জিজ্ঞেস করে (lesson 06)। কোথায় conversion কাজে আসে, আর কোথায় bug লুকিয়ে রাখে, lesson 04 দেখায়।

মূল কথা

  • Operator যেন কাজ করতে পারে, সেজন্য engine operand-এর type বদলে দেয়, এটাই coercion; Number(), String() আর Boolean() ইচ্ছে করে convert করে।
  • +-এর নিয়ম: যেকোনো পাশে string থাকলে + text জোড়া লাগায়। -, *, /, % আর ** সবসময় number বানায়।
  • Input-এর প্রতিটা token একটা string: সংখ্যা পড়ো nextInt() দিয়ে।
  • Falsy value হলো false, 0 (সাথে -0 আর 0n), "", null, undefined আর NaN; বাকি সব truthy।
  • NaN কারো সমান না, নিজেরও না, তাই এটা ধরো Number.isNaN দিয়ে।
  • === কোনো conversion ছাড়া type আর value দুটোই মেলায়, আর এটাই default; == আগে convert করে নেয়।
  • আরও গভীরে: Under the Hood, abstract equality algorithm আর floating point (Pro)।

এরপর lesson 02 প্রতিটা operator একটা একটা করে ধরবে, logical operator-গুলোও, যারা এমন value ফেরত দেয় যা তুমি হয়তো আশা করোনি।

lesson ১ শেষ

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

পরেরটা: প্রতিটা operator, একটা একটা করে

দুটো value একটা operator-এর সামনে: পুরো ছবিটা | Learn JavaScript | Progsity