Is there an elegant way to tell Harmony's slim arrow functions apart from regular functions and built-in functions?
The Harmony wiki states that:
Arrow functions are like built-in functions in that both lack .prototype and any [[Construct]] internal method. So new (() => {}) throws a TypeError but otherwise arrows are like functions
Which means, you can test for arrow functions like:
!(()=>{}).hasOwnProperty("prototype") // true
!(function(){}).hasOwnProperty("prototype") // false
But the test will also return true
for any built-in function, e.g. setTimeout
or Math.min
.
It sort of works in Firefox if you get the source code and check if it's "native code"
, but it doesn't seem much reliable nor portable (other browser implementations, NodeJS / iojs):
setTimeout.toSource().indexOf("[native code]") > -1
The small GitHub project node-is-arrow-function relies on RegExp-checks against the function source code, which isn't that neat.
edit: I gave the JavaScript parser acorn a try and it seems to work quite okay - even though it's pretty overkill.
acorn = require("./acorn");
function fn_sample(a,b){
c = (d,e) => d-e;
f = c(--a, b) * (b, a);
return f;
}
function test(fn){
fn = fn || fn_sample;
try {
acorn.parse("(" + fn.toString() + ")", {
ecmaVersion: 6,
onToken: function(token){
if(typeof token.type == "object" && token.type.type == "=>"){
console.log("ArrowFunction found", token);
}
}
});
} catch(e) {
console.log("Error, possibly caused by [native code]");
console.log(e.message);
}
}
exports.test = test;
As far as I can tell this should work:
All non-arrow functions when converted to String START with 'function '. Arrow functions don't.
Trying to test for the presence of '=>' is not a reliable way to test whether the function is an arrow or not because any non-arrow function can contain arrow-functions inside them and thus the '=>' can be present in their source-code.
ECMAScript waives a lot of its guarantees for host objects, and thus by extension, host functions. That makes the properties accessible via reflection mostly implementation-dependent with little guarantees for consistency, at least as far as the ecmascript spec is concerned, W3C specs may be more specific for browser host objects.
E.g. see
8.6.2 Object Internal Properties and Methods
So built-in functions might be callable but have no prototype (i.e. not inherit from function). Or they could have one.
The spec says they may behave differently. But they also may implement all the standard behavior, making them indistinguishable from normal functions.
Note that I'm quoting the ES5 spec. ES6 is still undergoing revisions, native and host objects are now called exotic objects. But the spec pretty much says the same. It provides some invariants that even they must fulfill, but otherwise only says that they may or may not fulfill all optional behaviors.
I wrote this for Node, should work in Chrome as well.
"Boundness" is detected (apparently, only on ES6) and reported as
native && bound
. This might or might not be an issue, depending on what you are using that information for.Believe it or not...
Testing for presence of "=>" in string representation of a function is likely the most reliable way (but not 100%).
Obviously we can't test against either of 2 conditions you mentioned — lack of prototype property and lack of
[[Construct]]
as that might give false positives with either host objects or built-in ones that lack[[Construct]]
(Math.floor
,JSON.parse
, etc.)We could, however, use good old
Function.prototype.toString
to check if function representation contains "=>".Now, I've always recommended against using
Function.prototype.toString
(so-called function decompilation) due to its implementation-dependent and historically unreliable nature (more details in State of function decompilation in Javascript).But ES6 actually tries to enforce rules on the way (at least) built-in and "user-created" (for the lack of better term) functions are represented.
I highlighted relevant chunks.
Arrow functions have internal
[[ECMAScriptCode]]
(which you can track from 14.2.17 — evaluation of arrow function - to FunctionCreate to FunctionInitialize).This means they must conform to ArrowFunction syntax:
..which means they must have => in
Function.prototype.toString
's output.You'll obviously need to ensure "=>" follows ArrowParameters and is not just something present in FunctionBody:
As for reliability — remember that this behavior is/might not be supported by any/all engines at the moment and that host objects' representation might lie (despite specs efforts) for whatever reasons.
toString
if
")=>"
exists with index greater or equal to 1 => 99.99% is an arrow function .DEMO :