JavaScript Create Object - كيفية تحديد الكائنات في JS

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

  • كائن حرفي
  • Object.create ()
  • الطبقات
  • وظائف المصنع

كائن حرفي

أولاً ، نحتاج إلى التمييز بين هياكل البيانات والكائنات الموجهة للكائنات. هياكل البيانات لديها بيانات عامة وليس لديها سلوك. هذا يعني أنه ليس لديهم طرق.

يمكننا بسهولة إنشاء مثل هذه الكائنات باستخدام بناء الجملة الحرفية للكائن. تبدو هكذا:

const product = { name: 'apple', category: 'fruits', price: 1.99 } console.log(product);

الكائنات في JavaScript عبارة عن مجموعات ديناميكية من أزواج القيمة الرئيسية. المفتاح دائمًا عبارة عن سلسلة ويجب أن يكون فريدًا في المجموعة. يمكن للقيمة أن تكون بدائية أو كائنًا أو حتى وظيفة.

يمكننا الوصول إلى خاصية باستخدام رمز النقطة أو المربع.

console.log(product.name); //"apple" console.log(product["name"]); //"apple"

هنا مثال حيث القيمة هي كائن آخر.

const product = { name: 'apple', category: 'fruits', price: 1.99, nutrients : { carbs: 0.95, fats: 0.3, protein: 0.2 } }

قيمة carbsالخاصية هي كائن جديد. هنا كيف يمكننا الوصول إلى carbsالممتلكات.

console.log(product.nutrients.carbs); //0.95

أسماء خاصية الاختزال

ضع في اعتبارك الحالة التي يتم فيها تخزين قيم خصائصنا في متغيرات.

const name = 'apple'; const category = 'fruits'; const price = 1.99; const product = { name: name, category: category, price: price }

يدعم JavaScript ما يسمى بأسماء خاصية الاختزال. يسمح لنا بإنشاء كائن باستخدام اسم المتغير فقط. سيتم إنشاء خاصية بنفس الاسم. الكائن الحرفي التالي يعادل الكائن السابق.

const name = 'apple'; const category = 'fruits'; const price = 1.99; const product = { name, category, price }

الكائن

بعد ذلك ، دعونا نلقي نظرة على كيفية تنفيذ الكائنات بالسلوك ، الكائنات الموجهة للكائنات.

جافا سكريبت لديها ما يسمى نظام النموذج الأولي الذي يسمح بمشاركة السلوك بين الكائنات. الفكرة الرئيسية هي إنشاء كائن يسمى النموذج الأولي بسلوك شائع ثم استخدامه عند إنشاء كائنات جديدة.

يسمح لنا نظام النموذج الأولي بإنشاء كائنات ترث السلوك من الكائنات الأخرى.

لنقم بإنشاء كائن نموذج أولي يسمح لنا بإضافة المنتجات والحصول على السعر الإجمالي من عربة التسوق.

const cartPrototype = { addProduct: function(product){ if(!this.products){ this.products = [product] } else { this.products.push(product); } }, getTotalPrice: function(){ return this.products.reduce((total, p) => total + p.price, 0); } }

لاحظ أن قيمة الخاصية هذه المرة addProductهي دالة. يمكننا أيضًا كتابة الكائن السابق باستخدام نموذج أقصر يسمى بناء جملة طريقة الاختزال.

const cartPrototype = { addProduct(product){/*code*/}, getTotalPrice(){/*code*/} }

و cartPrototypeهو كائن النموذج الذي يحافظ على السلوك المشترك ممثلة من قبل اثنين من الأساليب، addProductو getTotalPrice. يمكن استخدامه لبناء كائنات أخرى ترث هذا السلوك.

const cart = Object.create(cartPrototype); cart.addProduct({name: 'orange', price: 1.25}); cart.addProduct({name: 'lemon', price: 1.75}); console.log(cart.getTotalPrice()); //3

و cartكائن له cartPrototypeكما النموذج الأولي. يرث السلوك منه. cartله خاصية مخفية تشير إلى كائن النموذج الأولي.

عندما نستخدم طريقة على كائن ، يتم البحث في هذه الطريقة أولاً عن الكائن نفسه بدلاً من النموذج الأولي الخاص به.

هذه

لاحظ أننا نستخدم كلمة أساسية خاصة تسمى thisللوصول إلى البيانات الموجودة على الكائن وتعديلها.

تذكر أن الوظائف هي وحدات سلوك مستقلة في JavaScript. هم ليسوا بالضرورة جزء من كائن. عندما يكونون كذلك ، نحتاج إلى مرجع يسمح للوظيفة بالوصول إلى أعضاء آخرين على نفس الكائن. thisهو سياق الوظيفة. يتيح الوصول إلى خصائص أخرى.

البيانات

قد تتساءل لماذا لم نقم بتعريف وتهيئة productsالخاصية على كائن النموذج الأولي نفسه.

لا يجب أن نفعل ذلك. يجب استخدام النماذج الأولية لمشاركة السلوك وليس البيانات. ستؤدي مشاركة البيانات إلى الحصول على نفس المنتجات في العديد من عناصر سلة التسوق. ضع في اعتبارك الكود أدناه:

