【问题标题】:condense an if/else if statement using logical operators with javascript使用带有 javascript 的逻辑运算符压缩 if/else if 语句
【发布时间】:2017-06-07 23:29:38
【问题描述】:

我正在学习 AngularJS,尝试制作一个简单的计算器,我正在尝试浓缩这个 if/else if 语句到 1-2 行,使用 Javascript 逻辑运算符(&&||!

鉴于这个例子,我怎样才能减少它? (如果你不明白$scope,请忽略它。它基本上是一个视图。所以当有人点击9时,计算器会在答案屏幕上显示9)

$scope.setOperand = function (operandEntered) {

    if ($scope.leftOperand === null) {
        $scope.leftOperand = operandEntered;
    } 
    else if ($scope.operator === null) {
        $scope.leftOperand = $scope.leftOperand + operandEntered;
    } 
    else if ($scope.rightOperand === null) {
        $scope.rightOperand = operandEntered;
    } 
    else if ($scope.answer === null) {
        $scope.rightOperand = $scope.rightOperand + operandEntered;
    }
 };

【问题讨论】:

  • 为什么要这样做?它变得更难阅读和维护。编写尽可能短的代码绝对没有任何好处,因为您“可以”。顺便提一句。在现实世界中,代码会被 uglify 等工具缩小和优化,因此您应该尽可能以最易读的方式编写代码。
  • 我不知道我理解代码的逻辑。将其变为两行很容易,只需删除空格,直到它全部适合两行。

标签: javascript angularjs logical-operators


【解决方案1】:

一个人总是可以(尝试)变得聪明,但当代码变得更长且不可重用时,抽象并不总能得到回报。 KISS.

如果你愿意,我会选择

function addTo(property, x, operand) { // "x" for lack of a more meaningful name
    const shouldAdd = $scope[property] === null || $scope[x] === null;
    if (shouldAdd)
        $scope[property] += operand; // assuming "operand" is a number
// or   $scope[property] = ($scope[property] || "") + operand; // when it's a string
    return shouldAdd;
}
$scope.setOperand = function (operandEntered) {
    addTo("leftOperand", "operator", operandEntered) || addTo("rightOperand", "answer", operandEntered);
 };

如果您更关心简洁性而不是可读性,您甚至可以将助手缩短为

function addTo(property, x, operand) {
    return ($scope[property] === null || $scope[x] === null) && (($scope[property] += operand), true);
}

【讨论】:

  • 你介意看看我的回答吗?我不确定我是否匹配他们正在做的事情,尽管我试图解决它(主要是 $scope.answer 位)。
  • @JaredFarrish 是的,那些 answeroperator 位我也遇到了问题。不确定代码的真正意图是什么。
  • 意图是有一个计算,设置一个左操作数,一个运算符,然后是一个右操作数。抱歉,误解了。我有一个生成 $scope.answer 的 getAnswer 方法。我在答案部分的下面进一步发布了我的所有代码,以使其更有意义。该运算符还有一个 setOperator 方法,它可以生成 $scope.operator。这些都是很好的问题!太感谢了!它有助于知道我将来需要发布什么
【解决方案2】:

TLDR;

做出与以下相同的假设,这将起作用,当然非常简单:

$scope.setOperand = function (operand) {
    var prop = $scope['leftOperand'] === null ? 'leftOperand' : 'rightOperand';
    $scope[prop] = +$scope[prop] + operand;
};

关键是这部分:+$scope[prop] 这会将null 转换为 0,所以如果它是 null 或有值(这就是逻辑似乎是这样),你最终会将它添加到一侧或另一侧做)。 Bergi 指出,两个值的 nullnull 都没有处理,但我认为应该在其他地方进行计算:

$scope.calc = function(){
    return eval(
        +$scope.leftOperand         // Cast if null to 0
        + ($scope.operator || '+')  // Default to add if null
        +$scope.rightOperand‌        // Cast if null to 0
    );
};

假设您有一个左/右操作数(并且您没有尝试进行多项操作):

var $scope = {
    operator: '-',
    answer: null,
    leftOperand: null,
    rightOperand: 3,
};

我们可以从:

$scope.setOperand = function (operand) {
    var prop = ['leftOperand','rightOperand'].reduce(function(t, k) {
        return $scope[k] === null ? k : t;
    });
    $scope[prop] = +$scope[prop] + operand;
};

https://jsfiddle.net/w89dLrqw/

这是四行。我们可以通过一些小技巧来删除一行:

$scope.setOperand = function (operand) {
    [['leftOperand','rightOperand'].reduce(function(t, k) {
        return $scope[k] === null ? k : t;
    })].map(function(prop){$scope[prop] = +$scope[prop] + operand});
};

