5

我在十分钟内重新阅读了 Spencer Tipping 的优秀Javascript,我一生都无法弄清楚这个使用惰性作用域创建语法宏的示例中发生了什么:

var f = function () {return $0 + $1};  
var g = eval (f.toString ().replace (/\$(\d+)/g,  
           function (_, digits) {return 'arguments[' + digits + ']'}));  
g(5,6); // => 11 (except on IE)

尤其是,

  1. $0 和 $1 正在被函数定义所取代——如何评估函数?(大概是通过 eval(),但我没有看到这个)。
  2. 函数中单个下划线参数的目的是什么——如果我把它拿出来,代码就不再起作用了。大概它只是一个占位符,但为什么需要它呢?
4

2 回答 2

5

我在这里同意pst,这段代码非常可怕。这对于可读性来说是可怕的。不过,它很整洁:

  1. f被定义为一种占位符函数。它似乎是实际的 本身;数值变量在评估为g. 它们充当位置的可变参数,我们将在下面看到。
  2. g奇迹发生的地方:函数定义f被转换为字符串,宏定义中的数字变量f被替换为对索引参数的引用,因为定义中存在尽可能多的数字变量f(因此正则表达式和调用到replace)。之所以使用下划线,是因为我们不关心回调的第一个参数replace
  3. 然后整个事情被eval编辑,一次f基本上扩展到以下内容:

    function () { return arguments[0] + arguments[1] }
    

因此,它很简洁,因为您可以根据需要使用任意数量f的位置数字参数进行定义:

var f = function() { return $0 + $1 + $2 }

它会被评估为

function() { return arguments[0] + arguments[1] + arguments[2] }

整洁,但无用,可以说是危险的,不切实际的,难以阅读。我可能永远不会使用它。

于 2012-06-26T21:35:08.843 回答
5

那个代码吓到我了。完全不应该使用它。(除非有一些真正令人信服的理由这样做;我不知道有任何1 2。)此外,上面的代码中没有演示“函数式编程”,可能不包括回调的使用。但见鬼,即使 C 也可以轻松做到这一点,因为没有涉及到闭包。

_只是一个有效的标识符(如fooor_foo$0)。这里的 is 用于“不关心”(该值是整个匹配文本的值,因为该函数是 RegExp 匹配的“回调”)。

$0$1分别替换为arguments[0]arguments[1](记住这是函数“到字符串”值的文本替换!)。它可以在没有“宏”的情况下手动输入:

function () { return arguments[0] + arguments[1] }

或者我会做什么:

function (a,b) { return a + b }

其余的 ( Function.toStringand eval(functionStr)) 支持依赖于的“宏”东西是无稽之谈:Function -> codeString -> alteredCodeString -> Function.

此代码需要一个可以发出“原样”的工作。 Function.toString我不确定 IE 什么时候开始支持这个,但它似乎在 IE9 中工作。


1这是一个善意的谎言,但我使用这种方法的唯一地方涉及侧边栏小工具中的 IE,当弹出按钮被收回时,DOM 可能会“过早卸载”,以及尝试调用另一个函数时的一些其他混乱window语境。一个关于混乱的情况..

2函数式 JavaScript 库展示了没有 eval.

于 2012-06-26T21:30:39.363 回答