After many years I decided to see if I can take advantage of javascript inheritance that is properly available in the modern js versions through the class & extends keywords.
My standard operating procedure for errors for example is to create a new es3 class (function) "MyCustomError" and throw it from where it was detected at.
In the catch block, I check (e instanceof MyCustomError) and it tells me whether this was a standard uncaught garden-variety Error or my very special MyCustomError. This is ok really, but succeeds due to the throw/catch blocks which treat the thrown item as an "error" while preserving the actual class of it even if it isn't Error. Catch blocks like this are fine until you want to do something like catch all error instances and then dig deeper to see what kind of error it was without doing things like adding a custom property to an Error or dissecting its message for special strings.
So after looking for a while on how to make things inherit in ES3 js I came up with this and it appears to be working.
In the method down at the bottom it has a testMethod() function which should only ever return a valid result (string) or an Error. In the innerTestMethod() some possible errors of different kinds are thrown and inherit from Error. So when iterating through the results provided by testMethod we can be sure that we'll only come across either valid string results or one of the possibe Error object classes.
Now, what I learned is that in our ES3 there's no automatic intuitive inheriting as is in the modern javascript so we have to rig up through the Object.assign and prototypes such an object that javascript will think is actually in some other classes' prototype chain. However, what I have appears to be working and it's done with minimal code compared to some other "extend" polyfills and that's part of the reason why I'm not all 100% sure it's how it's done - but it works here.
This would be useful in cases where one wants to use instanceof to differentiate among objects which may be similar, but not want to do so by checking properties to determine with custom code on what the object actually is.
Check it out:
#target illustrator
#targetengine "TEST"
function test () {
// ------------------------------------------ necessary polyfills
if (typeof Object.create != 'function') {
Object.create = (function () {
var Temp = function () {};
return function (prototype) {
if (arguments.length > 1) {
throw Error('Second argument not supported');
}
if(prototype !== Object(prototype) && prototype !== null) {
throw TypeError('Argument must be an object or null');
}
if (prototype === null) {
throw Error('null [[Prototype]] not supported');
}
Temp.prototype = prototype;
var result = new Temp();
Temp.prototype = null;
return result;
};
})();
};
if (!('assign' in Object)) {
Object.assign = function (has) {
'use strict';
return assign;
function assign (target, source) {
for (var i = 1; i < arguments.length; i++) {
copy(target, arguments[i]);
}
return target;
}
function copy (target, source) {
for (var key in source) {
if (has.call(source, key)) {
target[key] = source[key];
}
}
}
}({}.hasOwnProperty);
}
// ----------------------------------------- /necessary polyfills
function CustomError (msg) {
this.message = null;
Object.assign(this, new Error(msg));
};
CustomError.prototype = Object.create(Error.prototype);
function SpecialTypeCustomError (msg, specialCategory) {
Object.assign(this, new CustomError(msg));
this.specialCategory = specialCategory;
};
SpecialTypeCustomError.prototype = Object.create(CustomError.prototype);
function DifferentError (msg, errorType) {
this.errorType = errorType;
Object.assign(this, new Error(msg));
};
DifferentError.prototype = Object.create(Error.prototype);
function SpecialTypeDifferentError (msg, errorType, specialCategory) {
this.errorType = errorType;
this.specialCategory = specialCategory;
Object.assign(this, new DifferentError(msg, errorType));
};
SpecialTypeDifferentError.prototype = Object.create(DifferentError.prototype);
try {
// throw new Error("Regular Error");
// throw new CustomError("A custom error");
// throw new SpecialTypeCustomError("A sub-class of a customer error", "ABC");
// throw new DifferentError("A 'different' error.", "Type-1");
// throw new SpecialTypeDifferentError("A <Special!> 'different' error.", "Type-SPCL", "1234");
} catch (e) {
var msg = "";
msg += ("Has message: " + ("message" in e)) + "\n";
msg += ("message: " + e.message) + "\n----------\n";
msg += ("Has description: " + ("description" in e)) + "\n";
msg += ("description: " + e.description) + "\n----------\n";
msg += ("Has specialCategory: " + ("specialCategory" in e)) + "\n";
msg += ("specialCategory: " + e.specialCategory) + "\n----------\n";
msg += ("Has errorType: " + ("errorType" in e)) + "\n";
msg += ("errorType: " + e.errorType) + "\n----------\n";
var msg2 = "";
msg2 += ("is Error: " + (e instanceof Error)) + "\n";
msg2 += ("is CustomError: " + (e instanceof CustomError)) + "\n";
msg2 += ("is SpecialTypeCustomError: " + (e instanceof SpecialTypeCustomError)) + "\n";
msg2 += ("is DifferentError: " + (e instanceof DifferentError)) + "\n";
msg2 += ("is SpecialTypeDifferentError: " + (e instanceof SpecialTypeDifferentError)) + "\n";
alert(msg + "\n\n" + msg2);
}
/**
* @9397041 {number} rand
*/
function innerTestMethod (rand) {
var product = 10 * rand;
var displayProduct = product.toFixed(2);
if (product < 3) {
throw new CustomError("Is less than 3 (" + displayProduct + ")");
} else if (product > 8) {
throw new SpecialTypeCustomError("Is more than 8 (" + displayProduct + ")", "8+");
} else if (product >=4 && product <=6) {
null.blah();
}
return "All clear";
}
/**
*/
function testMethod () {
var rand = Math.random();
var result;
try {
result = innerTestMethod(rand);
} catch (e) {
result = e;
}
return result;
};
/** @TyPe {Array<string | Error>} */
var allResults = [];
for (var i = 0; i < 10; i++) {
allResults.push(testMethod(i));
}
var thisItem;
var msg3 = "";
var prefix;
for (var i = 0; i < allResults.length; i++) {
thisItem = allResults[i];
prefix = (i + 1) + ") ";
if (typeof(thisItem) == "string") {
msg3 += prefix + thisItem + "\n";
} else if (thisItem instanceof Error) {
if (thisItem instanceof SpecialTypeCustomError) {
msg3 += prefix + "SpecialTypeCustomError (msg: " + thisItem.message + ", cat: " + /** @TyPe {SpecialTypeCustomError} */ (thisItem).specialCategory + ")" + "\n";
} else if (thisItem instanceof CustomError) {
msg3 += prefix + "CustomError (desc: " + thisItem.description + ")" + "\n";
} else {
msg3 += prefix + "Error (unhandled): " + thisItem.message + "\n";
}
}
}
alert(msg3);
};
test();