https://jsfiddle.net/b63x7aag/

或者,如果你愿意:

$scope.setOperand = function (operand) {
    [['leftOperand','rightOperand'].reduce(function(t, k) {return $scope[k] === null ? k : t;})]
    .map(function(prop){$scope[prop] = +$scope[prop] + operand});
};

还有一个(@bergi 的道具):

$scope.setOperand = function (operand) {
    (function(prop){$scope[prop] = +$scope[prop] + operand})
    (['leftOperand','rightOperand'].reduce(function(t, k){return !+$scope[k] ? k : t}));
};

https://jsfiddle.net/mh1bvhcj/1/

最后两个看起来缩小了,最后一个“颠倒”运行。我看不出这样写有什么用,因为它只占用很少的水平空间。

我不明白else if ($scope.answer === null) 的用途是什么,因为据我所知,拥有answer === null 似乎不会影响操作数。所以这可能会也可能不会起作用,这取决于那是关于什么的。

【讨论】:

  • 有趣。不过,它似乎没有涵盖根本没有分配任何东西的情况。另外我推荐一个简单的 IIFE 而不是 […].map(…)
  • 嗯。这不是评估操作的一部分吗?喜欢$scope.eval = function(){return eval(+$scope.leftOperand+$scope.operator+$scope.rightOperand)};
  • 我不知道我可以用 IIFE 把它全部塞进两三行。
  • 随便(function(prop){…})(['leftOperand','rightOperand'].reduce(…));
  • 您基本上可以在任何括号或大括号中任意插入换行符,以获得您想要的行数和格式感觉。我不是说它是单行的:-)
【解决方案3】:

嗯,有这种可能性:

$scope.setOperand=(operandEntered)=>{
    $scope.leftOperand=($scope.leftOperand===null)? // if
        operandEntered
        : // else if v
        ($scope.operator===null)?
            $scope.leftOperand+operandEntered
            : // else v
            (()=>{
                $scope.rightOperand=($scope.rightOperand===null)? // if
                    operandEntered
                    : // else if v
                    ($scope.answer===null)?
                        $scope.rightOperand+operandEntered
                        : // else v
                        $scope.rightOperand;
                return $scope.leftOperand;
            })();
};

然后缩短为:

$scope.setOperand=(operandEntered)=>{$scope.leftOperand=($scope.leftOperand===null)?operandEntered:($scope.operator===null)?$scope.leftOperand+operandEntered:(()=>{$scope.rightOperand=($scope.rightOperand===null)?operandEntered:($scope.answer===null)?$scope.rightOperand+operandEntered:$scope.rightOperand;return $scope.leftOperand;})();};

完全按照您的要求执行,并缩短每个 if/else if 语句。

【讨论】:

  • 问题是如何缩短它,而且如果他理解得更多,他也可以将它应用到其他东西上。
  • 这与 OP 中的代码不同。注意左右部分之间的else
  • 现在可以了,只是需要重新排列一些东西。
【解决方案4】:

我重新考虑过——你可以用一种方式让它变得更好,用另一种方式让它变得更糟。

对于这样的每个表达式:

$scope.leftOperand = $scope.leftOperand + operandEntered;

你可以使用赋值运算符:

$scope.leftOperand += operandEntered;

稍微缩短。

我已经重新重新考虑过。假设您实际上是在进行字符串连接以从输入的数字构建数字,我认为这就是您想要的(我确实跳过了“答案”条件,因为这是不应该发生的事情)。

$scope.setOperand = function (operandEntered) {
    var prop = ($scope.operator === null) ? 'leftOperand' : 'rightOperand';
    $scope[prop] = ($scope[prop] === null) ? operandEntered : $scope[prop]+operandEntered;
};

【讨论】:

  • 当然你可以这样做:var left = $scope.leftOperand*!$scope.operator; [$scope.leftOperand, $scope.rightOperand] = [left + operandEntered, !left && !$scope.answer*$scope.rightOperand + operandEntered || null]
  • 我不会认为!$scope.answer === null 的良好替代品——如果$scope.answer0 会怎样?
  • 是的,你说得对,应该这样做($scope.answer === null)*...。您可以通过按位运算轻松使其更安全和/或更小。但正如我在评论中所说,这样做没有任何好处。
  • @TEvon 我根据重新解释您的问题更改了答案。
  • 是的,这很好。我将其更改为空字符串。我更新了我的代码及其在上面的工作,我发布了一个答案并使用精简的 setOperand() 函数对其进行了更新,因此它没有 if、else if、else if、else if... 如果您看到任何其他调整或修改告诉我
