Object.prototype.__proto__
الخاصية Object.prototype.__proto__
هي خاصية وصول (أي أنَّها دالة getter و setter) التي تسمح بالوصول إلى خاصية [[Prototype]]
الداخلية للكائن (إما أن تكون قيمة هذه الخاصية هي كائن أو null
) الذي اُستخدمَت عليه.
الخاصية __proto__
مثيرةٌ للجدل، ومن المستحسن عدم استخدامها، ولم تكن موجودةً في الأساس في معيار ECMAScript، لكن المتصفحات الحديثة وضعتها في محركات JavaScript التي تستعملها على أيّ حال؛ ثم من فترة قريبة أصبحت الخاصية __proto__
خاصيةً معياريةً في ECMAScript 2015 بغرض توحيد سلوكها بين المتصفحات، لذا ستكون هذه الخاصية مدعومةً في المستقبل لكنها مهملة الاستخدام (deprecated) لصالح الدوال Object.getPrototypeOf
و Object.setPrototypeOf
.
لاحظ أنَّ بالإمكان استخدام الخاصية __proto__
عند تعريف الكائنات بالشكل المختصر لضبط قيمة الخاصية [[Prototype]]
عند إنشاء الكائن، مما يُشكِّل بديلًا عن استخدام الدالة Object.create()
.
تحذير: تغيير خاصية [[Prototype]]
لأحد الكائنات هي عمليةٌ بطيئةٌ جدًا بسبب طبيعة تحسين محركات JavaScript الأداء للوصول إلى الخاصيات، وهي بطيئةٌ في جميع المتصفحات ومحركات JavaScript، وتأثيرها على الأداء بسبب تعديل طريقة وراثة الكائنات كبيرٌ وذو مدى بعيد، وليس مقتصرًا على الوقت اللازم لتنفيذ التعبير obj.__proto__ = ...
فقط، لكنه سيتمد لأيّة شيفرات ستصل إلى أيّة كائنات تغيّرت فيها قيمة الخاصية [[Prototype]]
؛ لذا إذا كنتَ مهتمًا بالأداء فتجنب تعديل هذه الخاصية، وذلك بإنشاء كائن جديد له كائن [[Prototype]]
الذي تريده باستخدام الدالة Object.create()
.
الوصف
دالة getter المسماة __proto__
تكشف قيمة الخاصية [[Prototype]]
الداخلية للكائن. أما للكائنات المُنشَأة بالصيغة المختصرة، فقيمة تلك الخاصية هي Object.prototype
؛ وأما للكائنات المنشأة بالصيفة المختصرة للمصفوفات فقيمة تلك الخاصية هي Array.prototype
، وقيمتها للدوال هي Function.prototype
.
أما الكائنات التي تُنشَأ باستخدام الكلمة المحجوزة new
، مثل new fun
، إذ إنَّ fun
هي دالة بانية مضمَّنة في اللغة (أي Array
و Boolean
و Date
و Number
و Object
و String
وهلمّ جرًا، بما في ذلك الدوال البانية التي ستُضاف مستقبلًا إلى لغة JavaScript)، فستكون تلك القيمة هي fun.prototype
دومًا. أما للكائنات التي تُنشَأ باستخدام new fun
، إذ إنَّ fun
هي دالةٌ عرَّفها المستخدم في السكربت، فستكون هذه القيمة هي قيمة الخاصية fun.prototype
(وذلك إذا لم تعد الدالة البانية كائنًا مختلفًا أو لم يُعاد إسناد قيمة أخرى إلى الخاصية fun.prototype
منذ إنشاء نسخة الكائن).
دالة setter باسم __proto__
تسمح أن يُغيّر الكائن الموجود في الخاصية [[Prototype]]
، لكن يجب أن يكون الكائن قابلةً للتوسعة وفقًا للدالة Object.isExtensible()
؛ وإذ لم يكن كذلك فسيرمى الخطأ TypeError
، والقيمة التي يجب إسنادها هي كائن أو null
، وتوفير أيّة قيمة أخرى لن يؤدي إلى فعل شيء.
صحيحٌ أنَّ معيار ECMAScript 2015 يقول أنَّ دعم الخاصية __proto__
مطلوبٌ لمتصفحات الويب فقط، لكن قد تدعمها بقية بيئات التشغيل لأسباب تاريخية.
أمثلة
مثال عن تغيير قيمة [[Prototype]]
باستخدام __porto__
، لاحظ أنَّه لا يجدر بك استخدام هذه الطريقة:
var Circle = function () {};
var shape = {};
var circle = new Circle();
shape.__proto__ = circle;
console.log(shape.__proto__ === circle); // true
مثال آخر:
var shape = function () {
};
var p = {
a: function () {
console.log('aaa');
}
};
shape.prototype.__proto__ = p;
var circle = new shape();
circle.a(); //aaa
console.log(shape.prototype === circle.__proto__); //true
// أو
var shape = function () {
};
var p = {
a: function () {
console.log('a');
}
};
var circle = new shape();
circle.__proto__ = p;
circle.a(); // a
console.log(shape.prototype === circle.__proto__); //false
// أو
function test() {
}
test.prototype.myname = function () {
console.log('myname');
}
var a = new test()
console.log(a.__proto__ === test.prototype); //true
a.myname();//myname
// أو
var fn = function () {
};
fn.prototype.myname = function () {
console.log('myname');
}
var obj = {
__proto__: fn.prototype
};
obj.myname(); //myname
دعم المتصفحات
الميزة | Chrome | Firefox | Internet Explorer | Opera | Safari |
---|---|---|---|---|---|
الدعم الأساسي | نعم | نعم | 11 | نعم | نعم |
مصادر ومواصفات
- مسودة المعيار ECMAScript Latest Draft.
- معيار ECMAScript 2015 (6th Edition)، جعل هذه الخاصية معياريةً.