15.4.5.1 array.[[DefineOwnProperty]](P, Desc, Throw)

2010-07-05

boolean [[DefineOwnProperty]](P:string, Desc:PD, Throw:boolean) throws TypeError

Arrays use a special [[DefineOwnProperty]] method to handle the numbered indices properly. When you set a numbered index the length property might be updated if the index would be equal or larger than the length value.

Code: (Meta Ecma)
[[DefineOwnProperty]] = function(P, Desc, Throw){
// the specification assumes that this object is an array
if (this.[[Class]] != 'Array') throw TypeError;
// since this is an array, length will be a number
var oldLenDesc = this.[[GetOwnProperty]]("length");
var oldLen = oldLenDesc.[[Value]];
if (P == "length") {
if (!([[Value]] in Desc)) return A.[[DefineOwnProperty]]("length", Desc, Throw); // (18.12.9)
var newLenDesc = Desc; // todo: COPY! not by reference
var newLen = ToUint32(Desc.[[Value]]);
if (newLen != ToNumber(Desc.[[Value]])) throw RangeError; // ?
newLenDesc[[Value]] = newLen;
if (newLen >= oldLen) return A.[[DefineOwnProperty]]("length", newLenDesc, Throw); // (8.12.9)
if (!oldLenDesc.[[Writable]]) {
if (Throw) throw TypeError;
return false;
}
if (!([[Writable]] in newLenDesc) || newLenDesc.[[Writable]]) var newWritable = true;
else {
// we need to "defer" setting [[Writable]] to false because we need to delete elements
var newWritable = false;
newLenDesc.[[Writable]] = true;
}
var succeeded = [[DefineOwnProperty]]("length", newLenDesc, Throw); // (8.12.9)
if (succeeded == false) return succeeded;
while (newLen < oldLen) {
oldLen = oldLen - 1;
var cannotDelete = A.[[Delete]](ToString(oldLen), false);
if (cannotDelete) {
newLenDesc.[[Value]] = oldLen + 1;
if (!newWritable) newLenDesc.[[Writable]] = false;
this.[[DefineOwnProperty]]("length", newLenDesc, false); // 8.12.9
if (Throw) throw TypeError;
return false;
}
}
if (newWritable == false) {
this.[[DefineOwnProperty]]("length", PD{[[Writable]]:false}, false); // 8.12.9, should always return true
}
return true;
} else { // P is an array index (15.4)
var index = ToUint32(P);
if (index >= oldLen && oldLenDesc.[[Writable]] === false) {
if (Throw) throw TypeError;
return false;
}
var succeeded = this.[DefineOwnProperty]](P, Desc, false); // 8.12.9
if (!succeeded) {
if (Throw) throw TypeError;
return false;
}
if (index >= oldLen) {
oldLenDesc.[[Value]] = index + 1;
this.[[DefineOwnProperty]]("length", oldLenDesc, false); // 8.12.9 (should always return true)
}
return true;
}
return this.[[DefineOwnProperty]](P, Desc, Throw); // 8.12.9
}