使用 JavaScript 中的逻辑运算符压缩 if/else if 语句



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

鉴于此示例,我该如何减少它? (如果您不了解$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;
}
};

人们总是可以(尝试)聪明,但是当代码变得更长并且不能更可重用时,抽象并不总是有回报的。吻。

但如果你想去做,我会选择

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

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/

这是四行。我们可以删除一行带有一点 hijink:

$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似乎不会影响操作数。所以这可能有效,也可能无效,这取决于它是关于什么的。

嗯,有这种可能性:

$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 语句。

我重新考虑了一下 - 你可以以一种方式让它变得更好一点,而在另一种方式上更糟糕。

对于像这样的每个表达式:

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

简短的答案 - 所有代码都在我之前的答案中进一步增加。 已编辑,很好。

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

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

给定 OP 提供的更新代码,单个语句现在足以满足$scope.setOperand(),如下所示:

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

简单的三元解决了OP的原始关注点;请参阅此处的deno。

我无法让"C"按钮清除显示,这可能是由于 codepen.io 的配置方式,那里可能不允许location.reload()。 因此,我重新编码了该按钮,如下所示:

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

在此处查看演示。

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

if (answer % 1 !== 0)

这可确保只有浮点值显示为小数。 现在 1 + 2 等于 3 而不是 3.00。 (查阅此资源:如何检查数字是浮点数还是整数?

最新更新