JSにおける属性記述オブジェクト6
5701 ワード
制御対象の状態
JavaScriptは、オブジェクトの読み書き状態を正確に制御し、オブジェクトの変更を防ぐ3つの方法を提供します.最弱層の保護はObject.prevent Extensionsで、その次はObject.sealで、最強のObject.freezeです.
Object.prevent Extensions()
Object.prevent Extensions方法は、1つのオブジェクトが新しい属性を追加できなくなります.
Object.isExtensioble方法は、オブジェクトがObject.prevent Extensions方法を使用しているかどうかを確認するために使用されます.つまり、オブジェクトに属性を追加できるかどうかをチェックします.
Object.seal()
Object.sealメソッドは、オブジェクトに新しい属性を追加することも、古い属性を削除することもできません.
Object.sealは、実質的に属性記述オブジェクトのconfigurble属性をfalseとするので、属性記述オブジェクトは変更できなくなります.
書いてもいいです.ちょっと特別です.もしwritableがfalseであれば、Object.sealの方法を使ってから、それをtrueに変えることはできません.しかし、もしwritableがtrueであれば、依然としてfalseに変えることができます.
属性オブジェクトのvalueが変更できるかどうかは、writableが決定します.
Object.isSealed()
Object.isSealed方法は、オブジェクトがObject.sealメソッドを使用しているかどうかを確認するために使用されます.
Object.freezeメソッドは、オブジェクトに新しい属性を追加できなくなり、古い属性を削除できなくなり、属性の値を変更することができなくなり、このオブジェクトが実際に定数になります.
Object.isFrozen法は、オブジェクトがObject.freeze()メソッドを使用しているかどうかを確認するために使用されます.
限界性
上記の方法では、オブジェクトの書き込み可能性に穴がありますが、元のオブジェクトを変更することにより、オブジェクトの属性を増加することができます.
JavaScriptは、オブジェクトの読み書き状態を正確に制御し、オブジェクトの変更を防ぐ3つの方法を提供します.最弱層の保護はObject.prevent Extensionsで、その次はObject.sealで、最強のObject.freezeです.
Object.prevent Extensions()
Object.prevent Extensions方法は、1つのオブジェクトが新しい属性を追加できなくなります.
var o = new Object();
Object.preventExtensions(o);
Object.defineProperty(o, 'p', {
value: 'hello'
});
// TypeError: Cannot define property:p, object is not extensible.
o.p = 1;
o.p // undefined
厳格なモードであれば、エラーが発生します.(function () {
'use strict';
o.p = '1'
}());
// TypeError: Can't add property bar, object is not extensible
ただし、prevent Extens方法を使用したオブジェクトに対しては、deleteコマンドで既存の属性を削除することができます.var o = new Object();
o.p = 1;
Object.preventExtensions(o);
delete o.p;
o.p // undefined
Object.isExtensioble()Object.isExtensioble方法は、オブジェクトがObject.prevent Extensions方法を使用しているかどうかを確認するために使用されます.つまり、オブジェクトに属性を追加できるかどうかをチェックします.
var o = new Object();
Object.isExtensible(o) // true
Object.preventExtensions(o);
Object.isExtensible(o) // false
上のコードは新たにoオブジェクトを生成し、オブジェクトにObject.isExtensioble方法を使用して、trueに戻り、新しい属性を追加できることを示しています.このオブジェクトに対してObject.prevent Extensions方法を使用した後、Object.isExtensioble方法を使用してfalseに戻り、新しい属性を追加できなくなったということです.Object.seal()
Object.sealメソッドは、オブジェクトに新しい属性を追加することも、古い属性を削除することもできません.
var o = {
p: 'hello'
};
Object.seal(o);
delete o.p;
o.p // "hello"
o.x = 'world';
o.x // undefined
上のコードでは、オブジェクトがObject.sealメソッドを実行した後、新しい属性を追加したり、古い属性を削除したりすることができません.Object.sealは、実質的に属性記述オブジェクトのconfigurble属性をfalseとするので、属性記述オブジェクトは変更できなくなります.
var o = {
p: 'a'
};
// seal
Object.getOwnPropertyDescriptor(o, 'p')
// Object {
// value: "a",
// writable: true,
// enumerable: true,
// configurable: true
// }
Object.seal(o);
// seal
Object.getOwnPropertyDescriptor(o, 'p')
// Object {
// value: "a",
// writable: true,
// enumerable: true,
// configurable: false
// }
Object.defineProperty(o, 'p', {
enumerable: false
})
// TypeError: Cannot redefine property: p
上のコードでは、Object.sealメソッドを使うと、属性記述オブジェクトのconfigrable属性がfalseになり、enumerable属性を変更するとエラーが発生します.書いてもいいです.ちょっと特別です.もしwritableがfalseであれば、Object.sealの方法を使ってから、それをtrueに変えることはできません.しかし、もしwritableがtrueであれば、依然としてfalseに変えることができます.
var o1 = Object.defineProperty({}, 'p', {
writable: false
});
Object.seal(o1);
Object.defineProperty(o1, 'p', {
writable:true
})
// Uncaught TypeError: Cannot redefine property: p
var o2 = Object.defineProperty({}, 'p', {
writable: true
});
Object.seal(o2);
Object.defineProperty(o2, 'p', {
writable:false
});
Object.getOwnPropertyDescriptor(o2, 'p')
// {
// value: '',
// writable: false,
// enumerable: true,
// configurable: false
// }
上のコードの中で、同じくObject.seal方法を使っています.もしwritableがfalseであるなら、この設定を変更するとエラーが発生します.trueであれば、問題はありません.属性オブジェクトのvalueが変更できるかどうかは、writableが決定します.
var o = { p: 'a' };
Object.seal(o);
o.p = 'b';
o.p // 'b'
上のコードの中で、Object.sealメソッドがp属性のvalueに対して無効であるのは、このときp属性のwritableがtrueであるからです.Object.isSealed()
Object.isSealed方法は、オブジェクトがObject.sealメソッドを使用しているかどうかを確認するために使用されます.
var o = { p: 'a' };
Object.seal(o);
Object.isSealed(o) // true
このとき、Object.isExtenseble方法もfalseに戻ります.var o = { p: 'a' };
Object.seal(o);
Object.isExtensible(o) // false
Object.freeze()Object.freezeメソッドは、オブジェクトに新しい属性を追加できなくなり、古い属性を削除できなくなり、属性の値を変更することができなくなり、このオブジェクトが実際に定数になります.
var o = {
p: 'hello'
};
Object.freeze(o);
o.p = 'world';
o.p // hello
o.t = 'hello';
o.t // undefined
上のコードでは、既存の属性に対して値を再割り当て(o.p='world)したり、新しい属性を追加したりします.しかし、厳しいモードであれば、エラーが発生します.var o = {
p: 'hello'
};
Object.freeze(o);
//
(function () {
'use strict';
o.p = 'world';
}())
// TypeError: Cannot assign to read only property 'p' of #
Object.isFrozen()Object.isFrozen法は、オブジェクトがObject.freeze()メソッドを使用しているかどうかを確認するために使用されます.
var obj = {
p: 'hello'
};
Object.freeze(obj);
Object.isFrozen(obj) // true
前に述べましたが、オブジェクトが凍結されたら、その属性に値を付けます.厳しいモードでエラーが発生します.Object.isFrozen方法はこのようなエラーが発生するのを防ぐことができます.var obj = {
p: 'hello'
};
Object.freeze(obj);
if (!Object.isFrozen(obj)) {
obj.p = 'world';
}
上のコードの中で、objが凍結されていないことを確認してから、その属性に対して値を付けたら、エラーが発生しません.限界性
上記の方法では、オブジェクトの書き込み可能性に穴がありますが、元のオブジェクトを変更することにより、オブジェクトの属性を増加することができます.
var obj = new Object();
Object.preventExtensions(obj);
var proto = Object.getPrototypeOf(obj);
//
proto.t = 'hello';
obj.t
// hello
一つの解決策は原型を凍結することです.var obj = Object.seal(
Object.create(
Object.freeze({x: 1}),
{
y: {
value: 2,
writable: true
}
}
)
);
Object.getPrototypeOf(obj).hello = "hello";
obj.hello // undefined
もう一つの限界は、属性値がオブジェクトである場合、上記の方法は属性が指すオブジェクトを凍結するだけで、オブジェクト自体の内容を凍結することができません.var obj = {
foo: 1,
bar: ['a', 'b']
};
Object.freeze(obj);
obj.bar.push('c');
obj.bar // ["a", "b", "c"]
上のコードでは、Obj.bar属性は1つの配列を指しています.Objオブジェクトが凍結された後、この指向は変更できません.つまり、他の値を指すことはできませんが、指し示す配列は変更できます.