"إذا أراد العامل أن يؤدي عمله بشكل جيد، فعليه أولاً أن يشحذ أدواته." - كونفوشيوس، "مختارات كونفوشيوس. لو لينجونج"
الصفحة الأمامية > برمجة > OOP في JS -

OOP في JS -

تم النشر بتاريخ 2024-11-04
تصفح:460

OOP in JS -

  • تشبه فئات JS السكر النحوي، وليست مثل فئات اللغات الأخرى المكتوبة بقوة.
  • يضيف فقط التفاف بناء الجملة لجعله مألوفًا للمطورين القادمين من لغات أخرى.
  • الفصول هي نوع خاص من الوظائف الموجودة خلف الكواليس، وبالتالي يمكن كتابتها كتعبير عن الفصل بالإضافة إلى إعلان الفصل.
## class expression:
const Person = class {
}

## class declaration:
class Person {
  constructor(fName, bYear){
   this.fName = fName;
   this.bYear = bYear;
  }
  calcAge(){
   console.log(2024 - this.bYear);
  }
}

- constructor is a method of this class. Pass values for properties to have in objects created using this fn.
- then set the properties of the object using this.xxx = xxx;
- On using 'new' operator, this constructor will be called automatically and return a new object which will be stored in LHS variable as shown below.
Ex. const ronald = new Person('ronald',1975); // Person { fName: 'ronald', bYear: 1975 }
- Methods are written outside the constructor fn and will be added to the prototype property of the object which can be verified using devConsole.
Ex. ronald.calcAge(); // 49

ronald.__proto__ === Person.prototype; // true

- No commas need to be added while adding multiple methods below the constructor fn inside the class.

## Hence, the above syntax works same as constructor fn syntax but with a familiar syntax of strongly typed class based languages.

## Adding a fn explicitly to the prototype:
Person.prototype.greet = function(){
console.log(`Hey ${this.fName}`);
}
ronald.greet(); // 'Hey ronald'

نقاط التأثير:

  • يتم رفع إعلانات Fn بينما لا يتم رفع إعلانات الفئة.
  • أيضًا مواطن من الدرجة الأولى تمامًا مثل Fns، أي يمكن تمريره وإعادته منه.
  • يتم تنفيذ نص الفصل دائمًا في الوضع الصارم سواء قمنا بتنشيط الوضع الصارم أم لا.
  • تجعل الفصول الدراسية الكود يبدو أكثر نظافة، مع تقليل ضوضاء الأحرف بشرط أن تعرف كيفية تنفيذه تحت الغطاء. ** لكي تصبح خبيرًا في JS، عليك أن تفهم تفاصيل تنفيذ اللغة المعقدة كما هو الحال مع الفصول الدراسية.

خصائص الوصول: Getters & Setters، أي fns التي تحصل على القيمة وتعيينها. لكن من الخارج، لا تزال تبدو وكأنها عقارات عادية.

الخصائص العادية تسمى خصائص البيانات.

  • تعتبر Getters & Settters شائعة في جميع الكائنات في JS، أي يمكن أن يكون لكل كائن خاصية getter وsetter. تُسمى أداة getter-setter هذه بخصائص الوصول، بينما تُسمى الخصائص العادية كخصائص بيانات.

- Getter & setter عبارة عن fns تحصل على قيمة وتعيينها، من الخارج تبدو كخصائص عادية.

const account = {
  owner: 'jonas',
  movements: [200,300,100,500],
  get latest(){
    // will return an array with last value. Hence, use pop to get the value.
    return this.movements.slice(-1).pop();
  },
  set latest(mov){
    this.movements.push(mov);
  }
}

account.latest; // 500
account.latest = 50; 
account.latest; // 50

Just like above, classes also support the getter-setter methods but acccessed like using a property syntax.

These are very useful for data validation.

الأساليب الثابتة

