بازگشت به دوره

کار با JSON در جاوا اسکریپت

در بخش قبل با قالب JSON و نحوه‌ی ذخیره‌سازی داده‌ها با این قالب آشنا شدیم. همچنین اشاره شد که قالب JSON در جاوا اسکریپت بیشتر برای تبادل داده‌ها به کار می‌رود. در فصل بعدی خواهیم دید که تبادل داده‌ها با JSON نقش بسیار مهمی در تکنیک Ajax دارد. اما در این بخش قصد داریم با امکانات جاوا اسکریپت در زمینه‌ی پردازش داده‌های JSON آشنا شویم. یعنی امکان تبدیل داده‌های جاوا اسکریپت به قالب JSON، و امکان تبدیل داده‌های JSON به داده‌های جاوا اسکریپت.

 

شئ JSON

در استاندارد ECMAScript 5 شیئی به نام JSON به این استاندارد اضافه شده است. با استفاده از متدهای این شئ می‌توان داده‌های JSON را به داده‌های جاوا اسکریپت و یا داده‌های جاوا اسکریپت را به داده‌های JSON (یا رشته‌های JSON) تبدیل کرد. توجه کنید که شئ JSON مانند شئ Math یک شئ Singleton است. یعنی فقط یک شئ از این نوع در یک برنامه وجود دارد. و برای استفاده از متدهای این شئ نیازی به ایجاد اشیائی از نوع JSON با عملگر new نیست.

 

متد stringify

فرض کنید شئ زیر را در یک برنامه‌ی جاوا اسکریپت ایجاد کرده‌اید.


let book = {
	title: 'JavaScript: Beginner to Advanced',
	author: {
		firstname: 'Abbas',
		lastname: 'Moqaddam'
	},
	year: 2019
}

برای تبدیل این شئ به یک رشته‌ی JSON می‌توان از متد stringify استفاده کرد. قطعه کد زیر ابتدا شئ book را به یک رشته‌ی JSON تبدیل کرده و در متغیر jBook ذخیره می‌کند. سپس این رشته را در کنسول نمایش می‌دهد.


let jBook = JSON.stringify(book);
console.log(jBook);
← '{"title":"JavaScript: Beginner to Advanced","author":{"firstname":"Abbas","lastname":"Moqaddam"},"year":2019}'

توجه کنید که خروجی متد stringify یک رشته است. این رشته را می‌توان برای مقاصد مختلف به کار برد. مثلاً می‌توان آن را با تکنیک Ajax به سرور ارسال کرد. و یا آن را در یک فایل JSON ذخیره کرد. البته در مرورگرها معمولاً ذخیره‌سازی به صورت فایل انجام نمی‌شود.

نکته : هنگام تبدیل اشیاء جاوا اسکریپت به رشته‌های JSON توسط متد stringify، از تمام متدها صرف‌نظر می‌شود. یعنی فقط خاصیت‌های اشیاء در رشته‌ی خروجی ظاهر می‌شوند.

متد stringify در مجموع دارای ۳ پارامتر ورودی است که فقط پارامتر ورودی اول اجباری است و دو پارامتر بعدی اختیاری هستند. با استفاده از دو پارامتر بعدی می‌توان کنترل بیشتری بر روی نحوه‌ی تولید رشته‌ی JSON اعمال کرد.

با استفاده از آرگومان دوم می‌توان خاصیت‌هایی که باید در خروجی ظاهر شوند را مشخص کرد. این آرگومان که replacer نام دارد می‌تواند یک آرایه یا یک تابع باشد. در صورت استفاده از یک آرایه، فقط خاصیت‌هایی که نامشان در آرایه موجود است در خروجی ظاهر می‌شوند. به عنوان مثال دستور زیر فقط خاصیت‌های title و year را در خروجی قرار می‌دهد و از سایر خاصیت‌ها صرف‌نظر می‌کند.


let jBook = JSON.stringify(book , ['title' , 'year']);
console.log(jBook);
← '{"title":"JavaScript: Beginner to Advanced","year":2019}'

