এই পর্বে যা শিখবেন
- JSON কেন প্রায় সব API, config ফাইল আর ডেটাবেসের সাধারণ ভাষা, আর JavaScript object থেকে এর পার্থক্য
JSON.parse-এর ভুল সামলানো আর reviver দিয়ে তারিখকে আবার Date বানানোJSON.stringify-এর indentation, replacer আর নিজের class-এtoJSON- Round trip-এ কোন মান টেকে, কোনটি বদলায়, কোনটি error দেয় — আর বড় ID-র বিপদ
- Shallow copy, JSON-কৌশল আর
structuredClone-এর পার্থক্য; নিরাপদ যাচাই আর AI-এর লেখা JSON কোড পরখ
১ · JSON কী — প্রোগ্রামেরা যে লেখায় কথা বলে
একটি দৃশ্য ভাবুন। তানভীর একটি অনলাইন মুদি দোকানের ওয়েবসাইট বানাচ্ছেন। ক্রেতা ব্রাউজারে অর্ডার দেন, সার্ভার (হয়তো Java বা Python-এ লেখা) অর্ডারটি ডেটাবেসে রাখে, আর ডেলিভারি অ্যাপ (হয়তো Kotlin-এ লেখা) সেটি পড়ে রাইডারকে দেখায়। চারটি আলাদা প্রোগ্রাম, চারটি আলাদা ভাষা, আলাদা মেমরি। ব্রাউজারের মেমরিতে থাকা একটি JavaScript object সার্ভার সরাসরি দেখতে পায় না — মাঝখানে আছে নেটওয়ার্ক, আর নেটওয়ার্ক দিয়ে যায় শুধু byte, মানে লেখা।
তাই প্রোগ্রামগুলোকে একটি সাধারণ লেখার নিয়মে একমত হতে হয়: “একজন ডেটা এই আকারে লিখে পাঠাবে, অন্যজন ঠিক এই আকারে পড়ে নেবে।” আজকের ওয়েবে সেই সবচেয়ে প্রচলিত নিয়মটির নাম JSON — JavaScript Object Notation. নামে JavaScript থাকলেও এটি কোনো এক ভাষার সম্পত্তি নয়; Python, Java, Go, PHP, C# — প্রায় সব ভাষায় JSON পড়া-লেখার ব্যবস্থা আছে।
মেমরির মান থেকে লেখা, লেখা থেকে আবার মান
serialization (stringify) → পাঠানো বা রাখা → deserialization (parse)
- JavaScript মান
{ qty: 2 }মেমরিতে, reference দিয়ে জোড়া - JSON লেখা
'{"qty":2}'শুধু অক্ষর — যেকোনো জায়গায় পাঠানো যায় - নেটওয়ার্ক, ফাইল, ডেটাবেস
HTTP · .json · localStorageঅন্য প্রোগ্রাম, অন্য ভাষা - নতুন মান
{ qty: 2 }দেখতে একই, কিন্তু সম্পূর্ণ নতুন object
JSON.stringify মেমরির মানকে লেখা বানায়, JSON.parse লেখা থেকে নতুন মান গড়ে। মাঝখানে শুধু লেখা থাকে, তাই যা লেখায় প্রকাশ করা যায় না, তা পথে হারায়।ঈদের আগে ঢাকা থেকে গ্রামে একটি আলমারি পাঠাতে চান। পুরো আলমারি কুরিয়ারে যায় না — খুলে টুকরো করে বাক্সে ভরেন, সাথে একটি তালিকা দেন: “তাক ৪টি, দরজা ২টি, স্ক্রু ১৬টি।” গ্রামে সেই তালিকা দেখে আবার জোড়া লাগানো হয়। JSON ঠিক এই তালিকা। তবে খেয়াল করুন: আলমারির ভেতরে রাখা আপনার হাতের লেখা চিঠি (function) বা “দরজাটা একটু ঢিলা” ধরনের অভ্যাস (class-এর আচরণ) তালিকায় ওঠে না — ওপারে যা পৌঁছায় তা শুধু ডেটা।
এই প্রক্রিয়ার নাম serialization — মেমরির কাঠামোকে একটি ধারাবাহিক লেখা বা byte-সারিতে সাজানো; উল্টো কাজটি হলো deserialization. JavaScript-এ দুই কাজের জন্য আছে built-in JSON object-এর দুটি method: JSON.stringify(value) আর JSON.parse(text). ES5 (২০০৯) থেকে এগুলো ভাষার অংশ; তার আগে আলাদা library লাগত।
JSON হলো লেখা (string), আর JavaScript object হলো মেমরির মান. দুটি দেখতে প্রায় এক, কিন্তু এক নয়। JSON.parse প্রতিবার সম্পূর্ণ নতুন object বানায়; আর লেখায় শুধু ছয় ধরনের মান প্রকাশ করা যায় — তাই কোন জিনিস যাত্রায় টেকে আর কোনটি হারায়, সেটা জানাই এই পর্বের মূল কাজ।
JSON কোথায় কোথায় দেখবেন? প্রায় সব ওয়েব API-র উত্তর (পর্ব ৩৫-এ fetch দিয়ে এগুলো আনবেন), package.json আর tsconfig.json-এর মতো config ফাইল, MongoDB বা PostgreSQL-এর jsonb কলামের মতো ডেটাবেস, ব্রাউজারের localStorage (পর্ব ৪০), মোবাইল অ্যাপ আর সার্ভারের কথোপকথন — এমনকি AI মডেলের কাছ থেকে কাঠামোবদ্ধ উত্তর চাওয়ার সময়ও।
২০০১ সালে Douglas Crockford আর Chip Morningstar তাঁদের ছোট কোম্পানি State Software-এ ব্রাউজার আর সার্ভারের মধ্যে ডেটা পাঠাতে JavaScript-এর object literal-এর একটি ছোট অংশ ব্যবহার শুরু করেন। Crockford পরে বলেছেন, তিনি JSON “আবিষ্কার” (invent) করেননি, “খুঁজে পেয়েছেন” (discover) — কারণ জিনিসটি JavaScript-এর ভেতরেই ছিল। ২০০২ সালে তিনি json.org সাইটে এক পাতায় পুরো ব্যাকরণ প্রকাশ করেন। গল্পের বাকিটা ভাবনার প্রশ্ন ১-এ।
২ · JSON-এর ব্যাকরণ — JavaScript object-এর চেয়ে কড়া
JSON-এর পুরো ব্যাকরণ এক পাতায় ধরে যায়, আর এটাই তার শক্তি। মান হতে পারে মাত্র ছয় ধরনের: string, number, boolean (true/false), null, array আর object. ব্যস। এর বাইরে কিছু নেই — না undefined, না Date, না function. একটি সাধারণ অর্ডার দেখতে এরকম:
{
"orderId": "A-1017",
"customer": { "name": "রিনা আক্তার", "phone": null },
"items": [
{ "name": "চা পাতা", "price": 25000, "qty": 2 },
{ "name": "চিনি", "price": 13500, "qty": 1 }
],
"paid": true,
"note": "সন্ধ্যার পর ডেলিভারি \u09A6\u09BF\u09A8"
}শেষ লাইনের \u09A6\u09BF\u09A8 হলো Unicode escape sequence — পড়ার সময় হয়ে যায় “দিন”. JSON-এ যেকোনো অক্ষর \uXXXX আকারে লেখা যায়; ইমোজির মতো বড় অক্ষর লাগে দুটি \u দিয়ে (surrogate pair, পর্ব ০৯)। তবে বাংলা সরাসরি লিখলেও কোনো সমস্যা নেই — RFC 8259 বলে, প্রোগ্রামের বাইরে আদান-প্রদানের JSON হবে UTF-8, আর JSON.stringify বাংলা অক্ষর escape না করে যেমন আছে তেমনই রাখে।
| বিষয় | JavaScript object literal | JSON |
|---|---|---|
| Key | { qty: 2 }, { 'qty': 2 } — সব চলে | শুধু double quote-এ: {"qty": 2} |
| String | '…', "…", `…` | শুধু "…"; ভেতরে কাঁচা newline বা tab নিষেধ, লিখতে হবে \n, \t |
| শেষে বাড়তি কমা | [1, 2,] চলে | নিষেধ — SyntaxError |
| Comment | // আর /* */ | নেই, একদমই নেই |
| Number | 0xff, .5, +1, 1_000, NaN, Infinity | শুধু দশমিক: -12.5e3; শুরুতে বাড়তি শূন্য (012), +, .5, NaN, Infinity নিষেধ |
| অন্য মান | undefined, function, Date, Map, Symbol, BigInt… | শুধু string, number, true/false, null, array, object |
| একই key দুবার | শেষেরটি থাকে | মানদণ্ড এড়াতে বলে; JSON.parse শেষেরটি রাখে ({"a":1,"a":2} → { a: 2 }) |
কিছু প্রশ্ন প্রায়ই আসে। শুধু একটি সংখ্যা বা string কি বৈধ JSON? হ্যাঁ — 42, "হ্যালো", null সবই বৈধ JSON লেখা (২০০৬ সালের পুরোনো RFC 4627 বাইরের স্তরে শুধু object বা array চাইত, পরের সংস্করণে সেই শর্ত উঠে গেছে)। Key-এর ক্রম কি অর্থবহ? মানদণ্ডে না — object হলো ক্রমহীন key-value জোড়া। JavaScript সাধারণত লেখার ক্রম রাখে, কিন্তু অন্য ভাষার library ক্রম বদলাতে পারে, তাই ক্রমের ওপর নির্ভর করবেন না।
JSON-এ comment নেই — এটি ভুলে যাওয়া নয়, ইচ্ছাকৃত সিদ্ধান্ত (কারণ ভাবনার প্রশ্ন ৩-এ)। তাহলে VS Code-এর settings.json বা tsconfig.json-এ comment চলে কীভাবে? ওগুলো আসলে “JSON with Comments” (JSONC) — নিজস্ব parser দিয়ে পড়া হয়। একই ফাইল JSON.parse-এ দিলে SyntaxError আসবে। Config-এ comment লাগলে JSONC, JSON5 বা YAML-এর মতো ফরম্যাট বেছে নেওয়া হয়; ডেটা আদান-প্রদানে খাঁটি JSON.
৩ · JSON.parse — লেখা থেকে মান, ভুল ধরা আর reviver
JSON.parse(text) একটি string নেয়, অক্ষর ধরে ধরে ব্যাকরণ মিলিয়ে দেখে, আর মিললে নতুন JavaScript মান বানায়: JSON object থেকে সাধারণ object, array থেকে array, বাকিগুলো primitive. একটি অক্ষরও নিয়ম ভাঙলে পুরো কাজ বাতিল — ফল আসে না, ছোড়া হয় SyntaxError. মাঝামাঝি কোনো “যতটুকু পারলাম” ফল নেই।
বাস্তবে ভাঙা JSON খুব সাধারণ ঘটনা। সার্ভার ভুল করে HTML error পাতা পাঠায় (<html>502 Bad Gateway…), নেটওয়ার্কে উত্তর মাঝপথে কেটে যায়, কেউ হাতে config লিখে শেষে কমা রেখে দেয়, বা localStorage-এ পুরোনো সংস্করণের অন্য ফরম্যাটের ডেটা থেকে যায়। JSON.parse তখন exception ছোড়ে, আর ধরা না হলে পুরো script থেমে যায় — ব্যবহারকারী দেখেন সাদা পাতা। তাই নিয়ম একটাই: বাইরে থেকে আসা লেখা try/catch-এর ভেতরে parse করুন (error নিয়ে বিস্তারিত পর্ব ২৯-এ)।
Error বার্তাগুলো engine-ভেদে আলাদা। Edge/Chrome আর Node.js দুটোই V8 engine, তবু সংস্করণভেদে বার্তা একটু বদলায় — যেমন শেষে বাড়তি কমার জন্য Node 20 বলে:
SyntaxError: Expected double-quoted property name in JSON at position 10
আর নতুন Edge/Chrome আর Node-এর নতুন সংস্করণ (যেমন Node 24) একই বার্তার শেষে যোগ করে (line 1 column 11) — বড় ফাইলে ভুলের জায়গা খুঁজতে খুব কাজের। Firefox-এর বার্তা পুরো আলাদা ভাষায় লেখা। তাই কোডে কখনো error-এর বার্তা মিলিয়ে সিদ্ধান্ত নেবেন না; দেখুন e.name === "SyntaxError" বা e instanceof SyntaxError.
Reviver — parse-এর সময় মান বদলে দেওয়া
JSON-এ তারিখের কোনো টাইপ নেই, তাই তারিখ আসে string হয়ে — সাধারণত ISO 8601 আকারে: "2026-10-19T04:30:00.000Z". Parse করার পর এটি string-ই থাকে; order.placedAt.getFullYear() লিখলে TypeError. সমাধান হলো JSON.parse-এর দ্বিতীয় argument — reviver function. Parser প্রতিটি key-value জোড়ার জন্য একে ডাকে, আর reviver যা ফেরত দেয়, ফলাফলে সেটিই বসে (undefined ফেরত দিলে সেই key বাদ পড়ে)। ডাকার ক্রমটি মজার — ভেতর থেকে বাইরে। ধাপে ধাপে দেখুন:
1const text = '{"id":"A-17","placedAt":"2026-10-19T04:30:00.000Z","items":[{"qty":2}]}';2const order = JSON.parse(text, (key, value) => {3 if (key.endsWith("At")) return new Date(value);4 return value;5});6console.log(order.placedAt instanceof Date);
| key | |
| value | |
| ফেরত দিল |
- আগে পুরো লেখা পড়া। Parser প্রথমে পুরো লেখাটি সাধারণ নিয়মে পড়ে কাঁচা মানের একটি গাছ বানায় — এখনো reviver ডাকা হয়নি। কোথাও ব্যাকরণ ভাঙলে এখানেই SyntaxError, reviver পর্যন্ত যাওয়াই হয় না।
- প্রথম ডাক:
"id". এবার parser গাছটি ঘুরে প্রতিটি জোড়ার জন্য reviver ডাকে।"id"শেষ হয় না"At"দিয়ে, তাই লাইন ৪ মানটি অপরিবর্তিত ফেরত দেয়। মনে রাখুন: কিছু ফেরত না দিলে (মানেundefined) এই key ফলাফল থেকে মুছে যেত — reviver-এ শেষ লাইনেরreturn valueভুলবেন না। "placedAt"→ Date. Key মিলেছে, তাই string থেকেnew Date(value)বানিয়ে ফেরত দেওয়া হলো। ফলাফলের object-এ এখন string-এর জায়গায় সত্যিকারের Date বসবে। বাস্তবে শুধু নাম দেখে নয়, মানটি সত্যিই ISO-আকারের string কি না সেটাও যাচাই করা নিরাপদ।- ভেতরের
"qty"আগে।items-এর আগে তার ভেতরের জিনিসগুলোর পালা — parser গভীরতম স্তর থেকে শুরু করে (depth-first, bottom-up). তাই{"qty": 2}-এর"qty"ডাক আসেitems-এর ডাকের আগে। - Array-র ঘর: key
"0". Array-র প্রতিটি উপাদানের জন্যও reviver ডাকা হয়, key হিসেবে আসে index — তবে string আকারে,"0". এই সময়thisহলো array-টি নিজে (arrow function হলেthisপাবেন না — দরকার হলে সাধারণfunctionলিখুন)। - তারপর
"items". ভেতরের সবকিছু শেষ হওয়ার পর পুরো array নিয়ে"items"-এর ডাক। অর্থাৎ reviver যখন একটি object বা array পায়, তার ভেতরের মানগুলো আগেই revive হয়ে গেছে। - শেষ ডাক: খালি key
"". সবার শেষে মূল (root) মানটির জন্য একবার ডাকা হয়, key খালি string. এখানে চাইলে পুরো ফলাফল বদলে দেওয়া যায়। যা ফেরত যায়, সেটিইJSON.parse-এর ফল — তাইorder.placedAt instanceof Dateএখনtrue.
এবার একটি বাস্তব অর্ডার API-র উত্তর parse করি — reviver দিয়ে তারিখ ফেরাই, মোট দাম গুনি (দাম পয়সায়, পর্ব ১০-এর নিয়মে), আর কয়েকটি ভাঙা লেখা নিরাপদে সামলাই:
const text = `{
"orderId": "9007199254740993",
"placedAt": "2026-10-19T04:30:00.000Z",
"items": [
{ "name": "চা পাতা", "price": 25000, "qty": 2 },
{ "name": "চিনি", "price": 13500, "qty": 1 }
]
}`;
const reviver = (key, value) =>
key.endsWith("At") && typeof value === "string" ? new Date(value) : value;
const order = JSON.parse(text, reviver);
const total = order.items.reduce((sum, it) => sum + it.price * it.qty, 0);
console.log(order.orderId, order.placedAt instanceof Date);
console.log(order.placedAt.getUTCDate(), "মোট পয়সা:", total);
function safeParse(s) {
try { return { ok: true, data: JSON.parse(s) }; }
catch (e) { return { ok: false, error: e.name + ": " + e.message }; }
}
console.log(safeParse('{"qty": 2}'));
console.log(safeParse('{"qty": 2,}').error);
console.log(safeParse("{'qty': 2}").error);
console.log(safeParse("<html>502 Bad Gateway</html>").error);প্রথম লাইনে 9007199254740993 true — ID string হিসেবে এসেছে বলে শেষ অঙ্কটি অক্ষত (সংখ্যা হলে 253-এর ওপরে বলে …992 হয়ে যেত, অংশ ৫), আর reviver তারিখকে Date বানিয়েছে। তারপর 19 মোট পয়সা: 63500 — ২×২৫০ টাকা + ১৩৫ টাকা = ৬৩৫ টাকা। safeParse কখনো exception ছোড়ে না, বরং { ok, data } বা { ok, error } ফেরত দেয় — ডাকার কোডকে দুই ফলই সামলাতে বাধ্য করে। শেষ তিন লাইনে V8-এর তিনটি বার্তা: শেষে বাড়তি কমায় Expected double-quoted property name…, single quote-এ Expected property name or '}'…, আর HTML পাতায় Unexpected token '<', "<html>502 "... is not valid JSON. শেষেরটি দেখলেই বুঝবেন: সার্ভার JSON-এর বদলে HTML পাঠিয়েছে।
৪ · JSON.stringify — সুন্দর করে সাজানো, replacer আর toJSON
উল্টো দিকের কাজ JSON.stringify(value, replacer, space). শুধু প্রথম argument দিলে ফল আসে এক লাইনে, কোনো বাড়তি ফাঁকা ছাড়া — নেটওয়ার্কে পাঠানোর জন্য আদর্শ, কারণ প্রতিটি byte-এর দাম আছে। মানুষের পড়ার জন্য তৃতীয় argument-এ indentation দিন:
const settings = { theme: "dark", fontSize: 18, lang: ["bn", "en"] };
JSON.stringify(settings);
// '{"theme":"dark","fontSize":18,"lang":["bn","en"]}'
JSON.stringify(settings, null, 2);
// {
// "theme": "dark",
// "fontSize": 18,
// "lang": [
// "bn",
// "en"
// ]
// }space-এ সংখ্যা দিলে ততগুলো ফাঁকা (সর্বোচ্চ ১০), string দিলে (যেমন "\t") সেটিই প্রতিটি স্তরে বসে। কার্টের সেটিংস localStorage-এ রাখা, log ফাইলে লেখা বা config ফাইল বানানো — সবই এই এক লাইনের কাজ। আর একটি বিষয়: string মানের ভেতরের double quote, backslash আর newline stringify নিজেই escape করে ("\"", "\\", "\n") — হাতে string জোড়া দিয়ে JSON বানালে ঠিক এই কাজটিই ভুল হয় (অংশ ৮)।
Replacer — কোন জিনিস লেখায় যাবে, ঠিক করা
দ্বিতীয় argument replacer দুই রকম হতে পারে। Array দিলে শুধু সেই key-গুলো লেখায় যায় — একটি allow-list. Function দিলে প্রতিটি key-value-এর জন্য ডাকা হয় (প্রথম ডাক খালি key "" দিয়ে মূল মানের জন্য), আর যা ফেরত দেয় তা-ই লেখা হয়; undefined ফেরত দিলে key বাদ। সবচেয়ে চেনা ব্যবহার: log-এ বা ব্যবহারকারীর কাছে পাঠানোর আগে গোপন তথ্য সরানো।
const user = { name: "রিনা", email: "rina@example.com", password: "secret123", token: "abc" };
const SECRET = new Set(["password", "token"]);
JSON.stringify(user, (key, value) => (SECRET.has(key) ? undefined : value));
// '{"name":"রিনা","email":"rina@example.com"}'
JSON.stringify(user, ["name", "email"]); // allow-list — একই ফলদুটির মধ্যে নিরাপত্তার দিক থেকে allow-list বেশি নিরাপদ. Function-এ আপনি “কী লুকাব” তালিকা রাখেন — কাল কেউ object-এ otp বা nidNumber নামে নতুন field যোগ করলে সেটি নীরবে log-এ চলে যাবে। Array-তে “কী দেখাব” তালিকা — নতুন field নিজে থেকে বাইরে যায় না। খেয়াল করুন, array-replacer ভেতরের স্তরের key-তেও প্রযোজ্য, তাই nested object-এর key-গুলোও তালিকায় রাখতে হয়।
toJSON — নিজের class-এর লেখার রূপ নিজে ঠিক করা
কোনো object-এ toJSON() method থাকলে stringify object-টির বদলে সেই method-এর ফেরত মান লেখে। Date ঠিক এভাবেই কাজ করে — Date.prototype.toJSON ভেতরে toISOString() ডাকে, তাই Date লেখায় যায় ISO string হয়ে। নিজের class-এও একই কৌশল চলে:
class Money {
#paisa; // private — stringify দেখতে পায় না
constructor(paisa) { this.#paisa = paisa; }
toJSON() { return { amount: this.#paisa / 100, currency: "BDT" }; }
}
JSON.stringify({ total: new Money(52000) });
// '{"total":{"amount":520,"currency":"BDT"}}'এখানে দুটি শিক্ষা আছে। এক, #private field (পর্ব ২৬) stringify দেখতে পায় না — toJSON না থাকলে লেখা হতো শুধু {}. দুই, toJSON লেখার রূপ ঠিক করে, কিন্তু parse করলে Money ফেরত আসে না — আসে সাধারণ { amount, currency }. ফেরাতে চাইলে reviver-এ নিজে new Money(…) বানাতে হবে। stringify-এর ক্রম মনে রাখুন: আগে toJSON, তারপর replacer.
৫ · Round trip-এ কী হারায় — undefined, Date, Map, BigInt আর চক্র
JSON মাত্র ছয় ধরনের মান চেনে, অথচ JavaScript-এ মান আছে অনেক রকম। তাহলে বাকিদের কী হয়? stringify তাদের তিনভাবে সামলায় — নীরবে বাদ দেয়, নীরবে বদলে দেয়, অথবা error ছোড়ে. প্রথম দুটি বিপজ্জনক, কারণ কেউ কিছু টের পায় না। একটি পণ্যের object ধরে প্রতিটি field-এর ভাগ্য দেখুন:
1const item = {2 name: "চা পাতা",3 price: NaN,4 note: undefined,5 date: new Date("2026-10-19T04:30:00Z"),6 tags: new Set(["organic", "eid"])7};8console.log(JSON.stringify(item));
| name | |
| price | |
| note | |
| date | |
| tags |
- String — হুবহু যায়।
nameএকটি সাধারণ string, JSON-এ তার সরাসরি জায়গা আছে। বাংলা অক্ষর escape ছাড়াই যায়; শুধু quote, backslash আর control অক্ষর escape হয়। string, সাধারণ number, boolean, null, array আর সাধারণ object — এই ছয়টিই নিরাপদে যাতায়াত করে। NaN→null. JSON-এর সংখ্যার ব্যাকরণে NaN বা Infinity নেই, তাইstringifyএদের নীরবেnullলেখে (Infinityআর-Infinity-ও)। ওপারে parse করলে পাবেনnull— “দাম জানা নেই” আর “দাম হিসাবে ভুল হয়েছে” আলাদা করার উপায় আর থাকল না।-0-ও যায়0হয়ে।undefined— key-টিই উধাও। Object-এর ভেতরেundefined, function বা Symbol মানের key পুরোপুরি বাদ পড়ে। কিন্তু array-র ভেতরে এরা বাদ পড়লে index সরে যেত, তাই সেখানে লেখা হয়null:JSON.stringify([undefined, () => 1, NaN])→"[null,null,null]". আর একদম একাJSON.stringify(undefined)string-ই দেয় না, ফেরত দেয়undefined.- Date → ISO string. Date-এর
toJSONmethod আছে, সেটিtoISOString()ডেকে UTC সময়ের string দেয়। লেখায় তারিখ ঠিকই আছে, কিন্তু parse করলে ফেরত আসবে string, Date নয় — অংশ ৩-এর reviver এই কারণেই লাগে। ভুল Date (new Date("abc")) লেখা হয়null. - Set →
{}. Set (আর Map) তাদের ডেটা রাখে ভেতরের লুকানো জায়গায়, নিজস্ব enumerable property-তে নয়।stringifyশুধু নিজস্ব enumerable property দেখে, তাই পায় একটি খালি object —{}. কোনো error নেই, কোনো warning নেই; ট্যাগগুলো চিরতরে হারাল। সমাধান: আগে রূপান্তর —[...tags]বা Map-এর জন্যObject.fromEntries(map)/[...map]. - চূড়ান্ত লেখা। পাঁচটি field-এর মধ্যে মাত্র একটি (
name) অক্ষত পৌঁছাল।priceভুল অর্থ পেল,noteউধাও,dateটাইপ হারাল,tagsডেটা হারাল — আর পুরো সময় JavaScript একটি অভিযোগও করেনি। কোনো ডেটা JSON-এ পাঠানোর আগে প্রশ্ন করুন: “এর প্রতিটি field কি ছয় টাইপের মধ্যে?”
যেখানে stringify হার মানে — BigInt আর চক্র
দুই ক্ষেত্রে stringify নীরব থাকে না, TypeError ছোড়ে। প্রথমটি BigInt — JSON.stringify({ id: 10n }) দেয় TypeError: Do not know how to serialize a BigInt (V8-এর বার্তা)। কারণ JSON-এর number অন্য ভাষায় সাধারণত double হিসেবে পড়া হয়, তাই BigInt-কে নীরবে number বানালে নির্ভুলতা হারাত — ভাষা তাই ইচ্ছা করে থামিয়ে দেয়। BigInt পাঠাতে string বানান (id.toString()), বা replacer-এ typeof value === "bigint" ? value.toString() : value.
দ্বিতীয়টি circular reference — যখন একটি object ঘুরে নিজেকেই দেখায়। যেমন কার্টের প্রতিটি item-এ item.cart = cart রাখলে cart → items → item → cart → … অন্তহীন চক্র। লেখায় এটি প্রকাশ করার কোনো উপায় নেই, তাই V8 বলে:
TypeError: Converting circular structure to JSON
--> starting at object with constructor 'Object'
--- property 'self' closes the circle
বার্তাটি এমনকি চক্রটি কোথায় বন্ধ হলো, সেটাও দেখায় — DOM element বা বড় framework object ভুল করে stringify করলে প্রায়ই এই error আসে। সমাধান: পাঠানোর আগে ফিরতি-reference সরান (শুধু ID রাখুন: cartId: "C-9"), বা replacer-এ একটি WeakSet দিয়ে আগে দেখা object বাদ দিন।
বড় সংখ্যা — নীরব সবচেয়ে বড় বিপদ
পর্ব ১০-এ দেখেছেন, number হুবহু থাকে কেবল 253 − 1 পর্যন্ত (safe integer). অনেক ডেটাবেস ৬৪-বিট ID ব্যবহার করে। এমন ID JSON-এ সংখ্যা হয়ে এলে JSON.parse('{"id": 9007199254740993}').id দেয় 9007199254740992 — শেষ অঙ্ক নীরবে বদলে গেল, আর আপনি ভুল অর্ডার খুললেন। এজন্যই অনেক বড় API ID পাঠায় string হিসেবে (Twitter-এর পুরোনো API-তে id-এর পাশে আলাদা id_str থাকত)। নিয়ম: যে সংখ্যা দিয়ে হিসাব হয় না — ID, ফোন নম্বর, অ্যাকাউন্ট নম্বর — তা string. নতুন ব্রাউজারে reviver-এর তৃতীয় argument-এ মূল লেখাটি (context.source) পাওয়ার ব্যবস্থা এসেছে, কিন্তু Node 20-এর মতো পুরোনো পরিবেশে নেই — তাই string-ই সবচেয়ে বহনযোগ্য সমাধান।
| মান | Object-এর ভেতরে | Array-র ভেতরে | Parse করে ফেরত |
|---|---|---|---|
| string, finite number, boolean, null | হুবহু | হুবহু | একই মান ✓ |
undefined, function, Symbol | key বাদ | null | হারাল ✗ |
NaN, Infinity | null | null | null ✗ |
| Date | ISO string | ISO string | string (reviver লাগে) ⚠ |
| Map, Set | {} | {} | খালি object ✗ |
| class-এর instance | নিজস্ব public field | একই | সাধারণ object, method নেই ⚠ |
| BigInt | TypeError: Do not know how to serialize a BigInt | — | |
| চক্রাকার object | TypeError: Converting circular structure to JSON | — | |
৬ · কপি করা — shallow, JSON-কৌশল আর structuredClone
পর্ব ১৪-এ দেখেছেন, variable-এ object রাখলে আসলে রাখা হয় তার reference. তাই const copy = cart কোনো কপি নয় — একই কার্টের দ্বিতীয় নাম। ধরুন ক্রেতা চেকআউট পাতায় কার্ট এডিট করছেন, কিন্তু “বাতিল” চাপলে আগের অবস্থায় ফিরতে হবে। এর জন্য দরকার একটি সত্যিকারের, আলাদা কপি। তিনটি পরিচিত পথ আছে, আর তিনটির আচরণ আলাদা:
cart ──► { owner: "রিনা",
createdAt: ──► Date(2026-10-19)
items: ──────► [ ──► { name: "খাতা", qty: 2 } ]
coupons: ────► Set { "EID10" }
discount: NaN, note: undefined }
shallow ──► { owner: "রিনা", (নিজের কপি)
createdAt: ─┐
items: ─────┼──► মূলের একই Date, একই array, একই Set!
coupons: ───┘ }
shallow.items[0].qty = 5 → cart.items[0].qty === 5
viaJson ──► { owner: "রিনা",
createdAt: "2026-10-19T04:30:00.000Z" ← string
items: [ { name: "খাতা", qty: 2 } ] ← নতুন ✓
coupons: {} ← Set গেল
discount: null } ← note উধাও
clone ──► { owner: "রিনা",
createdAt: ──► নতুন Date
items: ──────► নতুন array ──► নতুন object
coupons: ────► নতুন Set { "EID10" }
discount: NaN, note: undefined } ← সব আছে
clone.items[0].qty = 9 → cart বদলায় না
ভেতরের object Date/Map/Set NaN/undefined চক্র function
{ ...x } ভাগাভাগি ভাগাভাগি ✓ ✓ ✓ (একই)
JSON-কৌশল নতুন হারায় হারায় Error বাদ
structuredClone নতুন ✓ ✓ ✓ Error
- মূল কার্ট। বাইরের object-এর কিছু property সরাসরি মান (string, number), আর কিছু আসলে অন্য object-এর দিকে তীর — Date, array, তার ভেতরের item, Set. “কপি” মানে কী — শুধু বাইরের বাক্স, নাকি সব তীরের মাথার জিনিসও? এই প্রশ্নের উত্তরেই তিন পদ্ধতির পার্থক্য।
- Shallow copy. Spread (
{ ...cart }, পর্ব ১৭) বাObject.assignনতুন বাইরের object বানায়, কিন্তু property-র মান কপি করে যেমন আছে — তীর হলে তীরটিই কপি হয়। ফলেshallow.itemsআরcart.itemsএকই array. কপিতে qty বদলালে মূল কার্টেও বদলায় — “বাতিল” চাপলেও ক্রেতার আগের কার্ট আর ফেরত আসবে না। - JSON-কৌশল। পুরো object-কে লেখা বানিয়ে আবার পড়লে সব স্তরে নতুন object আসে — deep copy. বহু বছর এটিই ছিল জনপ্রিয় এক-লাইনের সমাধান। কিন্তু অংশ ৫-এর সব ক্ষতি সাথে আসে: Date হয় string, Set হয়
{}, NaN হয় null, undefined key উধাও, class-এর instance সাধারণ object, আর চক্র থাকলে TypeError. তার ওপর পুরো ডেটা একবার লেখায় আর একবার ফিরিয়ে আনা — বড় ডেটায় ধীরও। structuredClone. ব্রাউজারের structured clone algorithm দিয়ে প্রতিটি স্তরের নতুন কপি বানায়, আর টাইপ চেনে: Date থাকে Date, Map/Set থাকে Map/Set, NaN আর undefined অক্ষত, typed array,RegExp, Error, Blob-ও কপি হয়, এমনকি চক্রও ঠিকঠাক নতুন চক্র হয়ে আসে। কপিতে যত খুশি বদলান — মূল কার্ট অক্ষত।- কোনটি কখন। শুধু এক স্তরের সাধারণ object আর ভেতরে কিছু বদলাবেন না — spread যথেষ্ট আর দ্রুত। সত্যিকারের আলাদা কপি দরকার —
structuredClone. JSON-কৌশল এখন শুধু তখনই অর্থবহ, যখন আপনি আসলেই JSON-এ রূপান্তর করছেন (যেমন পাঠানোর আগে ডেটাকে “JSON-নিরাপদ” কিনা যাচাই)। আর function বা DOM node থাকলে কোনো পদ্ধতিই সেগুলো কপি করে না।
নিজে চালিয়ে তিন পদ্ধতির পার্থক্য দেখুন — চেকআউটে এডিট শুরুর আগে কার্টের কপি:
const cart = {
owner: "রিনা",
createdAt: new Date("2026-10-19T04:30:00Z"),
items: [{ name: "খাতা", qty: 2 }],
coupons: new Set(["EID10"]),
discount: NaN,
note: undefined,
};
const shallow = { ...cart };
const viaJson = JSON.parse(JSON.stringify(cart));
const clone = structuredClone(cart);
shallow.items[0].qty = 5; // কপিতে বদল...
console.log("মূল কার্ট:", cart.items[0].qty); // ...মূলেও বদল!
console.log(typeof viaJson.createdAt, viaJson.coupons, viaJson.discount, "note" in viaJson);
console.log(clone.createdAt instanceof Date, clone.coupons.has("EID10"), clone.discount, "note" in clone);
clone.items[0].qty = 9;
console.log(cart.items[0].qty, clone.items[0].qty);
try { structuredClone({ total() { return 0; } }); }
catch (e) { console.log(e.name + ": " + e.message); }মূল কার্ট: 5 — shallow copy-তে বদল মূলেও পৌঁছেছে। JSON-কৌশলের লাইন string {} null false: Date এখন string, Set খালি object, NaN হলো null, আর note key-টিই নেই। structuredClone-এর লাইন true true NaN true — সব টাইপ অক্ষত। তারপর 5 9: clone-এ ৯ বসালেও মূল কার্ট ৫-এই আছে (৫ হয়েছিল shallow-এর কারণে)। শেষ লাইনে method-ওয়ালা object কপি করতে গিয়ে Edge/Chrome দেখায় DataCloneError: Failed to execute 'structuredClone' on 'Window': total() { return 0; } could not be cloned. Node.js-এ বার্তার শুরুর “Failed to execute…” অংশটি থাকে না, কিন্তু দুই জায়গাতেই error-এর নাম DataCloneError (একটি DOMException) — তাই কোডে নাম দেখে সিদ্ধান্ত নিন, বার্তা দেখে নয়।
structuredClone যা পারে না
- Function কপি হয় না: কোনো property-তে function থাকলে পুরো কাজ DataCloneError দিয়ে থামে — JSON-এর মতো নীরবে বাদ দেয় না।
- DOM node কপি হয় না:
structuredClone(document.body)DataCloneError দেয়। DOM কপি করতে আছেnode.cloneNode(true)(পর্ব ৩৭)। - Class-এর পরিচয় হারায়: class instance কপি হয় সাধারণ object হয়ে — নিজস্ব field থাকে, কিন্তু prototype (পর্ব ২৫) হয় সাধারণ
Object.prototype, তাই method আর getter থাকে না,instanceofদেয়false.#privatefield-ও কপি হয় না। - Getter-এর মান, setter নয়: getter থাকলে কপির সময় তার মান পড়ে সাধারণ property হিসেবে রাখা হয়; property descriptor,
Object.freeze-এর অবস্থা ইত্যাদি হারায়।
structuredClone নতুন কিছু নয় — ব্রাউজারের ভেতরে এই algorithm বহু বছর ধরে আছে। Web Worker-কে postMessage দিয়ে ডেটা পাঠানো (পর্ব ৪২), IndexedDB-তে object রাখা (পর্ব ৪০), history.pushState — সবখানে এটিই চলে। ২০২১–২২ সালে শুধু একে সরাসরি ডাকার মতো global function হিসেবে খুলে দেওয়া হয়েছে (ইতিহাস ভাবনার প্রশ্ন ৫-এ)। তাই কোন ডেটা worker-এ পাঠানো যায়, তার নিয়মও ঠিক এটাই।
৭ · বিশ্বাস নয়, যাচাই — validation, নিরাপত্তা, localStorage আর NDJSON
JSON.parse সফল হলো মানে শুধু এটুকু নিশ্চিত যে লেখাটির ব্যাকরণ ঠিক ছিল। ভেতরের ডেটা আপনার প্রত্যাশামতো কি না — সেটা সে জানে না, জানার কথাও না। API আপনাকে {"items": [...]} দেওয়ার কথা, কিন্তু নতুন সংস্করণে হয়তো দিল {"data": {"items": [...]}}; price number হওয়ার কথা, এলো "250" string; কোনো item-এ qty নেই। Parse ঠিকঠাক, কিন্তু পরের লাইনে undefined-এর ওপর .reduce — অথবা আরও খারাপ, "250" * 2 চুপচাপ ৫০০ দেয় আর "250" + 1 দেয় "2501".
তাই parse-এর ঠিক পরে একটি সীমান্ত-চৌকি বসান — যেমন বিমানবন্দরে ইমিগ্রেশন: পাসপোর্ট “দেখতে ঠিক” হলেই হয় না, প্রতিটি তথ্য মিলিয়ে দেখা হয়। ছোট ক্ষেত্রে হাতে যাচাই:
function parseOrder(text) {
const data = JSON.parse(text); // SyntaxError → ডাকার জায়গায় ধরুন
if (typeof data !== "object" || data === null || !Array.isArray(data.items)) {
throw new TypeError("অর্ডারের আকার ঠিক নেই");
}
for (const it of data.items) {
if (typeof it.name !== "string" || !Number.isSafeInteger(it.price) ||
!Number.isSafeInteger(it.qty) || it.qty <= 0) {
throw new TypeError("ভুল item: " + JSON.stringify(it));
}
}
return data;
}বড় প্রজেক্টে এই কাজ হাতে লেখা ক্লান্তিকর আর ভুলপ্রবণ, তাই schema validation library ব্যবহার হয় — ডেটার “আকার” একবার বর্ণনা করেন, library যাচাই করে স্পষ্ট error দেয়। জনপ্রিয় একটি হলো Zod (npm থেকে ইনস্টল করতে হয়, পর্ব ৪৬; তাই নিচের কোড এখানে চালানো যাবে না):
import { z } from "zod";
const Order = z.object({
orderId: z.string(),
placedAt: z.coerce.date(), // ISO string → Date
items: z.array(z.object({
name: z.string(),
price: z.number().int().nonnegative(),
qty: z.number().int().positive(),
})).min(1),
});
const result = Order.safeParse(JSON.parse(text));
if (!result.success) console.log(result.error.issues); // কোন field, কী সমস্যা
else useOrder(result.data); // এখানে ডেটা বিশ্বাসযোগ্যভাষা-নিরপেক্ষ বিকল্প হলো JSON Schema — schema নিজেই একটি JSON ফাইল, যা সার্ভার আর ক্লায়েন্ট দুজনেই পড়তে পারে। TypeScript (পর্ব ৪৭) শিখলে মনে রাখবেন: TypeScript-এর টাইপ শুধু compile-এর সময় থাকে, চলার সময় API কী পাঠাল সেটা যাচাই করে না — JSON.parse-এর ফল তাই runtime-এ যাচাই করতেই হয়।
নিরাপত্তা ১ — JSON কখনো eval করবেন না
JSON.parse আসার আগে (২০০৯-এর আগের ব্রাউজারে) অনেকে লিখত eval("(" + text + ")") — কারণ JSON তো JavaScript-এরই অংশ। কিন্তু eval লেখাটিকে কোড হিসেবে চালায়. সার্ভার বা মাঝপথের কেউ ডেটার জায়গায় কোড ঢোকালে সেটি আপনার পাতায়, আপনার ব্যবহারকারীর লগইনসহ চলবে — XSS-এর দরজা খোলা। JSON.parse শুধু ব্যাকরণ পড়ে, কোনো কোড চালায় না, কোনো function বানায় না — তাই এটিই একমাত্র ঠিক পথ।
নিরাপত্তা ২ — “__proto__” key আর prototype pollution
একটি সূক্ষ্ম বিপদ আছে, যা অনেক বড় npm library-তেও ধরা পড়েছে। JSON.parse('{"__proto__": {"isAdmin": true}}') নিজে নিরাপদ — সে "__proto__" নামে একটি সাধারণ নিজস্ব property বানায়, কারও prototype বদলায় না। বিপদ আসে পরে, যখন এই ডেটা কোনো সরল “deep merge” function দিয়ে অন্য object-এ মেশানো হয়:
// ভুল নকশা — দেখানোর জন্য
function naiveMerge(target, src) {
for (const key in src) {
if (typeof src[key] === "object" && src[key] !== null) {
target[key] = naiveMerge(target[key] ?? {}, src[key]); // key === "__proto__" হলে?
} else target[key] = src[key];
}
return target;
}
naiveMerge({}, JSON.parse('{"__proto__": {"isAdmin": true}}'));
console.log({}.isAdmin); // true — প্রোগ্রামের সব object এখন "admin"!কী ঘটল? target["__proto__"] পড়লে পাওয়া যায় Object.prototype — সব সাধারণ object-এর সাধারণ পূর্বপুরুষ। Merge তার ভেতরে isAdmin = true লিখে দিল। ফলে প্রোগ্রামের যেকোনো object, যার নিজের isAdmin নেই, এখন prototype থেকে true পায় — if (user.isAdmin) ধরনের যাচাই ভেঙে পড়ে। একে বলে prototype pollution. প্রতিরক্ষা:
আরেকটি সূক্ষ্মতা: spread ({ ...parsed }) নিজস্ব property হিসেবেই "__proto__" কপি করে, কিন্তু Object.assign({}, parsed) setter ব্যবহার করে বলে নতুন object-এর prototype বদলে দেয় — পুরো প্রোগ্রাম নয়, তবু অপ্রত্যাশিত। বিস্তারিত ওয়েব-নিরাপত্তা পর্ব ৪৩-এ।
localStorage — শুধু string রাখে
ব্রাউজারের localStorage (পর্ব ৪০) শুধু string রাখতে পারে। Object সরাসরি দিলে রাখা হয় "[object Object]" — ডেটা শেষ। তাই কার্টের সেটিংস রাখতে JSON-ই ভরসা (এই কোড পাতার ভেতরের sandbox-এ চলবে না, নিজের ব্রাউজারের console-এ চেষ্টা করুন):
const prefs = { theme: "dark", currency: "BDT", savedAt: new Date() };
localStorage.setItem("cartPrefs", JSON.stringify(prefs));
function loadPrefs() {
try {
return JSON.parse(localStorage.getItem("cartPrefs")) ?? { theme: "light" };
} catch {
return { theme: "light" }; // পুরোনো বা ভাঙা ডেটা — ডিফল্টে ফিরুন
}
}এখানে একটি ছোট কৌশল লুকিয়ে আছে: key না থাকলে getItem দেয় null, আর JSON.parse(null) আগে null-কে "null" লেখায় রূপান্তর করে, ফল দেয় null — error নয়। তারপর ?? ডিফল্ট বসায়। আর savedAt ফেরত আসবে string হয়ে — reviver ছাড়া Date নয়।
NDJSON — এক লাইনে এক JSON
পুরো ফাইল একটি বড় JSON array হলে, শেষ ] না আসা পর্যন্ত parse করা যায় না — লাখো log লাইন বা ধীরে ধীরে আসা stream-এর জন্য অসুবিধা। সমাধান NDJSON (newline-delimited JSON, যাকে JSON Lines-ও বলে): প্রতিটি লাইনে একটি সম্পূর্ণ JSON মান। text.trim().split("\n").map(line => JSON.parse(line)) — প্রতিটি লাইন আলাদাভাবে parse হয়, একটি ভাঙা লাইন বাকিগুলোকে নষ্ট করে না, আর নতুন লাইন শুধু শেষে জুড়ে দিলেই হয়। Log সিস্টেম, ডেটা export আর বেশ কিছু streaming API এই ফরম্যাট ব্যবহার করে; stream পড়ার কৌশল পর্ব ৪৯-এ।
C আর C++-এর standard library-তে JSON নেই — cJSON বা nlohmann/json-এর মতো library লাগে; Java-তেও built-in নেই, Jackson বা Gson দিয়ে object-কে class-এ map করা হয় (Java-র JSON ও serialization). Python-এর json.dumps/json.loads প্রায় JavaScript-এর মতো, তবে Python ডিফল্টে NaN লিখে ফেলে — যা আসলে বৈধ JSON নয়, আর copy.deepcopy অনেকটা structuredClone-এর ভূমিকা নেয় (Python-এর CSV ও JSON). JavaScript-এর সুবিধা হলো JSON-এর গঠন ভাষার object-এর সাথে প্রায় হুবহু মেলে, তাই কোনো mapping class লাগে না — আর অসুবিধাও সেখানেই: টাইপ যাচাইয়ের কাজটি পুরোপুরি আপনার।
- JSON আর JavaScript object-এর পার্থক্য? — JSON একটি টেক্সট ফরম্যাট (string); key ও string শুধু double quote-এ, comment ও শেষে বাড়তি কমা নেই, মান মাত্র ছয় ধরনের।
JSON.stringify({ a: undefined, b: () => 1, c: NaN })? —'{"c":null}'; undefined ও function-এর key বাদ, NaN হয় null.- Deep copy কীভাবে করবেন? —
structuredClone(obj); JSON-কৌশল Date, Map, Set, undefined হারায় আর চক্রে TypeError দেয়, spread শুধু shallow copy. - Parse-এর পর Date ফেরত পাবেন কীভাবে? — reviver function দিয়ে ISO string চিনে
new Date(value)ফেরত দিয়ে। evalদিয়ে JSON পড়া কেন বিপজ্জনক? — eval লেখাকে কোড হিসেবে চালায়, তাই ঢোকানো কোডও চলবে;JSON.parseশুধু ডেটা পড়ে।
৮ · AI-এর যুগে — JSON কোডে AI-এর চেনা ভুল
JSON নিয়ে AI-এর লেখা কোড সাধারণত “happy path”-এ নিখুঁত চলে — সার্ভার ঠিক উত্তর দিলে, ডেটায় Date বা Set না থাকলে। সমস্যা দেখা দেয় বাস্তবের ধাক্কায়: ভাঙা উত্তর, বদলে যাওয়া API, বিশেষ অক্ষর। AI যে কোটি কোটি লাইন কোড থেকে শিখেছে, তার বড় অংশ পুরোনো অভ্যাসে লেখা — তাই সে আত্মবিশ্বাসের সাথে সেই পুরোনো ভুলগুলোই দেয়।
| AI যা প্রায়ই লেখে | সমস্যা | যা চাইবেন |
|---|---|---|
'{"name":"' + name + '"}' — string জোড়া দিয়ে JSON | নামে " বা \ বা newline থাকলে JSON ভাঙে; ইচ্ছাকৃত ইনপুটে বাড়তি field ঢোকানো যায় | object বানিয়ে JSON.stringify |
JSON.parse(JSON.stringify(x)) দিয়ে deep copy | Date, Map, Set, undefined, NaN হারায়; চক্রে crash | structuredClone(x) |
try/catch ছাড়া JSON.parse | একটি ভাঙা উত্তরে পুরো পাতা থেমে যায় | try/catch আর পরিষ্কার ডিফল্ট বা error বার্তা |
data.items.map(...) — আকার যাচাই ছাড়া | API বদলালে undefined-এর ওপর TypeError; string-সংখ্যা নীরবে ভুল হিসাব | schema validation (Zod) বা হাতে টাইপ যাচাই |
Parse-এর পর order.date.getFullYear() | date আসলে string — TypeError | reviver বা স্পষ্ট new Date(...) |
| নিজের লেখা deep merge | "__proto__" key দিয়ে prototype pollution | বিপজ্জনক key বাদ, Map বা যাচাই করা library |
AI-কে JSON-এর কোড লিখতে বললে ঝুঁকিগুলো আগেই নাম ধরে বলে দিন, আর পরীক্ষার কেসও চেয়ে নিন:
AI-এর লেখা JSON কোড — যাচাইয়ের চেকলিস্ট
ভাবনার প্রশ্ন
প্রতিটি প্রশ্ন নিয়ে নিজে কিছুক্ষণ ভাবুন — তারপর “→ উত্তর” চাপুন। এগুলোই আপনাকে কোড-লেখক থেকে সিস্টেম-চিন্তক বানাবে।
প্র ০১Douglas Crockford কেন বলেন তিনি JSON “আবিষ্কার” করেননি, “খুঁজে পেয়েছেন”? এক পাতার একটি ফরম্যাট কীভাবে ওয়েবের ভাষা হলো?
২০০১ সালে Douglas Crockford আর Chip Morningstar State Software নামে একটি ছোট কোম্পানিতে এমন ওয়েব অ্যাপ বানাচ্ছিলেন, যেখানে পাতা পুরো রিলোড না করে সার্ভারের সাথে ডেটা আদান-প্রদান হবে — “AJAX” শব্দটি তখনো জন্মায়নি। সমস্যা ছিল: সার্ভার ডেটা কোন আকারে পাঠাবে? সে সময়ের আনুষ্ঠানিক উত্তর ছিল XML, কিন্তু ব্রাউজারে XML পড়া ছিল ঝামেলার আর ব্রাউজারভেদে আলাদা। তাঁদের মাথায় এলো সহজ একটি চিন্তা: ব্রাউজারে তো JavaScript আছেই, আর JavaScript-এর object literal দিয়ে যেকোনো ডেটা লেখা যায়। সার্ভার যদি ডেটাকে JavaScript-এর সেই আকারে পাঠায়, ব্রাউজার তা সরাসরি বুঝবে। এভাবেই প্রথম JSON বার্তাটি পাঠানো হয় ২০০১ সালের এপ্রিলে।
Crockford-এর যুক্তি হলো, তিনি নতুন কিছু বানাননি — JavaScript-এর ভেতরে যা আগে থেকেই ছিল, তার একটি নিরাপদ, ভাষা-নিরপেক্ষ অংশ বেছে নিয়েছেন, নাম দিয়েছেন আর লিখে রেখেছেন। তাই “discover”. কিন্তু “বেছে নেওয়া”-টাই ছিল আসল নকশা: key সবসময় quote-এ (কারণ JavaScript-এর reserved word key হিসেবে তখন ঝামেলা করত), শুধু double quote, কোনো function নেই, কোনো Date নেই, কোনো comment নেই। প্রতিটি “না” ফরম্যাটটিকে ছোট আর যেকোনো ভাষায় সহজে পড়ার যোগ্য রেখেছে।
২০০২ সালে তিনি json.org প্রকাশ করেন — এক পাতায় রেলপথের মতো ছবি (railroad diagram) দিয়ে পুরো ব্যাকরণ। এত ছোট বলে যেকোনো প্রোগ্রামার এক বিকেলে নিজের ভাষার জন্য parser লিখে ফেলতে পারতেন, আর লিখেছেনও — কয়েক বছরের মধ্যে প্রায় সব প্রধান ভাষার JSON library json.org-এর তালিকায় উঠে আসে। Crockford নিজে লিখেছিলেন json2.js, যা পুরোনো ব্রাউজারে JSON.parse আর JSON.stringify যোগ করত। শেষ পর্যন্ত ২০০৯ সালে ES5 এই দুটিকে ভাষার built-in অংশ করে নেয়, প্রায় একই নকশায়।
আরেকটি মজার দিক: Crockford JSON-এর ব্যাকরণ কখনো বদলাবেন না বলে ঘোষণা দিয়েছিলেন — কোনো সংস্করণ নম্বর নেই, “JSON 2.0” নেই। একটি আদান-প্রদানের ফরম্যাট যত কম বদলায়, তত বেশি প্রোগ্রাম বছরের পর বছর একে অপরকে বুঝতে পারে।
মূল উপলব্ধি: সবচেয়ে সফল মানদণ্ডগুলো প্রায়ই নতুন কিছু বানায় না — বিদ্যমান, পরিচিত জিনিস থেকে ছোট আর স্থির একটি অংশ বেছে নেয়। “কী রাখব না” সিদ্ধান্তটিই JSON-কে সর্বজনীন করেছে।
প্র ০২২০০০-এর দশকে XML ছিল “অফিসিয়াল” ডেটা ফরম্যাট। তবু ওয়েব API-তে JSON কীভাবে জিতল?
২০০০-এর দশকের শুরুতে বড় কোম্পানির সফটওয়্যারের জগতে XML ছিল প্রায় ধর্মের মতো। SOAP নামে একটি XML-ভিত্তিক প্রোটোকল, তার সাথে WSDL, XML Schema, WS-Security-র মতো ভারী মানদণ্ডের এক বিশাল পরিবার — Microsoft, IBM, Sun সবাই এর পেছনে। এমনকি ২০০৫ সালে Jesse James Garrett যখন “AJAX” নাম দিলেন, তার শেষ X ছিল XML-এর জন্য, আর ব্রাউজারের object-টির নামও XMLHttpRequest. তাহলে আজ প্রায় সব নতুন ওয়েব API JSON-এ কেন?
প্রথম কারণ আকার আর পড়ার সুবিধা। একই অর্ডার XML-এ লিখলে প্রতিটি মানের জন্য খোলা আর বন্ধ ট্যাগ লাগে — <qty>2</qty> — ফলে লেখা প্রায়ই অনেক বড় হয়। মোবাইল ইন্টারনেটের যুগে প্রতিটি byte-এর দাম ছিল। দ্বিতীয় কারণ গঠনের মিল। XML হলো document-এর ভাষা — attribute আর child element, mixed content, namespace; একটি তথ্য attribute হবে নাকি element, তা নিয়েই বিতর্ক। প্রোগ্রামের ডেটা কিন্তু সাধারণত শুধু তিনটি জিনিস: object, array আর সাধারণ মান। JSON ঠিক এই তিনটিই দেয়, আর JavaScript, Python, Ruby-র মতো ভাষায় সরাসরি নিজের dictionary বা list হয়ে যায় — কোনো DOM ঘোরাঘুরি নেই।
তৃতীয় কারণ ছিল ব্রাউজার নিজেই। JSON পড়তে প্রথম দিকে শুধু JavaScript-ই যথেষ্ট ছিল (আর পরে built-in JSON.parse, যা দ্রুত)। তার ওপর REST ধাঁচের সহজ API-র জনপ্রিয়তা বাড়ছিল — SOAP-এর ভারী কাঠামোর বদলে সাধারণ URL আর HTTP method. Yahoo, Google-এর মতো কোম্পানি তাদের ওয়েব সার্ভিসে JSON আউটপুট দিতে শুরু করে, আর ২০১২ সালে Twitter তাদের API-র নতুন সংস্করণ 1.1-এ XML বাদ দিয়ে শুধু JSON রাখে।
তবে XML হারিয়ে যায়নি — Microsoft Office-এর .docx ফাইল, SVG ছবি, Android-এর layout, ব্যাংকিংয়ের অনেক পুরোনো ব্যবস্থা এখনো XML. যেখানে ডেটা আসলে “document”, বা যেখানে কড়া schema আর namespace দরকার, সেখানে XML-এর শক্তি এখনো কাজের। JSON জিতেছে ওয়েবের অ্যাপ-থেকে-অ্যাপ ডেটা আদান-প্রদানে।
মূল উপলব্ধি: প্রযুক্তির যুদ্ধে প্রায়ই সবচেয়ে “সম্পূর্ণ” জিনিস জেতে না — জেতে সেটি, যা সবচেয়ে বেশি মানুষের রোজকার কাজকে সবচেয়ে সহজ করে। ডেটার আকার আর ভাষার data structure-এর মিল ছিল JSON-এর আসল জয়।
প্র ০৩JSON-এর মানদণ্ড কে লিখেছে — ECMA-404 নাকি RFC 8259? আর JSON-এ comment রাখা হয়নি কেন?
JSON-এর আনুষ্ঠানিক রূপ আসলে দুটি সংস্থার দুটি দলিল। প্রথম দলিল ২০০৬ সালে IETF-এর RFC 4627 — Crockford নিজেই লেখেন, মূলত application/json media type নিবন্ধনের জন্য। এরপর ২০১৩ সালে Ecma International (যারা JavaScript-এর মানদণ্ড ECMAScript দেখে) প্রকাশ করে ECMA-404 — খুব ছোট একটি দলিল, শুধু ব্যাকরণ। IETF ২০১৪ সালে RFC 7159 আর ২০১৭ সালের ডিসেম্বরে RFC 8259 প্রকাশ করে, যা এখন ইন্টারনেট মানদণ্ড STD 90. দুই দলিলের ব্যাকরণ এক রাখার ব্যাপারে দুই সংস্থা একমত হয়েছে।
পার্থক্য হলো মনোযোগে। ECMA-404 বলে “বৈধ JSON লেখা দেখতে কেমন” — ব্যস। RFC 8259 আরও বলে “বাস্তবে আলাদা প্রোগ্রাম যেন একে অপরকে বোঝে, তার জন্য কী করবেন”: প্রোগ্রামের বাইরে পাঠানো JSON হবে UTF-8; object-এ একই নাম দুবার রাখবেন না, কারণ কোনো parser প্রথমটি নেয়, কোনোটি শেষটি; আর খুব বড় বা খুব নির্ভুল সংখ্যা সব জায়গায় একভাবে পড়া হবে না, কারণ অনেক বাস্তবায়ন number-কে double হিসেবে পড়ে। অংশ ৫-এর বড় ID-র সমস্যাটি এই সতর্কবার্তারই বাস্তব রূপ। পরে RFC 7493 “I-JSON” নামে আরও কড়া একটি উপ-নিয়ম দেয় ইন্টারনেট প্রোটোকলের জন্য।
এবার comment. শুরুর দিকে JSON-এ comment ছিল। Crockford পরে ব্যাখ্যা করেন, তিনি comment সরিয়ে দেন কারণ দেখলেন মানুষ comment-এর ভেতরে parser-এর জন্য নির্দেশনা (parsing directive) লুকিয়ে রাখছে — যেমন “এই অংশটি অমুক নিয়মে পড়ো”. এতে একই ফাইল এক parser-এ এক অর্থ আর অন্যটিতে অন্য অর্থ পেত, যা আদান-প্রদানের ফরম্যাটের মূল উদ্দেশ্যই নষ্ট করে। তাঁর পরামর্শ: config ফাইলে comment চাইলে লিখুন, তারপর parser-এ দেওয়ার আগে JSMin-এর মতো টুল দিয়ে comment মুছে নিন।
সিদ্ধান্তটি আজও বিতর্কিত। মানুষের হাতে লেখা config-এ comment সত্যিই দরকারি — তাই জন্ম নিয়েছে JSON5 (comment, শেষে কমা, single quote চলে), JSONC (VS Code, TypeScript-এর config) আর অনেকে YAML বা TOML-এ চলে গেছেন। কিন্তু যন্ত্র-থেকে-যন্ত্র ডেটায় comment-এর অভাব কেউ টের পায় না, আর সেখানে নিয়মের কড়াকড়ি সত্যিই বিভ্রান্তি কমায়।
মূল উপলব্ধি: একটি ফরম্যাট দুই ধরনের পাঠকের জন্য — মানুষ আর যন্ত্র — একসাথে নিখুঁত হতে পারে না। JSON যন্ত্রের পক্ষে সিদ্ধান্ত নিয়েছে; মানুষের সুবিধার জন্য তার চারপাশে আলাদা ফরম্যাট জন্মেছে।
প্র ০৪বহু বছর ধরে JSON আসলে JavaScript-এর হুবহু উপসেট ছিল না। ES2019-এর “JSON superset” সংশোধন কী, আর কেন দরকার হলো?
JSON-এর নামেই আছে “JavaScript Object Notation”, আর সবাই ধরে নিত প্রতিটি বৈধ JSON লেখা একই সাথে বৈধ JavaScript expression. প্রায় সত্যি — কিন্তু দুটি অক্ষর বাদে: U+2028 (LINE SEPARATOR) আর U+2029 (PARAGRAPH SEPARATOR). দুটি অক্ষরই চোখে দেখা যায় না, Unicode-এ এরা “লাইন বা অনুচ্ছেদ ভাঙা”-র অক্ষর। JSON-এর নিয়মে string-এর ভেতরে এদের সরাসরি (escape ছাড়া) রাখা বৈধ। কিন্তু ES2019-এর আগের JavaScript এদের line terminator ধরত — newline-এর মতো — আর string literal-এর ভেতরে কাঁচা newline নিষেধ। ফলে "a[U+2028]b" বৈধ JSON, অথচ JavaScript কোডে বসালে SyntaxError.
দৈনন্দিন কাজে এটা ধরা পড়ত না, কারণ JSON.parse নিজের নিয়মে পড়ে, JavaScript-এর নিয়মে নয়। সমস্যা হতো যখন কেউ JSON-কে সরাসরি কোডের ভেতরে বসাত — যেমন সার্ভার HTML পাতার <script>-এ var data = {...}; লিখে দিত, বা পুরোনো JSONP কৌশলে (যেখানে উত্তর আসলে একটি function call). ব্যবহারকারীর লেখা কোনো মন্তব্যে কপি-পেস্টের সাথে এই অদৃশ্য অক্ষর ঢুকে গেলে পুরো পাতার script ভেঙে যেত — আর বাগটি খুঁজে পাওয়া ছিল প্রায় অসম্ভব, কারণ অক্ষরটি দেখাই যায় না।
TC39-এ Richard Gibson-এর “Subsume JSON” প্রস্তাব সমাধানটি দেয়: JavaScript-এর string literal-এর ভেতরে U+2028 আর U+2029 বৈধ করে দেওয়া। এটি ES2019-এ যুক্ত হয়, আর তখন থেকে JSON সত্যিই JavaScript-এর উপসেট। একই বছরে আরেকটি সংশোধন আসে — “well-formed JSON.stringify”: আগে একা পড়ে থাকা surrogate (যেমন অর্ধেক কাটা ইমোজি) stringify কাঁচা অবস্থায় লিখত, যা বৈধ UTF-8 নয়; এখন লেখে escape করে, "\ud800".
এই গল্পের শিক্ষা হলো, দুটি মানদণ্ড “প্রায়” মিললে ঝুঁকিটা লুকিয়ে থাকে ঠিক সেই “প্রায়”-এর ফাঁকে। এবং ডেটাকে কোডের ভেতরে বসানোর অভ্যাসটাই আসল ঝুঁকি — আজ নিরাপদ পথ হলো ডেটা আলাদা রাখা আর JSON.parse দিয়ে পড়া।
মূল উপলব্ধি: “X আসলে Y-এর অংশ” ধরনের দাবি পরীক্ষা না করে মেনে নেবেন না। ক্ষুদ্রতম ব্যতিক্রম — দুটি অদৃশ্য অক্ষর — বছরের পর বছর বাস্তব বাগ তৈরি করতে পারে, আর মানদণ্ড ঠিক করতে লেগে যায় পুরো এক প্রস্তাব-প্রক্রিয়া।
প্র ০৫structured clone algorithm ব্রাউজারে বহু বছর ছিল, তবু structuredClone() function এলো ২০২১–২২ সালে। এত দেরি কেন, আর এর সাথে Web Worker-এর সম্পর্ক কী?
HTML মানদণ্ডে “structured clone” নামে একটি algorithm অনেক আগে থেকেই আছে। এর কাজ: একটি JavaScript মানকে এমনভাবে কপি করা, যাতে সেটি অন্য একটি “জগতে” পাঠানো যায় — অন্য window-এ, অন্য thread-এ, বা ডিস্কে। window.postMessage দিয়ে অন্য tab বা iframe-কে বার্তা পাঠানো, Web Worker-কে ডেটা দেওয়া (পর্ব ৪২), IndexedDB-তে object রাখা, history.pushState-এ অবস্থা রাখা — সবখানে ব্রাউজার ভেতরে এটিই চালায়। কারণ worker আলাদা thread-এ চলে, তার মেমরি আলাদা; একই object দুই thread-এ ভাগাভাগি করলে data race হতো (পর্ব ০৫-এর single-threaded মডেল ভেঙে পড়ত)। তাই ডেটা পাঠানো মানে কপি পাঠানো।
মজার ব্যাপার হলো, algorithm-টি ব্রাউজারের ভেতরে থাকলেও প্রোগ্রামারের হাতে সরাসরি ডাকার কোনো function ছিল না। ফলে deep copy লাগলে মানুষ হয় JSON-কৌশল ব্যবহার করত (সব ক্ষতিসহ), নয়তো lodash-এর cloneDeep-এর মতো library, নয়তো অদ্ভুত কৌশল — একটি MessageChannel বানিয়ে নিজেকেই বার্তা পাঠানো, শুধু কপিটি ফেরত পাওয়ার জন্য। বছরের পর বছর এই চাহিদা জমতে থাকে।
শেষে HTML মানদণ্ডে global structuredClone() যোগ হয়, আর দ্রুত সব জায়গায় পৌঁছায়: Firefox 94 (২০২১-এর নভেম্বর), Node.js 17 (২০২১-এর অক্টোবর), Chrome ও Edge 98 (২০২২-এর ফেব্রুয়ারি), Safari 15.4 (২০২২-এর মার্চ)। এর সাথে আছে transfer option — বড় ArrayBuffer কপি না করে মালিকানা হস্তান্তর, যা worker-এ বড় ছবি বা অডিও পাঠাতে কাজে লাগে।
Algorithm-টির সীমাগুলোও এই ইতিহাস থেকেই বোঝা যায়। Function কপি হয় না, কারণ function-এর সাথে তার closure (পর্ব ২২) — চারপাশের variable-এর জগৎ — জড়িয়ে থাকে, যা অন্য thread-এ নেওয়ার অর্থ হয় না। DOM node কপি হয় না, কারণ worker-এ DOM নেই। আর class-এর prototype হারায়, কারণ অন্য জগতে সেই class-এর সংজ্ঞা থাকবেই, এমন নিশ্চয়তা নেই।
মূল উপলব্ধি: structuredClone-এর নিয়ম মানে “অন্য জগতে কী পাঠানো যায়”-এর নিয়ম। যে ডেটা structuredClone-এ টেকে, সেটি worker, IndexedDB আর postMessage-এও টেকে — তাই এটি শুধু কপির টুল নয়, ডেটার বহনযোগ্যতার পরীক্ষাও।
অনুশীলন
বেশিরভাগ কাজ browser console-এ (F12) কয়েকটি লাইন লিখেই করা যায় — ফল আগে অনুমান করুন, তারপর মিলিয়ে নিন।
-
ফল অনুমান করুন: (ক)
JSON.stringify([1, undefined, NaN])(খ)JSON.stringify({ a: undefined, b: null })(গ)JSON.stringify(new Map([["x", 1]]))(ঘ)JSON.parse("null")(ঙ)JSON.stringify("হ্যালো \"বন্ধু\"")(চ)typeof JSON.parse(JSON.stringify({ d: new Date(0) })).d(ক)
"[1,null,null]"— array-তে undefined আর NaN দুটোই null. (খ)'{"b":null}'— undefined key বাদ, null থাকে। (গ)"{}"— Map-এর ডেটা নিজস্ব property-তে নেই। (ঘ)null— একা null বৈধ JSON. (ঙ)'"হ্যালো \"বন্ধু\""'— বাংলা অক্ষর যেমন আছে, ভেতরের double quote escape হয়েছে। (চ)"string"— Date লেখায় ISO string হয়, ফেরত আসে string হয়েই। -
ভাঙা config সারান: একজন সহকর্মী হাতে এই
settings.jsonলিখেছেন, আর অ্যাপ চালু হচ্ছে না। কতগুলো ভুল আছে, আর ঠিক রূপটি কী?{ appName: 'দোকান', // নাম
"maxItems": 012, "taxRate": .15, "debug": True, "tags": ["new", "sale",], }অন্তত আটটি: (১)
appNamekey-তে quote নেই; (২) মানে single quote; (৩)// নামcomment; (৪)012-এ শুরুর শূন্য; (৫).15-এ শুরুতে অঙ্ক নেই; (৬)True— JSON-এ ছোট হাতেরtrue; (৭) tags-এর শেষে বাড়তি কমা; (৮) object-এর শেষে বাড়তি কমা। ঠিক রূপ:{"appName": "দোকান", "maxItems": 12, "taxRate": 0.15, "debug": true, "tags": ["new", "sale"]}. মন্তব্য রাখতেই হলে আলাদা"_comment"field বা JSONC/JSON5 ফরম্যাট বিবেচনা করুন। শিক্ষা: হাতে লেখা JSON-এ VS Code বাJSON.parseদিয়ে আগে যাচাই করুন — প্রথম ভুলেই parser থেমে যায়, তাই একবারে একটি করেই ভুল দেখায়। -
ফোন নম্বর ঢেকে দিন (কোড লিখুন): একটি replacer function লিখুন, যা যেকোনো স্তরে
phonekey পেলে শেষের ৩টি অঙ্ক ছাড়া বাকি সব*দিয়ে ঢেকে দেয়, আরpasswordkey পুরো বাদ দেয়। পরীক্ষা করুন:{ name: "রিনা", phone: "01711223344", password: "x", friend: { phone: "01999887766" } }.একটি সমাধান:
const mask = (key, value) => key === "password" ? undefined : key === "phone" && typeof value === "string" ? "*".repeat(value.length - 3) + value.slice(-3) : value;তারপরJSON.stringify(data, mask)দেয়{"name":"রিনা","phone":"********344","friend":{"phone":"********766"}}. Replacer প্রতিটি স্তরে ডাকা হয় বলে nestedfriend.phone-ও ঢাকা পড়েছে।typeof value === "string"যাচাই জরুরি — কেউ ফোন number হিসেবে রাখলে.sliceTypeError দিত (আর ফোন নম্বর number হিসেবে রাখাই ভুল — শুরুর 0 হারায়)। ভাবুন: এখানে “কী লুকাব” তালিকা ব্যবহার করা হয়েছে; log-এর জন্য allow-list কেন আরও নিরাপদ হতো? -
AI অডিট: যেকোনো AI-কে বলুন “JavaScript-এ একটি deepClone ফাংশন লেখো।” তারপর তার উত্তর এমন একটি object দিয়ে পরীক্ষা করুন, যাতে Date, Map, NaN, undefined আর একটি চক্র (
obj.self = obj) আছে। কী ভাঙল, আর কোন এক লাইন দিয়ে পুরো ফাংশনটি বদলানো যায়?সাধারণত AI দুটির একটি দেয়: (ক)
JSON.parse(JSON.stringify(obj))— চক্রেTypeError: Converting circular structure to JSON, আর চক্র সরালেও Date string হয়, Map{}, NaN null, undefined key উধাও। (খ) নিজে লেখা recursive function —typeof v === "object"দেখে{}-তে কপি; এতে Date আর Map সাধারণ খালি object হয়ে যায়, আর চক্রে অন্তহীন recursion — শেষেRangeError: Maximum call stack size exceeded. পুরো ফাংশনের বদলে এক লাইন:structuredClone(obj)— সব টাইপ আর চক্র অক্ষত। তবে object-এ function থাকলে DataCloneError আসবে; সেটা ভালো লক্ষণ — নীরবে হারানোর চেয়ে জোরে ব্যর্থ হওয়া ভালো।
নিজেকে যাচাই করুন
ভুল হলে কারণসহ ব্যাখ্যা পাবেন, আবার চেষ্টাও করতে পারবেন।
ক্রমএকটি API থেকে আসা অর্ডারের উত্তর নিরাপদে ব্যবহারের ধাপগুলো সঠিক ক্রমে সাজান (▲▼ চেপে সরান)
- উত্তরটি লেখা (string) হিসেবে হাতে পাওয়া
- try/catch-এর ভেতরে JSON.parse — ভাঙা লেখা হলে পরিষ্কার error
- Reviver দিয়ে ISO তারিখের string-কে Date বানানো
- আকার আর টাইপ যাচাই — items array কি না, দাম আর পরিমাণ সংখ্যা কি না
- যাচাই করা ডেটা দিয়ে মোট দাম হিসাব করে দেখানো
নিচের কোনটি বৈধ JSON লেখা?
{'qty': 2}{"qty": 2,}{"qty": 2}{qty: 2}
JSON.stringify({ a: undefined, b: () => 1, c: NaN })-এর ফল কী?
'{"a":undefined,"b":null,"c":NaN}''{"c":null}''{}'- TypeError
JSON.stringify({ tags: new Set(["a", "b"]) }) কী দেয়?
'{"tags":["a","b"]}'- TypeError
'{}''{"tags":{}}'
একটি object-এর createdAt property-তে Date আছে। JSON.parse(JSON.stringify(obj)).createdAt-এর টাইপ কী হবে?
- string
- Date
- number
- undefined
একটি object-এর একটি property-তে function আছে। structuredClone দিয়ে object-টি কপি করলে কী হয়?
- Function-এর key নীরবে বাদ পড়ে
- Function-সহ পুরো কপি হয়
- DataCloneError ছোড়ে
- শুধু shallow copy হয়
বাইরের API থেকে আসা JSON লেখা JavaScript-এ পড়ার সবচেয়ে নিরাপদ পথ কোনটি?
eval("(" + text + ")")- try/catch-এর ভেতরে
JSON.parse, তারপর আকার ও টাইপ যাচাই new Function("return " + text)()- try/catch বা যাচাই ছাড়া সরাসরি
JSON.parse
শব্দকোষ
লেখার মধ্যে ডটেড দাগ দেওয়া শব্দে মাউস রাখুন বা চাপুন — অর্থ দেখাবে। এই পর্বের সব নতুন শব্দ এখানে একসাথে:
মনে রাখুন
- JSON হলো লেখা: double quote, শেষে কমা নেই, comment নেই, মান মাত্র ছয় ধরনের — string, number, boolean, null, array, object.
JSON.parseবাইরের লেখায় সবসময় try/catch-এর ভেতরে; তারিখ ফেরাতে reviver, আর parse-এর পর আকার ও টাইপ যাচাই.JSON.stringify-এ indentation (null, 2), গোপন field সরাতে allow-list replacer, নিজের class-এর লেখার রূপ ঠিক করতেtoJSON.- Round trip-এ undefined/function বাদ, NaN → null, Date → string, Map/Set →
{}; BigInt আর চক্রে TypeError; বড় ID string. - Deep copy মানে
structuredClone— function, DOM node আর class-এর পরিচয় ছাড়া প্রায় সব টেকে;evalকখনো নয়,"__proto__"key মেশানোর আগে সাবধান।
আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ
- পর্ব ২০ · তারিখ, সময় আর Intl — বাংলায় ফরম্যাটপরবর্তী পর্বDate, time zone আর বাংলায় তারিখ-সময় সাজানো।
- JavaScript প্রোগ্রামিং · কোর্স হোম৫৯টি পর্বপুরো কোর্সের রোডম্যাপ — কোন পর্ব কখন।
- Python · CSV আর JSONপাশের ট্র্যাকএকই JSON, আরেক ভাষার চোখে — json module আর JSON Lines.
- Database Management Systems & SQLগভীরে যানডেটা কোথায় আর কোন আকারে রাখা হয় — টেবিল থেকে JSON কলাম।
- System Designপাশের ট্র্যাকবড় সিস্টেমে সার্ভিসগুলো কীভাবে API আর ডেটা ফরম্যাট দিয়ে কথা বলে।