Object.freeze()‎

من موسوعة حسوب

الدالة Object.freeze()‎ تُجمِّد كائنًا، مما يمنع إضافة خاصيات جديدة إليه، ويمنع حذف الخاصيات الموجودة فيه، ويمنع تعديل قيمة أو قابلية إحصاء أو قابلية ضبط أو قابلية الكتابة التابعة لخاصياته؛ ويمنع أيضًا تعديل سلسلة prototype، وستُعيد هذه الدالة الكائن في الحالة «المُجمَّدة».

البنية العامة

Object.freeze(obj)

obj

الكائن الذي سيُجمَّد.

القيمة المعادة

الكائن المُجمَّد.

الوصف

لا يمكن إضافة أو حذف أيّ شيء من خاصيات الكائنات المجمّدة؛ وأي محاولة لفعل ذلك ستفشل إما بصمت أو سترمي الاستثناء TypeError (وسيرمى هذا الخطأ عادةً في نمط strict).

لا يمكن تغيير قيم الخاصيات التي تحمل بيانات، أو دوال getter و setter، لاحظ أنَّه ما يزال بالإمكان تعديل قيم الكائنات المُسنَدة إلى الخاصيات ما لم تُجمَّد أيضًا.

من الممكن تجمد المصفوفات مثل الكائنات، إذ لن نستطيع تعديل قيم عناصرها، أو إضافة أو حذف عناصر منها.

لاحظ أنَّه في معيار ECMAScript 5 كان استعمال هذه الدالة على وسيطٍ ليس كائنًا (أي قيمةً أوليةً) سيؤدي إلى رمي TypeError، لكن بدءًا من ECMAScript 2015 (أي ES6) فستُعامل الوسائط التي لا تُمثِّل كائنات على أنها كائنات مُجمَّدة، أي أن قيمتها ستُعاد كما هي:

> Object.freeze(1)
TypeError: 1 is not an object // ES5

> Object.freeze(1)
1                             // ES2015

أمثلة

تجميد الكائنات

سنُنشِئ في المثال الآتي كائنًا باسم obj ونُضيف إليه خاصيات جديدة، ونُعدِّل خاصيات موجودة فيه، ونحذف أخرى:

var obj = {
  prop: function() {},
  foo: 'bar'
};

obj.foo = 'baz';
obj.lumpy = 'woof';
delete obj.prop;

لاحظ أنَّ الدالة Object.freeze()‎ ستُعيد الكائن المُجمّد، لكنها ستُجمِّد الكائن الأصلي أيضًا؛ لذا من غير الضروري حفظ الكائن المُعاد من الدالة لتجميد الكائن الأصلي:

var o = Object.freeze(obj);

o === obj; // true
Object.isFrozen(obj); // === true

لاحظ أنَّ عملية تعديل قيم الخاصيات أو إضافة خاصيات جديدة ستفشل بصمت، أما إذا كان نمط strict مفعَّلًا فسيرمى الخطأ TypeError:

obj.foo = 'quux'; // لن يحدث شيء
// ولن تُضاف الخاصية الجديدة
obj.quaxxor = 'the friendly duck';

function fail(){
  'use strict';
  obj.foo = 'sparky'; // TypeError
  delete obj.quaxxor; // TypeError
  obj.sparky = 'arf'; // TypeError
}

fail();

محاولة إجراء تعديلات باستخدام الدالة Object.defineProperty()‎ ستُسبِّب برمي الخطأ TypeError:

Object.defineProperty(obj, 'ohai', { value: 17 });   // TypeError
Object.defineProperty(obj, 'foo', { value: 'eit' }); // TypeError

من المستحيل تعديل قيمة الخاصية prototype، وكلا التعبيرين الآتيين سيرمي الخطأ TypeError:

Object.setPrototypeOf(obj, { x: 20 })
obj.__proto__ = { x: 20 }

تجميد المصفوفات

سنُنشِئ مصفوفةً باسم a، ثم سنجمِّدها ونحاول تعديل قيمها، وستفشل تلك المحاولات بصمت؛ أما إذا كنّا في نمط strict فسيرمى الخطأ TypeError:

let a = [0];
Object.freeze(a); // لم يعد بالإمكان تعديل المصفوفة

a[0]=1;    // ستفشل بصمت
a.push(2); // ستفشل بصمت

// سيرمى الخطأ TypeError
function fail() {
  "use strict"
  a[0] = 1;
  a.push(2);
}

fail();

التجميد العميق

صحيحٌ أنَّ الكائن المُجمَّد لن يكون قابلًا للتعديل، لكنه ليس «ثابتًا» (constant) بالضرورة؛ ففي المثال الآتي سيكون التجميد سطحيًا:

obj1 = {
  internal: {}
};

Object.freeze(obj1);
obj1.internal.a = 'aValue';

obj1.internal.a // 'aValue'

أما لجعل الكائن ساكنًا فيجب تجميد كل خاصية من خاصيات ذاك الكائن، وهذا ما يدعى «التجميد العميق»:

function deepFreeze(obj) {

  // الحصول على أسماء الخاصيات الموجودة في الكائن
  var propNames = Object.getOwnPropertyNames(obj);

  // تجميد تلك الخاصيات قبل تجميد الكائن
  propNames.forEach(function(name) {
    var prop = obj[name];

    // تجميد الخاصية إن كانت كائنًا
    if (typeof prop == 'object' && prop !== null)
      deepFreeze(prop);
  });

  // تجميد الكائن نفسه
  return Object.freeze(obj);
}

obj2 = {
  internal: {}
};

deepFreeze(obj2);
obj2.internal.a = 'anotherValue';
obj2.internal.a; // undefined

دعم المتصفحات

الميزة Chrome Firefox Internet Explorer Opera Safari
الدعم الأساسي 6 4 9 12 5.1

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