اما با ارسال یک تابع به عنوان آرگومان دوم به متد stringify می‌توان کنترل بیشتری بر روی نحوه‌ی تولید رشته‌ی خروجی اعمال کرد. این تابع باید دارای دو پارامتر ورودی باشد. این ورودی‌ها به ترتیب key و value نامیده می‌شوند. در واقع به ازای تمام خاصیت‌های شئ ارسال شده به متد stringify، یک بار تابع replacer فراخوانی می‌شود. و در هر فراخوانی نام و مقدار یکی از خاصیت‌ها در پارامترهای key و value قرار می‌گیرد. حال می‌توان با بررسی key و value تصمیم گرفت که خاصیت مورد نظر باید در خروجی باشد یا حذف شود. در این حالت حتی می‌توان مقدار هر خاصیت را در صورت نیاز تغییر داد.

در صورتی که قصد حذف کردن یک خاصیت را داشته باشیم باید مقدار undefined را به عنوان خروجی از تابع بازگردانیم. به عنوان مثال تابع زیر تمام خاصیت‌هایی که از نوع عددی باشند را حذف می‌کند. (در این مثال خاصیت year)


function replacer(key, value) {
	if (typeof value === 'number') {
		return undefined;
	}
	return value;
}
let jBook = JSON.stringify(book , replacer);
console.log(jBook);
← '{"title":"JavaScript: Beginner to Advanced","author":{"firstname":"Abbas","lastname":"Moqaddam"}}'

توجه کنید که به ازای تمام خاصیت‌هایی که باید در خروجی باقی بمانند حتماً باید مقداری توسط تابع replacer بازگردانده شود. به همین دلیل در خط آخر تابع فوق مقدار value از تابع بازگردانده شده است. همچنین در صورت نیاز می‌توان مقداری غیر از value را به عنوان مقدار خاصیت مورد نظر بازگرداند.

با استفاده از آرگومان سوم متد stringify نیز می‌توان با ایجاد خطوط جدید و تورفتگی، ظاهر رشته‌ی خروجی را زیباتر و خواناتر کرد. البته این کار معمولاً زمانی انجام می‌شود که نیاز به خواندن رشته‌ی JSON توسط انسان باشد. مقدار این آرگومان باید یک عدد صحیح (حداکثر 10) یا یک رشته باشد.

در صورت استفاده از یک عدد صحیح، به ازای هر سطح از اشیاء تو در تو، به تعداد مشخص شده فضای خالی (Space) در ابتدای خط ایجاد می‌شود. به عنوان مثال دستور زیر شئ book را به یک رشته‌ی JSON تبدیل کرده و در ابتدای هر سطر، به ازای هر سطح ۲ فضای خالی ایجاد می‌کنید.


let jBook = JSON.stringify(book , null , 2);

توجه کنید که مقدار آرگومان دوم null قرار داده شده است. در صورتی که فقط قصد استفاده از آرگومان سوم را داشته باشیم و نیازی به فیلتر کردن خاصیت‌ها نداشته باشیم، باید مقدار آرگومان دوم را null قرار دهیم. خروجی دستور فوق به شکل زیر خواهد بود.


{
  "title": "JavaScript: Beginner to Advanced",
  "author": {
    "firstname": "Abbas",
    "lastname": "Moqaddam"
  },
  "year": 2019
}

مشاهده می‌کنید که میزان تورفتگی به ازای هر سطح ۲ کاراکتر است. همچنین در صورت نیاز می‌توان یک رشته را به عنوان آرگومان سوم به متد stringify ارسال کرد. در این صورت به جای فضای خالی از رشته‌ی مورد نظر استفاده می‌شود. یعنی به ازای هر سطح، یک بار از رشته‌ی مورد نظر استفاده می‌شود. به عنوان مثال در دستور زیر از دو کاراکتر خط تیره به همراه دو کاراکتر Space به عنوان آرگومان سوم استفاده شده است.


let jBook = JSON.stringify(book , null , '- - ');

نتیجه‌ی اجرای این دستور رشته‌ی زیر خواهد بود.


