لنفترض أن لدينا كائنًا معقدًا، ونرغب في تحويله إلى سلسلة، أو إرساله عبر شبكة، أو مجرد إخراجه لأغراض التسجيل.
وبطبيعة الحال، يجب أن تتضمن هذه السلسلة جميع الخصائص المهمة.
يمكننا تنفيذ التحويل مثل هذا:
السماح للمستخدم = { الاسم: "جون"، العمر: 30, إلى سلسلة () { إرجاع `{اسم: "${this.name}"، العمر: ${this.age}}`؛ } }; تنبيه (المستخدم)؛ // {الاسم: "جون"، العمر: 30}
…ولكن في عملية التطوير، تتم إضافة خصائص جديدة، وإعادة تسمية العقارات القديمة وإزالتها. يمكن أن يصبح تحديث مثل toString
في كل مرة أمرًا مؤلمًا. يمكننا أن نحاول تكرار الخصائص فيه، ولكن ماذا لو كان الكائن معقدًا ويحتوي على كائنات متداخلة في الخصائص؟ سنحتاج إلى تنفيذ تحويلهم أيضًا.
لحسن الحظ، ليست هناك حاجة لكتابة التعليمات البرمجية للتعامل مع كل هذا. لقد تم حل المهمة بالفعل.
يعد JSON (JavaScript Object Notation) تنسيقًا عامًا لتمثيل القيم والكائنات. تم وصفه كما هو الحال في معيار RFC 4627. في البداية تم تصميمه خصيصًا لجافا سكريبت، ولكن العديد من اللغات الأخرى لديها مكتبات للتعامل معها أيضًا. لذلك من السهل استخدام JSON لتبادل البيانات عندما يستخدم العميل JavaScript ويكون الخادم مكتوبًا على Ruby/PHP/Java/Whatever.
توفر جافا سكريبت الطرق:
JSON.stringify
لتحويل الكائنات إلى JSON.
JSON.parse
لتحويل JSON مرة أخرى إلى كائن.
على سبيل المثال، هنا نقوم JSON.stringify
للطالب:
دع الطالب = { الاسم: "جون"، العمر: 30, المشرف: خطأ، الدورات: ['html'، 'css'، 'js']، الزوج: لا شيء }; دع json = JSON.stringify(student); تنبيه (نوع json)؛ // لدينا سلسلة! تنبيه (json)؛ /* كائن مشفر بـ JSON: { "الاسم": "جون"، "العمر": 30، "isAdmin": خطأ، "الدورات": ["html"، "css"، "js"]، "الزوج": لا شيء } */
تأخذ الطريقة JSON.stringify(student)
الكائن وتحوله إلى سلسلة.
تسمى سلسلة json
الناتجة كائنًا مشفرًا بـ JSON أو متسلسلًا أو مقيدًا أو منظمًا . نحن على استعداد لإرساله عبر السلك أو وضعه في مخزن بيانات عادي.
يرجى ملاحظة أن الكائن المشفر بـ JSON له عدة اختلافات مهمة عن الكائن الحرفي:
تستخدم السلاسل علامات الاقتباس المزدوجة. لا توجد علامات اقتباس مفردة أو علامات خلفية في JSON. لذلك يصبح 'John'
"John"
.
يتم أيضًا وضع علامات اقتباس مزدوجة على أسماء خصائص الكائنات. هذا واجب. لذا age:30
يصبح "age":30
.
يمكن تطبيق JSON.stringify
على العناصر الأولية أيضًا.
يدعم JSON أنواع البيانات التالية:
الكائنات { ... }
المصفوفات [ ... ]
البدائيون:
سلاسل,
أرقام،
القيم المنطقية true/false
،
null
.
على سبيل المثال:
// الرقم في JSON هو مجرد رقم تنبيه(JSON.stringify(1)) // 1 // لا تزال السلسلة النصية في JSON عبارة عن سلسلة نصية، ولكنها تحتوي على علامتي اقتباس مزدوجتين تنبيه (JSON.stringify('اختبار')) // "اختبار" تنبيه (JSON.stringify(صحيح))؛ // حقيقي تنبيه( JSON.stringify([1, 2, 3])); // [1،2،3]
JSON عبارة عن مواصفات مستقلة عن اللغة للبيانات فقط، لذا يتم تخطي بعض خصائص الكائنات الخاصة بـ JavaScript بواسطة JSON.stringify
.
وهي:
خصائص الوظيفة (الأساليب).
المفاتيح والقيم الرمزية.
الخصائص التي تخزن undefined
.
السماح للمستخدم = { sayHi() { // تم التجاهل تنبيه("مرحبا"); }, [الرمز ("المعرف")]: 123، // تم التجاهل شيء: غير محدد // تم تجاهله }; تنبيه (JSON.stringify(user)); // {} (كائن فارغ)
عادة هذا جيد. إذا لم يكن هذا ما نريده، فسنرى قريبًا كيفية تخصيص العملية.
والشيء الرائع هو أن الكائنات المتداخلة يتم دعمها وتحويلها تلقائيًا.
على سبيل المثال:
دع اللقاء = { العنوان: "المؤتمر"، غرفة: { العدد: 23، المشاركون: ["جون"، "آن"] } }; تنبيه (JSON.stringify (لقاء))؛ /* الهيكل بأكمله مقيد: { "العنوان": "مؤتمر"، "الغرفة":{"number":23,participants":["john"،"ann"]}, } */
القيد المهم: يجب ألا تكون هناك مراجع دائرية.
على سبيل المثال:
اترك مساحة = { الرقم: 23 }; دع اللقاء = { العنوان: "المؤتمر"، المشاركون: ["جون"، "آن"] }; meetup.place = الغرفة; // غرفة مراجع اللقاء Room.OccupiedBy = meetup; // لقاء مراجع الغرفة JSON.stringify(meetup); // خطأ: تحويل البنية الدائرية إلى JSON
هنا، يفشل التحويل، بسبب المرجع الدائري: room.occupiedBy
meetup
و meetup.place
room
بناء الجملة الكامل لـ JSON.stringify
هو:
دع json = JSON.stringify (القيمة [، البديل، المسافة])
قيمة
قيمة للتشفير.
بديل
مجموعة من الخصائص المراد تشفيرها أو وظيفة التعيين function(key, value)
.
فضاء
مقدار المساحة المستخدمة للتنسيق
في أغلب الأحيان، يتم استخدام JSON.stringify
مع الوسيطة الأولى فقط. لكن إذا أردنا ضبط عملية الاستبدال، مثل تصفية المراجع الدائرية، فيمكننا استخدام الوسيط الثاني لـ JSON.stringify
.
إذا مررنا مجموعة من الخصائص إليه، فسيتم تشفير هذه الخصائص فقط.
على سبيل المثال:
اترك مساحة = { الرقم: 23 }; دع اللقاء = { العنوان: "المؤتمر"، المشاركون: [{الاسم: "جون"}، {الاسم: "أليس"}]، المكان: الغرفة // غرفة مراجع اللقاء }; Room.OccupiedBy = meetup; // لقاء مراجع الغرفة تنبيه( JSON.stringify(meetup, ['title', 'participants']) ); // {"title": "المؤتمر"، "المشاركين":[{},{}]}
ربما نكون هنا صارمين للغاية. يتم تطبيق قائمة الخصائص على بنية الكائن بالكامل. لذا فإن الكائنات الموجودة في participants
فارغة، لأن name
غير موجود في القائمة.
دعونا ندرج في القائمة كل خاصية باستثناء room.occupiedBy
OccupiedBy التي من شأنها أن تسبب المرجع الدائري:
اترك مساحة = { الرقم: 23 }; دع اللقاء = { العنوان: "المؤتمر"، المشاركون: [{الاسم: "جون"}، {الاسم: "أليس"}]، المكان: الغرفة // غرفة مراجع اللقاء }; Room.OccupiedBy = meetup; // لقاء مراجع الغرفة تنبيه( JSON.stringify(meetup, ['title', 'participants', 'place', 'name', 'number']) ); /* { "العنوان": "مؤتمر"، "المشاركين":[{"name": "جون"},{"name": "Alice"}], "المكان":{"الرقم":23} } */
الآن يتم إجراء تسلسل لكل شيء باستثناء occupiedBy
. لكن قائمة الخصائص طويلة جدًا.
لحسن الحظ، يمكننا استخدام دالة بدلاً من المصفوفة replacer
.
سيتم استدعاء الوظيفة لكل زوج (key, value)
ويجب أن تُرجع القيمة "المستبدلة"، والتي سيتم استخدامها بدلاً من القيمة الأصلية. أو undefined
إذا كان سيتم تخطي القيمة.
في حالتنا، يمكننا إرجاع value
"كما هي" لكل شيء باستثناء occupiedBy
. لتجاهل occupiedBy
، يُرجع الكود أدناه undefined
:
اترك مساحة = { الرقم: 23 }; دع اللقاء = { العنوان: "المؤتمر"، المشاركون: [{الاسم: "جون"}، {الاسم: "أليس"}]، المكان: الغرفة // غرفة مراجع اللقاء }; Room.OccupiedBy = meetup; // لقاء مراجع الغرفة تنبيه (JSON.stringify (لقاء، وظيفة استبدال (مفتاح، قيمة) { تنبيه(`${مفتاح}: ${value}`); العودة (المفتاح == 'المحتلة')؟ غير محدد: القيمة؛ })); /* المفتاح: أزواج القيمة التي تأتي للاستبدال: : [كائن كائن] العنوان: مؤتمر المشاركون: [كائن كائن]، [كائن كائن] 0: [كائن كائن] الاسم: جون 1: [كائن كائن] الاسم: أليس المكان: [كائن كائن] الرقم: 23 مشغول بواسطة: [كائن كائن] */
يرجى ملاحظة أن وظيفة replacer
تحصل على كل زوج من المفاتيح/القيمة بما في ذلك الكائنات المتداخلة وعناصر المصفوفة. يتم تطبيقه بشكل متكرر. قيمة this
replacer
الداخلي هي الكائن الذي يحتوي على الخاصية الحالية.
المكالمة الأولى خاصة. يتم إجراؤه باستخدام "كائن مجمّع" خاص: {"": meetup}
. بمعنى آخر، يحتوي الزوج الأول (key, value)
على مفتاح فارغ، والقيمة هي الكائن الهدف ككل. ولهذا السبب فإن السطر الأول هو ":[object Object]"
في المثال أعلاه.
تتمثل الفكرة في توفير أكبر قدر ممكن من الطاقة replacer
: لديه فرصة لتحليل واستبدال/تخطي الكائن بأكمله إذا لزم الأمر.
الوسيطة الثالثة لـ JSON.stringify(value, replacer, space)
هي عدد المسافات التي سيتم استخدامها للتنسيق الجميل.
في السابق، لم يكن لجميع الكائنات النصية أي مسافات بادئة أو مسافات إضافية. هذا جيد إذا أردنا إرسال كائن عبر الشبكة. يتم استخدام الوسيطة space
حصريًا للحصول على نتائج جيدة.
هنا space = 2
تخبر JavaScript بإظهار الكائنات المتداخلة على أسطر متعددة، مع مسافة بادئة بمسافتين داخل الكائن:
السماح للمستخدم = { الاسم: "جون"، العمر: 25, الأدوار: { المشرف: خطأ، المحرر: صحيح } }; تنبيه (JSON.stringify (user، null، 2))؛ /* مسافة بادئة ذات مسافتين: { "الاسم": "جون"، "العمر": 25، "الأدوار": { "isAdmin": خطأ، "isEditor": صحيح } } */ /* بالنسبة إلى JSON.stringify(user, null, 4) ستكون النتيجة ذات مسافة بادئة أكبر: { "الاسم": "جون"، "العمر": 25، "الأدوار": { "isAdmin": خطأ، "isEditor": صحيح } } */
يمكن أن تكون الوسيطة الثالثة أيضًا سلسلة. في هذه الحالة، يتم استخدام السلسلة للمسافة البادئة بدلاً من عدد المسافات.
يتم استخدام المعلمة space
فقط لأغراض التسجيل والإخراج الجيد.
مثل toString
لتحويل السلسلة، قد يوفر الكائن طريقة toJSON
للتحويل إلى JSON. يستدعيه JSON.stringify
تلقائيًا إذا كان متاحًا.
على سبيل المثال:
اترك مساحة = { الرقم: 23 }; دع اللقاء = { العنوان: "المؤتمر"، التاريخ: تاريخ جديد (Date.UTC(2017, 0, 1)))، غرفة }; تنبيه (JSON.stringify (لقاء))؛ /* { "العنوان": "مؤتمر"، "date":":2017-01-01T00:00:00.000Z"، // (1) "الغرفة": {"الرقم":23} // (2) } */
هنا يمكننا أن نرى أن date
(1)
أصبح سلسلة. وذلك لأن جميع التواريخ تحتوي على طريقة toJSON
مضمنة تقوم بإرجاع هذا النوع من السلسلة.
الآن دعونا نضيف toJSON
مخصصًا room
الكائنات (2)
:
اترك مساحة = { العدد: 23، toJSON() { إرجاع هذا الرقم؛ } }; دع اللقاء = { العنوان: "المؤتمر"، غرفة }; تنبيه (JSON.stringify (غرفة))؛ // 23 تنبيه (JSON.stringify (لقاء))؛ /* { "العنوان": "مؤتمر"، "الغرفة": 23 } */
كما نرى، يتم استخدام toJSON
للمكالمة المباشرة JSON.stringify(room)
وعندما تكون room
متداخلة في كائن مشفر آخر.
لفك تشفير سلسلة JSON، نحتاج إلى طريقة أخرى تسمى JSON.parse.
بناء الجملة:
Let value = JSON.parse(str[, إحياء]);
شارع
سلسلة JSON للتحليل.
منعش
وظيفة اختيارية (مفتاح، قيمة) سيتم استدعاؤها لكل زوج (key, value)
ويمكنها تحويل القيمة.
على سبيل المثال:
// مصفوفة متماسكة دع الأرقام = "[0، 1، 2، 3]"؛ أرقام = JSON.parse(numbers); تنبيه(أرقام[1]); // 1
أو للكائنات المتداخلة:
Let userData = '{ "name": "John"، "age": 35، "isAdmin": false، "friends": [0,1,2,3] }'; السماح للمستخدم = JSON.parse(userData); تنبيه(user.friends[1]); // 1
قد يكون JSON معقدًا حسب الضرورة، ويمكن أن تتضمن الكائنات والمصفوفات كائنات ومصفوفات أخرى. ولكن يجب عليهم الالتزام بنفس تنسيق JSON.
فيما يلي الأخطاء النموذجية في JSON المكتوبة بخط اليد (أحيانًا يتعين علينا كتابتها لأغراض تصحيح الأخطاء):
دع جسون = `{ الاسم: "جون"، // خطأ: اسم الخاصية بدون علامات الاقتباس "اللقب": 'سميث'، // خطأ: علامات الاقتباس المفردة في القيمة (يجب أن تكون مزدوجة) 'isAdmin': خطأ // خطأ: علامات الاقتباس المفردة في المفتاح (يجب أن تكون مزدوجة) "عيد الميلاد": تاريخ جديد (2000، 2، 3)، // خطأ: غير مسموح بـ "جديد"، فقط القيم المجردة "friends": [0,1,2,3] // هنا كل شيء على ما يرام }`;
الى جانب ذلك، JSON لا يدعم التعليقات. إضافة تعليق إلى JSON يجعله غير صالح.
هناك تنسيق آخر يسمى JSON5، والذي يسمح بالمفاتيح غير المقتبسة والتعليقات وما إلى ذلك. ولكن هذه مكتبة مستقلة، وليست في مواصفات اللغة.
JSON العادي صارم إلى هذا الحد ليس لأن مطوريه كسالى، ولكن للسماح بتنفيذ سهل وموثوق وسريع جدًا لخوارزمية التحليل.
تخيل أننا حصلنا على كائن meetup
مقيد من الخادم.
يبدو مثل هذا:
// العنوان: (عنوان اللقاء)، التاريخ: (تاريخ اللقاء) Let str = '{"title": "Conference"، "date": "2017-11-30T12:00:00.000Z"}'؛
… والآن نحن بحاجة إلى إلغاء تسلسله، للعودة مرة أخرى إلى كائن JavaScript.
فلنفعل ذلك عن طريق استدعاء JSON.parse
:
Let str = '{"title": "Conference"، "date": "2017-11-30T12:00:00.000Z"}'؛ دع اللقاء = JSON.parse(str); تنبيه (meetup.date.getDate())؛ // خطأ!
عفوًا! خطأ!
قيمة meetup.date
عبارة عن سلسلة، وليست كائن Date
. كيف يمكن JSON.parse
أن يعرف أنه يجب عليه تحويل تلك السلسلة إلى Date
؟
دعنا نمرر إلى JSON.parse
وظيفة الإحياء باعتبارها الوسيطة الثانية، التي تُرجع جميع القيم "كما هي"، ولكن date
سيصبح Date
:
Let str = '{"title": "Conference"، "date": "2017-11-30T12:00:00.000Z"}'؛ دع اللقاء = JSON.parse(str, function(key, value) { إذا (مفتاح == 'تاريخ') يُرجع تاريخًا جديدًا (قيمة) ؛ قيمة الإرجاع؛ }); تنبيه (meetup.date.getDate())؛ // يعمل الآن!
بالمناسبة، هذا ينطبق أيضًا على الكائنات المتداخلة:
دع الجدول الزمني = `{ "لقاءات": [ {"title": "المؤتمر"، "التاريخ": "2017-11-30T12:00:00.000Z"}, {"title":"عيد ميلاد"، "التاريخ": "2017-04-18T12:00:00.000Z"} ] }`; الجدول الزمني = JSON.parse(schedule, function(key, value) { إذا (مفتاح == 'تاريخ') يُرجع تاريخًا جديدًا (قيمة) ؛ قيمة الإرجاع؛ }); تنبيه (جدول لقاءات[1].date.getDate())؛ // يعمل!
JSON هو تنسيق بيانات له معياره ومكتباته المستقلة لمعظم لغات البرمجة.
يدعم JSON الكائنات العادية والمصفوفات والسلاسل والأرقام والقيم المنطقية والقيمة null
.
توفر JavaScript طرق JSON.stringify للتسلسل إلى JSON وJSON.parse للقراءة من JSON.
تدعم كلتا الطريقتين وظائف المحولات للقراءة/الكتابة الذكية.
إذا كان الكائن يحتوي على toJSON
، فسيتم استدعاؤه بواسطة JSON.stringify
.
الأهمية: 5
قم بتحويل user
إلى JSON ثم قم بقراءته مرة أخرى في متغير آخر.
السماح للمستخدم = { الاسم: "جون سميث"، العمر: 35 };
السماح للمستخدم = { الاسم: "جون سميث"، العمر: 35 }; Let user2 = JSON.parse(JSON.stringify(user));
الأهمية: 5
في الحالات البسيطة للمراجع الدائرية، يمكننا استبعاد خاصية مخالفة من التسلسل حسب اسمها.
لكن في بعض الأحيان لا يمكننا استخدام الاسم فقط، حيث يمكن استخدامه في كل من المراجع الدائرية والخصائص العادية. حتى نتمكن من التحقق من العقار من خلال قيمته.
اكتب دالة replacer
لتقييد كل شيء، ولكن قم بإزالة الخصائص التي تشير إلى meetup
:
اترك مساحة = { الرقم: 23 }; دع اللقاء = { العنوان: "المؤتمر"، مشغول بواسطة: [{الاسم: "جون"}، {الاسم: "أليس"}]، المكان: غرفة }; // مراجع دائرية Room.OccupiedBy = meetup; meetup.self = meetup; تنبيه (JSON.stringify (لقاء، وظيفة استبدال (مفتاح، قيمة) { /* الكود الخاص بك */ })); /* النتيجة يجب أن تكون: { "العنوان": "مؤتمر"، "محتلة":[{"name": "John"},{"name": "Alice"}], "المكان":{"الرقم":23} } */
اترك مساحة = { الرقم: 23 }; دع اللقاء = { العنوان: "المؤتمر"، مشغول بواسطة: [{الاسم: "جون"}، {الاسم: "أليس"}]، المكان: غرفة }; Room.OccupiedBy = meetup; meetup.self = meetup; تنبيه (JSON.stringify (لقاء، وظيفة استبدال (مفتاح، قيمة) { العودة (مفتاح! = "" && القيمة == لقاء)؟ غير محدد: القيمة؛ })); /* { "العنوان": "مؤتمر"، "محتلة":[{"name": "John"},{"name": "Alice"}], "المكان":{"الرقم":23} } */
نحتاج هنا أيضًا إلى اختبار key==""
لاستبعاد الاستدعاء الأول حيث يكون من الطبيعي أن تكون value
meetup
.