【解决方案5】:

简短回答 - 所有代码都在我之前的回答中。已编辑,好走。

$scope.setOperand = function (operandEntered) {
        if ($scope.operator){
            $scope.rightOperand += operandEntered;
        }
        else {
            $scope.leftOperand += operandEntered;
        };
    };

【讨论】:

    【解决方案6】:

    ----------------已更新------------工作代码---- ---------------

    ** HTML **

    <!DOCTYPE html>
    <html lang="en-us" ng-app="calcApp" class="full-height">
    <head>
        <title>Hello World</title>
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <base href="/Tom-s-Journal/">
        <link rel='shortcut icon' type='image/x-icon' href='favicon.ico' />
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
        <link rel="stylesheet" href="JournalCSS.css">
    </head>
    
    
    <body class="full-height overflow-hidden" ng-cloak>
    
        <div class="theCalculator" ng-controller="calcCtrl" id="outsideCalcEdge">
            <div class="calcButtonsrow" id="1stLine">
                <div id="answerScreen">
                    <span>{{leftOperand}}</span> 
                    <span>{{operator}}</span> 
                    <span>{{rightOperand}}</span> 
                    <span>{{clear}}</span>
                </div>
            </div>
    
            <div class="calcButtonsrow" title="brand" id="brand">
                <span id="calcBrand">*Basic Calculator*</span><br>
                <span id="kogoSoftwareLLC">Kogo Software LLC</span>
            </div>
            <div class="calcButtonsrow" id="2ndLine">
                <button class="number" id="7" ng-click="setOperand('7')">7</button>
                <button class="number" id="8" ng-click="setOperand('8')">8</button>
                <button class="number" id="9" ng-click="setOperand('9')">9</button>
                <button id="divideBySign" ng-click="setOperator('/')" class=" operator">/</button>
            </div>
            <div class="calcButtonsrow" id="3rdLine">
                <button class="number" id="4" ng-click="setOperand('4')">4</button>
                <button class="number" id="5" ng-click="setOperand('5')">5</button>
                <button class="number" id="6" ng-click="setOperand('6')">6</button>
                <button id="multiplySign" ng-click="setOperator('*')" class=" operator">*</button>
            </div>
            <div class="calcButtonsrow" id="4thLine">
                <button class="number" id="1" ng-click="setOperand('1')">1</button>
                <button class="number" id="2" ng-click="setOperand('2')">2</button>
                <button class="number" id="3" ng-click="setOperand('3')">3</button>
                <button id="minusSign" ng-click="setOperator('-')" class=" operator">-</button>
    
            </div>
            <div class="calcButtonsrow" id="5thLine">
                <button id="clear" ng-click="setClear('C')">C</button>
                <button class="number" id="0" ng-click="setOperand('0')">0</button>
                <button id="equalSign" ng-click="getAnswer('=')" 
                ng-disabled="!leftOperand || !operator || !rightOperand">=</button>
                <button id="plusSign" ng-click="setOperator('+')" class=" operator">+</button>
            </div>
        </div>
    
    
        <script 
        src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js">
    </script>
    
    <script src="calculator.js"></script>
    
    </body>
    </html>
    

    AngularJS

    var calcApp = angular.module('calcApp', []);
    
    calcApp.controller('calcCtrl', function ($scope) {
        $scope.leftOperand = "";
        $scope.operator = "";
        $scope.rightOperand = "";
        $scope.answer = "";
    
    
        $scope.setOperand = function (operandEntered) {
            if ($scope.operator){
                $scope.rightOperand += operandEntered;
            }
            else {
                $scope.leftOperand += operandEntered;
            };
        };
        $scope.setOperator = function (operatorEntered) {
            $scope.operator = operatorEntered;
        };
    
        $scope.getAnswer = function () {
            var result = $scope.leftOperand + $scope.operator + $scope.rightOperand;
            var answer = eval(result);
            if (answer % 2 !== 0){
                $scope.answer = answer.toFixed(2);
            }
            else {$scope.answer = answer;}
    
            $scope.leftOperand = $scope.answer;
            $scope.operator = "";
            $scope.rightOperand = "";
        };
    
        $scope.setClear = function (a) {
            $scope.clear = location.reload();
        };
    
    
    });
        var windowProperties = "width=255,height=367,menubar=yes,location=no,resizable=no,scrollbars=no";
        var windowObjectReference = function openCalc() {
            window.open("/Tom-s-Journal/calculatorHTML.html", "calcWindow", windowProperties);
    };
    

    CSS

    @font-face {
        font-family: 'sickCalculatorFont';
        src: url('./calcFontFiles/digital-7.ttf');
    }
    #answerScreen {
        background-color: lightgray;
        border-style: inset;
        border-color: white;
        border-width:5px;
        font-family: 'sickCalculatorFont';
        font-size: 25px;
        font-weight: bold;
        height: 50px;
        padding-left: 3px;
        width: 215px;
    }
    
    button {
        border-radius: 10px;
        font-weight: bold;
        height: 50px;
        width: 50px;
    }
    
    
    
    #brand {
        color: #000;
        font-weight: bold;
        font-size: 11px;
        text-align: center;
    }
    
    .calcButtonsrow {
        padding: 5px;
    }
    
    #calcButtonsBox {
        border-style: groove;
    }
    
    #clear {
        background-color: #FFAAAA;
    }
    
    .overflow-hidden {
        overflow: hidden;
    }
    #divideBySign {
        border-radius: 10px;
        font-weight: bold;
        height: 50px;
        width: 50px;
    }
    #divideBySign:hover {
        background-color: #4CAF50;
        color: white;
    }
    
    #equalSign{
        color: #FA6800;
    }
    
    #kogoSoftwareLLC {
        color: grey;
        font-weight: bold;
    }
    
    #minusSign {
        border-radius: 10px;
        font-weight: bold;
        height: 50px;
        width: 50px;
    }
    #minusSign:hover {
        background-color: #4CAF50;
        color: white;
    }
    
    #modalCalcButt {
        height: 150px !important;
        width: 150px !important;
    }
    
    #multiplySign {
        border-radius: 10px;
        font-weight: bold;
        height: 50px;
        width: 50px;
    }
    #multiplySign:hover {
        background-color: #4CAF50;
        color: white;
    }
    
    
    .number:hover {
        background-color: yellow;
        color: black;
    }
    
    #outsideCalcEdge {
        border-style: solid;
        border-width: 3px;
        border-radius: 3px;
        margin-left: 2px;
        margin-bottom: 50px;
        padding: 10px;
        width: 250px;
    }
    
    .operator {
        color: white;
        background-color: #0E2F5C;
    }
    
    #plusSign {
        border-radius: 10px;
        font-weight: bold;
        height: 50px;
        width: 50px;
    }
    #plusSign:hover {
        background-color: #4CAF50;
        color: white;
    }
    
    .theCalculator {
        background-color: lightskyblue;
    }
    
    [disabled] {
        color: gray !important;
        /*            the id of #equalSign takes precedence over [disabled], !important over rides that*/
    }
    
    [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
        display: none !important;
    }
    

    【讨论】:

    • 感谢您对 JS 和 HTML 的澄清。 JS 只需要将它添加到最后一行“});”以避免“意外的输入结束”错误。
    • 我编辑了上面的帖子,所以它工作正常,没有错误,准备好了。
    【解决方案7】:

    鉴于 OP 提供的更新代码,现在单个语句就足够了 $scope.setOperand(),如下所示:

    $scope.setOperand = function (operandEntered) {
              $scope.operator
              ? $scope.rightOperand += operandEntered 
              : $scope.leftOperand += operandEntered;
        };
    

    简单的三元组解决了 OP 最初的关注点;请参阅 deno here

    我无法使用“C”按钮来清除显示,这可能是由于 codepen.io 上的配置方式,location.reload() 在那里可能是不允许的。所以,我重新编码了那个按钮,如下:

    $scope.setClear = function (a) {
    
              $scope.leftOperand = "";
              $scope.operator = "";
              $scope.rightOperand = "";
              $scope.answer = "";
    
        };
    

    查看演示here

    现在显示清除,无需等待页面重新加载。我所做的另一个更改如下:

    if (answer % 1 !== 0)
    

    这确保只有浮点值显示为小数。现在 1 + 2 等于 3 而不是 3.00。 (参考本资源:How do I check that a number is float or integer?

    【讨论】:

    • 不是两行。哈哈,开个玩笑。所以你是说这是一道经典的计算机科学课题?我将if 块逻辑解释为在空字段上设置操作数,或者,如果不为空,则添加到一侧,先离开
    • 您能否让 OP 的多个 if 语句代码用作计算器?如果是,那么您的解释可能是正确的。我只记得当我还是另一种语言的新手时,我的教授是 C。要求学生实现一个逆波兰符号计算器,它必须在 Windows 环境中执行。从下面显示 JS 和 HTML 的帖子来看,OP 显然有另一种计算器。
    猜你喜欢
    • 1970-01-01
    • 2019-05-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-01
    • 1970-01-01
    • 2021-05-30
    相关资源
    最近更新 更多