السابق. Array.from() = يحول البنية الشبيهة بالمصفوفة إلى مصفوفة.
Array.from(document.querySelector('h1'));
Array.from(document.querySelectorAll('h1'));

السابق. يتم إرفاق .from بمنشئ المصفوفة، وليس بخاصية النموذج الأولي للمنشئ. وبالتالي فإن جميع المصفوفات لا ترث هذا fn.
[1،2،3].من()؛ // .from ليس دالة

السابق. Number.parseFloat(12) هي طريقة ثابتة في مُنشئ الأرقام، وهي غير متوفرة في متغيرات الأرقام.

إنشاء طريقة ثابتة.

// Static methods are not inherited. They are not added to prototype.
className.fnName = function(){
  console.log(this); // Entire constructor() which is calling the method
  console.log("JS is awesome")
};
className.fnName();

// Rule =  whatever object is calling the method, 'this' points to that object inside the fn. Hence its simply the entire constructor() above.

//Inside class, we need to use static keyword for adding a static method.
static fnName = function(){
  console.log(this); // can point to the entire class defn
  console.log("JS is awesome")
};

// Static methods and instance methods will be different from each other.
// instance methods will be prototype, hence all instances can have access to them

كائن.إنشاء ():

يتم استخدامه يدويًا لتعيين النموذج الأولي لكائننا على أي كائن نريده.
سيتم استخدامها لتنفيذ فئات الميراث b/w.
تم تنفيذ الوراثة النموذجية باستخدام هذا fn.
يقوم Object.create بإرجاع كائن فارغ.
يعمل بطريقة مختلفة حيث يعمل المُنشئ fns والفئات.
لا تزال هناك فكرة عن وراثة النموذج الأولي، حتى بدون مشاركة "النموذج الأولي"، "المنشئ ()"، المشغل "الجديد".

const PersonProto = {
  // This method will be looked up using __proto__ link
  calcAge(){
    console.log(2024 - this.bYear);
  }
};

// baba will be created, with its prototype set to PersonProto object.
const baba = Object.create(PersonProto);
baba;

baba.name = 'Roger';
baba.bYear = '2000';
baba.calcAge();

المنشئ Fn --(.prototype)--> Person.prototype
مثيل الكائن --(proto)--> Person.prototype

يعمل تمامًا كما كان الحال مع منشئي fn أو في الفصول الدراسية
ليست هناك حاجة إلى خاصية منشئ() أو .prototype لتحقيق هذا الهدف.

const PersonProto = {
  // This method will be looked up using __proto__ link
  calcAge(){
    console.log(2024 - this.bYear);
  },
  // Noting special with init name, its a normal fn here.
  // This has nothing to with ES6 constructor()
  // Manual way of initialzing an object.
  init(fName, bYear){
    this.fName = fName;
    this.bYear = bYear;
  }
};

// baba will be created, with its prototype set to PersonProto object.
const baba = Object.create(PersonProto);
baba;

baba.name = 'Roger';
baba.bYear = '2000';
baba.calcAge();

baba.__proto__;    // { calcAge: [Function: calcAge] }
baba.__proto__ === PersonProto; //true


const alice = Object.create(PersonProto);
alice.init("alice", 2000);
alice;   // { fName: 'alice', bYear: 2000 }  

طرق إنشاء الوراثة النموذجية:
منشئ الجبهة الوطنية
فئات ES6
كائن.إنشاء

الوراثة بين الفئات باستخدام المُنشئ ():

كل هذه التقنيات تسمح للكائن بالبحث عن الأساليب في نموذجه الأولي.
الطبقات الحقيقية غير موجودة في JS.

const Person = function(firstName, bYear){
  this.firstName = firstName;
  this.bYear = bYear;
};

Person.prototype.calcAge = function(){
  console.log(2024 - this.bYear);
};

const Student = function(firstName, bYear, course){
  // This is the duplicate code, any change in Person won't be reflected here.
  this.firstName = firstName;
  this.bYear = bYear;
  this.course = course;
};

