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

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