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 نعم نعم

مصادر ومواصفات