يقدم
تعد أوضاع إعادة استخدام الرمز الأربعة التي تم تقديمها في هذه المقالة أفضل الممارسات ويوصى بها للجميع أثناء عملية البرمجة.
النمط 1: ميراث النموذج الأولي
ميراث النموذج الأولي هو السماح للكائن الأصل أن يكون النموذج الأولي للكائن الطفل ، وذلك لتحقيق الغرض من الميراث:
نسخة الكود كما يلي:
كائن الوظيفة (س) {
وظيفة f () {
}
f.prototype = o ؛
إرجاع جديد f () ؛
}
// كائن الوالدين للوراثة
var parent = {
الاسم: "بابا"
} ؛
// كائن جديد
var child = object (parent) ؛
// امتحان
console.log (child.name) ؛ // "بابا"
// مُنشئ الوالدين
وظيفة person () {
// خاصية "خاصة"
this.name = "Adam" ؛
}
// إضافة سمات جديدة إلى النموذج الأولي
person.prototype.getName = function () {
إرجاع هذا.
} ؛
// إنشاء شخص جديد
var papa = شخص جديد () ؛
// الميراث
var kid = object (papa) ؛
console.log (kid.getName ()) ؛ // "آدم"
// مُنشئ الوالدين
وظيفة person () {
// خاصية "خاصة"
this.name = "Adam" ؛
}
// إضافة سمات جديدة إلى النموذج الأولي
person.prototype.getName = function () {
إرجاع هذا.
} ؛
// الميراث
var kid = object (person.prototype) ؛
console.log (typeof kid.getName) ؛ // "وظيفة" ، لأنه محدد في النموذج الأولي
console.log (typeof kid.name) ؛ // "غير محدد" ، لأن النموذج الأولي فقط ورث
في الوقت نفسه ، يوفر ECMASCRIPT5 أيضًا طريقة مماثلة تسمى Object.create لكائنات مورث ، والاستخدام كما يلي:
نسخة الكود كما يلي:
/* استخدم الإصدار الجديد من Ecmascript 5 لتوفير الميزات*/
var child = object.create (parent) ؛
var child = object.create (الوالد ، {
العمر: {value: 2} // ecma5 و descriptor
}) ؛
console.log (child.hasownproperty ("Age")) ؛ // حقيقي
علاوة على ذلك ، يمكن أيضًا تعريف الخصائص على المعلمة الثانية بطريقة أكثر حبيبة:
نسخة الكود كما يلي:
// أولاً ، حدد رجل جديد
var man = object.create (null) ؛
// التالي ، قم بإنشاء إعداد تكوين يحتوي على خصائص
// يتم تعيين الخصائص على القابلة للكتابة ، والتعداد ، والقابلة للتكوين
var config = {
قابل للكتابة: صحيح ،
التعداد: صحيح ،
قابل للتكوين: صحيح
} ؛
// عادةً ما استخدم Object.DefineProperty () لإضافة خصائص جديدة (دعم ECMASCRIPT5)
// الآن ، للراحة ، نقوم بتخصيص وظيفة التغليف
var defineProp = function (obj ، key ، value) {
config.value = value ؛
Object.DefineProperty (OBJ ، Key ، config) ؛
}
DefineProp (Man ، 'Car' ، 'Delorean') ؛
DefineProp (Man ، 'Dob' ، '1981') ؛
DefineProp (رجل ، "بيرد" ، خطأ) ؛
لذلك ، يمكن القيام بالميراث:
نسخة الكود كما يلي:
var driver = object.create (man) ؛
DefineProp (Driver ، 'Topspeed' ، '100mph') ؛
driver.topspeed // 100mph
ولكن هناك شيء واحد يجب ملاحظته ، أي أن النموذج الأولي للكائن الذي تم إنشاؤه بواسطة Object.create (NULL) غير محدد ، أي أنه لا يوجد أساليب tostring وقيمة ، لذلك سيحدث خطأ عند التنبيه (MAN) ؛ ولكن في حالة تأهب (man.car) ؛ بخير.
الوضع 2: انسخ جميع سمات الميراث
الميراث بهذه الطريقة هو نسخ جميع الخصائص الموجودة في الكائن الأصل للكائن الطفل. بشكل عام ، يمكن للكائن الطفل استخدام بيانات الكائن الأصل.
دعونا نلقي نظرة أولاً على مثال نسخة ضحلة:
نسخة الكود كما يلي:
/* نسخة ضحلة*/
تمتد الوظيفة (الوالد ، الطفل) {
var i ؛
طفل = طفل || {} ؛
ل (أنا في الوالد) {
if (parent.hasownproperty (i)) {
الطفل [i] = الوالد [i] ؛
}
}
إعادة الطفل
}
var dad = {name: "adam"} ؛
var kid = تمديد (أبي) ؛
console.log (kid.name) ؛ // "آدم"
فار أبي = {
التهم: [1 ، 2 ، 3] ،
تقرأ: {paper: true}
} ؛
var kid = تمديد (أبي) ؛
kid.counts.push (4) ؛
console.log (dad.counts.toString ()) ؛ // "1،2،3،4"
console.log (dad.Reads === Kid.Reads) ؛ // حقيقي
في السطر الأخير من الكود ، يمكنك أن تجد أن قراءات Dad and Kid متشابهة ، أي أنها تستخدم نفس المرجع ، وهي المشكلة الناجمة عن النسخة الضحلة.
لنلقي نظرة على النسخة العميقة:
نسخة الكود كما يلي:
/* نسخة عميقة*/
وظيفة تمتد (الوالد ، الطفل) {
var i ،
tostr = object.prototype.tostring ،
ASTR = "[كائن صفيف]" ؛
طفل = طفل || {} ؛
ل (أنا في الوالد) {
if (parent.hasownproperty (i)) {
if (typeof parent [i] === 'Object') {
الطفل [i] = (tostr.call (الوالد [i]) === ast)؟ []: {} ؛
ExtendDeep (الوالد [i] ، الطفل [i]) ؛
} آخر {
الطفل [i] = الوالد [i] ؛
}
}
}
إعادة الطفل
}
فار أبي = {
التهم: [1 ، 2 ، 3] ،
تقرأ: {paper: true}
} ؛
var kid = ExtendDeep (dad) ؛
kid.counts.push (4) ؛
console.log (kid.counts.toString ()) ؛ // "1،2،3،4"
console.log (dad.counts.toString ()) ؛ // "1،2،3"
console.log (dad.Reads === Kid.Reads) ؛ // خطأ شنيع
kid.reads.paper = false ؛
بعد النسخ العميق ، لم تعد القيمتان متساوية ، البنغو!
الوضع 3: مزيج
يتم خلطه في نسخ خصائص واحدة أو أكثر (أو كلها) (أو طرق) لكائن آخر إلى كائن آخر. دعنا نعطي مثالا:
نسخة الكود كما يلي:
وظيفة MIX () {
var arg ، prop ، child = {} ؛
لـ (arg = 0 ؛ arg <ediuments.length ؛ arg += 1) {
لـ (prop in endress [arg]) {
إذا (الحجج [Arg] .hasownproperty (prop)) {
الطفل [prop] = الحجج [arg] [prop] ؛
}
}
}
إعادة الطفل
}
كعكة var = مزيج (
{البيض: 2 ، كبير: صحيح} ،
{الزبدة: 1 ، مملح: صحيح} ،
{الدقيق: '3 أكواب'} ،
{السكر: "بالتأكيد!" }
) ؛
console.dir (كعكة) ؛
تقوم دالة المزيج بنسخ سمات الطفل لجميع المعلمات التي تم تمريرها إلى كائن الطفل لإنشاء كائن جديد.
فكيف نريد فقط خلط بعض السمات؟ كيف تفعل ذلك؟ في الواقع ، يمكننا استخدام معلمات إضافية لتحديد الخصائص التي تحتاج إلى خلطها ، مثل المزيج (الطفل ، الوالد ، الطريقة 1 ، الطريقة 2) بحيث يمكننا فقط مزج الطريقة 1 و method2 في الوالد إلى الطفل. على الرمز:
نسخة الكود كما يلي:
// سيارة
var car = function (الإعدادات) {
this.model = settings.model || "لم يتم توفير نموذج" ؛
this.colour = settings.colour || "لم يتم توفير لون" ؛
} ؛
// Mixin
var mixin = function () {} ؛
mixin.prototype = {
DriveForward: Function () {
console.log ('Drive Forward') ؛
} ،
DRAIDBARKWARD: FUNCTION () {
console.log ('Drive Backward') ؛
}
} ؛
.
وظيفة زيادة (TrabsObj ، GiveObj) {
// إذا تم توفير اسم الطريقة المحددة ، فهناك 3 معلمات إضافية
إذا (الحجج [2]) {
لـ (var i = 2 ، len = ediuments.length ؛ i <len ؛ i ++) {
receivingobj.prototype [الوسيطات [i]] = GiveObj.Prototype [الحجج [i]] ؛
}
}
// إذا لم تحدد المعلمة الثالثة ، أو المزيد من المعلمات ، فسيتم خلط جميع الطرق
آخر {
لـ (var methodName in GiveObj.prototype) {
// تحقق من أن الكائن المستلم لا يحتوي على الاسم المراد خلطه ، لذلك إذا تم تضمينه ، فلن يتم خلطه
if (! receivingobj.prototype [methodName]) {
receivingobj.prototype [methodName] = GiveObj.Prototype [methodName] ؛
}
}
}
}
// امزج السمات الخاصة بالسيارة ، ولكن يتم خلط القيم مع "DriveForward" و "DROFERBACKWARD"*/
mupment (Car ، Mixin ، "DriveForward" ، "DRAINBARKWARD") ؛
// إنشاء سيارة كائن جديدة
var choice = new car ({model: 'ford escort' ، color: 'Blue'}) ؛
// طريقة لاختبار ما إذا كان يتم الحصول على الخلط بنجاح
motter.driveforward () ؛
motter.driveward () ؛
هذه الطريقة أكثر مرونة للاستخدام.
النمط 4: طريقة الاقتراض
يستعير كائن واحد طريقًا أو طريقتين لكائن آخر ، ولا يوجد اتصال مباشر بين هذين الكائنين. لا حاجة لشرح المزيد ، فقط استخدم الكود لشرح:
نسخة الكود كما يلي:
var one = {
الاسم: "كائن" ،
قل: وظيفة (تحية) {
إرجاع تحية + '،' + this.name ؛
}
} ؛
// امتحان
console.log (one.say ('hi')) ؛ // "مرحبًا ، كائن"
var two = {
الاسم: "كائن آخر"
} ؛
console.log (one.say.apply (اثنين ، ['hello'])) ؛ // "مرحبا ، كائن آخر"
.
فار يقول = واحد.
console.log (say ('hoho')) ؛ // "Hoho ، غير محدد"
// تمرير رد اتصال وظيفة رد الاتصال
var yetanother = {
الاسم: "كائن آخر" ،
الطريقة: وظيفة (رد الاتصال) {
عودة رد الاتصال ('hola') ؛
}
} ؛
console.log (yetanother.method (One.say)) ؛ // "Holla ، غير محدد"
وظيفة bind (o ، m) {
وظيفة الإرجاع () {
Return M.Apply (O ، [] .Slice.Call (الحجج)) ؛
} ؛
}
var twosay = bind (اثنين ، one.say) ؛
console.log (twosay ('yo')) ؛ // "يو ، كائن آخر"
// ECMASCRIPT 5 يضيف طريقة bind () إلى الوظيفة. النمط النمط بحيث يكون من السهل استخدام تطبيق () و call ().
if (typeof function.prototype.bind === 'undefined') {
function.prototype.bind = function (thisarg) {
var fn = هذا ،
slice = array.prototype.slice ،
args = slice.call (الحجج ، 1) ؛
وظيفة الإرجاع () {
return fn.apply (thisarg ، args.concat (slice.call (الحجج))) ؛
} ؛
} ؛
}
var twosay2 = One.say.bind (اثنين) ؛
console.log (twosay2 ('bonjour')) ؛ // "Bonjour ، كائن آخر"
var twosay3 = One.say.bind (اثنان ، 'Enchanté') ؛
console.log (twosay3 ()) ؛ // "Enchanté ، كائن آخر"
لخص
لا حاجة لتلخيص.