Scala在Javascript中的“for comprehension”

时间:2014-03-07 15:53:27

标签: javascript scala underscore.js lodash

我已经习惯了Scala的“for”构造并喜欢它。我现在正在编写一些Javascript代码并使用Lo-Dash(基本上是Underscore的扩展)。有没有办法模仿Scala在javascript中的“for”理解?

我的目标是清理类似于此的map / reduce代码:

var rawCoordinates = _.map( directionsRoute.legs, function ( leg ) {
   return _.map( leg.steps, function ( step ) {
      return _.map( step.path, function ( latLng ) {
         return [ latLng.lng(), latLng.lat() ];
      } );
   } );
} );
var finalCoordinates = _.flatten( rawCoordinates, true );

在代码中,我正在生成[[coord1,coord2,coord3],[coord4,coord5]]格式的坐标数组,其中每个坐标为[39.5, -106.2](它是每个Google地图指示步骤的坐标数组。

在Scala中,同样的事情可以写成这样(如果我错了,请纠正我):

val stepCoordinates:List[List[Tuple2[Number,Number]]] = for {
   leg <- legs;
   step <- leg.steps;
   path <- step.path;
   latLng <- path
} yield (latLng.lng(), latLng.lat())

谢谢!

1 个答案:

答案 0 :(得分:2)

Javascript无法使用新的关键字或运算符进行扩展,但这些并不重要。我们可以使用通常的功能,它们可能看起来不那么好,但非常易读。下面是一个执行嵌套for循环的函数示例。

function deepMap(xs, path, fn) {
    function impl(xs, path, args) {
        var result = new Array(xs.length);
        if (path.length == 0) {
            for (var i = 0; i < xs.length; i++) {
                result[i] = fn.apply(null, args.concat([xs[i]]));
            }
            return result;
        } else {
            for (var i = 0; i < xs.length; i++) {
                result[i] = impl(xs[i][path[0]], path.slice(1), args.concat(xs[i]));
            }
            return result.reduce(function(x, y) {return x.concat(y)}, []);
        }
    }
    return impl(xs, path, []);
}

// for generating lat and long functions
function x(x) {return function() {return x}}

// sample data
var legs = [{
    steps: [{
        path: [{lat: x(1), lng: x(2)}]
    }, {
        path: [{lat: x(2), lng: x(3)}]
    }]
}, {
    steps: [{
        path: [{lat: x(3), lng: x(4)}]
    }, {
        path: [{lat: x(4), lng: x(5)}]
    }]
}];

// prints [ '(1, 2)', '(2, 3)', '(3, 4)', '(4, 5)' ]
console.log(deepMap(legs, ['steps', 'path'], function(leg, step, ll) {
    return "(" + ll.lat() + ", " +  ll.lng() + ")";
}));