在JavaScript中,void,eval和Function构造函数之间有什么区别?

时间:2012-04-27 01:16:54

标签: javascript eval void ecmascript-5 function-constructor

void(document.body.innerText += 'hi')

eval(document.body.innerText +='\nbye')

Function(document.body.innerText += '\n!!!')

void(Function(function foo(){document.body.innerText += '\n>hi2'; return true}).toString())();

eval(Function(function foo(){document.body.innerText += '\nbye2'; return true}).toString())();

Function(Function(function foo(){document.body.innerText += '\n!!!2'; return true}).toString())();

在这些不同的语句中执行代码的处理模型是什么?

void(alert('hi'))
undefined

eval(alert('hi'))
undefined

Function(alert('hi'))
function anonymous() {
  undefined
}

eval(Function(function foo(){return true}).toString())();
TypeError: undefined is not a function

void(Function(function foo(){return true}).toString())();
TypeError: string is not a function

Function(Function(function foo(){return true}).toString())();
undefined

3 个答案:

答案 0 :(得分:3)

this article中解释了evalFunction构造函数:

  

(...)全局内置eval函数评估a范围内的代码   呼叫者

     

Function构造函数创建的函数内执行的代码   并不真正在全球范围内执行。但是,它不会执行   当地范围,这可能导致混乱。   Function构造函数创建一个范围链包含的函数   除了全局范围之外(在函数自己的激活之前)   对象,当然)。通过创建的函数中包含的任何代码   Function构造函数在该函数的范围内计算,而不是在   全球范围。但是,它几乎就像代码全局执行一样   全局对象是范围链中的下一个对象。

根据this pagevoid只返回undefined

  

在许多语言中,void是一种没有值的类型。在JavaScript中,   void是一个运算符,它接受一个操作数并返回undefined。这个   没有用,而且非常令人困惑。避免使用void

答案 1 :(得分:1)

答案 2 :(得分:0)

值得注意的是你完全滥用这些功能

  • void只是评估一些表达式并返回undefined。

    注意它是一个操作符而不是一个函数,所以不需要将操作符包装在括号内。

    如果您担心undefined可能被遮挡,或者您想要输入较少的字符,这仅对于获取未定义的值非常有用。

    而不是

    var undef = void(document.body.innerText += 'hi')
    

    更好地使用

    document.body.innerText += 'hi';
    var undef = void 0;
    

    如果您不需要定义,请不要使用void

  • eval应该用字符串调用。它将该字符串计算为代码。确切的行为取决于您是以严格模式还是以草率模式调用它,以及它是直接呼叫还是间接呼叫。

    如果你不用字符串调用它,它只会返回参数。

    在您的情况下,eval(document.body.innerText += '\nbye')将:

    1. 运行document.body.innerText += '\nbye',返回新值,例如"hello\nbye"
    2. 将结果文本评估为代码。很可能这会抛出。
    3. 我几乎确定eval(document.body.innerText +='\nbye')不是您想要的,但这是一个(不推荐)反例:

      
      
      var myvar = 0;
      var bye = 123
      eval(document.body.innerText += '\nbye');
      console.log(myvar); // 123
      
      myvar =
      
      
      

    4. Function构造函数基本上类似于eval,但它创建了一个函数,而不是立即将字符串作为代码运行。

      document.body.innerText += '\n!!!'无法返回有效字符串,因此只会抛出。

    5. 然后你有一些奇怪的混合这些功能。

      如果将函数传递给Function构造函数,它将被字符串化。 Function构造函数将返回一个匿名函数,该函数只声明一个类似参数的函数。这毫无意义。

      如果您拨打toString,则会对匿名函数进行字符串化。

      然后,void(Function(function foo(){document.body.innerText += '\n>hi2'; return true}).toString())();将尝试调用此字符串化。但字符串不可调用。错误。

      eval(Function(function foo(){document.body.innerText += '\nbye2'; return true}).toString())();将评估字符串化。为什么?但函数声明不会返回一个值,因此您将获得未定义的,这是不可调用的。错误。

      Function(Function(function foo(){document.body.innerText += '\n!!!2'; return true}).toString())();将字符串化foo,将其解析为匿名函数,对匿名函数进行字符串化,然后再将其解析为另一个匿名函数。请不要这样做。最后,调用将返回undefined,因为那里没有return语句。