功能Javascript书籍示例中的错误

时间:2013-10-28 05:06:03

标签: javascript functional-programming underscore.js

我正在阅读Michael Fogus的书 Functional JavaScript ,本书中的一个例子不起作用。这是代码:

function existy(x) {
    return x != null;
};

function truthy(x) {
    return (x !== false) && existy(x);
};

function cat() {
    var head = _.first(arguments);
    if (existy(head))
        return head.concat.apply(head, _.rest(arguments));
    else
        return [];
};

function construct(head, tail) {
    return cat([head], _.toArray(tail));
};

function rename(obj, newNames) {
    return _.reduce(newNames, function(o, nu, old) {
        console.log("o: " + o);
        console.log("nu: " + nu);
        console.log("old: " + old);
        if (_.has(obj, old)) {
            o[nu] = obj[old];
            return o;
        }
        else
            return o;
    },
    _.omit.apply(null, construct(old, _.keys(newNames))));
};

rename({a: 1, b: 2}, {'a': 'AAA'});
// => {AAA: 1, b: 2}

除rename()外,所有功能都能正常工作。本质上,它的目标是获取一个对象并返回具有使用newName对象更新的属性名称的对象。我并不完全理解它,但是reduce方法看起来并没有正确的参数。这是我调用rename()时得到的错误:

ReferenceError: old is not defined

任何有助于理解它不起作用的帮助都将非常感谢!

2 个答案:

答案 0 :(得分:3)

function rename(obj, newNames) {
    return _.reduce(newNames, function(o, nu, old) {
        console.log("o: " + o);
        console.log("nu: " + nu);
        console.log("old: " + old);
        if (_.has(obj, old)) {
            o[nu] = obj[old];
            return o;
        }
        else
            return o;
    },
    _.omit.apply(null, construct(old, _.keys(newNames))));
}

调用时,执行

_.reduce(newNames, function(o, nu, old) {
    console.log("o: " + o);
    console.log("nu: " + nu);
    console.log("old: " + old);
    if (_.has(obj, old)) {
        o[nu] = obj[old];
        return o;
    }
    else
        return o;
},
_.omit.apply(null, construct(old, _.keys(newNames))));

调用

_.omit.apply(null, construct(old, _.keys(newNames)))

old仅存在于_.reduce的回调中。如果它是第一个对象,您可以使用newNames[0]

但我不相信一本在函数定义之后添加分号的书......


就个人而言,如果我要实现“功能性”,它看起来像这样:

function objectMap(obj, func) {
    var result = {};

    for (var x in obj) {
        if (obj.hasOwnProperty(x)) {
            var r = func(x, obj[x]);
            result[r[0]] = r[1];
        }
    }

    return result;
}

function rename(obj, newNames) {
    return objectMap(obj, function(k, v) {
        return [newNames[k] || k, v];
    });
}

答案 1 :(得分:1)

Per @minitech,问题是“旧”只存在于_.reduce回调中,因此当它在_.omit函数中调用时,它超出了'old'的范围。事实证明,有一个简单的解决方案。如果你将'old'改为'obj'(这可能是作者的意图),该函数似乎正常工作并保留其功能性:

function rename(obj, newNames) {
    return _.reduce(newNames, function(o, nu, old) {
        if (_.has(obj, old)) {
            o[nu] = obj[old];
            return o;
        }
        else
            return o;
    },
    _.omit.apply(null, construct(obj, _.keys(newNames))));
}; 

rename({a: 1, b: 2}, {'a': 'AAA'});
// => {AAA: 1, b: 2} -> success!