const cartPrototype = { products:[], addProduct: function(product){ this.products.push(product); }, getTotalPrice: function(){} } const cart1 = Object.create(cartPrototype); cart1.addProduct({name: 'orange', price: 1.25}); cart1.addProduct({name: 'lemon', price: 1.75}); console.log(cart1.getTotalPrice()); //3 const cart2 = Object.create(cartPrototype); console.log(cart2.getTotalPrice()); //3

كل من cart1و cart2الكائنات وراثة السلوك المشترك من cartPrototypeمشاركة أيضا نفس البيانات. لا نريد ذلك. يجب استخدام النماذج الأولية لمشاركة السلوك وليس البيانات.

صف دراسي

نظام النموذج الأولي ليس طريقة شائعة لبناء الكائنات. المطورون أكثر دراية ببناء الكائنات من الفصول الدراسية.

يسمح بناء جملة الفئة بطريقة أكثر شيوعًا لإنشاء كائنات تشترك في سلوك مشترك. لا يزال ينشئ نفس النموذج الأولي خلف الكواليس لكن بناء الجملة أكثر وضوحًا ونتجنب أيضًا المشكلة السابقة المتعلقة بالبيانات. يقدم الفصل مكانًا محددًا لتحديد البيانات المميزة لكل كائن.

هذا هو نفس الكائن الذي تم إنشاؤه باستخدام بناء جملة سكر الفئة:

class Cart{ constructor(){ this.products = []; } addProduct(product){ this.products.push(product); } getTotalPrice(){ return this.products.reduce((total, p) => total + p.price, 0); } } const cart = new Cart(); cart.addProduct({name: 'orange', price: 1.25}); cart.addProduct({name: 'lemon', price: 1.75}); console.log(cart.getTotalPrice()); //3 const cart2 = new Cart(); console.log(cart2.getTotalPrice()); //0

لاحظ أن الفصل يحتوي على أسلوب مُنشئ قام بتهيئة تلك البيانات المميزة لكل كائن جديد. لا يتم مشاركة البيانات في المنشئ بين المثيلات. من أجل إنشاء مثيل جديد ، نستخدم newالكلمة الرئيسية.

أعتقد أن بنية الفصل أكثر وضوحًا ومألوفة لدى معظم المطورين. ومع ذلك ، فإنه يفعل شيئًا مشابهًا ، فهو ينشئ نموذجًا أوليًا بجميع الأساليب ويستخدمه لتحديد كائنات جديدة. يمكن الوصول إلى النموذج الأولي باستخدام Cart.prototype.

اتضح أن نظام النموذج الأولي مرن بدرجة كافية للسماح ببناء الجملة. لذلك يمكن محاكاة نظام الفصل باستخدام نظام النموذج الأولي.

الممتلكات الخاصة

الشيء الوحيد هو أن productsالخاصية على الكائن الجديد تكون عامة بشكل افتراضي.

console.log(cart.products); //[{name: "orange", price: 1.25} // {name: "lemon", price: 1.75}]

يمكننا جعله خاصًا باستخدام #بادئة التجزئة .

Private properties are declared with #name syntax. # is a part of the property name itself and should be used for declaring and accessing the property. Here is an example of declaring products as a private property:

class Cart{ #products constructor(){ this.#products = []; } addProduct(product){ this.#products.push(product); } getTotalPrice(){ return this.#products.reduce((total, p) => total + p.price, 0); } } console.log(cart.#products); //Uncaught SyntaxError: Private field '#products' must be declared in an enclosing class

Factory Functions

Another option is to create objects as collections of closures.

Closure is the ability of a function to access variables and parameters from the other function even after the outer function has executed. Take a look at the cart object built with what is called a factory function.

function Cart() { const products = []; function addProduct(product){ products.push(product); } function getTotalPrice(){ return products.reduce((total, p) => total + p.price, 0); } return { addProduct, getTotalPrice } } const cart = Cart(); cart.addProduct({name: 'orange', price: 1.25}); cart.addProduct({name: 'lemon', price: 1.75}); console.log(cart.getTotalPrice()); //3

addProduct and getTotalPrice are two inner functions accessing the variable products from their parent. They have access to the products variable event after the parent Cart has executed. addProduct and getTotalPrice are two closures sharing the same private variable.

Cart is a factory function.

The new object cart created with the factory function has the products variable private. It cannot be accessed from the outside.

console.log(cart.products); //undefined

Factory functions don’t need the new keyword but you can use it if you want. It will return the same object no matter if you use it or not.

Recap

Usually, we work with two types of objects, data structures that have public data and no behavior and object-oriented objects that have private data and public behavior.

Data structures can be easily built using the object literal syntax.

JavaScript offers two innovative ways of creating object-oriented objects. The first is using a prototype object to share the common behavior. Objects inherit from other objects. Classes offer a nice sugar syntax to create such objects.

الخيار الآخر هو تحديد الكائنات عبارة عن مجموعات من الإغلاق.

لمزيد من المعلومات حول أساليب الإغلاق وبرمجة الوظائف ، راجع سلسلة كتابي البرمجة الوظيفية باستخدام JavaScript و React.

و البرمجة وظيفية في جافا سكريبت الكتاب هو الخروج.