2013-10-28 2 views
1

Я читаю книгу Майкла Фогуса Функциональный JavaScript, и один из примеров в книге не работает. Вот код:Ошибка в функциональном примере Javascript book

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. Я не совсем понимаю это полностью, но метод сокращения не похож на правильные аргументы. Вот ошибка я получаю, когда я звоню переименовать():

ReferenceError: old is not defined 

Любая помощь, чтобы понять, почему это не работает, было бы весьма признателен!

ответ

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 «s. Если бы это был первый объект, вы могли бы использовать 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]; 
    }); 
} 
+0

+1 «Я не доверяю книге, ставит точки с запятой после определения функций ... » –

+0

Спасибо! Любое предложение относительно того, как я должен это исправить? – EmptyArsenal

+0

@ EmptyArsenal: Я все еще не совсем уверен, что он делает. Требуется ли '{a: 52}' и '{a:" b "}' и создавать '{b: 52}'? – Ryan

1

Per @minitech, проблема в том, что «old» существует только в обратном вызове _.reduce, поэтому, когда он вызывается в функции _.omit, он выходит за рамки «старого». Оказывается, есть легкое решение. Если вы измените «старый» на «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! 
Смежные вопросы