除了常规功能和内置功能之外,还有一种优雅的方式可以告诉Harmony的纤细箭头功能吗?
Harmony wiki表示:
箭头函数就像内置函数一样,缺少.prototype 和任何[[Construct]]内部方法。所以new(()=> {})抛出TypeError,否则箭头就像函数
这意味着,您可以测试箭头功能,如:
!(()=>{}).hasOwnProperty("prototype") // true
!(function(){}).hasOwnProperty("prototype") // false
但是对于任何内置函数,测试也会返回true
,例如setTimeout
或Math.min
。
如果您获得源代码并检查它是否为"native code"
,它在Firefox中是有效的,但它看起来不太可靠也不可移植(其他浏览器实现,NodeJS / iojs):
setTimeout.toSource().indexOf("[native code]") > -1
小的GitHub项目node-is-arrow-function依赖于函数源代码的RegExp检查,这不是那么整洁。
编辑:我尝试了JavaScript解析器acorn,它似乎工作得很好 - 即使它太过分了。
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;
答案 0 :(得分:7)
信不信由你......
测试是否存在“=>”函数的字符串表示可能是最可靠的方式(但不是100%)。
显然我们无法测试你提到的两个条件中的任何一个 - 缺少原型属性和缺少[[Construct]]
,因为这可能会导致主机对象或缺少{{1}的内置对象的误报}([[Construct]]
,Math.floor
等。)
但是,我们可以使用好的旧JSON.parse
来检查函数表示是否包含“=>”。
现在,我一直建议使用Function.prototype.toString
(所谓的函数反编译)反对,因为它依赖于实现且历史上不可靠(更多) State of function decompilation in Javascript)中的详细信息。
但ES6实际上tries to enforce rules在路上(至少)内置并且“用户创建”(缺少更好的术语)功能被表示出来。
- 醇>
如果Type(func)是Object并且是内置函数对象或 有一个[[ECMAScriptCode]]内部插槽,然后
一个。返回func的依赖于实现的String源代码表示。表示必须符合以下规则。
...
toString表示要求:
字符串表示必须具有FunctionDeclaration FunctionExpression,GeneratorDeclaration的语法, GeneratorExpession,ClassDeclaration,ClassExpression, ArrowFunction , MethodDefinition或GeneratorMethod取决于实际 对象的特征。
在表示字符串中使用和放置空格,行终止符和分号 实现相关的。
如果使用ECMAScript代码定义了对象,并且返回的字符串表示形式不是MethodDefinition或 那么GeneratorMethod的表示必须是这样的 在词汇上下文中使用eval来评估字符串 相当于用于创建原始对象的词法上下文, 它将导致一个新的功能相当的对象。在这种情况下 返回的源代码不能自由提及任何变量 原始函数的源代码没有自由提及,甚至 如果这些“额外”名称最初属于范围。
如果实现无法生成满足这些条件的源代码字符串,那么它必须返回一个eval将抛出的字符串 一个SyntaxError异常。
我强调了相关的块。
箭头函数具有内部Function.prototype.toString
(您可以从14.2.17 - 箭头函数的评估 - 到 FunctionCreate 到 FunctionInitialize )进行跟踪。
这意味着他们必须符合ArrowFunction syntax:
[[ECMAScriptCode]]
..这意味着他们必须拥有=>在ArrowFunction[In, Yield] :
ArrowParameters[?Yield] [no LineTerminator here] => ConciseBody[?In]
的输出中。
你显然需要确保“=>”遵循ArrowParameters并且不仅仅是FunctionBody中存在的东西:
Function.prototype.toString
至于可靠性 - 请记住,目前任何/所有引擎都不支持此行为,并且无论出于何种原因,主机对象的表示都可能存在(尽管规范有所作为)。
答案 1 :(得分:3)
我为Node写了这个,也应该在Chrome中工作。
检测到“界限”(apparently, only on ES6)并报告为native && bound
。这可能是也可能不是问题,具体取决于您使用该信息的内容。
const flags = {
function: f instanceof Function,
name: undefined,
native: false,
bound: false,
plain: false,
arrow: false
};
if (flags.function) {
flags.name = f.name || '(anonymous)';
flags.native = f.toString().trim().endsWith('() { [native code] }');
flags.bound = flags.native && flags.name.startsWith('bound ');
flags.plain = !flags.native && f.hasOwnProperty('prototype');
flags.arrow = !(flags.native || flags.plain);
}
return flags;
答案 2 :(得分:3)
Kangax提出了一个很重要的观点。如果您想要完美,则可以使用AST解析器库来确定函数类型,但这对您中的许多人来说可能是过大的选择。
为此,以下是使用正则表达式实现的方法:
/** 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
逻辑
这假定所有非箭头功能块必须用{}包围。我认为不存在会导致这种情况的环境,但是如果我做错了,请告诉我。
注意:正则表达式的编写还假定函数的=>将始终位于第一行。可以很容易地更改它,但是同样,我无法想象在它之前会出现换行符。
它如何工作?
问题?
如果发现无法使用的情况,请发表评论,我会看看我们是否可以容纳。
答案 3 :(得分:2)
据我所知,这应该有效:
转换时的所有非箭头功能 使用'function'字符串START。 箭头功能没有。
尝试测试是否存在'=>' 不是一种可靠的测试方法 函数是否为箭头,因为 任何非箭头功能都可以包含 箭头 - 在它们内部的功能,因此 '=>'可以出现在他们的源代码中。
答案 4 :(得分:1)
ECMAScript放弃了对主机对象的许多保证,因此通过扩展来放弃主机功能。 这使得属性可以通过反射访问,主要是依赖于实现,几乎不保证一致性,至少就ecmascript规范而言,W3C规范可能更具体的浏览器主机对象。
E.g。见
表9总结了本规范使用的内部属性,这些属性仅适用于某些ECMAScript对象。 [...] 主机对象可能支持具有任何依赖于实现的行为的这些内部属性,只要它与本文档中声明的特定主机对象限制一致。
所以内置函数可能是可调用的,但没有原型(即不从函数继承)。或者他们可以有一个。
规范说它们可能表现不同。但它们也可能实现所有标准行为,使它们与正常功能无法区分。
请注意,我引用了ES5规范。 ES6仍在进行修订,本机和主机对象现在称为外来对象。但规范几乎也是这样说的。它提供some invariants即使他们必须履行,但只是说他们可能会或可能不会履行所有可选行为。
答案 5 :(得分:1)
Ron S的解决方案效果很好,但可以检测到误报:
/** Check if function is Arrow Function */
const isArrowFn = (fn) => (typeof fn === 'function') && /^[^{]+?=>/.test(fn.toString());
/* False positive */
const fn = function (callback = () => null) { return 'foo' }
console.log(
isArrowFn(fn) // true
)
答案 6 :(得分:1)
我找不到误报。对罗恩·S(Ron S)的做法进行了小改动:
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
答案 7 :(得分:0)
尝试了上述所有解决方案并阅读了@kangax等人的精彩文章之后,我涵盖所有用例的唯一方法是构建自己的解析器,名为check-is-arrow-function(灵感来自我的名字, ?)。到目前为止,它已经处理了我抛出的所有问题……包括:
() => {}
()=>{}
() => 1
(x) => x
(x) => (y) => x + y
(callback = () => 4) => callback
(callback=()=>4)=>callback
({prop}) => prop
(callback = () => "(yo") => callback
(callback = () => "\"(yo") => callback
(() => {})
r => r
...and more
易于使用且轻巧:
checkIsArrowFunction(r => r); // true
checkIsArrowFunction(function a () { return () => 0 }); // false
希望它也可以帮助其他人!
答案 8 :(得分:0)
基于documentation基于mozilla.org,并考虑了Use of the new operator
和that page的副作用,我们可以尝试执行以下操作:
function isArrow (fn) {
if (typeof fn !== 'function') return false
try {
new fn()
} catch(err) {
if(err.name === 'TypeError' && err.message === 'fn is not a constructor') {
return true
}
}
return false
}
console.log(isArrow(()=>{})) // true
console.log(isArrow(function () {})) // false
console.log(isArrow({})) // false
console.log(isArrow(1)) // false
let hacky = function () { throw new TypeError('fn is not a constructor') }
console.log(isArrow(hacky)) // unfortunately true
答案 9 :(得分:0)
验证箭头函数的现代解决方案:
const isArrowFunction = obj => typeof obj === 'function' && obj.prototype === undefined;
isArrowFunction(() => 10); // true
isArrowFunction(function() {}); // false
答案 10 :(得分:-1)
toString
如果")=>"
存在且索引大于或等于1 => 99.99%是箭头功能。
F.toString().replace(/\s+/g, '').indexOf(')=>')>=1
var fn1=function(e){
e.target.value=new Date();
};
var fn2=(a,b)=> a+b;
function isArrow(name,F){
if(F.toString().replace(/\s+/g, '').indexOf(')=>')>=1){
console.log(`${name} is arrow-function`);
}else{
console.log(`${name} is classic-function`);
}
}
isArrow('fn1',fn1);
isArrow('fn2',fn2);

答案 11 :(得分:-1)
JavaScript的箭头功能不具有prototype
属性。
function isArrowFunc(fn){
return typeof(fn)=="function" && fn.prototype === undefined && !(/\{\s*\[native code\]\s*\}/).test(fn.toString());
}
isArrowFunc(()=>{}) // true
isArrowFunc(function(){}) // false
isArrowFunc(123) // false