Object.create()
الدالة Object.create()
تُنشِئ كائنًا جديدًا له كائن prototype مُحدَّد، وتكون خاصياته معطية.
البنية العامة
Object.create(proto[, propertiesObject])
proto
الكائن الذي يجب أن يُسنَد إلى خاصية prototype
للكائن المُنشأ.
propertiesObject
هذا الوسيط اختياريٌ، وإذا حُدِّدَت قيمته ولم تكن undefined
، فهو كائنٌ فيه خاصياتٌ تابعةٌ له وقابلةٌ للإحصاء تُحدِّد واصفات الخاصيات (property descriptors) التي ستُضاف إلى الكائن المُنشَأ والتي سترتبط بأسماء الخاصيات. وهذه الخاصيات تشبه الوسيط الثاني المُمرَّر إلى الدالة Object.defineProperties()
(ارجع إلى تلك الصفحة إن وجدتَ الكلام السابق غامضًا).
القيمة المعادة
كائن جديد يملك كائن prototype وخاصيات تابعة له.
الاستثناءات
سيُرمى الاستثناء TypeError
إذا كانت قيمة المعامل propertiesObject
لا تساوي null
أو لم تكن كائنًا.
أمثلة
الوراثة التقليدية مع Object.create()
المثال الآتي يبيّن كيفية استخدام الدالة Object.create()
لتحقيق الوراثة التقليدية في JavaScript؛ وهذه وراثة أحادية (single inheritance، أي ليست من كائنات متعددة)، وتدعمها كل كائنات JavaScript. لاحظ كيف أنشأنا الكائن Shape
وعرِّفنا الدالة move
في خاصية prototype
التابعة له، ثم عرّفنا صنفًا فرعيًا باسم Rectangle
(الذي استدعى الدالة البانية للكائن Shape
)، ثم استخدمنا الدالة Object.create()
لإسناد سلسلة prototype للكائن Shape
إلى خاصية prototype
للكائن Rectangle
:
// Shape - الصنف الأب
function Shape() {
this.x = 0;
this.y = 0;
}
// دالة في الصنف الأب
Shape.prototype.move = function(x, y) {
this.x += x;
this.y += y;
console.info('Shape moved.');
};
// Rectangle - الصنف الابن
function Rectangle() {
Shape.call(this); // استدعاء الدالة البانية للصنف الأب
}
// وراثة الصنف الابن للصنف الأب
Rectangle.prototype = Object.create(Shape.prototype);
Rectangle.prototype.constructor = Rectangle;
var rect = new Rectangle();
console.log('Is rect an instance of Rectangle?',
rect instanceof Rectangle); // true
console.log('Is rect an instance of Shape?',
rect instanceof Shape); // true
rect.move(1, 1); // 'Shape moved.'
أما إذا أردتَ الوراثة من عدِّة كائنات، فاستعمل الدالة Object.assign()
لنسخ الخاصيات من الخاصية prototype
للكائن OtherSuperClass
إلى خاصية prototype
للكائن MyClass
، مما يجعلها متاحةً لجميع نسخ الكائن MyClass
؛ لاحظ أنَّ الدالة Object.assign()
قد أُضيفَت في معيار EMCAScript 2015 (أي ES6) لكن يمكن تعويض نقص دعم المتصفحات لها (انظر صفحة تلك الدالة):
function MyClass() {
SuperClass.call(this);
OtherSuperClass.call(this);
}
// الوراثة من أحد الكائنات
MyClass.prototype = Object.create(SuperClass.prototype);
// ومن كائن آخر
Object.assign(MyClass.prototype, OtherSuperClass.prototype);
// إعادة إسناد الدالة البانية
MyClass.prototype.constructor = MyClass;
MyClass.prototype.myMethod = function() {
// ...
};
استخدام الوسيط propertiesObject
لاحظ أنَّ الوسيط الثاني للدالة Object.create()
يربط المفاتيح بواصفات الخاصيات (property descriptors):
var o;
// إنشاء كائن دون سلسلة prototype
o = Object.create(null);
o = {};
// ما سبق يكافئ التعبير الآتي
o = Object.create(Object.prototype);
// لاحظ أنَّ الوسيط الثاني يربط المفاتيح بواصفات الخاصيات
o = Object.create(Object.prototype, {
// foo is a regular 'value property'
foo: {
writable: true,
configurable: true,
value: 'hello'
},
// هذه الخاصية لها getter و setter
bar: {
configurable: false,
get: function() { return 10; },
set: function(value) {
console.log('Setting `o.bar` to', value);
}
}
});
لاحظ أنَّه افتراضيًا لا تكون الخاصيات قابلةً للكتابة أو الضبط أو الإحصاء:
function Constructor() {}
o = new Constructor();
// ما سبق يكافئ
o = Object.create(Constructor.prototype);
// لكن لاحظ أنَّ استخدام هذه الدالة لا يؤدي إلى تنفيذ الشيفرات الموجودة
// ضمن الدالة البانية
// إنشاء كائن جديد له خاصية واحدة
o = Object.create({}, { p: { value: 42 } });
// تكون الخاصيات افتراضيًا غير قابلة للكتابة أو الضبط أو الإحصاء
o.p = 24;
o.p;
// 42
o.q = 12;
for (var prop in o) {
console.log(prop);
}
// 'q'
delete o.p;
// false
// لتعريف الخاصيات الاعتيادية
o2 = Object.create({}, {
p: {
value: 42,
writable: true,
enumerable: true,
configurable: true
}
});
تعويض نقص دعم المتصفحات
هذه الشيفرة تغطي حالة الاستخدام الرئيسية التي هي إنشاء كائن جديد مع تحديد كائن ليُستخدَم في خاصية prototype
؛ لكن لا تأخذ الوسيط الثاني الذي تقبله الدالة Object.create()
في الحسبان.
لاحظ أنَّ ضبط القيمة null
كقيمة لخاصية prototype (أي [[Prototype]]
) هو أمرٌ مدعوم في الدالة Object.create()
في ES5؛ لكن الشيفرة الآتية لا تستطيع فعل ذلك لأنه غير ممكن في إصدارات ECMAScript الأقل من 5.
if (typeof Object.create !== "function") {
Object.create = function (proto, propertiesObject) {
if (typeof proto !== 'object' && typeof proto !== 'function') {
throw new TypeError('Object prototype may only be an Object: ' + proto);
} else if (proto === null) {
throw new Error("This browser's implementation of Object.create is a shim and doesn't support 'null' as the first argument.");
}
if (typeof properties != 'undefined') throw new Error("This browser's implementation of Object.create is a shim and doesn't support a second argument.");
function F() {}
F.prototype = proto;
return new F();
};
}
دعم المتصفحات
الميزة | Chrome | Firefox | Internet Explorer | Opera | Safari |
---|---|---|---|---|---|
الدعم الأساسي | 5 | 4 | 9 | 11.6 | 5 |
مصادر ومواصفات
- مسودة المعيار ECMAScript Latest Draft.
- معيار ECMAScript 2015 (6th Edition).
- معيار ECMAScript 5.1.