المادة ، التي ننشر ترجمتها اليوم ، مخصصة لدراسة الكائنات - أحد الجواهر الرئيسية لجافا سكريبت. تم تصميمه في المقام الأول للمطورين المبتدئين الذين يرغبون في تبسيط معرفتهم بالأشياء.

الكائنات في JavaScript هي مجموعات ديناميكية من الخصائص التي تحتوي ، بالإضافة إلى ذلك ، على خاصية "مخفية" وهي نموذج أولي للكائن. تتميز خصائص الكائنات بالمفاتيح والقيم. لنبدأ المحادثة حول كائنات JS باستخدام المفاتيح.
مفاتيح خصائص الكائن
مفتاح خاصية الكائن هو سلسلة فريدة. يمكنك استخدام طريقتين للوصول إلى الخصائص: الوصول إليها من خلال فترة وتحديد مفتاح الكائن بين قوسين مربعين. عند الوصول إلى الخصائص من خلال نقطة ، يجب أن يكون المفتاح معرف جافا سكريبت صالحًا. فكر في مثال:
let obj = { message : "A message" } obj.message //"A message" obj["message"] //"A message"
عند محاولة الوصول إلى خاصية غير موجودة لكائن ، لن تظهر رسالة خطأ ، ولكن سيتم إرجاع القيمة
undefined
:
obj.otherProperty
عند استخدام الأقواس المربعة للوصول إلى الخصائص ، يمكنك استخدام مفاتيح ليست معرّفات جافا سكريبت صالحة (على سبيل المثال ، يمكن أن يكون المفتاح عبارة عن سلسلة تحتوي على مسافات). يمكن أن يكون لها أي قيمة يمكن طرحها في سلسلة:
let french = {}; french["merci beaucoup"] = "thank you very much"; french["merci beaucoup"];
إذا تم استخدام قيم غير سلسلة كمفاتيح ، يتم تحويلها تلقائيًا إلى سلاسل (باستخدام طريقة
toString()
إن أمكن):
et obj = {}; //Number obj[1] = "Number 1"; obj[1] === obj["1"]; //true //Object let number1 = { toString : function() { return "1"; } } obj[number1] === obj["1"]; //true
في هذا المثال ، يتم استخدام الكائن
number1
كمفتاح. عند محاولة الوصول إلى خاصية ، يتم تحويلها إلى السطر
1
، ويتم استخدام نتيجة هذا التحويل كمفتاح.
قيم خصائص الكائن
يمكن أن تكون خصائص الكائن قيمًا بدائية أو كائنات أو دالات.
b الكائن كقيمة خاصية الكائن
يمكن وضع الكائنات في كائنات أخرى. فكر
في مثال :
let book = { title : "The Good Parts", author : { firstName : "Douglas", lastName : "Crockford" } } book.author.firstName;
يمكن استخدام نهج مماثل لإنشاء مساحات الأسماء:
let app = {}; app.authorService = { getAuthors : function() {} }; app.bookService = { getBooks : function() {} };
▍ يعمل كقيمة خاصية الكائن
عند استخدام دالة كقيمة لخاصية كائن ، فإنها عادة ما تصبح طريقة كائن. داخل الطريقة ، للوصول إلى الكائن الحالي ، استخدم
this
.
ومع ذلك ، قد يكون لهذه الكلمة الأساسية معانٍ مختلفة ، اعتمادًا على كيفية استدعاء الوظيفة.
هنا يمكنك أن تقرأ عن المواقف التي يفقد فيها
this
السياق.
الطبيعة الديناميكية للأشياء
الكائنات في JavaScript ، بحكم طبيعتها ، هي كيانات ديناميكية. يمكنك إضافة خصائص إليها في أي وقت ، وينطبق الشيء نفسه على حذف الخصائص:
let obj = {}; obj.message = "This is a message"; // obj.otherMessage = "A new message"; // delete obj.otherMessage; //
الكائنات كمصفوفات ترابطية
يمكن اعتبار الكائنات صفائف ترابطية. مفاتيح الصفيف الترابطية هي أسماء خصائص الكائن. من أجل الوصول إلى المفتاح ، لا تحتاج إلى إلقاء نظرة على جميع الخصائص ، أي أن عملية الوصول إلى مفتاح صفيف الترابط على أساس كائن يتم في O (1) الوقت.
نماذج الكائنات
تحتوي الكائنات على ارتباط "مخفي" ،
__proto__
، يشير إلى كائن نموذج أولي يرث الكائن خصائصه منه.
على سبيل المثال ، يحتوي الكائن الذي تم إنشاؤه باستخدام كائن حرفي على ارتباط إلى
Object.prototype
:
var obj = {}; obj.__proto__ === Object.prototype;
objects أشياء فارغة
كما رأينا للتو ، فإن الكائن "الفارغ" ،
{}
، ليس فارغًا في الواقع ، لأنه يحتوي على مرجع إلى
Object.prototype
. لإنشاء كائن فارغ حقًا ، تحتاج إلى استخدام البناء التالي:
Object.create(null)
بفضل هذا ، سيتم إنشاء كائن بدون نموذج أولي. عادة ما يتم استخدام هذه الأشياء لإنشاء صفائف ترابطية.
Chain سلسلة النموذج الأولي
يمكن أن يكون لكائنات النموذج الأولي نماذج أولية خاصة بها. إذا حاولت الوصول إلى خاصية كائن غير موجود فيه ، فستحاول JavaScript العثور على هذه الخاصية في النموذج الأولي لهذا الكائن ، وإذا لم تكن الخاصية المطلوبة موجودة ، فستتم محاولة العثور عليها في النموذج الأولي للنموذج الأولي. سيستمر هذا حتى يتم العثور على الخاصية المطلوبة ، أو حتى يتم الوصول إلى نهاية سلسلة النموذج الأولي.
قيم النوع البدائي وأغلفة الأشياء
تسمح لك JavaScript بالعمل مع قيم الأنواع البدائية ككائنات ، بمعنى أن اللغة تسمح لك بالوصول إلى خصائصها وأساليبها.
(1.23).toFixed(1); //"1.2" "text".toUpperCase(); //"TEXT" true.toString(); //"true"
علاوة على ذلك ، بطبيعة الحال ، فإن قيم الأنواع البدائية ليست كائنات.
لتنظيم الوصول إلى "خصائص" قيم الأنواع البدائية ، تقوم JavaScript ، إذا لزم الأمر ، بإنشاء كائنات مجمعة ، والتي ، بعد أن تصبح غير ضرورية ، يتم تدميرها. تم تحسين عملية إنشاء وتدمير كائنات الغلاف بواسطة محرك JS.
تتضمن أغلفة الكائنات قيمًا رقمية وسلسلة وأنواع منطقية. يتم تمثيل كائنات الأنواع المقابلة بوظائف المنشئ
Number
و
String
و
Boolean
.
النماذج الأولية المضمنة
ترث كائنات الأرقام خصائص وأساليب من النموذج الأولي
Number.prototype
، وهو سليل
Object.prototype
:
var no = 1; no.__proto__ === Number.prototype; //true no.__proto__.__proto__ === Object.prototype; //true
النموذج الأولي لكائنات السلسلة هو
String.prototype
. النموذج الأولي للكائنات المنطقية هو
Boolean.prototype
. النموذج الأولي للمصفوفات (التي هي أيضًا كائنات) هو
Array.prototype
.
الوظائف في JavaScript هي أيضًا كائنات لها نموذج أولي
Function.prototype
. للوظائف طرق مثل
bind()
،
apply()
call()
.
جميع الكائنات والوظائف والكائنات التي تمثل قيم النوع البدائية (باستثناء القيم
null
وغير
undefined
) ترث الخصائص والأساليب من
Object.prototype
. هذا يؤدي إلى حقيقة أن لديهم ، على سبيل المثال ، طريقة
toString()
.
تمديد الكائنات المضمنة مع رقاقات متعددة
تجعل JavaScript من السهل توسيع الكائنات المضمنة بميزات جديدة باستخدام ما يسمى بـ polyfill. بوليفيل هو قطعة من التعليمات البرمجية التي تنفذ الميزات التي لا يدعمها أي مستعرضات.
▍ استخدام polyfills
على سبيل المثال ، يوجد
Object.assign()
لطريقة
Object.assign()
. يسمح لك بإضافة وظيفة جديدة
Object
إذا لم تكن متوفرة فيه.
وينطبق الشيء نفسه على
Array.from()
، التي إذا كانت الطريقة
from()
غير موجودة في كائن
Array
، فتجهزها بهذه الطريقة.
▍ Polyfill والنماذج الأولية
بمساعدة polyfills ، يمكن إضافة طرق جديدة لنماذج الكائنات. على سبيل المثال ، يتيح لك
String.prototype.trim()
الخاص بـ
String.prototype.trim()
تجهيز جميع كائنات السلسلة بطريقة
trim()
:
let text = " A text "; text.trim(); //"A text"
يتيح لك
Array.prototype.find()
الخاص بـ
Array.prototype.find()
تجهيز كافة المصفوفات بطريقة
find()
. يعمل
Array.prototype.findIndex()
لـ
Array.prototype.findIndex()
بطريقة مماثلة:
let arr = ["A", "B", "C", "D", "E"]; arr.indexOf("C");
ميراث واحد
يتيح لك الأمر
Object.create()
إنشاء كائنات جديدة باستخدام كائن نموذج أولي. يستخدم هذا الأمر في جافا سكريبت لتطبيق آلية وراثة واحدة. فكر
في مثال :
let bookPrototype = { getFullTitle : function(){ return this.title + " by " + this.author; } } let book = Object.create(bookPrototype); book.title = "JavaScript: The Good Parts"; book.author = "Douglas Crockford"; book.getFullTitle();
الوراثة المتعددة
Object.assign()
الأمر
Object.assign()
الخصائص من كائن واحد أو أكثر إلى الكائن الهدف. يمكن استخدامه لتنفيذ مخططات الميراث المتعددة. هنا
مثال :
let authorDataService = { getAuthors : function() {} }; let bookDataService = { getBooks : function() {} }; let userDataService = { getUsers : function() {} }; let dataService = Object.assign({}, authorDataService, bookDataService, userDataService ); dataService.getAuthors(); dataService.getBooks(); dataService.getUsers();
كائنات غير قابلة للتغيير
يتيح لك أمر
Object.freeze()
"تجميد" كائن. لا يمكنك إضافة خصائص جديدة لمثل هذا الكائن. لا يمكن حذف الخصائص ، ولا يمكن تغيير قيمها. باستخدام هذا الأمر ، يصبح الكائن غير قابل للتغيير أو غير قابل للتغيير:
"use strict"; let book = Object.freeze({ title : "Functional-Light JavaScript", author : "Kyle Simpson" }); book.title = "Other title";//: Cannot assign to read only property 'title'
ينفذ الأمر
Object.freeze()
ما يسمى "التجميد الضحل" للكائنات. هذا يعني أنه يمكن تعديل الكائنات المتداخلة في كائن "مجمّد". من أجل "تجميد عميق" لكائن ما ، تحتاج إلى "تجميد" جميع خصائصه بشكل متكرر.
كائنات الاستنساخ
لإنشاء نسخ (نسخ) من الكائنات ، يمكنك استخدام الأمر
Object.assign()
:
let book = Object.freeze({ title : "JavaScript Allongé", author : "Reginald Braithwaite" }); let clone = Object.assign({}, book);
يقوم هذا الأمر بنسخ الكائنات الضحلة ، أي أنه ينسخ فقط خصائص المستوى الأعلى. تصبح الأشياء المتداخلة شائعة للكائنات الأصلية ونسخها.
كائن حرفي
تعطي العناصر الحرفية للمطورين طريقة بسيطة ومباشرة لإنشاء الكائنات:
let timer = { fn : null, start : function(callback) { this.fn = callback; }, stop : function() {}, }
ومع ذلك ، فإن هذه الطريقة في إنشاء الكائنات لها عيوب. على وجه الخصوص ، مع هذا النهج ، تكون جميع خصائص الكائن متاحة للجمهور ، ويمكن إعادة تعريف طرق الكائن ، ولا يمكن استخدامها لإنشاء مثيلات جديدة لنفس الكائنات:
timer.fn;//null timer.start = function() { console.log("New implementation"); }
Object.create () الأسلوب
يمكن حل المشكلتين المذكورتين أعلاه من خلال الاستخدام المشترك
Object.create()
و
Object.freeze()
.
نطبق هذه التقنية على مثالنا السابق. أولاً ، أنشئ نموذجًا أوليًا للنموذج المجمد يحتوي على جميع الأساليب التي تحتاجها المثيلات المختلفة للكائن. بعد ذلك ، أنشئ كائنًا يخلف
timerPrototype
:
let timerPrototype = Object.freeze({ start : function() {}, stop : function() {} }); let timer = Object.create(timerPrototype); timer.__proto__ === timerPrototype; //true
إذا كان النموذج الأولي محميًا من التغييرات ، فلن يتمكن الكائن الذي هو وريثه من تغيير الخصائص المحددة في النموذج الأولي. الآن لا يمكن تجاوز طريقتين
start()
و
stop()
:
"use strict"; timer.start = function() { console.log("New implementation"); }
يمكن استخدام
Object.create(timerPrototype)
لإنشاء كائنات متعددة بنفس النموذج الأولي.
وظيفة المنشئ
جافا سكريبت لها ما يسمى بوظائف المنشئ ، وهي "السكر النحوي" لأداء الخطوات المذكورة أعلاه لإنشاء كائنات جديدة. فكر
في مثال :
function Timer(callback){ this.fn = callback; } Timer.prototype = { start : function() {}, stop : function() {} } function getTodos() {} let timer = new Timer(getTodos);
يمكنك استخدام أي وظيفة كمنشئ. يسمى المنشئ باستخدام الكلمة الأساسية
new
. سيتلقى الكائن الذي تم إنشاؤه باستخدام دالة منشئ يسمى
FunctionConstructor.prototype
نموذج
FunctionConstructor.prototype
:
let timer = new Timer(); timer.__proto__ === Timer.prototype;
هنا ، لمنع حدوث تغيير في النموذج الأولي ، مرة أخرى ، يمكنك تجميد النموذج الأولي:
Timer.prototype = Object.freeze({ start : function() {}, stop : function() {} });
▍ كلمة رئيسية جديدة
عند تنفيذ أمر للنموذج
new Timer()
يتم تنفيذ نفس الإجراءات التي تؤديها الدالة
newTimer()
أدناه:
function newTimer(){ let newObj = Object.create(Timer.prototype); let returnObj = Timer.call(newObj, arguments); if(returnObj) return returnObj; return newObj; }
يتم إنشاء كائن جديد هنا ،
Timer.prototype
الأولي هو
Timer.prototype
. ثم يتم استدعاء وظيفة
Timer
، وتعيين الحقول للكائن الجديد.
الكلمة الأساسية للفئة
قدم ECMAScript 2015 طريقة جديدة لأداء الإجراءات المذكورة أعلاه ، وهي مجموعة أخرى من "السكر النحوي". نحن نتحدث عن الكلمة الأساسية
class
والبنيات المرتبطة بها. فكر
في مثال :
class Timer{ constructor(callback){ this.fn = callback; } start() {} stop() {} } Object.freeze(Timer.prototype);
يحتوي الكائن الذي تم إنشاؤه باستخدام الكلمة الأساسية
class
بناءً على فئة تسمى
ClassName
على النموذج الأولي
ClassName.prototype
. عند إنشاء كائن بناءً على فصل دراسي ، استخدم الكلمة الأساسية
new
:
let timer= new Timer(); timer.__proto__ === Timer.prototype;
استخدام الفصول لا يجعل النماذج الأولية غير قابلة للتغيير. إذا لزم الأمر ، يجب "تجميدها" بنفس الطريقة التي فعلنا بها بالفعل:
Object.freeze(Timer.prototype);
الوراثة القائمة على النموذج الأولي
في JavaScript ، ترث الكائنات الخصائص والأساليب من الكائنات الأخرى. وظائف وفئات المنشئ هي "السكر النحوي" لإنشاء كائنات نموذجية تحتوي على جميع الطرق الضرورية. باستخدامها ، يتم إنشاء كائنات جديدة هي ورثة النموذج الأولي ، ويتم تعيين خصائصها ، الخاصة بمثيل معين ، باستخدام وظيفة المُنشئ أو باستخدام آليات الفئة.
سيكون من اللطيف أن تعمل وظائف المنشئ والفئات تلقائيًا على جعل النماذج الأولية ثابتة.
تتمثل نقاط قوة وراثة النموذج الأولي في توفير الذاكرة. والحقيقة هي أنه يتم إنشاء نموذج أولي مرة واحدة فقط ، وبعد ذلك تستخدمه جميع الكائنات التي تم إنشاؤها على أساسها.
▍ مشكلة عدم وجود آليات تغليف مدمجة
لا يستخدم قالب الوراثة النموذجي فصل خصائص الأشياء إلى خاص وعام. جميع خصائص الأشياء متاحة للجمهور.
على سبيل المثال ، يقوم الأمر
Object.keys()
بإرجاع صفيف يحتوي على كافة مفاتيح خصائص الكائن. يمكن استخدامه للتكرار على جميع خصائص الكائن:
function logProperty(name){ console.log(name); // console.log(obj[name]); // } Object.keys(obj).forEach(logProperty);
هناك نمط واحد يحاكي الخصائص الخاصة ، بالاعتماد على حقيقة أن المطورين لن يصلوا إلى تلك الخصائص التي تبدأ أسماؤها بشرطة سفلية (
_
):
class Timer{ constructor(callback){ this._fn = callback; this._timerId = 0; } }
ميزات المصنع
يمكن إنشاء كائنات مغلفة في JavaScript باستخدام وظائف المصنع. يبدو هذا:
function TodoStore(callback){ let fn = callback; function start() {}, function stop() {} return Object.freeze({ start, stop }); }
هنا المتغير
fn
خاص. تتوفر طريقتا
start()
و
stop()
فقط للجمهور. لا يمكن تعديل هذه الطرق خارجيًا. لا يتم استخدام هذه الكلمة الرئيسية هنا ، لذلك ، عند استخدام هذه الطريقة في إنشاء الكائنات ، فإن مشكلة فقدان
this
السياق ليست ذات صلة.
يستخدم الأمر
return
كائنًا حرفيًا يحتوي على وظائف فقط. علاوة على ذلك ، يتم الإعلان عن هذه الوظائف في الإغلاق ؛ فهي تشترك في دولة مشتركة. لتجميد واجهة برمجة تطبيقات عامة لكائن ، يتم
Object.freeze()
الأمر
Object.freeze()
المعروف بالفعل.
هنا ، في الأمثلة ، استخدمنا كائن
Timer
. في
هذه المادة يمكنك العثور على تنفيذها الكامل.
الملخص
في JavaScript ، يتم التعامل مع قيم الأنواع البدائية والكائنات العادية والوظائف ككائنات. الكائنات لها طبيعة ديناميكية ، يمكن استخدامها كمصفوفات ترابطية. الكائنات هي وراثة كائنات أخرى. وظائف وفئات المُنشئ هي "السكر النحوي" ؛ وهي تسمح لك بإنشاء كائنات بناءً على النماذج الأولية. يمكنك استخدام طريقة
Object.create()
لتنظيم الوراثة الفردية ، و
Object.create()
لتنظيم الوراثة المتعددة. يمكنك استخدام وظائف المصنع لإنشاء كائنات مغلفة.
أعزائي القراء! إذا كنت قد وصلت إلى JavaScript من لغات أخرى ، فيرجى إخبارنا بما يعجبك أو لا يعجبك في كائنات JS ، مقارنةً بتنفيذ الكائنات بلغات تعرفها بالفعل.
