eval(fn) 和 eval(arrowFn) returns 不同的值

eval(fn) and eval(arrowFn) returns different value

根据 Mozilla docs 为了使用 eval 执行一个函数,它必须被包裹在 ( ) 里面,即如果你不使用它们那么它被视为字符串。

eval as a string defining function requires "(" and ")" as prefix and suffix

当我执行正常功能时,它 returns undefined 如预期的那样,但在 ES6 功能的情况下却不是。我的问题是 javascript 引擎或仅在 eval 函数中对 ES6 函数进行不同处理。

var fn = "function a(){}";
var es6fn = "()=>{}";

console.log(eval(fn)); // undefined
console.log(eval(es6fn)); // ()=>{}
console.log(typeof eval(es6fn)); // ()=>{} i.e. a function

在您的示例中,a 被声明为一个命名函数。在第二种情况下,您只需编写一个表达式,它是一个 lambda 函数。参见 here and here

如果你想为 fn 获得相同的效果,请执行

`console.log(eval("var a = function(){}"))`; //`function(){}`.

首先,EcmaScript 是 JavaScript 的 "official" 名称。现在 ES2015 已经完成,对大多数人来说它实际上变成了 JavaScript v6。因此,这种差异并非来自不同的引擎。

不同行为的起源来自于 eval 函数中写入的字符串的结果。第一个 eval 字符串的结果是一个函数定义,return 没有任何内容。另一方面,第二个 eval 正在评估 lambda 函数,因此 eval 的结果就是该函数。要清楚这个概念,你可以像下面这样重写代码:

var fn = "function a(){ return 1;}";
var es6fn = "()=>{}";

console.log(eval(fn)); // undefined
console.log(eval(es6fn)); // ()=>{}
console.log(typeof eval(es6fn)); // ()=>{} i.e. a function
console.log(a()); // call the a() function

如您所见,a() 被定义为一个函数,您可以在第一次 eval 之后使用该函数。因此,第一个 eval 是 运行 并且全部返回到 eval 函数的 return 值。

文档没有提及函数 执行。这些函数不会被执行,除非它们像 (() => {})().

这样明确地执行

引用

eval as a string defining function requires "(" and ")" as prefix and suffix

指将字符串解释为函数表达式而不是函数声明。

// will throw SyntaxError
// because function declaration requires a name
typeof eval('function (){}'); 

typeof eval('function a(){}') === 'undefined';
typeof eval('(function a(){})') === 'function';
typeof eval('null, function a(){}') === 'function';
typeof eval('()=>{}') === 'function';

箭头函数始终是一个表达式,它不需要逗号或括号等辅助结构来解释是一个表达式,这是不同之处。

让我们退后一步,看看这里到底发生了什么。我认为您误解了 MDN 试图表达的观点。在您的示例中执行的唯一函数是 eval。文档中提到的 (...) 不是为了在字符串中执行函数,而是为了改变 函数定义的计算方式 .

函数调用会 function a(){}() 但文档讨论将函数定义 放在 括号内:(function(){}).


函数的定义主要有以下几种方式:

  1. 函数声明

    function foo() {}
    
  2. 函数表达式

    var foo = function() {}
    
  3. 箭头函数

    var foo = () => {}
    

要理解函数声明和函数表达式之间的区别,我们必须理解之间的区别statementsexpressions(声明基本上就像一个语句)。

语句是具有副作用并且不会产生价值的东西。 ifforswitch等都是语句.

表达式是产生值的东西。例如。 5 是一个数字 literal 产生值 5。5 + 3 是一个计算两个文字之和的表达式,即计算它会 return 值 8.

一个函数声明就像一个语句。它本身不产生值,但作为副作用,定义了一个变量,其值是一个函数(you can see in the specification that nothing happens when a function declaration is evaluated(它们在那个时候已经被处理过) ).

函数表达式非常相似,但不是定义变量,而是简单地计算它的结果是函数对象。

这就是为什么

eval('function a() {}') // undefined, but a is defined as side effect
eval('(function a() {})') // a function object

产生不同的结果。第一个被解释为函数声明。将创建变量 a,但不会创建 eval 可以 return 的值。在第二种情况下,分组运算符(...))强制将函数定义解释为函数表达式,这意味着eval.

产生了一个值 return

现在关于箭头函数:这里没有歧义。箭头函数定义总是表达式,即对它们求值总是产生一个值。

eval(`() => {}`) // a function object

总结

虽然箭头函数和函数 declarations/expressions 之间存在差异,但这种差异并不是您在 eval 中看到的结果的原因。这里的区别是因为 evaling 一个 statement/declaration 和一个表达式。