今天来介绍我个人很常用的小撇步,关於 OR (||
) 与 AND (&&
),除了很单纯用来判断回传布林值,同时也可以拿来赋值哦!
但同时,这种方式也很容易因为意想不到的 truthy、falsy value,造成不如预期的结果,需要特别小心。
今天也会讲到与其息息相关的 Short Circuit Evaluation,可以大幅缩短判断式的长度,提高可读性。
今天就来看看,如何应用它们,以及实战容易踩到的地雷。
大概可以直翻成「短路取值」,好像应该先来了解一下「短路」:
最上面是电池,S 是开关,L 是灯泡,S 没有连通的情况下,电流只能够走 L;但当 S 接通了,电流可以选择走 S 或 L,肯定会选电阻比较小的 S,就会造成短路。
没错,物理课开始罗!想不到物理知识也可以应用在写程序呢!
说到短路,大部分人抱持负面印象,因为短路可能会造成火灾,或者造成电器损坏,甚至还有「脑袋短路」这种很有趣的说法。
但事实上,如果今天站在一个电子的立场来看,短路才是最正常的啊!因为短路其实就像字面上的意思,要走路的当然挑「短」的路,没事让自己这麽累干嘛?但短的路不一定轻松,所以更正确来说,是要找「电阻最小」的路。
那如果套用到写程序,要怎麽找到「阻碍最小」、「最轻松」的路呢?
那当然是让「运算愈少愈好」!
OR 运算子 (||
) 在一般的理解中,就是当「或」的概念在使用:
const hasVIPcard = false;
const money = 1500;
if (money > 1000 || hasVIPcard) {
console.log('尊荣会员');
}
比如上面这个例子,如果 money
大於 1000 或 hasVIPcard
为 true
,任何一个成立都可以是尊荣会员。
但是对於程序来说,既然「只要任何一个成立都可以」,那我当然走短路啊!
由左至右,任何一个判断式为
true
,就回传true
,後面就不执行了。
因此,上面的程序其实完全没有去读 hasVIPcard
的值,就已经进入第 4 行跑 console.log
了。
怎麽知道的呢?我们稍微改一下这个范例:
const isUserHasVipCard = () => {
console.log('是否有 VIP card?');
return false;
};
const money = 1500;
if (money > 1000 || isUserHasVipCard()) {
console.log('尊荣会员');
}
执行结果
尊荣会员
可以看到 isUserHasVipCard
这个函式完全没有进去,因为程序走「短路」,第一个判断式就知道答案了,何必再去执行第二个?
应用上述的原理,其实 OR 运算子不只能够用在判断式,也能够用在赋值(取值):
const fruit = 'orange' || 'apple';
const fruit2 = '' || 'apple';
console.log(fruit);
console.log(fruit2);
执行结果
orange
apple
很神奇吧!我们平常使用 ||
都是拿来「判断」,都是回传 boolean,结果这边居然可以回传字串!
原理其实跟上面的短路概念是类似的,挑最轻松的路走:
const result = a || b
如果 a
是 truthy value,就直接回传 a
,若否则回传 b
。相当於:
let result;
if (a) {
result = a;
} else {
result = b;
}
const result = a || b || c
如果 a
是 truthy value,就直接回传 a
,若否则看 b
是否为 truthy value,若否则回传 c
。相当於:
let result;
if (a) {
result = a;
} else if (b) {
result = b;
} else {
result = c;
}
想像你是个想要早点打卡下班的电脑程序,当然能少走一个 if 是一个啊!
有了上述的基础,我们对於「||
」有了全新的认识,透过 OR 的短路取值,经常被用在当作 default 值:
const arr = [
{ name: 'washing machine', price: 8000 },
{ name: 'TV' },
{ name: 'laptop', price: 25000 },
];
arr.reduce((sum, item) => {
const price = item.price || 0;
return sum + price;
}, 0);
执行结果
33000
第 8 行如果少了那个关键的 || 0
,跑出来的结果会直接变 NaN
哦!
如果今天网页上有个重点广告区:
const arr = [
{ name: 'washing machine', price: 8000, vip: false },
{ name: 'TV', price: 13500, vip: false },
{ name: 'laptop', price: 25000, vip: false },
];
const advertisement =
arr.filter(item => item.vip)[0] ||
arr.filter(item => item.price > 10000)[0] ||
arr[0];
console.log(advertisement.name);
执行结果
TV
以上是关於 OR 短路取值的应用,但使用这招时(尤其是当预设值时),需要特别注意这种「长得像 falsy 的 truthy」:
const fruitList = [] || ['apple', 'orange', 'banana'];
执行结果
[]
And 运算子 (&&
) 在一般的理解中,就是当「而且」的概念在使用:
const hasVIPcard = true;
const money = 500;
if (money > 1000 && hasVIPcard) {
console.log('尊荣又有钱的会员');
}
比如上面这个例子,如果 money
大於 1000 而且 hasVIPcard
为 true
,两个都要成立才会是尊荣又有钱的会员。
但是对於程序来说,既然「只要任何一个不成立就不是」,那我当然走短路啊!
由左至右,任何一个判断式为
false
,就回传false
,後面就不执行了。
因此,上面的程序其实完全没有去读 hasVIPcard
的值,就已经进入第 4 行跑 console.log
了。
怎麽知道的呢?我们稍微改一下这个范例:
const isUserHasVipCard = () => {
console.log('是否有 VIP card?');
return true;
};
const money = 500;
if (money > 1000 && isUserHasVipCard()) {
console.log('尊荣又有钱的会员');
}
执行结果
可以看到 isUserHasVipCard
这个函式完全没有进去,因为程序走「短路」,第一个判断式就知道答案了,何必再去执行第二个?
应用上述的原理,其实 And 运算子不只能够用在判断式,也能够用在赋值(取值):
const fruit = 'orange' && 'apple';
const fruit2 = '' && 'apple';
console.log(fruit);
console.log(fruit2);
执行结果
apple
很神奇吧!我们平常使用 &&
都是拿来「判断」,都是回传 boolean,结果这边居然可以回传字串!
原理其实跟上面的短路概念是类似的,挑最轻松的路走:
const result = a && b
如果 a
是 falsy value,就直接回传 a
,若否则回传 b
。相当於:
let result;
if (!a) {
result = a;
} else {
result = b;
}
const result = a && b && c
如果 a
是 falsy value,就直接回传 a
,若否则看 b
是否为 falsy value,若否则回传 c
。相当於:
let result;
if (!a) {
result = a;
} else if (!b) {
result = b;
} else {
result = c;
}
比起上面 OR 的版本,就只是多了一个惊叹号,将 boolean 反转而已!
有了上述的基础,我们对於「&&
」有了全新的认识,透过 AND 的短路取值,可以用来快速判断一个有很多层的(nested) object,取得指定的深层 property。
比如以下范例会出错:
const personList = [
{
height: 173,
weight: 63,
car: {
color: 'white',
price: 500000
}
},
{
height: 163,
weight: 55
}
];
personList.forEach(person => {
const carPrice = person.car.price;
console.log(carPrice);
});
执行结果
500000
Uncaught TypeError: Cannot read property 'price' of undefined
主要是因为有些 person
是没有 car
的,因此如果硬是取 price
有可能会出错。
可以改成用 &&
来协助取值:
const personList = [
{
height: 173,
weight: 63,
car: {
color: 'white',
price: 500000
}
},
{
height: 163,
weight: 55
}
];
personList.forEach(person => {
const carPrice = person && person.car && person.car.price;
if (carPrice) {
console.log(carPrice);
}
});
执行结果
500000
这样写,会在判断到 person.car
这个 falsy value 时,直接回传 undefined
,就不会继续找 person.car.price
了。
当然这样写起来是非常不美观的,如果只有一两层还可以这样写,若真的要很多层,也可以考虑使用第三方套件(如:lodash/get
)来代替。
今天介绍了大家原本应该很熟的 OR 与 AND,原来它们不只可以透过短路取值来提升效率,甚至还可以用这个方式,做到原本需要一堆 if else
才做得到的事情!
当然这中间是需要相当细心的,因为短路取值的判断根本,是用昨天讨论到的 truthy/falsy value,所以如果对於这两个概念不熟悉,很容易就会在短路取值上撞墙,务必好好学习这两天的内容,未来写的程序可以简化许多唷!
在真与假之中
拼凑未来的模样
<<: Day 20 中场休息,来做点酷东西(型别修正跟除点小虫)
>>: 【把玩Azure DevOps】Day23 CI/CD从这里:建立第一个Releases Pipeline
组合式哑铃 | 用过就回不去惹 | 还不快new一个~ ...
提升(Hoisting) 在 JavaScript 里指的是在执行代码之前,直译器(interpre...
我们每新增一个函式,浏览器都会向函式内新增一个属性叫 prototype function Per...
今天我们来配 OSPF。 OSPF 是一种 IGP (Interior Gateway Protoc...
今日练习档 ԅ( ¯་། ¯ԅ) 今天要来带大家认识两个与时间有关的函式,分别为TODAY()以及N...