Student.prototype.introduce = function(){
  console.log(`My name is ${this.firstName} and I study ${this.course}`);
}

const matt = new Student("Matt", 2000, "CSE");
matt.introduce(); //  'My name is Matt and I study CSE'

إزالة الكود الزائد من المثال أعلاه:

const Person = function(firstName, bYear){
  this.firstName = firstName;
  this.bYear = bYear;
};

Person.prototype.calcAge = function(){
  console.log(2024 - this.bYear);
};

const Student = function(firstName, bYear, course){
  // Person(firstName, bYear); -> This doesn't work because we are calling it as a regular fn call. 'new' has to be used to call this fn constructor. This fn call is simply a regular fn call, in which 'this' is set 'undefined'. Hence, an error as it cannot set firstName on undefined.
  // We want to set the 'this' inside this fn to be same as inside Person above.
  Person.call(this, firstName, bYear);
  this.course = course;
};

Student.prototype.introduce = function(){
  console.log(`My name is ${this.firstName} and I study ${this.course}`);
}

const matt = new Student("Matt", 2000, "CSE");
matt.introduce(); //  'My name is Matt and I study CSE'

'new' يُنشئ رابطًا تلقائيًا بين مثيل الكائن ونموذجه الأولي عبر proto
الفكرة الكاملة للميراث هي أن الفصل الفرعي يمكنه مشاركة السلوك من الفصل الأصلي حتى سلسلة النموذج الأولي.
النموذج الأولي[Object.prototype] = null; // يقع أعلى سلسلة النموذج الأولي.

const Person = function(firstName, bYear){
  this.firstName = firstName;
  this.bYear = bYear;
};

Person.prototype.calcAge = function(){
  console.log(2024 - this.bYear);
};

const Student = function(firstName, bYear, course){
  Person.call(this, firstName, bYear);
  this.course = course;
};

// Student.prototype = Person.prototype; => This doesn't work because we won't get the prototype chain, rather we will get 
// Constructor fn[i.e Person()]    --------------> Person.prototype
// Constructor fn[i.e Student()]   --------------> Person.prototype
// Object [Matt] __proto__: Student.prototype ---> Person.prototype

// Student.prototype manually linked for lookup to Person.prototype.
// This has to be done here and not after else Object.create will overwrite any of the existing methods like introduce() on it.
Student.prototype = Object.create(Person.prototype);

Student.prototype.introduce = function(){
  console.log(`My name is ${this.firstName} and I study ${this.course}`);
}

const matt = new Student("Matt", 2000, "CSE");
matt.introduce(); //  'My name is Matt and I study CSE'
matt.calcAge();    // 24

matt.__proto__;                   // Person { introduce: [Function (anonymous)] }
matt.__proto__.__proto__;        // { calcAge: [Function (anonymous)] }
matt.__proto__.__proto__.__proto__;   // [Object: null prototype] {}

Student.prototype.constructor = Student;   // [Function: Student]

matt instanceof Student; // true
matt instanceof Person; // true
matt instanceof Object; // true
بيان الافراج تم نشر هذه المقالة على: https://dev.to/mahf001/oops-in-js-22-5a2n?1 إذا كان هناك أي انتهاك، يرجى الاتصال بـ [email protected] لحذفه
أحدث البرنامج التعليمي أكثر>

تنصل: جميع الموارد المقدمة هي جزئيًا من الإنترنت. إذا كان هناك أي انتهاك لحقوق الطبع والنشر الخاصة بك أو الحقوق والمصالح الأخرى، فيرجى توضيح الأسباب التفصيلية وتقديم دليل على حقوق الطبع والنشر أو الحقوق والمصالح ثم إرسالها إلى البريد الإلكتروني: [email protected]. سوف نتعامل مع الأمر لك في أقرب وقت ممكن.

Copyright© 2022 湘ICP备2022001581号-3