/* Date.prototype.toJSON() is a generic function, check that it behaves * that way. * * E5.1 Section 15.9.5.44. */ var obj; /*=== 2012-01-02T03:04:05.006Z ===*/ try { // this ends up in toISOString(), so output is exact print(new Date('2012-01-02T03:04:05.006Z').toJSON()); } catch (e) { print(e.name); } /*=== TypeError TypeError ===*/ try { // Step 1: ToObject(undefined) -> TypeError Date.prototype.toJSON.call(undefined); } catch (e) { print(e.name); } try { // Step 1: ToObject(null) -> TypeError Date.prototype.toJSON.call(undefined); } catch (e) { print(e.name); } /*=== valueOf() toString() toISOString() ISOString ===*/ try { // Step 2: ToPrimitive(hint Number) -> valueOf first, toString second obj = { valueOf: function() { // non-primitive value -> toString() will get called print('valueOf()'); return []; }, toString: function() { print('toString()'); return 'foo'; }, toISOString: function() { print('toISOString()'); return 'ISOString'; } }; print(Date.prototype.toJSON.call(obj)); } catch (e) { print(e.name); } /*=== valueOf() TypeError ===*/ try { // toISOString does not exist -> TypeError obj = { valueOf: function() { // primitive value -> toString() won't be called print('valueOf()'); return 123; }, toString: function() { print('toString()'); return 'foo'; } }; print(Date.prototype.toJSON.call(obj)); } catch (e) { print(e.name); } /*=== valueOf() null valueOf() null valueOf() null valueOf() toISOString() ISOString valueOf() toISOString() ISOString ===*/ // ToPrimitive returns a non-finite number -> returns 'null' try { obj = { valueOf: function() { print('valueOf()'); return Number.POSITIVE_INFINITY; } }; print(Date.prototype.toJSON.call(obj)); } catch (e) { print(e.name); } try { obj = { valueOf: function() { print('valueOf()'); return Number.NEGATIVE_INFINITY; } }; print(Date.prototype.toJSON.call(obj)); } catch (e) { print(e.name); } try { obj = { valueOf: function() { print('valueOf()'); return Number.NaN; } }; print(Date.prototype.toJSON.call(obj)); } catch (e) { print(e.name); } try { obj = { valueOf: function() { // Note: returning a finite number which is still outside // Ecmascript range should NOT cause a 'null' return! print('valueOf()'); return (100e6 * 86400e3) + 1e10; }, toISOString: function() { print('toISOString()'); return 'ISOString'; } }; print(Date.prototype.toJSON.call(obj)); } catch (e) { print(e.name); } try { obj = { valueOf: function() { print('valueOf()'); return -(100e6 * 86400e3) - 1e10; }, toISOString: function() { print('toISOString()'); return 'ISOString'; } }; print(Date.prototype.toJSON.call(obj)); } catch (e) { print(e.name); } /*=== valueOf() TypeError ===*/ try { // toISOString exists but is not callable -> TypeError obj = { valueOf: function() { // primitive value -> toString() won't be called print('valueOf()'); return 123; }, toString: function() { print('toString()'); return 'foo'; }, toISOString: 1 }; print(Date.prototype.toJSON.call(obj)); } catch (e) { print(e.name); } /*=== Number.prototype.toISOString() this binding type: object ISOString ===*/ try { // toISOString gets the ToObject() coercion of the base value as // its 'this' binding Number.prototype.toISOString = function() { print('Number.prototype.toISOString()'); print('this binding type: ' + typeof this); return 'ISOString'; } print(Date.prototype.toJSON.call(123)); } catch (e) { print(e.name); } /*=== toISOString() this matches: true ISOString ===*/ try { // another 'this' binding test with an object value obj = { toISOString: function() { print('toISOString()'); print('this matches: ' + (this === obj)); return 'ISOString'; } } print(Date.prototype.toJSON.call(obj)); } catch (e) { print(e.name); }