condense an if/else if statement using logical operators with javascript

…衆ロ難τιáo~ 提交于 2019-12-10 10:29:52

问题


I'm learning AngularJS, trying to make a simple calculator, and I'm trying to condense this if/else if statement to 1-2 lines, using the Javascript logical Operators (&&, ||, !)

Given this example, how could I reduce it? (if you don't understand $scope, ignore it. Its basically a view. So when someone clicks 9, the calculator will display 9 on the answer screen)

$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;
    }
 };

回答1:


One can always (try to) be clever, but abstraction doesn't always pay off when the code becomes longer and not more reusable. KISS.

But if you want to go for it, I'd choose

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);
 };

If you care more about conciseness than about readability, you can even shorten the helper to

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



回答2:


TLDR;

Making all the same assumptions as below, this will work and of course is dead simple:

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

The key is this part: +$scope[prop] That casts null to 0, so you end up adding it to one side or the other, if it's null or has a value (which is what the logic seems to do). Bergi pointed out that null and null for both values isn't handled, but I'd say the calculation should be done elsewhere:

$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
    );
};

Assuming you have one left/right operand (and you're not trying to do multiple operations):

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

We can start with:

$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/

Which is four lines. We can remove one line with a little hijinks:

$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/

Or, if you will:

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

And another one (props to @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/

That last two look minified, and that last one runs "upside-down". I can't see how this is useful to write it this way just so it takes up very little horizontal space.

What I don't understand is what the else if ($scope.answer === null) is in there for, since having answer === null doesn't seem like it would affect the operands as far as I can tell. So this may or may not work, depending on what that's about.




回答3:


Well there is this ppossibility where:

$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;
            })();
};

Which then shortens to this:

$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;})();};

Which does exactly as you asks, and shortens each if/else if statement.




回答4:


I reconsidered - you can make it a bit better in one way, and worse in another.

For each expression like this:

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

you can use the assignment operator:

$scope.leftOperand += operandEntered;

to shorten it slightly.

I have re-re-re-considered. Assuming you are actually doing string concatenation to build numbers from entered digits, I think this is what you want (I did skip over the 'answer' condition as something that shouldn't happen).

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



回答5:


short answer - all of the code is further above in a previous answer i made. edited, good to go.

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



回答6:


----------------------------UPDATED------------WORKING CODE-------------------

** 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;
}



回答7:


Given the updated code that the OP has provided, a single statement will now suffice for $scope.setOperand(), as follows:

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

The simple ternary addresses the original concern of the OP; see deno here.

I was unable to get the "C" button to clear the display which may be due to the way things are configured at codepen.io where location.reload() is perhaps not permissible there. So, I recoded that button, as follows:

$scope.setClear = function (a) {

          $scope.leftOperand = "";
          $scope.operator = "";
          $scope.rightOperand = "";
          $scope.answer = "";

    };

See demo here.

Now the displays clears and without any wait for a page reload. Another change I made is as follows:

if (answer % 1 !== 0)

This ensures that only floating point values display as decimals. Now 1 + 2 equals 3 instead of 3.00. (Consulted this resource: How do I check that a number is float or integer?)



来源:https://stackoverflow.com/questions/44424336/condense-an-if-else-if-statement-using-logical-operators-with-javascript

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!