ملخص
جميع الكائنات في JavaScript لها سلسلة الميراث الخاصة بها. أي أن كل كائن يرث كائنًا آخر ، والذي يسمى كائن "النموذج الأولي". باستثناء NULL ، ليس لديها كائن النموذج الأولي الخاص بها.
تكمن أهمية كائن النموذج الأولي في أنه إذا كان الكائن A هو نموذج أولي للكائن B ، يمكن للكائن B الحصول على جميع خصائص وطرق الكائن A. يتم استخدام طريقة comple.getPrototypof للحصول على كائن النموذج الأولي للكائن الحالي.
var p = object.getPrototypeof (OBJ) ؛
في الكود أعلاه ، الكائن P هو كائن النموذج الأولي لكائن OBJ.
يتم استخدام طريقة كائن. لإنشاء كائن جديد وروث الكائن المحدد.
var obj = object.create (p) ؛
في الكود أعلاه ، فإن النموذج الأولي لكائن OBJ الذي تم إنشاؤه حديثًا هو كائن p.
يمكن أن تعيد سمة __proto__ غير القياسية (اثنان من السطحين في المقدمة وخلفها) إعادة كتابة كائن النموذج الأولي لكائن معين. ومع ذلك ، يجب أن تحاول استخدام هذه الخاصية بأقل قدر ممكن ، ولكن استخدام Object.getPrototypeoF () و Object.setProtypeOf () لقراءة وكتابة الكائنات النموذجية.
var obj = {} ؛ var p = {} ؛ obj .__ proto__ = p ؛ object.getProtypeof (obj) === p // trueيعين الرمز أعلاه كائن P كنموذج أولي لكائن OBJ من خلال سمة __proto__.
هنا مثال عملي.
var a = {x: 1} ؛ var b = {__proto__: a} ؛ bx // 1في الكود أعلاه ، يقوم الكائن B بتعيين كائن النموذج الأولي الخاص به ككائن من خلال سمة __proto__ ، بحيث يمكن للكائن B الحصول على جميع خصائص وطرق الكائن A. لا يحتوي الكائن B نفسه على سمة X ، لكن محرك JavaScript يجد كائن النموذج الأولي الخاص به A من خلال سمة __proto__ ، ثم يقرأ سمة X لـ A.
ينشئ الأمر الجديد كائن مثيل جديد من خلال مُنشئ. إنه يرتبط بشكل أساسي النموذج الأولي لكائن المثيل إلى خاصية النموذج الأولي للمُنشئ ، ثم تنفيذ المُنشئ على كائن المثيل.
var o = new foo () ؛ // يعادل var o = new Object () ؛ o .__ proto__ = foo.prototype ؛ foo.call (o) ؛
يمكن أن تشير سمة __proto__ لكائن النموذج الأولي إلى كائنات أخرى ، وبالتالي تشكيل مستوى "سلسلة النموذج الأولي" حسب المستوى.
var a = {x: 1} ؛ var b = {__proto__: a} ؛ var c = {__proto__: b} ؛ cx // 1تجدر الإشارة إلى أن البحث عن سمة معينة في سلسلة النموذج الأولي له تأثير على الأداء. كلما ارتفع مستوى كائن النموذج الأولي الذي تبحث عنه ، زاد التأثير على الأداء. إذا كنت تبحث عن خاصية غير موجودة ، فسوف يعبر سلسلة النموذج الأولي بأكمله.
هذا الإجراء يشير
بغض النظر عن المكان الذي يتم فيه تحديد ذلك ، عند استخدامه ، فإنه يشير دائمًا إلى الكائن الحالي ، وليس كائن النموذج الأولي.
var o = {a: 2 ، m: function (b) {return this.a + 1 ؛ }} ؛ var p = object.create (o) ؛ pa = 12 ؛ pm () // 13في الكود أعلاه ، تأتي طريقة M لكائن P من كائن النموذج الأولي O. في هذا الوقت ، لا يشير هذا الكائن داخل طريقة M إلى O ، ولكن إلى P.
ميراث المنشئين
يقدم هذا القسم كيفية جعل أحد المنشئ يرث مُنشئًا آخر.
افترض أن هناك مُنشئ الشكل.
وظيفة وظيفة () {this.x = 0 ؛ this.y = 0 ؛} lape.prototype.move = function (x ، y) {this.x += x ؛ this.y += y ؛ console.info ("تم نقل الشكل") ؛} ؛ يرث مُنشئ المستطيل الشكل. الدالة rectangle () {lape.call (this) ؛ // استدعاء مُنشئ الفئة الأصل} // طريقة أخرى لكتابة الدالة rectangle () {this.base = form ؛ this.base () ؛} // يرث الفئة الفرعية طريقة الفئة الأصل stangle.prototype = object.create (form.prototype) ؛ rect.prototype.constructor = rectangle ؛ var rectangle = new rectangle () ؛ rect stealof rectangle // truerect exture // truerect.move (1 ، 1) // 'تم نقل الشكل.'يوضح الرمز أعلاه أن وراثة المُنشئ مقسمة إلى جزأين ، أحدهما هو أن الفئة الفرعية تستدعي طريقة مُنشئ الفئة الأصل ، والآخر هو أن النموذج الأولي للكنيسة الفرعية يشير إلى النموذج الأولي للفئة الأصل.
في الكود أعلاه ، ترث الفئة الفرعية فئة الأصل ككل. في بعض الأحيان ، لا يلزم سوى ميراث طريقة واحدة ، ويمكن استخدام طريقة الكتابة التالية.
classb.prototype.print = function () {classa.prototype.print.call (this) ؛ // بعض الكود}في الكود أعلاه ، تقوم طريقة الطباعة بالفئة الفرعية B أولاً باستدعاء طريقة الطباعة للفئة A ، ثم تنشر التعليمات البرمجية الخاصة بها. هذا يعادل وراثة طريقة الطباعة للفئة الأصل A.
__proto__ السمة
تشير سمة __proto__ إلى كائن النموذج الأولي للكائن الحالي ، أي سمة النموذج الأولي للمركبة.
var obj = new Object () ؛ obj .__ proto__ === object.prototype // trueobj .__ proto__ === obj.constructor.prototype // true
يقوم الرمز أعلاه أولاً بإنشاء كائن جديد OBJ ، سمة __proto__ ، مشيرًا إلى سمة النموذج الأولي للمُنشئ (الكائن أو OBJ.Constructor). لذلك ، بعد مقارنة الاثنين ، ارجع صحيح.
لذلك ، هناك ثلاث طرق للحصول على كائن النموذج الأولي لكائن مثيل OBJ.
من بين الطرق الثلاثة المذكورة أعلاه ، لا يمكن الاعتماد على الأولين. ينص أحدث معيار ES6 على أن المتصفح فقط يحتاج إلى نشر سمة __proto__ ، ولا يجوز نشر بيئات أخرى. ومع ذلك ، قد يفشل Obj.constructor.prototype عند تغيير كائن النموذج الأولي يدويًا.
var p = function () {} ؛ var p = new p () ؛ var c = function () {} ؛ c.prototype = p ؛ var c = new c () ؛في الكود أعلاه ، يتم تغيير كائن النموذج الأولي لمؤسسة C إلى P ، والنتيجة هي أن النمط c.constructor.protatepe مشوه. لذلك ، عند تغيير كائن النموذج الأولي ، يجب تعيين سمة المنشئ في نفس الوقت.
c.prototype = p ؛ c.prototype.constructor = c ؛ c.constructor.prototype === p // true
لذلك ، يوصى باستخدام طريقة الكائن الثالث. GetPrototypeOF للحصول على كائن النموذج الأولي. استخدام هذه الطريقة على النحو التالي.
var o = new Object () ؛ object.getPrototypeof (o) === object.prototype // true
يمكنك استخدام طريقة GOOB.GetPrototypeOF للتحقق مما إذا كان المتصفح يدعم سمة __proto__ ، والتي لا تدعمها المتصفحات القديمة.
Object.getPrototypeof ({__proto__: null}) === nullيقوم الرمز أعلاه بتعيين سمة __proto__ لكائن ما إلى خالية ، ثم يستخدم طريقة comple.getPrototypeOF للحصول على النموذج الأولي لهذا الكائن لتحديد ما إذا كان مساوياً لـ NULL. إذا كانت البيئة الحالية تدعم سمة __proto__ ، فيجب أن تكون نتيجة المقارنة بين الاثنين صحيحة.
باستخدام سمة __proto__ ، من السهل إعداد النموذج الأولي لكائن المثيل. لنفترض أن هناك ثلاثة كائنات: الماكينة والسيارة والسيارة ، حيث تكون الماكينة هي النموذج الأولي للمركبة والمركبة هي النموذج الأولي للسيارة ، والتي يمكن تعيينها بخطين فقط من التعليمات البرمجية.
مركبة .__ proto__ = machine ؛ car .__ proto__ = مركبة ؛
فيما يلي مثال. تتم قراءة الخصائص المحددة على كائن النموذج الأولي على التوالي من خلال سمة __proto__ وسمة النمط.
Array.Prototype.p = 'abc' ؛ var a = new array () ؛ a .__ proto __.
من الواضح أن __proto__ تبدو أكثر إيجازًا قليلاً.
عندما يتم إنشاء كائن مثيل من خلال مُنشئ ، فإن سمة __proto__ لكائن المثيل تشير تلقائيًا إلى كائن النموذج الأولي للمُنشئ.
var f = function () {} ؛ var a = {} ؛ f.prototype = a ؛ var o = new f () ؛ o .__ proto__ === a // trueميراث السمات
هناك نوعان من السمات. إحداها هي السمة الأصلية للكائن نفسه ، والآخر هو السمة الموروثة الموروثة من النموذج الأولي.
الخصائص الأصلية للكائن
يمكن الحصول على جميع خصائص الكائن نفسه باستخدام طريقة الكائن.
Object.getOndPropertyNames (Date) // ["parse" ، "alcessions" ، "UTC" ، "Caller" ، "Name" ، "OrityType" ، "Now" ، "Length"]
من بين خصائص الكائن نفسه ، بعضها لا يمكن تعداده (التعداد) ، في حين أن البعض الآخر لا يمكن تعداده. فقط الحصول على تلك الخصائص التي يمكن تعدادها ، استخدم طريقة الكائن.
Object.Keys (التاريخ) // [] hasownproperty ()
تُرجع طريقة HasOwNproperty قيمة منطقية لتحديد ما إذا كان يتم تعريف خاصية معينة على الكائن نفسه أو على سلسلة النموذج الأولي.
date.hasownproperty ('length') // truedate.hasownproperty ('toString') // falseطريقة HasOwnProperty هي الطريقة الوحيدة في JavaScript التي لا تعبر سلسلة النموذج الأولي عند معالجة خصائص الكائن.
خصائص الميراث لكائن
سوف ترث الكائنات التي تم إنشاؤها باستخدام الكائن.
var proto = {p1: 123} ؛ var o = object.create (proto) ؛ o.p1 // 123o.hasownproperty ("p1") // falseاحصل على جميع السمات
لتحديد ما إذا كان للكائن خاصية معينة (سواء كان ذلك أو ورثًا) ، استخدم المشغل في.
"طول" في التاريخ // صحيح "tostring" في التاريخ // صحيح
احصل على جميع خصائص التعداد لكائن (سواء كان خاصًا أو ورثًا) ، ويمكنك استخدام حلقة من أجل الوصول.
var o1 = {p1: 123} ؛ var o2 = object.create (o1 ، {p2: {value: "abc" ، enumeries: true}}) ؛ for (p in o2) {console.info (p) ؛} // p2 // p1من أجل الحصول على خصائص الكائن الخاصة في ... في الحلقة ، يمكنك استخدام طريقة HasownProperty للحكم.
لـ (اسم var في الكائن) {if (object.hasownproperty (name)) { / * loop code * /}}للحصول على جميع خصائص الكائن (سواء كان خاصًا أو ورثًا ، وما إذا كان غير قابل للتعداد) ، يمكنك استخدام الوظيفة التالية.
دالة inlortedPropertyNames (obj) {var props = {} ؛ بينما (obj) {object.getownProperTyNames (obj). obj = object.getPrototypeof (OBJ) ؛ } إرجاع object.getownpropertynames (الدعائم) ؛}الاستخدام كما يلي:
MornittedPropertyNames (التاريخ) // ["المتصل" ، "مُنشئ" ، "tostring" ، "UTC" ، "Call" ، "Parse" ، "النموذج الأولي" ، "__definesetter__" ، "__lookupsetter__" ، "الطول" ، "الحجج" ، "__ lookepgetter__" ، " "propertyisenumerable" ، "valueof" ، "تطبيق" ، "__definegetter__" ، "الاسم" ، "الآن" ، "hasownproperty"]
نسخة من الكائن
إذا كنت ترغب في نسخ كائن ، فأنت بحاجة إلى القيام بأمرين التاليين.
تأكد من أن الكائن النسخ يحتوي على نفس كائن النموذج الأولي ككائن أصلي.
تأكد من أن الكائن النسخ له نفس خصائص الكائن الأصلي.
فيما يلي وظيفة نسخ الكائن المكتوب بناءً على النقطتين أعلاه.
دالة copyObject (Orig) {var copy = object.create (object.getPrototypeof (Orig)) ؛ copyOwnPropertiesFrom (نسخة ، أصول) ؛ return copy ؛} function copyOwnPropertiesFrom (الهدف ، المصدر) {object .getOndProperTyNames (source). الهدف الإرجاع ؛}ميراث متعدد
لا يوفر JavaScript وظائف ميراث متعددة ، أي أنها لا تسمح لكائن واحد براث كائنات متعددة في نفس الوقت. ومع ذلك ، يمكن تحقيق هذه الوظيفة من خلال الحلول.
الدالة m1 (prop) {this.hello = prop ؛} function m2 (prop) {this.world = prop ؛} function s (p1 ، p2) {this.base1 = m1 ؛ this.base1 (p1) ؛ this.base2 = m2 ؛ this.base2 (p2) ؛} s.prototype = new M1 () ؛ var s = new S (111 ، 222) ؛ S.Hello // 111S.World // 222في الكود أعلاه ، يرث الفئة الفرعية كلا الفئتين الأصل M1 و M2. بالطبع ، من منظور سلسلة الميراث ، يتم تنفيذ S فقط من فئة الوالدين M1 ، ولكن منذ أن تم تنفيذ منشئو M1 و M2 في نفس الوقت ، فإنه يرث طرق هاتين الفئتين في نفس الوقت.