避免Javascript

时间:2017-08-22 10:53:37

标签: javascript optimization functional-programming parameter-passing purely-functional

为了编写具有良好可读性的高质量代码,我采用currying functions方法并为大多数重复代码片段制作纯辅助函数。我刚观察到我的项目中到处都存在/类型检查,以避免任何可能的错误,例如type of undefined.

支票如下:

if (param){
 action...
}

我正在考虑创建一个应该采用两个参数的全局辅助函数;需要检查的paramaction function以便在检查通过时执行操作。类似的东西:

function isExist(param, action){
  if (param){
    action();
  }
}

此功能并非适用于所有代码段/案例。如何使其在所有情况下都高效且全局运行?这也是正确的方法。如果没有那么我在这里实现目标的最佳方法是什么?

示例

if (userInput){
  saveToDB(userInput);
}
if (valueFromDB){
  performSomeAction();
}
if (username && password){
  validate(username, password)
}

我希望我的代码中不同点的所有这些检查都被单个辅助函数替换为:

isExist( userInput, saveToDB(userInput) );
isExist( valueFromDB, performSomeAction );
isExist( (username && password), validate(username, password) );

通过这种方式,我们用三行代替了这9行代码。这就是我想要达到的目标。

4 个答案:

答案 0 :(得分:2)

好吧,如果你试着想出一个好名字

function isExist(param, action){
  if (param){
    action();
  }
}

然后我认为一个好的候选人将是conditionalExecute(condition, codeToExecute)。这种工作听起来很熟悉吗?你确定你不只是重新发明if语句吗?

也许我错过了你的观点,但我个人看不到封装if语句逻辑的好处比现在更多。

编辑:应该注意在Javascript的上下文中代码

if(someVariable){
  // do something
}

已经读过"如果someVariabletruthyundefined不是)那么....

但是可以肯定的是,如果你只是想检查是否存在(一个变量没有被定义),如果你说它有一个更明确的命名功能,那么我不会反对你。

在这种情况下,我认为仅仅封装实际存在检查(或者你想要检查的内容)更清楚,而不是条件性(因为我们已经有了if语句)。像

这样的东西
function exists(x) {
  return x !== undefined; // or something like that
}
function isNotNull(x) {
  //TODO:
}

然后您的代码将变得更加明确和可读,如果您愿意,您可以组合这些功能

function neitherUndefinedNorNull(x){
   return exists(x) && isNotNull(x);
}

if(neitherUndefinedNorNull(X)){
  // your "regular" code here
}

如果重复了if语句中的代码,那么也将其作为函数提取。

function myRepeatedCode() {
   // do stuff
}

function someAlternativeCondition(x){ 
  // test
}

if(neitherUndefinedNorNull ){
  myRepeatedCode();
} else if(someAlternativeCondition(x)) {
  myRepeatedCode();
}

// OR combine them in the same if-statement
if(neitherUndefinedNorNull(x) || someAlternativeCondition(x)){
  myRepeatedCode();
}

上次修改:如果你正在追逐角色,你甚至可以写

// because of short-circuiting, myFunc1 and myFunc2 will only
// execute if myCond1 resp myCond2  is true (or truthy).
myCond1(x) && myFunc1(x)
myCond2(y) && myFunc2(y)

答案 1 :(得分:2)

这是使用Maybe的理想场所:

const enumerable = true;

// data Maybe a = Nothing | Just a

const Maybe   = {};
const Nothing = Object.create(Maybe);
const Just    = value => Object.create(Maybe, {value: {enumerable, value}});

// instance Functor Maybe where

Nothing.map = _ => Nothing;
Maybe.map = function (fun) { return Just(fun(this.value)); };

// instance Applicative Maybe where

Maybe.of = Just;
Nothing.ap = _ => Nothing;
Maybe.ap = function (maybe) { return maybe.map(this.value); };

// instance Monad Maybe where

Nothing.chain = _ => Nothing;
Maybe.chain = function (kleisli) { return kleisli(this.value); };

Maybe 跟随Fantasy Land Specification [1] 。使用Maybe可以编写如下代码:

// userInput :: Maybe Data
// saveToDB  :: Data -> Something
userInput.map(saveToDB); // :: Maybe Something

// valueFromDB       :: Maybe Data
// performSomeAction :: Data -> Maybe Something
valueFromDB.chain(performSomeAction); // :: Maybe Something

// username :: Maybe String
// password :: Maybe Password
// validate :: String -> Password -> Something
Maybe.of(validate).ap(username).ap(password); // :: Maybe Something

无论如何,如果你真的对函数式编程感兴趣,那么我建议你Learn You A Haskell

[1] 我不同意flipping the arguments of ap上的幻想土地规范。

答案 2 :(得分:1)

怎么样,它可以同时处理参数。

function test(a,b,c)
{
    console.log("%s,%s,%s",a,b,c)
}

function check_and_run(param,action){
    var args = Array.prototype.slice.call(arguments); //turn arguments to array
    args.shift();  //remove param and action
    args.shift(); 
    if(param)
        action.apply(this,args)  
}


check_and_run(1,test,1,2,3)  //this will invoke test(1,2,3)
check_and_run(0,test,1,2,3)  //this will do nothing

答案 3 :(得分:1)

也许是这样的:

function conFun(fnCondition, fnCall, defaultResult=undefined) {
  return (...rest) => {
    if( fnCondition(...rest) ) {
      return fnCall(...rest)
    }
    return defaultResult;
  }
}

const add = conFun(
   (...rest) => rest.every(n => typeof n === 'number'),
   (...rest) => rest.reduce((a, n) => a+n), 
   NaN);

add("1", "2"); //=> NaN
add(1, 2);     //=> 3

所以在你的问题中,你可能会在第一个参数未被定义之后:

const firstDefined = (v) => typeof v !== 'undefined';
const cSomeFun = conFun(firstDefined, someFun, "");

cSomeFun(); // ==> ""
cSomeFun("test"); // ==> whatever someFun("test") returns

如果你只是想根据非未定义的参数调用某些东西,你可以简单地定义它:

function callDefined(fn, ...rest) {
  if( rest.every(firstDefined) ) {
    return fn(...rest)
  }
  return undefined;
}

callDefined( saveToDB.bind(this, userInput), userInput);
callDefined( performSomeAction, valueFromDB);
callDefined( calidate.bind(this, username, password), username, password);
相关问题