edge-cases.md
May 13, 2020 ยท View on GitHub
Edge cases
The three values (true, false, null) are mutually exclusive, but theorically classical functions can play multiple roles (constructors, methods, plain functions) so there will be false positives.
If we use own data property API form (f.thisArgumentExpected), programmers could reconfig the property for these edge cases. If we use other API form, we would need some other mechnism to deal with them or just ignore them.
The following code use thisArgumentExpected data property API form for demostration.
Direct eval
function func() {}
func.thisArgumentExpected // false
function directEval() {
eval('this')
}
directEval.thisArgumentExpected // false
Object.defineProperty(directEval, 'thisArgumentExpected', {value: true})
Old style constructor functions
function OldStyleConstructor(foo) {
this.foo = foo
}
new OldStyleConstructor(42)
OldStyleConstructor.thisArgumentExpected // true
Object.defineProperty(OldStyleConstructor, 'thisArgumentExpected', {value: null})
function OldStyleConstructor(foo) {
if (new.target === undefined) return new OldStyleConstructor(foo)
this.foo = foo
}
Object.defineProperty(OldStyleConstructor, 'thisArgumentExpected', {value: false})
Optional this argument
class X {
static of(...args) {
return new (this ?? X)(args)
}
}
X.of.thisArgumentExpected // true
Object.defineProperty(X.of, 'thisArgumentExpected', {value: false})
Retrieve global this
let getGlobalThis = new Function('return this')
getGlobalThis.thisArgumentExpected // true
Object.defineProperty(getGlobalThis, 'thisArgumentExpected', {value: false})
Avoid edge cases
If you have the control of the source code of these edge case functions, there are possible ways to eliminate some cases without reconfiguration. For example, use classes to replace old style constructor functions. Generally, if we have function decorators available, we could use some declarative form like @thisArgumentExpected(true) function f() {}.