| class base { |
| constructor() { } |
| method() { this.methodCalled++; } |
| } |
| |
| class derived extends base { |
| constructor() { super(); this.methodCalled = 0; } |
| |
| // Test orderings of various evaluations relative to the superbase |
| |
| // Unlike in regular element evaluation, the propVal is evaluated before |
| // checking the starting object ([[HomeObject]].[[Prototype]]) |
| testElem() { super[ruin()]; } |
| |
| // The starting object for looking up super.method is determined before |
| // ruin() is called. |
| testProp() { super.method(ruin()); } |
| |
| // The entire super.method property lookup has concluded before the args |
| // are evaluated |
| testPropCallDeleted() { super.method(()=>delete base.prototype.method); } |
| |
| // The starting object for looking up super["prop"] is determined before |
| // ruin() is called. |
| testElemAssign() { super["prop"] = ruin(); } |
| |
| // Test the normal assignment gotchas |
| testAssignElemPropValChange() { |
| let x = "prop1"; |
| super[x] = (()=>(x = "prop2", 0))(); |
| assertEq(this.prop1, 0); |
| assertEq(this.prop2, undefined); |
| } |
| |
| testAssignProp() { |
| Object.defineProperty(base.prototype, "piggy", |
| { |
| configurable: true, |
| set() { throw "WEE WEE WEE WEE"; } |
| }); |
| |
| // The property lookup is noted, but not actually evaluated, until the |
| // right hand side is. Please don't make the piggy cry. |
| super.piggy = (() => delete base.prototype.piggy)(); |
| } |
| testCompoundAssignProp() { |
| let getterCalled = false; |
| Object.defineProperty(base.prototype, "horse", |
| { |
| configurable: true, |
| get() { getterCalled = true; return "Of course"; }, |
| set() { throw "NO!"; } |
| }); |
| super.horse += (()=>(delete base.prototype.horse, ", of course!"))(); |
| assertEq(getterCalled, true); |
| |
| // So, is a horse a horse? |
| assertEq(this.horse, "Of course, of course!"); |
| } |
| } |
| |
| function ruin() { |
| Object.setPrototypeOf(derived.prototype, null); |
| return 5; |
| } |
| |
| function reset() { |
| Object.setPrototypeOf(derived.prototype, base.prototype); |
| } |
| |
| let instance = new derived(); |
| assertThrowsInstanceOf(() => instance.testElem(), TypeError); |
| reset(); |
| |
| instance.testProp(); |
| assertEq(instance.methodCalled, 1); |
| reset(); |
| |
| instance.testPropCallDeleted(); |
| assertEq(instance.methodCalled, 2); |
| |
| instance.testElemAssign(); |
| assertEq(instance.prop, 5); |
| reset(); |
| |
| instance.testAssignElemPropValChange(); |
| |
| instance.testAssignProp(); |
| |
| instance.testCompoundAssignProp(); |
| |
| if (typeof reportCompare === 'function') |
| reportCompare(0,0,"OK"); |