JavaScript中匿名函数的占位符

时间:2014-06-12 05:51:36

标签: javascript scala d3.js

我一直在编写d3代码,最终会有很多这样的函数:

selection.attr('x', function(d) { return d.layout.x; });

有没有办法模拟Scala的占位符语法,这将允许我写这个:

selection.attr('x', _.layout.x);

显然,需要告诉getter要应用的特定参数名称,或者可以定义一种“meta-getter”,它使用获取所需命名属性的匿名函数进行响应。

我有兴趣知道是否存在类似这样的东西,例如CoffeeScript。 ES6 lambda函数更接近,但仍然不像占位符语法那样具有语义和清晰度。

2 个答案:

答案 0 :(得分:2)

你不能说出你希望它运行的环境,因此,假设the bleeding edge没问题,让我们使用Proxy

var _ = new Proxy({}, {
    get: function(target, name) {
        return createProxyForPath(name, []);
    }
});

function createProxyForPath(name, path) {
    var newPath = path.slice();
    newPath.push(name);
    return new Proxy({}, {
        get: function(target, name) {
            if (name !== "$") return createProxyForPath(name, newPath);
            return function getter(obj) {
                return newPath.reduce(function(prev, curr) {
                    return prev[curr];
                }, obj);
            };
        },
        apply: function(target, context, args) {
          // TODO: Preserve function calls and args here
        }
    });
}

您可以这样使用它:

> [{x: 1}, {x: 2}, {x: 3}].map(_.x.$)
[1, 2, 3]

它并不是Scala魔法下划线的完全替代品(例如,它现在不会捕获方法调用,因此您无法_.x.toString().slice(0, 3)执行此操作举个例子)。此外,它需要一个明确的$来表示链的末尾。但对于简单的吸气剂,它的效果非常好。

或者,如果您现在需要支持不是Firefox的浏览器,您可以编写sweet.js macro来生成getter:

// Via Daniel
macro _ {
  rule { . $m ... } => { function (value) { return value.$m ... } }
}

selection.attr('x', _.layout.x + 1);

将扩展为:

selection.attr('x', function(value) {
  return value.layout.x + 1;
});

(如果你自己在函数sweet.js do the right thing中使用value并将参数重命名为value$some-integer以避免匿名函数内的任何名称冲突。)

它确实处理方法调用,但当然这些方法都没有处理使用占位符,例如函数参数:

selection.attr('x', someFunction(_));

答案 1 :(得分:1)

这可以使用函数而不是对象进行模拟:

var getter = function(properties) {
  props = properties.split('.');
  return function(d) {
    return props.reduce(function(prev, curr) {
      return prev[curr];
    }, d);
  };
};

selection.attr('x', getter('layout.x'));

哪个......好吧,但我想知道JS能否做得更好。