دعنا نقول أن لدينا كائن معقد ونريد تحويله إلى نص (string) لإرساله عن طريق شبكة الإنترنت أو أن نطبعه فقط.
من المفترض أن يحتوى النص هذا على كل الخصائص المهمه للكائن.
يمكننا إجراء التحويل كالآتى:
let user = {
name: "John",
age: 30,
toString() {
return `{name: "${this.name}", age: ${this.age}}`;
}
};
alert(user); // {name: "John", age: 30}
…ولكن عند التطبيق العملى يتم إضافة خصائص جديده أو إعادة تسمية خصائص قديمه أو إزالتها. فتحديث النص عن طريق الدالة toString كل مرة سيكون صعبًا. يمكننا أن نقوم بالتكرار على كل الخصائص فى هذا الكائن ولكن ماذا إذا كان هذا الكائن معقدًا ويحتوى على كائنات أخرى بداخله؟ يجب أن نقوم بتحويلهم أيضًا.
لحسن الحظ، ليس هناك حاجه لكتابة كود يقوم بالتعامل مع ذلك. فقد تم حل هذه المشكله بالفعل.
JSON.stringify
إن الكائن JSON (JavaScript Object Notation) هو شكل عام لعرض الكائنات والقيم. وقد تم وصفه كما فى ال RFC 4627. لقد صُنع فى البداية من أجل جافا سكريبت، ولكن هناك لغات ومكتبات أخرى للتعامل معه أيضًا. ولذلك من السهل استخدام الكائن JSON لتبادل البيانات عندما تكون الواجهة بجافا سكريبت والسيرفر / الباك اند بلغة مثل Ruby/PHP/Java أو أيًا كان.
تحتوى جافا سكريبت على دوال للتعامل مع الكائن JSON:
JSON.stringifyلتحويل الكائن إلى جيسون.JSON.parseلتحويل الجيسون مرة أخرى إلى كائن.
على سبيل المثال، هنا قمنا بتحويل الكائن student باستخدام JSON.stringify:
let student = {
name: 'John',
age: 30,
isAdmin: false,
courses: ['html', 'css', 'js'],
wife: null
};
let json = JSON.stringify(student);
alert(typeof json); // لدينا نص!
alert(json);
/* JSON-encoded object:
{
"name": "John",
"age": 30,
"isAdmin": false,
"courses": ["html", "css", "js"],
"wife": null
}
*/
تستقبل الدالة JSON.stringify(student) كائنًا وتحوّله إلى نص.
والجيسون الناتج عن ذلك يسمى JSON-encoded object أو serialized object أو stringified object أو marshalled object. والآن يمكننا أن نرسله عن طريق الشبكة أو نضعه فى مكان ما لتخزين البيانات.
لاحظ أن الكائن المحوَّل يختلف عن الكائن العادى فى عدة نقاط:
- النصوص تستخدم العلامات النصيه
""ولا توجد العلامه المفرده''أو هذه. فإن'John'يتحول إلى"John". - أسماء الخواص فى الكائن تكون محاطه بالعلامه النصيه الثنائية أيضًا
"". ولذلك فإنage:30يتحول إلى"age":30.
ويمكن استخادم JSON.stringify مع القيم المفردة أيضًا وليس مع الكائنات فقط.
يدعم الجيسون أنواع البيانات الآتية:
- الكائنات
{ ... } - القوائم (arrays)
[ ... ] - القيم المفردة (Primitives):
- النصوص (strings),
- الأرقام,
- القيم المنطقيه (booleans)
true/false, null.
على سبيل المثال:
// الرقم المحوِّل إلى جيسون هو رقم أيضًا
alert(JSON.stringify(1)); // 1
// النص المحوَّل إلى جيسون هو نصٌ أيضًا ولكن محاط بعلامة التنصيص الثنائية ""
alert(JSON.stringify('test')); // "test"
alert(JSON.stringify(true)); // true
alert(JSON.stringify([1, 2, 3])); // [1,2,3]
الجيسون يستخدم خصيصًا لعرض البيانات فقط ولذلك فإن بعض خصائص الكائنات فى جافا سكريبت يتم تخطيها عند استخدام JSON.stringify.
وهى:
- Function properties (methods).
- Symbolic keys and values.
- Properties that store
undefined.
let user = {
sayHi() {
// يتم تجاهلها
alert('Hello');
},
[Symbol('id')]: 123, // يتم تجاهلها
something: undefined, // يتم تجاهلها
};
alert(JSON.stringify(user)); // {} (كائن فارغ)
عادةً ما يكون هذا جيدً. وإذا لم يكن هذا مانريده، إذا سنرى قريبًا كيف يمكن أن نعدل هذه العملية لصالحنا.
الشئ الجيد هنا أن الكائنات الموجوده بداخل أخرى مدعومة ويتم تحويلها تلقائيًا.
على سبيل المثال:
let meetup = {
title: "Conference",
room: {
number: 23,
participants: ["john", "ann"]
}
};
alert( JSON.stringify(meetup) );
/* الشكل بالكامل تم تحويله إلى نص:
{
"title":"Conference",
"room":{"number":23,"participants":["john","ann"]},
}
*/
هناك شئ مهم يمنع هذا: وهو أنه لابد أن لا يحتوى الكائن على كائن هو أيضًا يحتوى على الكائن الأول.
على سبيل المثال:
let room = {
number: 23
};
let meetup = {
title: "Conference",
participants: ["john", "ann"]
};
meetup.place = room; // meetup يحتوى على room
room.occupiedBy = meetup; // room يحتوى على meetup
JSON.stringify(meetup); // خطأ: Converting circular structure to JSON
فى هذه الحالة يفضل التحويل وهذا بسبب احتواء كل كائن على آخر (circular reference): room.occupiedBy تحتوى على meetup، و meetup.place تحتوى على room
Excluding and transforming: replacer
كيفية استخدام JSON.stringify هو كالآتى:
let json = JSON.stringify(value[, replacer, space])
- value
- هي القيمة التى ستحوَّل.
- replacer
- قائمة (array) من الخصائص لتحويلها أو دالة لتنفيذعا على كل خاصية.
- space
- كم المسافه التى يجب استخدامها من أجل التنظيم.
فى أغلب الوقت تُستخدم JSON.stringify مع أول متغير فقط، ولكن إذا أردنا أن نتحكم فى كيفية عمل هذه الدالة، مثل التحقق من وجود كائن بداخل آخر يحتوى على هذا الكائن والعكس (circular references)، إذًا يمكننا استخدام المتغير الثاني للدالة JSON.stringify.
إذا مررنا قائمة من الخصائص للدالة، فسيتم تحويل قيم هذه الخصائص فقط.
على سبيل المثال:
let room = {
number: 23
};
let meetup = {
title: "Conference",
participants: [{name: "John"}, {name: "Alice"}],
place: room // meetup يحتوى علي room
};
room.occupiedBy = meetup; // room يحتوى علي meetup
alert( JSON.stringify(meetup, ['title', 'participants']) );
// {"title":"Conference","participants":[{},{}]}
هنا نحن محَدَّدين. حيث أن القائمة المُمرَّرة هي للكائن بأكمله ولذلك فإن الكائنات بداخل participants فارغة لأن الخاصية name ليست فى القائمة.
هيا نحِّل كل الخصائص عدا room.occupiedBy والتى يمكن أن تسبب المرجع الدائرى (circular reference):