First, even when configurable
is false
, writable
can be changed from true
to false
. This is the only attribute change allowed when configurable
is false
. This transition was allowed because some built-in properties including (most notably) the length
property of arrays (including Array.prototype
) are specified to be writable: true, configurable: false
. This is a legacy of previous ECMAScript editions. If configurable: false
prevented changing writable
from true
to false
then it would be impossible to freeze arrays.
Object.defineProperty
doesn't work quite like you're assuming. In particular, how it processes the property descriptor works differently depending upon whether or not the property already exists. If a property does not exist, the descriptor is supposed to provide a definition of all attributes so any missing attributes in the descriptor are assigned default values before the descriptor is used to create the property. However, for an already existing property the descriptor is taken as a set of delta changes from the current attribute settings of the property. Attributes that are not listed in the descriptor are not changed. Also, a attribute that has the same value in the delta descriptor as the current property attribute value is also consider no change. So the following are all legal:
Object.defineProperty(x, "a", {writable:false}); // can always change writable to false.
//others attributes, not changed
Object.defineProperty(x, "a", {}); // no attributes, so nothing changes
Object.freeze(x); // same as Object.defineProperty(x, "a", {writable:false});
Object.defineProperty(x, "a", {enumerable:true, configurable: false}); //no change,
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…