JavaScript ES6:测试箭头函数、内置函数、常规函数?
有没有一种优雅的方法将Harmony的细长箭头功能与常规功能和内置功能区分开来 缔约国指出: 箭头函数类似于内置函数,因为缺少.prototype和任何[[Construct]]内部方法。所以new(()=>{})抛出一个TypeError,但在其他方面箭头类似于函数 也就是说,您可以测试箭头功能,如:JavaScript ES6:测试箭头函数、内置函数、常规函数?,javascript,function,ecmascript-6,ecmascript-harmony,arrow-functions,Javascript,Function,Ecmascript 6,Ecmascript Harmony,Arrow Functions,有没有一种优雅的方法将Harmony的细长箭头功能与常规功能和内置功能区分开来 缔约国指出: 箭头函数类似于内置函数,因为缺少.prototype和任何[[Construct]]内部方法。所以new(()=>{})抛出一个TypeError,但在其他方面箭头类似于函数 也就是说,您可以测试箭头功能,如: !(()=>{}).hasOwnProperty("prototype") // true !(function(){}).hasOwnProperty("prototype") // f
!(()=>{}).hasOwnProperty("prototype") // true
!(function(){}).hasOwnProperty("prototype") // false
但是对于任何内置函数,测试也会返回true
,例如setTimeout
或Math.min
如果您获取源代码并检查它是否为“本机代码”
,那么它在Firefox中可以正常工作,但它似乎不太可靠,也不可移植(其他浏览器实现,NodeJS/iojs):
小型GitHub项目依赖于RegExp检查函数源代码,这并不是很整洁
edit:我尝试了一下JavaScript解析器,它似乎工作得很好——尽管它有点过头了
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;
ECMAScript放弃了对宿主对象的许多保证,因此扩展了宿主函数。 这使得通过反射访问的属性主要依赖于实现,对一致性几乎没有保证,至少就ecmascript规范而言,W3C规范可能更具体地针对浏览器主机对象 例如,见 表9总结了本规范使用的仅适用于某些ECMAScript对象的内部属性。[...] 主机对象可以通过任何依赖于实现的行为支持这些内部属性,只要它符合本文档中规定的特定主机对象限制 所以内置函数可能是可调用的,但没有原型(即不从函数继承)。或者他们可以有一个 说明书上说他们的行为可能不同。但它们也可以实现所有标准行为,使它们与正常功能无法区分 请注意,我引用的是ES5规范。ES6仍在进行修订,本机对象和宿主对象现在称为外来对象。但是说明书上说的差不多。它规定,即使他们必须履行,但除此之外,只说他们可能履行或不履行所有可选行为。信不信由你 测试函数的字符串表示中是否存在“=>”可能是最可靠的方法(但不是100%) 显然,我们无法针对您提到的两种情况中的任何一种进行测试—缺少原型属性和缺少
[[Construct]]
,因为这可能会导致主机对象或缺少[[Construct]]
的内置对象出现误报(Math.floor
,JSON.parse
,等等)
然而,我们可以使用好的Function.prototype.toString
检查函数表示是否包含“=>”
现在,我一直建议不要使用Function.prototype.toString
(所谓的函数反编译),因为它依赖于实现,而且历史上不可靠(更多详细信息请参见)
但ES6实际上正在(至少)呈现内置和“用户创建”(因为缺少更好的术语)功能
- 字符串表示必须具有FunctionDeclaration FunctionExpression、GeneratorDeclaration、, GeneratorExpression、类声明、类表达式、箭头函数, MethodDefinition,或GeneratorMethod,具体取决于实际 对象的特征
- 在表示字符串中使用和放置空格、行终止符和分号是不正确的 依赖于实现
- 如果对象是使用ECMAScript代码定义的,并且返回的字符串表示形式不是MethodDefinition或 GeneratorMethod则表示形式必须为 字符串的求值,在以下词法上下文中使用eval 相当于用于创建原始对象的词汇上下文, 它将产生一个新的功能等效对象。那么 返回的源代码不能随意提及 没有被原始函数的源代码自由提及,甚至 如果这些“额外”名称最初在范围内
- 如果实现无法生成满足这些条件的源代码字符串,那么它必须返回eval将抛出的字符串 SyntaxError异常
[[ECMAScriptCode]]
(您可以从14.2.17-箭头函数的评估-到函数创建到函数初始化进行跟踪)
这意味着它们必须符合:
..这意味着它们必须在Function.prototype.toString
的输出中具有=>
显然,您需要确保“=>”遵循箭头参数,而不仅仅是FunctionBody中的内容:
function f() { return "=>" }
至于可靠性-请记住,目前任何/所有引擎都支持/可能不支持此行为,并且无论出于何种原因,主机对象的表示可能存在(尽管规范做出了努力)。- 将函数转换为字符串
toString
- 删除此字符串的所有空格李>
- 如果存在索引大于或等于1的
”=>99.99%是一个箭头函数”=>“
F.toString().replace(/\s+/g, '').indexOf(')=>')>=1
var fn1=函数(e){
e、 目标。
function f() { return "=>" }
F.toString().replace(/\s+/g, '').indexOf(')=>')>=1
/** Check if function is Arrow Function */
const isArrowFn = (fn) => (typeof fn === 'function') && /^[^{]+?=>/.test(fn.toString());
/* Demo */
const fn = () => {};
const fn2 = function () { return () => 4 }
isArrowFn(fn) // True
isArrowFn(fn2) // False
const isArrowFn = f => typeof f === 'function' && (/^([^{=]+|\(.*\)\s*)?=>/).test(f.toString().replace(/\s/, ''))
const obj = {
f1: () => {},
f2 () {}
}
isArrowFn(obj.f1) // true
isArrowFn(() => {}) // true
isArrowFn((x = () => {}) => {}) // true
isArrowFn(obj.f2) // false
isArrowFn(function () {}) // false
isArrowFn(function (x = () => {}) {}) // false
isArrowFn(function () { return () => {} }) // false
isArrowFn(Math.random) // false
const isArrowFunction = obj => typeof obj === 'function' && obj.prototype === undefined;
isArrowFunction(() => 10); // true
isArrowFunction(function() {}); // false