{
- - "title": "JavaScript: Beginner to Advanced",
- - "author": {
- - - - "firstname": "Abbas",
- - - - "lastname": "Moqaddam"
- - },
- - "year": 2019
}

واضح است که رشته‌ی فوق، یک رشته‌ی معتبر JSON نیست. بنابراین این حالت زمانی کاربرد دارد که رشته‌ی JSON فقط توسط انسان خوانده شود. زیرا مفسرهای JSON چنین رشته‌ای را نمی‌توانند تفسیر کنند.

 

متد parse

شئ JSON متد دیگری به نام parse دارد که دقیقاً عمل معکوس متد stringify را انجام می‌دهد. یعنی یک رشته‌ی JSON را به عنوان ورودی دریافت می‌کند. و یک شئ یا آرایه‌ی جاوا اسکریپت را بازمی‌گرداند. به عنوان مثال قطعه کد زیر یک شئ جدید را از روی یک رشته‌ی JSON ایجاد کرده و در متغیر book ذخیره می‌کند.


let str = '{"title":"JavaScript: Beginner to Advanced","author":{"firstname":"Abbas","lastname":"Moqaddam"},"year":2019}';
let book = JSON.parse(str);

شئ ایجاد شده با دستورات فوق، دقیقاً معادل شیئی است که در مثال اول این بخش تعریف شده بود. برای اعمال کنترل بیشتر بر روی نحوه‌ی تولید شئ خروجی، می‌توان یک تابع را به عنوان آرگومان دوم به متد parse ارسال کرد. این تابع که reviver نام دارد، مشابه تابع replacer در متد stringify رفتار می‌کند. یعنی به ازای تمام خاصیت‌های موجود در رشته‌ی JSON یک بار فراخوانی می‌شود. و در هر فراخوانی نام و مقدار یکی از خاصیت‌ها به این تابع ارسال می‌شود. در بدنه‌ی این تابع می‌توان با بررسی مقدار موجود در پارامترهای key و value تصمیم مناسب را در مورد هر خاصیت اتخاذ کرد.

در صورتی که مقدار undefined به ازای یک خاصیت بازگردانده شود، خاصیت مورد نظر از خروجی حذف می‌شود. و در صورت بازگرداندن هر مقداری غیر از undefined، همان مقدار در خاصیت مورد نظر ذخیره می‌شود. البته معمولاً مقدار بازگشتی از تابع reviver، به ازای خاصیت‌هایی که قصد حذف کردن آنها را نداریم، همان مقدار value است. اما در صورت نیاز می‌توان مقداری متفاوت را از این تابع بازگرداند. به عنوان مثال رشته‌ی JSON زیر را در نظر بگیرید.


let str = `{
	"title": "JavaScript: Beginner to Advanced",
	"author": {
		"firstname": "Abbas",
		"lastname": "Moqaddam"
	},
	"year": 2019,
	"releaseDate": "2019-09-21"
}`;

در صورت استفاده از تابع زیر به عنوان reviver، مقدار خاصیت releaseDate در شئ خروجی یک رشته نخواهد بود. بلکه یک شئ از نوع Date خواهد بود.


function reviver(key, value){
	if (key == "releaseDate"){
		return new Date(value);
	} else {
		return value;
	}
}

حال با استفاده از دستورات زیر رشته‌ی str را به یک شئ جاوا اسکریپت تبدیل کرده و نوع خاصیت releaseDate را نیز به نوع Date تغییر می‌دهیم.


const book = JSON.parse(str , reviver)
console.log(book.releaseDate.getFullYear());
← 2019

مشاهده می‌کنید که با توجه به تبدیل شدن خاصیت releaseDate به نوع Date، می‌توان از متدهای شئ Date برای دسترسی به اجزاء تاریخ ذخیره شده در این خاصیت استفاده کرد. این مثال را می‌توانید اینجا در CodePen اجرا کنید.

در این بخش با امکانات جاوا اسکریپت برای کار با JSON آشنا شدیم. در فصل بعد خواهیم دید که چطور با استفاده از این امکانات، می‌توان داده‌ها را بین مرورگر و سرور مبادله کرد.