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 |
مصادر ومواصفات
- مسودة المعيار ECMAScript Latest Draft.
- معيار ECMAScript 2015 (6th Edition).
- معيار ECMAScript 5.1.